diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7093effc8fe0a..4ab15ee03420e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -36,6 +36,7 @@ /tmva/ @lmoneta /tree/ @pcanal /tutorials/ @couet +/tree/dataframe @dpiparo @bluehood # Projects that span over several code modules: /bindings/r/ @omazapa @@ -49,11 +50,8 @@ /core/multiproc/ @gganis /graf2d/qt/ @bellenot /graf2d/cocoa/ @TimurP -/graf2d/ios/ @TimurP /graf3d/eve/ @osschar /net/http/ @linev -/tree/treeplayer/**/TDataFrame.* @dpiparo @bluehood -/tree/treeplayer/**/TDF* @dpiparo @bluehood /cmake/ @amadio *.cmake @amadio diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c760d0fdb979..a3a0f59925297 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -426,8 +426,7 @@ if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_INSTALL_PREFIX) PATTERN "rootd.xinetd" EXCLUDE PATTERN "proofd.xinetd" EXCLUDE PATTERN "root.mimes" EXCLUDE - PATTERN "cmake" EXCLUDE - PATTERN "http" EXCLUDE ) + PATTERN "cmake" EXCLUDE ) install(DIRECTORY fonts/ DESTINATION ${CMAKE_INSTALL_FONTDIR}) install(DIRECTORY icons/ DESTINATION ${CMAKE_INSTALL_ICONDIR}) install(DIRECTORY macros/ DESTINATION ${CMAKE_INSTALL_MACRODIR}) diff --git a/README.md b/README.md index b0ba178d2c778..c97426c7e81b6 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,10 @@ acquisition, simulation and data analysis systems. |--------|------------|---------| | master | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-incremental-master)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-incremental-master/) | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-nightly-master)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-nightly-master/) | | master-noimt | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-incremental-master-noimt)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-incremental-master-noimt/) | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-nightly-master-noimt)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-nightly-master-noimt/) | -| v5-34-00-patches | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-incremental-v5-34-00-patches)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-incremental-v5-34-00-patches/) | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-nightly-v5-34-00-patches)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-nightly-v5-34-00-patches/) | +| v6-14-00-patches | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-incremental-v6-14-00-patches)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-incremental-v6-14-00-patches/) | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-nightly-v6-14-00-patches)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-nightly-v6-14-00-patches/) | +| v6-12-00-patches | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-incremental-v6-12-00-patches)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-incremental-v6-12-00-patches/) | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-nightly-v6-12-00-patches)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-nightly-v6-12-00-patches/) | | v6-10-00-patches | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-incremental-v6-10-00-patches)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-incremental-v6-10-00-patches/) | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-nightly-v6-10-00-patches)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-nightly-v6-10-00-patches/) | +| v5-34-00-patches | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-incremental-v5-34-00-patches)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-incremental-v5-34-00-patches/) | [![Build Status](https://epsft-jenkins.cern.ch/buildStatus/icon?job=root-nightly-v5-34-00-patches)](https://epsft-jenkins.cern.ch/view/ROOT/job/root-nightly-v5-34-00-patches/) | ## Cite We are [![DOI](https://zenodo.org/badge/10994345.svg)](https://zenodo.org/badge/latestdoi/10994345) diff --git a/README/CREDITS b/README/CREDITS index 7ba31a8c382f0..71ac2d8b48689 100644 --- a/README/CREDITS +++ b/README/CREDITS @@ -531,7 +531,7 @@ D: Integrating Minuit2 in Roofit and adding support for MPI N: Wim Lavrijsen E: WLavrijsen@lbl.gov -D: PyRoot package +D: PyROOT package, Cppyy package N: Kerry Lee E: kerry.t.lee@nasa.gov @@ -621,7 +621,7 @@ D: pioneer on many fronts, installation, support N: Pere Mato E: Pere.Mato@cern.ch -D: PyRoot package +D: PyROOT package D: cmake build system N: Richard Maunder @@ -917,7 +917,7 @@ D: Paint3DAlgorithms used by the LEGO and SURF options N: Enric Tejedor E: enric.tejedor@cern.ch -D: IO, Parallelisation, Jupyter integration, TDataFrame +D: IO, Parallelisation, Jupyter integration, TDataFrame, PyROOT N: Jan Therhaag E: therhaag@users.sourceforge.net diff --git a/README/ReleaseNotes/empty.md b/README/ReleaseNotes/empty.md index a204982959ee5..3e0a56b9cfe09 100644 --- a/README/ReleaseNotes/empty.md +++ b/README/ReleaseNotes/empty.md @@ -8,7 +8,7 @@ ROOT version 6.??/00 is scheduled for release in ???. For more information, see: -[http://root.cern.ch](http://root.cern.ch) +[http://root.cern](http://root.cern) The following people have contributed to this new version: diff --git a/README/ReleaseNotes/v614/index.md b/README/ReleaseNotes/v614/index.md index 41230dc8a44b5..6341511c5f79b 100644 --- a/README/ReleaseNotes/v614/index.md +++ b/README/ReleaseNotes/v614/index.md @@ -13,28 +13,44 @@ For more information, see: The following people have contributed to this new version: + Kim Albertsson, CERN/EP-ADP-OS,\ Guilherme Amadio, CERN/SFT,\ Bertrand Bellenot, CERN/SFT,\ Brian Bockelman, UNL,\ Rene Brun, CERN/SFT,\ Philippe Canal, FNAL,\ - David Clark, ANL (SULI),\ Olivier Couet, CERN/SFT,\ Gerri Ganis, CERN/SFT,\ Andrei Gheata, CERN/SFT,\ Enrico Guiraud, CERN/SFT,\ + Raphael Isemann, Chalmers Univ. of Tech.,\ + Vladimir Ilievski, GSOC 2017,\ Sergey Linev, GSI,\ - Timur Pocheptsov, CERN/SFT,\ Pere Mato, CERN/SFT,\ Lorenzo Moneta, CERN/SFT,\ Axel Naumann, CERN/SFT,\ Danilo Piparo, CERN/SFT,\ Fons Rademakers, CERN/SFT,\ Enric Tejedor Saavedra, CERN/SFT,\ - Peter van Gemmeren, ANL,\ - Vassil Vassilev, Princeton/CMS,\ Oksana Shadura, UNL,\ - Wouter Verkerke, NIKHEF/Atlas, RooFit + Saurav Shekhar, GSOC 2017,\ + Xavier Valls Pla, UJI, CERN/SFT,\ + Vassil Vassilev, Princeton/CMS,\ + Wouter Verkerke, NIKHEF/Atlas, RooFit,\ + Stefan Wunsch, CERN/SFT, \ + Zhe Zhang, UNL + +## Important Notice + +The default compression algorithm used when writing ROOT files has been updated to use LZ4 in particular to improve read (decompression) performance. You can change this default for each file through (for example) the `TFile constructor` or `TFile::SetCompressionAlgorithm`. + +It should be noted that ROOT files written with LZ4 compression can not be read with older release of ROOT. Support for LZ4 was however back-ported to the patch branches of previous releases and the following tags (and later release in the same patch series) can read ROOT files written with LZ4 compression: + +* v5.34/38 +* v6.08/06 [not yet released] +* v6.10/08 +* v6.12/02 + ## Removed interfaces @@ -45,16 +61,30 @@ The following people have contributed to this new version: - In `TClingCallFunc`, support r-value reference parameters. This paves the way for the corresponding support in PyROOT (implemented now in the latest Cppyy). - Included the new TSequentialExecutor in ROOT, sharing the interfaces of TExecutor.This should improve code economy when providing a fallback for TThreadExecutor/TProcessExecutor. +### Thread safety + - Resolved several race conditions, dead-locks, performance and order of initialization/destruction issues still lingering because of or despite the new read-write lock mechanism. + +## Interpreter + + - Enabled use of multi-threaded code from the interpreter. + - Previouslyl multi-threaded code could be run from the interpreter as long as the call starting the threada was the same code that initialized the ROOT global lock, any other uses, including attempting to run the same code a second time in the same session would lead to a dead lock (if any other thread attempted to take on the ROOT lock). + - The interpreter now suspend the ROOT lock (which is taken to protect the interpreter global state) during user code execution. + ## I/O Libraries - LZ4 (with compression level 4) is now the default compression algorithm for new ROOT files (LZ4 is lossless data compression algorithm that is focused on compression and decompression speed, while in ROOT case providing benefit in faster decompression at the price of a bit worse compression ratio comparing to ZLIB) + - If two or more files have an identical streamer info record, this is only treated once therewith avoiding to take the global lock. + - Allow writing temporary objects (with same address) in the same TBuffer(s). A new flag to TBuffer*::WriteObject allows to skip the mechanism that prevent the 2nd streaming of an object. This allows the (re)use of temporary objects to store different data in the same buffer. + - Reuse branch proxies internally used by TTreeReader{Value,Array} therewith increasing performance when having multiple readers pointing to the same branch. - Implement reading of objects data from JSON - Provide TBufferJSON::ToJSON() and TBufferJSON::FromJSON() methods - Provide TBufferXML::ToXML() and TBufferXML::FromXML() methods - Converts NaN and Infinity values into null in JSON, there are no other direct equivalent ## TTree Libraries + - Enable the TTreeCache by default of `TTree::Draw`, `TTreeReader` and `RDataFrame` + - Significant enhancement in the `TTreeCache` filling algorithm to increase robustness in case of oddly clustered `TTree` and under provisioned cache size. See the [merge request](https://github.com/root-project/root/pull/1960) for more details. - Proxies are now properly re-used when multiple TTreeReader{Value,Array}s are associated to a single branch. Deserialisation is therefore performed once. This is an advantage for complex TDataFrame graphs. - - Add TBranch::BackFill to allowing the addition of new branches to an existing tree and keep the new basket clustered in the same way as the rest of the TTree. Use with the following pattern, + - Add TBranch::BackFill to allow the addition of new branches to an existing tree and keep the new basket clustered in the same way as the rest of the TTree. Use with the following pattern, make sure to to call BackFill for the same entry for all the branches consecutively: ``` for(auto e = 0; e < tree->GetEntries(); ++e) { // loop over entries. @@ -66,8 +96,16 @@ The following people have contributed to this new version: ``` Since we loop over all the branches for each new entry all the baskets for a cluster are consecutive in the file. -### TDataFrame - - Histograms and profiles returned by TDataFrame (e.g. by a Histo1D action) are now not associated to a ROOT directory (their fDirectory is a nullptr). +### RDataFrame (formerly TDataFrame) +#### Behaviour, interface and naming changes + - `TDataFrame` and `TDataSource` together with their federation of classes have been renamed according to the coding conventions for new interfaces and extracted from the `Experimental` namespace: they can now be found in the ROOT namespace and they are called `ROOT::RDataFrame` and `ROOT::RDataSource`. + - `ROOT::Experimental::TDF::TResultProxy` has been renamed to `ROOT::RDF::RResultPtr`. + - `Report` now behaves identically to all other actions: it executes lazily and returns a `RResultPtr` (see the `New features` section for more details). + - `Snapshot` now returns a `RResultPtr` like all other actions: specifically, this is a pointer to a new `RDataFrame` which will run on the snapshotted dataset. + - `RDataFrame` has been removed from tree/treeplayer and put in its own package, tree/dataframe. The library where this code can be found is `libROOTDataFrame`. This new library is included in the list provided by `root-config --libs`. + - The `TArrayBranch` class has been removed and replaced by the more powerful `RVec` (see the `New features` section for more details). + - All `RDataFrame` tutorials are now prefixed with `df` rather than `tdf`. + - Histograms and profiles returned by RDataFrame (e.g. by a Histo1D action) are now not associated to a ROOT directory (their fDirectory is a nullptr). The following still works as expected: ``` auto h = tdf.Histo1D("x"); @@ -110,12 +148,30 @@ Since we loop over all the branches for each new entry all the baskets for a clu ## Histogram Libraries - - Per object statsoverflow flag has been added. This change is required to prevent non reproducible behaviours in a multithreaded environments. For example, if several threads change the `TH1::fgStatOverflows` flag and fill histograms, the behaviour will be undefined. + - Per object statsoverflow flag has been added. This change is required to prevent non reproducible behaviours in a multithreaded environments. For example, if several threads change the + `TH1::fgStatOverflows` flag and fill histograms, the behaviour will be undefined. + - A fix has been added in resetting the statistics of histograms with label. The bug was causing the histogram entries to be set as zero and this was making failing the merging of those + histogram (see ROOT-9336). ## Math Libraries + ## RooFit Libraries +- A fix has been added in the component selection, which is used for plotting simultaneous models. See [PR #2033](https://github.com/root-project/root/pull/2033). + +## TMVA Library + +#### New Deep Learning Module + + - TMVA contains a new set of Deep Learning classes ( `MethodDL` ), with support, in addition to dense layer, also convolutional and recurrent layer. + +#### Other New TMVA Features + +- Support for Parallelization of BDT using Multi-Threads +- Several improvements in Cross Validation including support for Multi-Process cross-validation running. + + ## 2D Graphics Libraries - `TMultiGraph::GetHistogram` now works even if the multigraph is not drawn. Make sure it never returns a null pointer. @@ -167,6 +223,7 @@ Since we loop over all the branches for each new entry all the baskets for a clu - Make EnableImplicitMT no-op if IMT is already on - Decompress `TTreeCache` in parallel if IMT is on (upgrade of the `TTreeCacheUnzip` class). - In `TTreeProcessorMT` delete friend chains after the main chain to avoid double deletes. + - If IMT is enabled, the multithreaded execution of the fit respects the number of threads IMT has been initialized with. ## Language Bindings @@ -233,48 +290,28 @@ Upgrade JSROOT to v5.4.1. Following new features implemented: ## Build System and Configuration -CMake exported targets now have the `INTERFACE_INCLUDE_DIRECTORIES` property set -([ROOT-8062](https://sft.its.cern.ch/jira/browse/ROOT-8062)). - -The `-fPIC` compile flag is no longer propagated to dependent projects via -`CMAKE_CXX_FLAGS` ([ROOT-9212](https://sft.its.cern.ch/jira/browse/ROOT-9212)). - -Several builtins have updated versions: - -- OpenSSL was updated from 1.0.2d to 1.0.2.o (latest lts release, - [ROOT-9359](https://sft.its.cern.ch/jira/browse/ROOT-9359)) -- Davix was updated from 0.6.4 to 0.6.7 (support for OpenSSL 1.1, - [ROOT-9353](https://sft.its.cern.ch/jira/browse/ROOT-9353)) -- Vdt has been updated from 0.3.9 to 0.4.1 (includes new atan function) -- XRootd has been updated from 4.6.1 to 4.8.2 (for GCC 8.x support) -- Builtin TBB can now be used on Windows -- xxHash and LZ4 have been separated so that a system version of LZ4 - can be used even if it does not include xxHash headers - ([ROOT-9099](https://sft.its.cern.ch/jira/browse/ROOT-9099)) - -In addition, several updates have been made to fix minor build system issues, -such as not checking for external packages if their builtin is turned off, or -checking for packages even when the respective option is disabled -([ROOT-8806](https://sft.its.cern.ch/jira/browse/ROOT-8806), -[ROOT-9190](https://sft.its.cern.ch/jira/browse/ROOT-9190), -[ROOT-9315](https://sft.its.cern.ch/jira/browse/ROOT-9315), -[ROOT-9385](https://sft.its.cern.ch/jira/browse/ROOT-9385)). - -The `python3` option to CMake has been removed -([ROOT-9033](https://sft.its.cern.ch/jira/browse/ROOT-9033), -[ROOT-9143](https://sft.its.cern.ch/jira/browse/ROOT-9143)). Python support is -enabled by default. To configure ROOT to use specific Python versions, there is -a new option called `python_version`. This is how to configure ROOT and Python -for the common use cases: - -* Use the default Python interpreter: - - `-Dpython=ON` (default) -* Search only for Python 2.x or only 3.x: - - `-Dpython_version=2` or `-Dpython_version=3` -* Use a specific version of Python from `$PATH`: - - `-Dpython_version=2.7` or `-Dpython_version=3.5` -* Use a specific Python interpreter, whatever the version: - - `-DPYTHON_EXECUTABLE=/usr/local/bin/python` + - ROOT can now be built against an externally built llvm and clang (llvm can be used unpatched, clang still require ROOT specific patches). The options are builtin_llvm and builtin_clang both defaulting to ON. + - Update RConfigure.h with R__HAS__VDT if the package is found/builtin + - CMake exported targets now have the `INTERFACE_INCLUDE_DIRECTORIES` property set ([ROOT-8062](https://sft.its.cern.ch/jira/browse/ROOT-8062)). + - The `-fPIC` compile flag is no longer propagated to dependent projects via `CMAKE_CXX_FLAGS` ([ROOT-9212](https://sft.its.cern.ch/jira/browse/ROOT-9212)). + - Several builtins have updated versions: + - OpenSSL was updated from 1.0.2d to 1.0.2.o (latest lts release, [ROOT-9359](https://sft.its.cern.ch/jira/browse/ROOT-9359)) + - Davix was updated from 0.6.4 to 0.6.7 (support for OpenSSL 1.1, [ROOT-9353](https://sft.its.cern.ch/jira/browse/ROOT-9353)) + - Vdt has been updated from 0.3.9 to 0.4.1 (includes new atan function) + - XRootd has been updated from 4.6.1 to 4.8.2 (for GCC 8.x support) + - Builtin TBB can now be used on Windows + - xxHash and LZ4 have been separated so that a system version of LZ4 can be used even if it does not include xxHash headers ([ROOT-9099](https://sft.its.cern.ch/jira/browse/ROOT-9099)) + - In addition, several updates have been made to fix minor build system issues, such as not checking for external packages if their builtin is turned off, or checking for packages even when the respective option is disabled ([ROOT-8806](https://sft.its.cern.ch/jira/browse/ROOT-8806), [ROOT-9190](https://sft.its.cern.ch/jira/browse/ROOT-9190), [ROOT-9315](https://sft.its.cern.ch/jira/browse/ROOT-9315), [ROOT-9385](https://sft.its.cern.ch/jira/browse/ROOT-9385)). + - The `python3` option to CMake has been removed ([ROOT-9033](https://sft.its.cern.ch/jira/browse/ROOT-9033), [ROOT-9143](https://sft.its.cern.ch/jira/browse/ROOT-9143)). Python support is enabled by default. To configure ROOT to use specific Python versions, there is a new option called `python_version`. This is how to configure ROOT and Python for the common use cases: + + * Use the default Python interpreter: + - `-Dpython=ON` (default) + * Search only for Python 2.x or only 3.x: + - `-Dpython_version=2` or `-Dpython_version=3` + * Use a specific version of Python from `$PATH`: + - `-Dpython_version=2.7` or `-Dpython_version=3.5` + * Use a specific Python interpreter, whatever the version: + - `-DPYTHON_EXECUTABLE=/usr/local/bin/python` Note: The use of `PYTHON_EXECUTABLE` requires the full path to the interpreter. diff --git a/README/ReleaseNotes/v616/index.md b/README/ReleaseNotes/v616/index.md index 19fa7df446156..30229bc94d002 100644 --- a/README/ReleaseNotes/v616/index.md +++ b/README/ReleaseNotes/v616/index.md @@ -1,14 +1,14 @@ -% ROOT Version ?.?? Release Notes -% 20??-??-?? +% ROOT Version 6.16 Release Notes +% 2018-06-25 ## Introduction -ROOT version 6.??/00 is scheduled for release in ???. +ROOT version 6.16/00 is scheduled for release end of 2018. For more information, see: -[http://root.cern.ch](http://root.cern.ch) +[http://root.cern](http://root.cern) The following people have contributed to this new version: @@ -29,15 +29,48 @@ The following people have contributed to this new version: Vassil Vassilev, Princeton/CMS,\ Wouter Verkerke, NIKHEF/Atlas, \ Jan Musinsky, SAS Kosice + Enrico Guiraud, CERN, \ + Massimo Tumolo, Politecnico di Torino + +## Deprecation and Removal + +### Ruby bindings + +The ruby binding has been unmaintained for several years; it does not build with current ruby versions. +Given that this effectively meant that Ruby was dysfunctional and given that nobody (but package maintainers) has complained, we decided to remove it. + +### Removal of previously deprecated or disabled packages + +The packages `afs`, `chirp`, `glite`, `sapdb`, `srp` and `ios` have been removed from ROOT. +They were deprecated before, or never ported from configure, make to CMake. + ## Core Libraries +### Fish support for thisroot script + +`. bin/thisroot.fish` sets up the needed ROOT environment variables for one of the ROOT team's favorite shells, the [fish shell](https://fishshell.com/). + +### Change of setting the compression algorithm in `rootrc` + +The previous setting called `ROOT.ZipMode` is now unused and ignored. +Instead, use `Root.CompressionAlgorithm` which sets the compression algorithm according to the values of [ECompression](https://root.cern/doc/master/Compression_8h.html#a0a7df9754a3b7be2b437f357254a771c): + +* 0: use the default value of `R__ZipMode` (currently selecting LZ4) +* 1: use zlib (the default until 6.12) +* 2: use lzma +* 3: legacy, please don't use +* 4: LZ4 (the current default) + ## I/O Libraries ## TTree Libraries - +### RDataFrame + - Optimise the creation of the set of branches names of an input dataset, + doing the work once and caching it in the RInterface. + - Add StdDev action ## Histogram Libraries @@ -62,9 +95,14 @@ The following people have contributed to this new version: the "gs" command (https://ghostscript.com). Example: + ~~~ {.cpp} canvas->Print("example.pdf","EmbedFonts"); ~~~ + - In TAttAxis::SaveAttributes` take into account the new default value for `TitleOffset`. + - When the histograms' title's font was set in pixel the position of the + `TPaveText` containing the title was not correct. This problem was reported + [here](https://root-forum.cern.ch/t/titles-disappear-for-font-precision-3/). ## 3D Graphics Libraries diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index 1c74e6e4e9f2c..3caed6ded3a6c 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -1,5 +1,9 @@ if(python) - add_subdirectory(pyroot) + if(NOT pyroot_experimental) + add_subdirectory(pyroot) + else() + add_subdirectory(pyroot_experimental) + endif() endif() if(ruby) add_subdirectory(ruby) diff --git a/bindings/pyroot/src/Pythonize.cxx b/bindings/pyroot/src/Pythonize.cxx index 8eb4e46da4275..0c4817217f13a 100644 --- a/bindings/pyroot/src/Pythonize.cxx +++ b/bindings/pyroot/src/Pythonize.cxx @@ -48,6 +48,7 @@ #include #include #include +#include #include #include // only needed for Cling TMinuit workaround @@ -2262,6 +2263,23 @@ namespace { return BindCppObject( addr, (Cppyy::TCppType_t)Cppyy::GetScope( "TObject" ), kFALSE ); } + //- Pretty printing with cling::PrintValue + PyObject *ClingPrintValue(ObjectProxy *self) + { + PyObject *cppname = PyObject_GetAttrString((PyObject *)self, "__cppname__"); + if (!PyROOT_PyUnicode_Check(cppname)) + return 0; + std::string className = PyROOT_PyUnicode_AsString(cppname); + Py_XDECREF(cppname); + + std::string pprint; + std::stringstream calcPrintValue; + calcPrintValue << "*((std::string*)" << &pprint << ") = cling::printValue((" << className << "*)" + << self->GetObject() << ");"; + gInterpreter->Calc(calcPrintValue.str().c_str()); + return PyROOT_PyUnicode_FromString(pprint.c_str()); + } + //- Adding array interface to classes --------------- void AddArrayInterface(PyObject *pyclass, PyCFunction func) { @@ -2331,9 +2349,12 @@ Bool_t PyROOT::Pythonize( PyObject* pyclass, const std::string& name ) if ( pyclass == 0 ) return kFALSE; -//- method name based pythonization -------------------------------------------- + // add pretty printing + Utility::AddToClass(pyclass, "__str__", (PyCFunction)ClingPrintValue); + + //- method name based pythonization -------------------------------------------- -// for smart pointer style classes (note fall-through) + // for smart pointer style classes (note fall-through) if ( HasAttrDirect( pyclass, PyStrings::gDeref ) ) { Utility::AddToClass( pyclass, "__getattr__", (PyCFunction) DeRefGetAttr, METH_O ); } else if ( HasAttrDirect( pyclass, PyStrings::gFollow ) ) { diff --git a/bindings/pyroot/test/CMakeLists.txt b/bindings/pyroot/test/CMakeLists.txt index 2da5c0240e398..4530e911d5dc9 100644 --- a/bindings/pyroot/test/CMakeLists.txt +++ b/bindings/pyroot/test/CMakeLists.txt @@ -3,5 +3,6 @@ ROOT_ADD_PYUNITTEST(pyroot_list_initialization list_initialization.py) if(NUMPY_FOUND) ROOT_ADD_PYUNITTEST(pyroot_array_interface array_interface.py) ROOT_ADD_PYUNITTEST(pyroot_ttree_asmatrix ttree_asmatrix.py) + ROOT_ADD_PYUNITTEST(pyroot_pretty_printing pretty_printing.py) endif() diff --git a/bindings/pyroot/test/pretty_printing.py b/bindings/pyroot/test/pretty_printing.py new file mode 100644 index 0000000000000..63addb52e19d1 --- /dev/null +++ b/bindings/pyroot/test/pretty_printing.py @@ -0,0 +1,55 @@ +import unittest +import ROOT + + +class PrettyPrinting(unittest.TestCase): + # Helpers + def _print(self, obj): + print("print({}) -> {}".format(obj.__cppname__, obj)) + + # Tests + def test_RVec(self): + x = ROOT.VecOps.RVec("float")(4) + for i in range(x.size()): + x[i] = i + self._print(x) + self.assertIn("{ 0", x.__str__()) + + def test_STLVector(self): + x = ROOT.std.vector("float")(4) + for i in range(x.size()): + x[i] = i + self._print(x) + self.assertIn("{ 0", x.__str__()) + + def test_STLMap(self): + x = ROOT.std.map("string", "int")() + for i, s in enumerate(["foo", "bar"]): + x[s] = i + self._print(x) + self.assertIn("foo", x.__str__()) + self.assertIn("bar", x.__str__()) + + def test_STLPair(self): + x = ROOT.std.pair("string", "int")("foo", 42) + self._print(x) + self.assertIn("foo", x.__str__()) + + def test_TNamed(self): + x = ROOT.TNamed("name", "title") + self._print(x) + self.assertEqual("Name: name Title: title", x.__str__()) + + def test_TObject(self): + x = ROOT.TObject() + self._print(x) + self.assertEqual("Name: TObject Title: Basic ROOT object", x.__str__()) + + def test_TH1F(self): + x = ROOT.TH1F("name", "title", 10, 0, 1) + self._print(x) + self.assertEqual("Name: name Title: title NbinsX: 10", x.__str__()) + + +if __name__ == '__main__': + unittest.main() diff --git a/bindings/pyroot_experimental/CMakeLists.txt b/bindings/pyroot_experimental/CMakeLists.txt new file mode 100644 index 0000000000000..0f9a014ddae6d --- /dev/null +++ b/bindings/pyroot_experimental/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(cppyy) +add_subdirectory(PyROOT) diff --git a/bindings/pyroot_experimental/PyROOT/CMakeLists.txt b/bindings/pyroot_experimental/PyROOT/CMakeLists.txt new file mode 100644 index 0000000000000..e7152f521373d --- /dev/null +++ b/bindings/pyroot_experimental/PyROOT/CMakeLists.txt @@ -0,0 +1,23 @@ +set(py_sources + ROOT/__init__.py + ROOT/pythonization/__init__.py + ROOT/pythonization/_ttree.py +) + +set(sources + src/PyROOTModule.cxx + src/PyROOTStrings.cxx + src/PyROOTWrapper.cxx + src/TTreePyz.cxx +) + +file(COPY python/ROOT DESTINATION ${localruntimedir}) +install(DIRECTORY python/ROOT DESTINATION ${runtimedir}) + +set(d $ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/${runtimedir}) +foreach(py_source ${py_sources}) + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile ${d}/${py_source})") + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile ${d}/${py_source})") +endforeach() + +ROOT_LINKER_LIBRARY(ROOTPython ${sources} LIBRARIES Core Tree cppyy) diff --git a/bindings/pyroot_experimental/PyROOT/python/ROOT/__init__.py b/bindings/pyroot_experimental/PyROOT/python/ROOT/__init__.py new file mode 100644 index 0000000000000..31a05455a783f --- /dev/null +++ b/bindings/pyroot_experimental/PyROOT/python/ROOT/__init__.py @@ -0,0 +1,27 @@ + +import cppyy +import ROOT.pythonization as pyz + +import pkgutil +import importlib + +def pythonization(fn): + """ + Pythonizor decorator to be used in pythonization modules. + + Parameters + ---------- + fn : function + Function that implements some pythonization. + The function must accept two parameters: the class + to be pythonized and the name of that class. + """ + cppyy.py.add_pythonization(fn) + +# Trigger the addition of the pythonizations +for _, module_name, _ in pkgutil.walk_packages(pyz.__path__): + module = importlib.import_module(pyz.__name__ + '.' + module_name) + +# Redirect ROOT to cppyy.gbl +import sys +sys.modules['ROOT'] = cppyy.gbl diff --git a/bindings/pyroot_experimental/PyROOT/python/ROOT/pythonization/__init__.py b/bindings/pyroot_experimental/PyROOT/python/ROOT/pythonization/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/bindings/pyroot_experimental/PyROOT/python/ROOT/pythonization/_ttree.py b/bindings/pyroot_experimental/PyROOT/python/ROOT/pythonization/_ttree.py new file mode 100644 index 0000000000000..5853e4edf1b0e --- /dev/null +++ b/bindings/pyroot_experimental/PyROOT/python/ROOT/pythonization/_ttree.py @@ -0,0 +1,33 @@ + +from libROOTPython import PythonizeTTree + +from ROOT import pythonization + +# TTree iterator +def _TTree__iter__(self): + i = 0 + bytes_read = self.GetEntry(i) + while 0 < bytes_read: + yield self + i += 1 + bytes_read = self.GetEntry(i) + + if bytes_read == -1: + raise RuntimeError("TTree I/O error") + +# Pythonizor function +@pythonization +def pythonize_ttree(klass, name): + # Parameters: + # klass: class to be pythonized + # name: string containing the name of the class + + if name == 'TTree': + # Pythonic iterator + klass.__iter__ = _TTree__iter__ + + # C++ pythonizations + # - tree.branch syntax + PythonizeTTree(klass) + + return True diff --git a/bindings/pyroot_experimental/PyROOT/src/PyROOTModule.cxx b/bindings/pyroot_experimental/PyROOT/src/PyROOTModule.cxx new file mode 100644 index 0000000000000..334b192ee044a --- /dev/null +++ b/bindings/pyroot_experimental/PyROOT/src/PyROOTModule.cxx @@ -0,0 +1,104 @@ + +// Bindings +#include "PyROOTPythonize.h" +#include "PyROOTStrings.h" +#include "PyROOTWrapper.h" + +// Cppyy +#include "CPyCppyy.h" +#include "CallContext.h" +#include "ProxyWrappers.h" +#include "Utility.h" + +// ROOT +#include "TROOT.h" +#include "TSystem.h" + +// Standard +#include +#include +#include +#include + +using namespace CPyCppyy; + +namespace PyROOT { +PyObject *gRootModule = 0; +} + +// Methods offered by the interface +static PyMethodDef gPyROOTMethods[] = {{(char *)"PythonizeTTree", (PyCFunction)PyROOT::PythonizeTTree, METH_VARARGS, + (char *)"Pythonizations for class TTree"}, + {NULL, NULL, 0, NULL}}; + +#if PY_VERSION_HEX >= 0x03000000 +struct module_state { + PyObject *error; +}; + +#define GETSTATE(m) ((struct module_state *)PyModule_GetState(m)) + +static int rootmodule_traverse(PyObject *m, visitproc visit, void *arg) +{ + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int rootmodule_clear(PyObject *m) +{ + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + +static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, "libROOTPython", NULL, + sizeof(struct module_state), gPyROOTMethods, NULL, + rootmodule_traverse, rootmodule_clear, NULL}; + + +/// Initialization of extension module libROOTPython + +#define PYROOT_INIT_ERROR return NULL +extern "C" PyObject *PyInit_libROOTPython() +#else // PY_VERSION_HEX >= 0x03000000 +#define PYROOT_INIT_ERROR return +extern "C" void initlibROOTPython() +#endif +{ + using namespace PyROOT; + + // load commonly used python strings + if (!PyROOT::CreatePyStrings()) + PYROOT_INIT_ERROR; + +// setup PyROOT +#if PY_VERSION_HEX >= 0x03000000 + gRootModule = PyModule_Create(&moduledef); +#else + gRootModule = Py_InitModule(const_cast("libROOTPython"), gPyROOTMethods); +#endif + if (!gRootModule) + PYROOT_INIT_ERROR; + + // keep gRootModule, but do not increase its reference count even as it is borrowed, + // or a self-referencing cycle would be created + + // policy labels + PyModule_AddObject(gRootModule, (char *)"kMemoryHeuristics", PyInt_FromLong((int)CallContext::kUseHeuristics)); + PyModule_AddObject(gRootModule, (char *)"kMemoryStrict", PyInt_FromLong((int)CallContext::kUseStrict)); + PyModule_AddObject(gRootModule, (char *)"kSignalFast", PyInt_FromLong((int)CallContext::kFast)); + PyModule_AddObject(gRootModule, (char *)"kSignalSafe", PyInt_FromLong((int)CallContext::kSafe)); + + // setup PyROOT + PyROOT::Init(); + + // signal policy: don't abort interpreter in interactive mode + CallContext::SetSignalPolicy(gROOT->IsBatch() ? CallContext::kFast : CallContext::kSafe); + + // inject ROOT namespace for convenience + PyModule_AddObject(gRootModule, (char *)"ROOT", CreateScopeProxy("ROOT")); + +#if PY_VERSION_HEX >= 0x03000000 + Py_INCREF(gRootModule); + return gRootModule; +#endif +} diff --git a/bindings/pyroot_experimental/PyROOT/src/PyROOTPythonize.h b/bindings/pyroot_experimental/PyROOT/src/PyROOTPythonize.h new file mode 100644 index 0000000000000..e5e562671b97b --- /dev/null +++ b/bindings/pyroot_experimental/PyROOT/src/PyROOTPythonize.h @@ -0,0 +1,13 @@ + +#ifndef PYROOT_PYTHONIZE_H +#define PYROOT_PYTHONIZE_H + +#include "Python.h" + +namespace PyROOT { + +PyObject *PythonizeTTree(PyObject *self, PyObject *args); + +} // namespace PyROOT + +#endif // !PYROOT_PYTHONIZE_H diff --git a/bindings/pyroot_experimental/PyROOT/src/PyROOTStrings.cxx b/bindings/pyroot_experimental/PyROOT/src/PyROOTStrings.cxx new file mode 100644 index 0000000000000..774e8137cb6c5 --- /dev/null +++ b/bindings/pyroot_experimental/PyROOT/src/PyROOTStrings.cxx @@ -0,0 +1,51 @@ + +// Bindings +#include "CPyCppyy.h" +#include "PyROOTStrings.h" + +// Define cached python strings +PyObject *PyROOT::PyStrings::gBranch = nullptr; +PyObject *PyROOT::PyStrings::gFitFCN = nullptr; +PyObject *PyROOT::PyStrings::gROOTns = nullptr; +PyObject *PyROOT::PyStrings::gSetBranchAddress = nullptr; +PyObject *PyROOT::PyStrings::gSetFCN = nullptr; +PyObject *PyROOT::PyStrings::gTClassDynCast = nullptr; + +#define PYROOT_INITIALIZE_STRING(var, str) \ + if (!(PyStrings::var = CPyCppyy_PyUnicode_InternFromString((char *)#str))) \ + return false + +bool PyROOT::CreatePyStrings() +{ + // Build cache of commonly used python strings (the cache is python intern, so + // all strings are shared python-wide, not just in PyROOT). + PYROOT_INITIALIZE_STRING(gBranch, Branch); + PYROOT_INITIALIZE_STRING(gFitFCN, FitFCN); + PYROOT_INITIALIZE_STRING(gROOTns, ROOT); + PYROOT_INITIALIZE_STRING(gSetBranchAddress, SetBranchAddress); + PYROOT_INITIALIZE_STRING(gSetFCN, SetFCN); + PYROOT_INITIALIZE_STRING(gTClassDynCast, _TClass__DynamicCast); + + return true; +} + +/// Remove all cached python strings. + +PyObject *PyROOT::DestroyPyStrings() +{ + Py_DECREF(PyStrings::gBranch); + PyStrings::gBranch = nullptr; + Py_DECREF(PyStrings::gFitFCN); + PyStrings::gFitFCN = nullptr; + Py_DECREF(PyStrings::gROOTns); + PyStrings::gROOTns = nullptr; + Py_DECREF(PyStrings::gSetBranchAddress); + PyStrings::gSetBranchAddress = nullptr; + Py_DECREF(PyStrings::gSetFCN); + PyStrings::gSetFCN = nullptr; + Py_DECREF(PyStrings::gTClassDynCast); + PyStrings::gTClassDynCast = nullptr; + + Py_INCREF(Py_None); + return Py_None; +} diff --git a/bindings/pyroot_experimental/PyROOT/src/PyROOTStrings.h b/bindings/pyroot_experimental/PyROOT/src/PyROOTStrings.h new file mode 100644 index 0000000000000..f6eb3b36b88ae --- /dev/null +++ b/bindings/pyroot_experimental/PyROOT/src/PyROOTStrings.h @@ -0,0 +1,28 @@ + +#ifndef PYROOT_PYSTRINGS_H +#define PYROOT_PYSTRINGS_H + +#include "Python.h" +#include "DllImport.h" + +namespace PyROOT { + +// python strings kept for performance reasons + +namespace PyStrings { + +R__EXTERN PyObject *gBranch; +R__EXTERN PyObject *gFitFCN; +R__EXTERN PyObject *gROOTns; +R__EXTERN PyObject *gSetBranchAddress; +R__EXTERN PyObject *gSetFCN; +R__EXTERN PyObject *gTClassDynCast; + +} // namespace PyStrings + +bool CreatePyStrings(); +PyObject *DestroyPyStrings(); + +} // namespace PyROOT + +#endif // !PYROOT_PYSTRINGS_H diff --git a/bindings/pyroot_experimental/PyROOT/src/PyROOTWrapper.cxx b/bindings/pyroot_experimental/PyROOT/src/PyROOTWrapper.cxx new file mode 100644 index 0000000000000..90abc911ece6d --- /dev/null +++ b/bindings/pyroot_experimental/PyROOT/src/PyROOTWrapper.cxx @@ -0,0 +1,42 @@ + +// Bindings +#include "PyROOTWrapper.h" + +// Cppyy +#include "CPyCppyy.h" +#include "ProxyWrappers.h" + +// ROOT +#include "TROOT.h" +#include "TSystem.h" +#include "TClass.h" +#include "TInterpreter.h" +#include "DllImport.h" + +namespace PyROOT { +R__EXTERN PyObject *gRootModule; +} + +using namespace PyROOT; + +namespace { + +static void AddToGlobalScope(const char *label, const char * /* hdr */, TObject *obj, Cppyy::TCppType_t klass) +{ + // Bind the given object with the given class in the global scope with the + // given label for its reference. + PyModule_AddObject(gRootModule, const_cast(label), CPyCppyy::BindCppObjectNoCast(obj, klass)); +} + +} // unnamed namespace + +void PyROOT::Init() +{ + // Initialize and acquire the GIL to allow for threading in ROOT + PyEval_InitThreads(); + + // Bind ROOT globals that will be needed in ROOT.py + AddToGlobalScope("gROOT", "TROOT.h", gROOT, Cppyy::GetScope(gROOT->IsA()->GetName())); + AddToGlobalScope("gSystem", "TSystem.h", gSystem, Cppyy::GetScope(gSystem->IsA()->GetName())); + AddToGlobalScope("gInterpreter", "TInterpreter.h", gInterpreter, Cppyy::GetScope(gInterpreter->IsA()->GetName())); +} diff --git a/bindings/pyroot_experimental/PyROOT/src/PyROOTWrapper.h b/bindings/pyroot_experimental/PyROOT/src/PyROOTWrapper.h new file mode 100644 index 0000000000000..fe104b8044b1b --- /dev/null +++ b/bindings/pyroot_experimental/PyROOT/src/PyROOTWrapper.h @@ -0,0 +1,12 @@ + +#ifndef PYROOT_ROOTWRAPPER_H +#define PYROOT_ROOTWRAPPER_H + +namespace PyROOT { + +// initialize ROOT +void Init(); + +} // namespace PyROOT + +#endif // !PYROOT_ROOTWRAPPER_H diff --git a/bindings/pyroot_experimental/PyROOT/src/TTreePyz.cxx b/bindings/pyroot_experimental/PyROOT/src/TTreePyz.cxx new file mode 100644 index 0000000000000..19303a9674071 --- /dev/null +++ b/bindings/pyroot_experimental/PyROOT/src/TTreePyz.cxx @@ -0,0 +1,175 @@ + +// Bindings +#include "CPyCppyy.h" +#include "PyROOTPythonize.h" +#include "CPPInstance.h" +#include "ProxyWrappers.h" +#include "Converters.h" +#include "Utility.h" + +// ROOT +#include "TClass.h" +#include "TTree.h" +#include "TBranch.h" +#include "TBranchElement.h" +#include "TBranchObject.h" +#include "TLeaf.h" +#include "TLeafElement.h" +#include "TLeafObject.h" +#include "TStreamerElement.h" +#include "TStreamerInfo.h" + +using namespace CPyCppyy; + +static TClass *GetClass(const CPPInstance *pyobj) +{ + return TClass::GetClass(Cppyy::GetFinalName(pyobj->ObjectIsA()).c_str()); +} + +static TBranch *SearchForBranch(TTree *tree, const char *name) +{ + TBranch *branch = tree->GetBranch(name); + if (!branch) { + // for benefit of naming of sub-branches, the actual name may have a trailing '.' + branch = tree->GetBranch((std::string(name) + '.').c_str()); + } + return branch; +} + +static TLeaf *SearchForLeaf(TTree *tree, const char *name, TBranch *branch) +{ + TLeaf *leaf = tree->GetLeaf(name); + if (branch && !leaf) { + leaf = branch->GetLeaf(name); + if (!leaf) { + TObjArray *leaves = branch->GetListOfLeaves(); + if (leaves->GetSize() && (leaves->First() == leaves->Last())) { + // i.e., if unambiguously only this one + leaf = (TLeaf *)leaves->At(0); + } + } + } + return leaf; +} + +static PyObject *BindBranchToProxy(TTree *tree, const char *name, TBranch *branch) +{ + // for partial return of a split object + if (branch->InheritsFrom(TBranchElement::Class())) { + TBranchElement *be = (TBranchElement *)branch; + if (be->GetCurrentClass() && (be->GetCurrentClass() != be->GetTargetClass()) && (0 <= be->GetID())) { + Long_t offset = ((TStreamerElement *)be->GetInfo()->GetElements()->At(be->GetID()))->GetOffset(); + return BindCppObjectNoCast(be->GetObject() + offset, Cppyy::GetScope(be->GetCurrentClass()->GetName())); + } + } + + // for return of a full object + if (branch->IsA() == TBranchElement::Class() || branch->IsA() == TBranchObject::Class()) { + TClass *klass = TClass::GetClass(branch->GetClassName()); + if (klass && branch->GetAddress()) + return BindCppObjectNoCast(*(void **)branch->GetAddress(), Cppyy::GetScope(branch->GetClassName())); + + // try leaf, otherwise indicate failure by returning a typed null-object + TObjArray *leaves = branch->GetListOfLeaves(); + if (klass && !tree->GetLeaf(name) && !(leaves->GetSize() && (leaves->First() == leaves->Last()))) + return BindCppObjectNoCast(nullptr, Cppyy::GetScope(branch->GetClassName())); + } + + return nullptr; +} + +static PyObject *WrapLeaf(TLeaf *leaf) +{ + if (1 < leaf->GetLenStatic() || leaf->GetLeafCount()) { + // array types + std::string typeName = leaf->GetTypeName(); + Converter *pcnv = CreateConverter(typeName + '*', leaf->GetNdata()); + + void *address = 0; + if (leaf->GetBranch()) + address = (void *)leaf->GetBranch()->GetAddress(); + if (!address) + address = (void *)leaf->GetValuePointer(); + + PyObject *value = pcnv->FromMemory(&address); + delete pcnv; + + return value; + } else if (leaf->GetValuePointer()) { + // value types + Converter *pcnv = CreateConverter(leaf->GetTypeName()); + PyObject *value = 0; + if (leaf->IsA() == TLeafElement::Class() || leaf->IsA() == TLeafObject::Class()) + value = pcnv->FromMemory((void *)*(void **)leaf->GetValuePointer()); + else + value = pcnv->FromMemory((void *)leaf->GetValuePointer()); + delete pcnv; + + return value; + } + + return nullptr; +} + +// Allow access to branches/leaves as if they were data members +PyObject *GetAttr(const CPPInstance *self, PyObject *pyname) +{ + const char *name_possibly_alias = CPyCppyy_PyUnicode_AsString(pyname); + if (!name_possibly_alias) + return 0; + + // get hold of actual tree + TTree *tree = (TTree *)GetClass(self)->DynamicCast(TTree::Class(), self->GetObject()); + + if (!tree) { + PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer"); + return 0; + } + + // deal with possible aliasing + const char *name = tree->GetAlias(name_possibly_alias); + if (!name) + name = name_possibly_alias; + + // search for branch first (typical for objects) + TBranch *branch = SearchForBranch(tree, name); + + if (branch) { + // found a branched object, wrap its address for the object it represents + auto proxy = BindBranchToProxy(tree, name, branch); + if (proxy != nullptr) + return proxy; + } + + // if not, try leaf + TLeaf *leaf = SearchForLeaf(tree, name, branch); + + if (leaf) { + // found a leaf, extract value and wrap with a Python object according to its type + auto wrapper = WrapLeaf(leaf); + if (wrapper != nullptr) + return wrapper; + } + + // confused + PyErr_Format(PyExc_AttributeError, "\'%s\' object has no attribute \'%s\'", tree->IsA()->GetName(), name); + return 0; +} + +//////////////////////////////////////////////////////////////////////////// +/// \brief Add pythonizations to the TTree class. +/// \param[in] self Always null, since this is a module function. +/// \param[in] args Pointer to a Python tuple object containing the arguments +/// received from Python. +/// +/// Inject new behaviour into the TTree class so that it can be used from +/// Python in a simpler or more pythonic way. +/// +/// This function adds the following pythonizations: +/// - Allow access to branches/leaves as if they were data members (e.g. mytree.branch) +PyObject *PyROOT::PythonizeTTree(PyObject */* self */, PyObject *args) +{ + PyObject *pyclass = PyTuple_GetItem(args, 0); + Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)GetAttr, METH_O); + Py_RETURN_NONE; +} diff --git a/bindings/pyroot_experimental/cppyy/CMakeLists.txt b/bindings/pyroot_experimental/cppyy/CMakeLists.txt new file mode 100644 index 0000000000000..420916b8726f6 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CMakeLists.txt @@ -0,0 +1,7 @@ +if(NOT (cxx14 OR cxx17)) + message(FATAL_ERROR "Cppyy requires C++14 standard or later") +endif() + +add_subdirectory(cppyy-backend) +add_subdirectory(CPyCppyy) +add_subdirectory(cppyy) diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/.gitignore b/bindings/pyroot_experimental/cppyy/CPyCppyy/.gitignore new file mode 100644 index 0000000000000..0de22a4662245 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/.gitignore @@ -0,0 +1,14 @@ +# python compiled files +*.pyc +*.pyo + +# dictionary products +*.so +*.pcm +*.rootmap + +# build products +dist +*.egg-info +.cache +build diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/CMakeLists.txt b/bindings/pyroot_experimental/cppyy/CPyCppyy/CMakeLists.txt new file mode 100644 index 0000000000000..ebaaf1e1ff784 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/CMakeLists.txt @@ -0,0 +1,48 @@ +set(headers + include/TPyArg.h + include/TPyException.h + include/TPyReturn.h + include/TPython.h +) + +set(sources + src/CallContext.cxx + src/Converters.cxx + src/CPPClassMethod.cxx + src/CPPConstructor.cxx + src/CPPDataMember.cxx + src/CPPFunction.cxx + src/CPPInstance.cxx + src/CPPMethod.cxx + src/CPPOverload.cxx + src/CPPScope.cxx + src/CPPSetItem.cxx + src/CPyCppyyModule.cxx + src/CustomPyTypes.cxx + src/Executors.cxx + src/LowLevelViews.cxx + src/MemoryRegulator.cxx + src/ProxyWrappers.cxx + src/PyStrings.cxx + src/Pythonize.cxx + src/TemplateProxy.cxx + src/TPyArg.cxx + src/TPyClassGenerator.cxx + src/TPyException.cxx + src/TPyReturn.cxx + src/TPython.cxx + src/TupleOfInstances.cxx + src/TypeManip.cxx + src/Utility.cxx +) + +add_library(cppyy SHARED ${headers} ${sources}) +target_compile_options(cppyy PRIVATE + -Wno-shadow -Wno-strict-aliasing -Wno-unused-but-set-parameter) +target_include_directories(cppyy PUBLIC ${PYTHON_INCLUDE_DIRS} + $ + $) +target_link_libraries(cppyy cppyy_backend ${PYTHON_LIBRARIES}) + +set_property(GLOBAL APPEND PROPERTY ROOT_EXPORTED_TARGETS cppyy) +install(TARGETS cppyy EXPORT ${CMAKE_PROJECT_NAME}Exports DESTINATION ${runtimedir}) diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/LICENSE.txt b/bindings/pyroot_experimental/cppyy/CPyCppyy/LICENSE.txt new file mode 100644 index 0000000000000..bea39a7007530 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/LICENSE.txt @@ -0,0 +1,51 @@ +Copyright (c) 2003, The Regents of the University of California, +through Lawrence Berkeley National Laboratory (subject to receipt of +any required approvals from the U.S. Dept. of Energy). All rights +reserved. Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following +conditions are met: + +(1) Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +(2) Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +(3) Neither the name of the University of California, Lawrence Berkeley +National Laboratory, U.S. Dept. of Energy nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +You are under no obligation whatsoever to provide any bug fixes, +patches, or upgrades to the features, functionality or performance of +the source code ("Enhancements") to anyone; however, if you choose to +make your Enhancements available either publicly, or directly to +Lawrence Berkeley National Laboratory, without imposing a separate +written license agreement for such Enhancements, then you hereby grant +the following license: a non-exclusive, royalty-free perpetual license +to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such Enhancements +or derivative works thereof, in binary and source code form. + + + +Additional copyright holders +---------------------------- + +Except when otherwise stated (look for LICENSE files or information in +source files), this package contains files copyrighted by one or more of +the following people and organizations: + + CERN + Toby StClere-Smithe diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/MANIFEST.in b/bindings/pyroot_experimental/cppyy/CPyCppyy/MANIFEST.in new file mode 100644 index 0000000000000..546a5c7e41542 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/MANIFEST.in @@ -0,0 +1,10 @@ +# Include the license file +include LICENSE.txt + +# Include all headers +include include/*.h +include src/*.h + +# Include source files +include src/*.cxx +include src/*.inc diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/README.rst b/bindings/pyroot_experimental/cppyy/CPyCppyy/README.rst new file mode 100644 index 0000000000000..ad1f2da970a77 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/README.rst @@ -0,0 +1,21 @@ +.. -*- mode: rst -*- + +CPyCppyy: Python-C++ bindings interface based on Cling/LLVM +=========================================================== + +CPyCppyy is the CPython equivalent of _cppyy in PyPy. +It provides dynamic Python-C++ bindings by leveraging the Cling C++ +interpreter and LLVM. +Details and performance are described in +`this paper `_. + +CPyCppyy is a CPython extension module built on top of the same backend API +as PyPy/_cppyy. +It thus requires the installation of the +`cppyy backend `_ +for use, which will pull in Cling. +CPython/cppyy and PyPy/cppyy are designed to be compatible, although there +are differences due to the former being reference counted and the latter +being garbage collected. + +Full documentation: `cppyy.readthedocs.io `_. diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPyArg.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPyArg.h new file mode 100644 index 0000000000000..95902e6ec9a92 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPyArg.h @@ -0,0 +1,49 @@ +#ifndef CPYCPPYY_TPYARG +#define CPYCPPYY_TPYARG + +////////////////////////////////////////////////////////////////////////////// +// // +// TPyArg // +// // +// Morphing argument type from evaluating python expressions. // +// // +////////////////////////////////////////////////////////////////////////////// + +// Python +struct _object; +typedef _object PyObject; + +// Standard +#include + + +class TPyArg { +public: +// converting constructors + TPyArg(PyObject*); + TPyArg(int); + TPyArg(long); + TPyArg(double); + TPyArg(const char*); + + TPyArg(const TPyArg&); + TPyArg& operator=(const TPyArg&); + virtual ~TPyArg(); + +// "extractor" + operator PyObject*() const; + +// constructor and generic dispatch + static void CallConstructor( + PyObject*& pyself, PyObject* pyclass, const std::vector& args); + static void CallConstructor(PyObject*& pyself, PyObject* pyclass); // default ctor + static PyObject* CallMethod(PyObject* pymeth, const std::vector& args); + static void CallDestructor( + PyObject*& pyself, PyObject* pymeth, const std::vector& args); + static void CallDestructor(PyObject*& pyself); + +private: + mutable PyObject* fPyObject; //! converted C++ value as python object +}; + +#endif // !CPYCPPYY_TPYARG diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPyException.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPyException.h new file mode 100644 index 0000000000000..4abaea3fcb63c --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPyException.h @@ -0,0 +1,49 @@ +#ifndef CPYCPPYY_TPyException +#define CPYCPPYY_TPyException + +////////////////////////////////////////////////////////////////////////////// +// // +// TPyException // +// // +// Purpose: A C++ exception class for throwing python exceptions // +// through C++ code. // +// Created: Apr, 2004, Scott Snyder, from the version in D0's python_util. // +// // +// The situation is: // +// - We're calling C++ code from python. // +// - The C++ code can call back to python. // +// - What to do then if the python callback throws an exception? // +// // +// We need to get the control flow back to where CPyCppyy calls C++. // +// To do that we throw a TPyException. // +// We can then catch this exception when we do the C++ call. // +// // +// Note that we don't need to save any state in the exception -- it's // +// already in the python error info variables. // +// (??? Actually, if the program is multithreaded, this is dangerous // +// if the code has released and reacquired the lock along the call chain. // +// Punt on this for now, though.) // +// // +////////////////////////////////////////////////////////////////////////////// + +// Standard +#include + + +namespace CPyCppyy { + +class TPyException : public std::exception { +public: +// default constructor + TPyException(); + +// destructor + virtual ~TPyException() noexcept; + +// give reason for raised exception + virtual const char* what() const noexcept; +}; + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_TPyException diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPyReturn.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPyReturn.h new file mode 100644 index 0000000000000..5626d0144271b --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPyReturn.h @@ -0,0 +1,59 @@ +#ifndef CPYCPPYY_TPYRETURN +#define CPYCPPYY_TPYRETURN + +////////////////////////////////////////////////////////////////////////////// +// // +// TPyReturn // +// // +// Morphing return type from evaluating python expressions. // +// // +////////////////////////////////////////////////////////////////////////////// + + +// Python +struct _object; +typedef _object PyObject; + + +class TPyReturn { +public: + TPyReturn(); + TPyReturn(PyObject* pyobject); + TPyReturn(const TPyReturn&); + TPyReturn& operator=(const TPyReturn&); + virtual ~TPyReturn(); + +// conversions to standard types, may fail if unconvertible + operator char*() const; + operator const char*() const; + operator char() const; + + operator long() const; + operator int() const { return (int)operator long(); } + operator short() const { return (short)operator long(); } + + operator unsigned long() const; + operator unsigned int() const { + return (unsigned int)operator unsigned long(); + } + operator unsigned short() const { + return (unsigned short)operator unsigned long(); + } + + operator double() const; + operator float() const { return (float)operator double(); } + +// used for both TObject and PyObject conversions + operator void*() const; + + template + operator T*() const { return (T*)(void*)*this; } + +// used strictly for PyObject conversions + operator PyObject*() const; + +private: + PyObject* fPyObject; //! actual python object +}; + +#endif // !CPYCPPYY_TPYRETURN diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPython.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPython.h new file mode 100644 index 0000000000000..de257fab7b60e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/include/TPython.h @@ -0,0 +1,59 @@ +#ifndef CPYCPPYY_TPYTHON +#define CPYCPPYY_TPYTHON + +////////////////////////////////////////////////////////////////////////////// +// // +// TPython // +// // +// Access to the python interpreter and API onto CPyCppyy. // +// // +////////////////////////////////////////////////////////////////////////////// + + +// Bindings +#include "TPyReturn.h" + + +class TPython { + +private: + static bool Initialize(); + +public: +// import a python module, making its classes available + static bool Import(const char* name); + +// load a python script as if it were a macro + static void LoadMacro(const char* name); + +// execute a python stand-alone script, with argv CLI arguments + static void ExecScript(const char* name, int argc = 0, const char** argv = 0); + +// execute a python statement (e.g. "import sys") + static bool Exec(const char* cmd); + +// evaluate a python expression (e.g. "1+1") + static const TPyReturn Eval(const char* expr); + +// enter an interactive python session (exit with ^D) + static void Prompt(); + +// type verifiers for CPPInstance + static bool CPPInstance_Check(PyObject* pyobject); + static bool CPPInstance_CheckExact(PyObject* pyobject); + +// type verifiers for CPPOverload + static bool CPPOverload_Check(PyObject* pyobject); + static bool CPPOverload_CheckExact(PyObject* pyobject); + +// object proxy to void* conversion + static void* CPPInstance_AsVoidPtr(PyObject* pyobject); + +// void* to object proxy conversion, returns a new reference + static PyObject* CPPInstance_FromVoidPtr( + void* addr, const char* classname, bool python_owns = false); + + virtual ~TPython() { } +}; + +#endif // !CPYCPPYY_TPYTHON diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/setup.cfg b/bindings/pyroot_experimental/cppyy/CPyCppyy/setup.cfg new file mode 100644 index 0000000000000..8debd01371e4f --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +universal=0 + +[metadata] +license_file = LICENSE.txt diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/setup.py b/bindings/pyroot_experimental/cppyy/CPyCppyy/setup.py new file mode 100755 index 0000000000000..2c5f94919590a --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/setup.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +import os, glob, subprocess +from setuptools import setup, find_packages, Extension +from distutils.command.build_ext import build_ext as _build_ext +from wheel.bdist_wheel import bdist_wheel as _bdist_wheel +from codecs import open + + +here = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + +try: + root_install = os.environ["ROOTSYS"] +except KeyError: + root_install = None + +def get_cflags(): + config_exec = 'cling-config' + if root_install: + config_exec = 'root-config' + cli_arg = subprocess.check_output([config_exec, '--auxcflags']) + return cli_arg.decode("utf-8").strip() + +class my_build_extension(_build_ext): + def build_extension(self, ext): + ext.extra_compile_args = ['-O2']+get_cflags().split() + return _build_ext.build_extension(self, ext) + +class my_bdist_wheel(_bdist_wheel): + def run(self, *args): + # wheels do not respect dependencies; make this a no-op so that it fails (mostly) silently + pass + +setup( + name='CPyCppyy', + version='1.0.1', + description='Cling-based Python-C++ bindings for CPython', + long_description=long_description, + + url='http://cppyy.readthedocs.io/', + + # Author details + author='Wim Lavrijsen', + author_email='WLavrijsen@lbl.gov', + + license='LBNL BSD', + + classifiers=[ + 'Development Status :: 5 - Production/Stable', + + 'Intended Audience :: Developers', + + 'Topic :: Software Development', + 'Topic :: Software Development :: Interpreters', + + 'License :: OSI Approved :: BSD License', + + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: C', + 'Programming Language :: C++', + + 'Natural Language :: English' + ], + + install_requires=['cppyy-backend>=0.5'], + + keywords='C++ bindings data science', + + cmdclass = { + 'build_ext': my_build_extension, + 'bdist_wheel': my_bdist_wheel + }, + + ext_modules=[Extension('libcppyy', + sources=glob.glob('src/*.cxx'), + include_dirs=['include'])], +) diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPClassMethod.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPClassMethod.cxx new file mode 100644 index 0000000000000..d850cee8eac41 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPClassMethod.cxx @@ -0,0 +1,26 @@ +// Bindings +#include "CPyCppyy.h" +#include "CPPClassMethod.h" + + +//- public members -------------------------------------------------------------- +PyObject* CPyCppyy::CPPClassMethod::Call( + CPPInstance*&, PyObject* args, PyObject* kwds, CallContext* ctxt) +{ +// preliminary check in case keywords are accidently used (they are ignored otherwise) + if (kwds && PyDict_Size(kwds)) { + PyErr_SetString(PyExc_TypeError, "keyword arguments are not yet supported"); + return nullptr; + } + +// setup as necessary + if (!this->Initialize(ctxt)) + return nullptr; + +// translate the arguments + if (!this->ConvertAndSetArgs(args, ctxt)) + return nullptr; + +// execute function + return this->Execute(nullptr, 0, ctxt); +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPClassMethod.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPClassMethod.h new file mode 100644 index 0000000000000..4cbfdc055fae9 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPClassMethod.h @@ -0,0 +1,21 @@ +#ifndef CPYCPPYY_CPPCLASSMETHOD_H +#define CPYCPPYY_CPPCLASSMETHOD_H + +// Bindings +#include "CPPMethod.h" + + +namespace CPyCppyy { + +class CPPClassMethod : public CPPMethod { +public: + using CPPMethod::CPPMethod; + + virtual PyCallable* Clone() { return new CPPClassMethod(*this); } + virtual PyObject* Call( + CPPInstance*&, PyObject* args, PyObject* kwds, CallContext* ctxt = nullptr); +}; + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CPPCLASSMETHOD_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPConstructor.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPConstructor.cxx new file mode 100644 index 0000000000000..e1d43e0602f14 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPConstructor.cxx @@ -0,0 +1,90 @@ +// Bindings +#include "CPyCppyy.h" +#include "CPPConstructor.h" +#include "CPPInstance.h" +#include "Executors.h" +#include "MemoryRegulator.h" + +// Standard +#include + + +//- protected members -------------------------------------------------------- +bool CPyCppyy::CPPConstructor::InitExecutor_(Executor*& executor, CallContext*) +{ +// pick up special case new object executor + executor = CreateExecutor("__init__"); + return true; +} + +//- public members ----------------------------------------------------------- +PyObject* CPyCppyy::CPPConstructor::GetDocString() +{ +// GetMethod() may return an empty function if this is just a special case place holder + const std::string& clName = Cppyy::GetFinalName(this->GetScope()); + return CPyCppyy_PyUnicode_FromFormat("%s::%s%s", + clName.c_str(), clName.c_str(), this->GetMethod() ? this->GetSignatureString().c_str() : "()"); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CPPConstructor::Call( + CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* ctxt) +{ +// preliminary check in case keywords are accidently used (they are ignored otherwise) + if (kwds && PyDict_Size(kwds)) { + PyErr_SetString(PyExc_TypeError, "keyword arguments are not yet supported"); + return nullptr; + } + +// do not allow instantiation of abstract classes + if (Cppyy::IsAbstract(this->GetScope())) { + PyErr_Format(PyExc_TypeError, "cannot instantiate abstract class \'%s\'", + Cppyy::GetScopedFinalName(this->GetScope()).c_str()); + return nullptr; + } + +// setup as necessary + if (!this->Initialize(ctxt)) + return nullptr; // important: 0, not Py_None + +// fetch self, verify, and put the arguments in usable order + if (!(args = this->PreProcessArgs(self, args, kwds))) + return nullptr; + +// translate the arguments + if (!this->ConvertAndSetArgs(args, ctxt)) { + Py_DECREF(args); + return nullptr; + } + +// perform the call, 0 makes the other side allocate the memory + Long_t address = (Long_t)this->Execute(nullptr, 0, ctxt); + +// done with filtered args + Py_DECREF(args); + +// return object if successful, lament if not + if (address) { + Py_INCREF(self); + + // note: constructors are no longer set to take ownership by default; instead that is + // decided by the method proxy (which carries a creator flag) upon return + self->Set((void*)address); + + // TODO: consistent up or down cast ... + MemoryRegulator::RegisterPyObject(self, (Cppyy::TCppObject_t)address); + + // done with self + Py_DECREF(self); + + Py_RETURN_NONE; // by definition + } + + if (!PyErr_Occurred()) // should be set, otherwise write a generic error msg + PyErr_SetString(PyExc_TypeError, const_cast( + (Cppyy::GetScopedFinalName(GetScope()) + " constructor failed").c_str())); + +// do not throw an exception, '0' might trigger the overload handler to choose a +// different constructor, which if all fails will throw an exception + return nullptr; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPConstructor.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPConstructor.h new file mode 100644 index 0000000000000..036daad9d8081 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPConstructor.h @@ -0,0 +1,28 @@ +#ifndef CPYCPPYY_CPPCONSTRUCTOR_H +#define CPYCPPYY_CPPCONSTRUCTOR_H + +// Bindings +#include "CPPMethod.h" + + +namespace CPyCppyy { + +class CPPConstructor : public CPPMethod { +public: + using CPPMethod::CPPMethod; + +public: + virtual PyObject* GetDocString(); + virtual PyCallable* Clone() { return new CPPConstructor(*this); } + +public: + virtual PyObject* Call( + CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* ctxt = nullptr); + +protected: + virtual bool InitExecutor_(Executor*&, CallContext* ctxt = nullptr); +}; + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CPPCONSTRUCTOR_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPDataMember.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPDataMember.cxx new file mode 100644 index 0000000000000..c5fb1b3436e7e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPDataMember.cxx @@ -0,0 +1,253 @@ +// Bindings +#include "CPyCppyy.h" +#include "PyStrings.h" +#include "CPPDataMember.h" +#include "CPPInstance.h" +#include "Utility.h" + +// Standard +#include + + +namespace CPyCppyy { + +enum ETypeDetails { + kNone = 0, + kIsStaticData = 1, + kIsEnumData = 2, + kIsConstData = 4, + kIsArrayType = 8 +}; + +//= CPyCppyy data member as Python property behavior ========================= +static PyObject* pp_get(CPPDataMember* pyprop, CPPInstance* pyobj, PyObject*) +{ +// normal getter access + void* address = pyprop->GetAddress(pyobj); + if (!address || (ptrdiff_t)address == -1 /* Cling error */) + return nullptr; + +// for fixed size arrays + void* ptr = address; + if (pyprop->fProperty & kIsArrayType) + ptr = &address; + +// non-initialized or public data accesses through class (e.g. by help()) + if (!ptr || (ptrdiff_t)ptr == -1 /* Cling error */) { + Py_INCREF(pyprop); + return (PyObject*)pyprop; + } + + if (pyprop->fConverter != 0) { + PyObject* result = pyprop->fConverter->FromMemory(ptr); + if (!result) + return result; + + // ensure that the encapsulating class does not go away for the duration + // of the data member's lifetime, if it is a bound type (it doesn't matter + // for builtin types, b/c those are copied over into python types and thus + // end up being "stand-alone") + if (pyobj && CPPInstance_Check(result)) { + if (PyObject_SetAttr(result, PyStrings::gLifeLine, (PyObject*)pyobj) == -1) + PyErr_Clear(); // ignored + } + + return result; + } + + PyErr_Format(PyExc_NotImplementedError, + "no converter available for \"%s\"", pyprop->GetName().c_str()); + return nullptr; +} + +//----------------------------------------------------------------------------- +static int pp_set(CPPDataMember* pyprop, CPPInstance* pyobj, PyObject* value) +{ +/// Set the value of the C++ datum held. + const int errret = -1; + +// filter const objects to prevent changing their values + if (pyprop->fProperty & kIsConstData) { + PyErr_SetString(PyExc_TypeError, "assignment to const data not allowed"); + return errret; + } + + ptrdiff_t address = (ptrdiff_t)pyprop->GetAddress(pyobj); + if (!address || address == -1 /* Cling error */) + return errret; + +// for fixed size arrays + void* ptr = (void*)address; + if (pyprop->fProperty & kIsArrayType) + ptr = &address; + +// actual conversion; return on success + if (pyprop->fConverter && pyprop->fConverter->ToMemory(value, ptr)) + return 0; + +// set a python error, if not already done + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_RuntimeError, "property type mismatch or assignment not allowed"); + +// failure ... + return errret; +} + +//= CPyCppyy data member construction/destruction =========================== +static CPPDataMember* pp_new(PyTypeObject* pytype, PyObject*, PyObject*) +{ +// Create and initialize a new property descriptor. + CPPDataMember* pyprop = (CPPDataMember*)pytype->tp_alloc(pytype, 0); + + pyprop->fOffset = 0; + pyprop->fProperty = 0; + pyprop->fConverter = nullptr; + pyprop->fEnclosingScope = 0; + new (&pyprop->fName) std::string(); + + return pyprop; +} + +//---------------------------------------------------------------------------- +static void pp_dealloc(CPPDataMember* pyprop) +{ +// Deallocate memory held by this descriptor. + using namespace std; + delete pyprop->fConverter; + pyprop->fName.~string(); + + Py_TYPE(pyprop)->tp_free((PyObject*)pyprop); +} + + +//= CPyCppyy data member type ================================================ +PyTypeObject CPPDataMember_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + (char*)"cppyy.CPPDataMember", // tp_name + sizeof(CPPDataMember), // tp_basicsize + 0, // tp_itemsize + (destructor)pp_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + (char*)"cppyy data member (internal)", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + (descrgetfunc)pp_get, // tp_descr_get + (descrsetfunc)pp_set, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + (newfunc)pp_new, // tp_new + 0, // tp_free + 0, // tp_is_gc + 0, // tp_bases + 0, // tp_mro + 0, // tp_cache + 0, // tp_subclasses + 0 // tp_weaklist +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +} // namespace CPyCppyy + + +//- public members ----------------------------------------------------------- +void CPyCppyy::CPPDataMember::Set(Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata) +{ + fEnclosingScope = scope; + fName = Cppyy::GetDatamemberName(scope, idata); + fOffset = Cppyy::GetDatamemberOffset(scope, idata); // TODO: make lazy + fProperty = Cppyy::IsStaticData(scope, idata) ? kIsStaticData : 0; + + int size = Cppyy::GetDimensionSize(scope, idata, 0); + if (0 < size) + fProperty |= kIsArrayType; + + if (size == INT_MAX) // meaning: incomplete array type + size = -1; + + std::string fullType = Cppyy::GetDatamemberType(scope, idata); + if (Cppyy::IsEnumData(scope, idata)) { + fullType = Cppyy::ResolveEnum(fullType); // enum might be any type of int + fProperty |= kIsEnumData; + } + + if (Cppyy::IsConstData(scope, idata)) + fProperty |= kIsConstData; + + fConverter = CreateConverter(fullType, size); +} + +//----------------------------------------------------------------------------- +void CPyCppyy::CPPDataMember::Set(Cppyy::TCppScope_t scope, const std::string& name, void* address) +{ + fEnclosingScope = scope; + fName = name; + fOffset = (ptrdiff_t)address; + fProperty = (kIsStaticData | kIsConstData | kIsEnumData /* true, but may chance */); + fConverter = CreateConverter("UInt_t", -1); // TODO: use general enum_t type +} + +//----------------------------------------------------------------------------- +void* CPyCppyy::CPPDataMember::GetAddress(CPPInstance* pyobj) +{ +// class attributes, global properties + if (fProperty & kIsStaticData) + return (void*)fOffset; + +// special case: non-static lookup through class + if (!pyobj) { + PyErr_SetString(PyExc_AttributeError, "attribute access requires an instance"); + return nullptr; + } + +// instance attributes; requires valid object for full address + if (!CPPInstance_Check(pyobj)) { + PyErr_Format(PyExc_TypeError, + "object instance required for access to property \"%s\"", GetName().c_str()); + return nullptr; + } + + void* obj = pyobj->GetObject(); + if (!obj) { + PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer"); + return nullptr; + } + +// the proxy's internal offset is calculated from the enclosing class + ptrdiff_t offset = 0; + if (pyobj->ObjectIsA() != fEnclosingScope) + offset = Cppyy::GetBaseOffset(pyobj->ObjectIsA(), fEnclosingScope, obj, 1 /* up-cast */); + + return (void*)((ptrdiff_t)obj + offset + fOffset); +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPDataMember.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPDataMember.h new file mode 100644 index 0000000000000..d848d142ee741 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPDataMember.h @@ -0,0 +1,74 @@ +#ifndef CPYCPPYY_CPPDATAMEMBER_H +#define CPYCPPYY_CPPDATAMEMBER_H + +// Bindings +#include "Converters.h" + +// Standard +#include + + +namespace CPyCppyy { + +class CPPInstance; + +class CPPDataMember { +public: + void Set(Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata); + void Set(Cppyy::TCppScope_t scope, const std::string& name, void* address); + + std::string GetName() { return fName; } + void* GetAddress(CPPInstance* pyobj /* owner */); + +public: // public, as the python C-API works with C structs + PyObject_HEAD + ptrdiff_t fOffset; + Long_t fProperty; + Converter* fConverter; + Cppyy::TCppScope_t fEnclosingScope; + std::string fName; + +private: // private, as the python C-API will handle creation + CPPDataMember() = delete; +}; + + +//- property proxy for C++ data members, type and type verification ---------- +extern PyTypeObject CPPDataMember_Type; + +template +inline bool CPPDataMember_Check(T* object) +{ + return object && PyObject_TypeCheck(object, &CPPDataMember_Type); +} + +template +inline bool CPPDataMember_CheckExact(T* object) +{ + return object && Py_TYPE(object) == &CPPDataMember_Type; +} + +//- creation ----------------------------------------------------------------- +inline CPPDataMember* CPPDataMember_New( + Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata) +{ +// Create an initialize a new property descriptor, given the C++ datum. + CPPDataMember* pyprop = + (CPPDataMember*)CPPDataMember_Type.tp_new(&CPPDataMember_Type, nullptr, nullptr); + pyprop->Set(scope, idata); + return pyprop; +} + +inline CPPDataMember* CPPDataMember_NewConstant( + Cppyy::TCppScope_t scope, const std::string& name, void* address) +{ +// Create an initialize a new property descriptor, given the C++ datum. + CPPDataMember* pyprop = + (CPPDataMember*)CPPDataMember_Type.tp_new(&CPPDataMember_Type, nullptr, nullptr); + pyprop->Set(scope, name, address); + return pyprop; +} + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CPPDATAMEMBER_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPFunction.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPFunction.cxx new file mode 100644 index 0000000000000..8ccf2687fef7a --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPFunction.cxx @@ -0,0 +1,59 @@ +// Bindings +#include "CPyCppyy.h" +#include "CPPFunction.h" +#include "CPPInstance.h" + + +//- public members -------------------------------------------------------------- +PyObject* CPyCppyy::CPPFunction::PreProcessArgs( + CPPInstance*& self, PyObject* args, PyObject*) +{ +// no self means called as a free function; all ok + if (!self) { + Py_INCREF(args); + return args; + } + +// otherwise, add self as part of the function arguments (means bound member) + Py_ssize_t sz = PyTuple_GET_SIZE(args); + PyObject* newArgs = PyTuple_New(sz+1); + for (int i = 0; i < sz; ++i) { + PyObject* item = PyTuple_GET_ITEM(args, i); + Py_INCREF(item); + PyTuple_SET_ITEM(newArgs, i+1, item); + } + + Py_INCREF(self); + PyTuple_SET_ITEM(newArgs, 0, (PyObject*)self); + + return newArgs; +} + +//--------------------------------------------------------------------------- +PyObject* CPyCppyy::CPPFunction::Call( + CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* ctxt) +{ +// preliminary check in case keywords are accidently used (they are ignored otherwise) + if (kwds && PyDict_Size(kwds)) { + PyErr_SetString(PyExc_TypeError, "keyword arguments are not yet supported"); + return nullptr; + } + +// setup as necessary + if (!this->Initialize(ctxt)) + return nullptr; + +// reorder self into args, if necessary + if (!(args = this->PreProcessArgs(self, args, kwds))) + return nullptr; + +// translate the arguments + bool bConvertOk = this->ConvertAndSetArgs(args, ctxt); + Py_DECREF(args); + + if (bConvertOk == false) + return nullptr; + +// execute function + return this->Execute(nullptr, 0, ctxt); +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPFunction.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPFunction.h new file mode 100644 index 0000000000000..93b9c84180117 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPFunction.h @@ -0,0 +1,23 @@ +#ifndef CPYCPPYY_CPPFUNCTION_H +#define CPYCPPYY_CPPFUNCTION_H + +// Bindings +#include "CPPMethod.h" + + +namespace CPyCppyy { + +class CPPFunction : public CPPMethod { +public: + using CPPMethod::CPPMethod; + + virtual PyCallable* Clone() { return new CPPFunction(*this); } + + virtual PyObject* PreProcessArgs(CPPInstance*& self, PyObject* args, PyObject* kwds); + virtual PyObject* Call( + CPPInstance*&, PyObject* args, PyObject* kwds, CallContext* ctx = nullptr); +}; + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CPPFUNCTION_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPInstance.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPInstance.cxx new file mode 100644 index 0000000000000..b61fa6163d601 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPInstance.cxx @@ -0,0 +1,390 @@ +// Bindings +#include "CPyCppyy.h" +#include "CPPInstance.h" +#include "MemoryRegulator.h" +#include "ProxyWrappers.h" +#include "PyStrings.h" +#include "TypeManip.h" +#include "Utility.h" + +// Standard +#include + + +//______________________________________________________________________________ +// Python-side proxy objects +// ========================= +// +// C++ objects are represented in Python by CPPInstances, which encapsulate +// them using either a pointer (normal), pointer-to-pointer (kIsReference set), +// or as an owned value (kIsValue set). Objects held as reference are never +// owned, otherwise the object is owned if kIsOwner is set. +// +// In addition to encapsulation, CPPInstance offers rudimentary comparison +// operators (based on pointer value and class comparisons); stubs (with lazy +// lookups) for numeric operators; and a representation that prints the C++ +// pointer values, rather than the PyObject* ones as is the default. + + +//---------------------------------------------------------------------------- +void CPyCppyy::op_dealloc_nofree(CPPInstance* pyobj) { +// Destroy the held C++ object, if owned; does not deallocate the proxy. + bool isSmartPtr = pyobj->fFlags & CPPInstance::kIsSmartPtr; + Cppyy::TCppType_t klass = isSmartPtr ? pyobj->fSmartPtrType : pyobj->ObjectIsA(); + + if (!(pyobj->fFlags & CPPInstance::kIsReference)) + MemoryRegulator::UnregisterPyObject(pyobj, klass); + + if (pyobj->fFlags & CPPInstance::kIsValue) { + void* addr = isSmartPtr ? pyobj->fObject : pyobj->GetObject(); + Cppyy::CallDestructor(klass, addr); + Cppyy::Deallocate(klass, addr); + } else if (pyobj->fObject && (pyobj->fFlags & CPPInstance::kIsOwner)) { + void* addr = isSmartPtr ? pyobj->fObject : pyobj->GetObject(); + Cppyy::Destruct(klass, addr); + } + pyobj->fObject = nullptr; +} + + +namespace CPyCppyy { + +//= CPyCppyy object proxy null-ness checking ================================= +static PyObject* op_nonzero(CPPInstance* self) +{ +// Null of the proxy is determined by null-ness of the held C++ object. + PyObject* result = self->GetObject() ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + +//= CPyCppyy object explicit destruction ===================================== +static PyObject* op_destruct(CPPInstance* self) +{ +// User access to force deletion of the object. Needed in case of a true +// garbage collector (like in PyPy), to allow the user control over when +// the C++ destructor is called. This method requires that the C++ object +// is owned (no-op otherwise). + op_dealloc_nofree(self); + Py_RETURN_NONE; +} + +//= CPyCppyy object dispatch support ========================================= +static PyObject* op_dispatch(PyObject* self, PyObject* args, PyObject* /* kdws */) +{ +// User-side __dispatch__ method to allow selection of a specific overloaded +// method. The actual selection is in the __overload__() method of CPPOverload. + PyObject *mname = nullptr, *sigarg = nullptr; + if (!PyArg_ParseTuple(args, const_cast("O!O!:__dispatch__"), + &CPyCppyy_PyUnicode_Type, &mname, &CPyCppyy_PyUnicode_Type, &sigarg)) + return nullptr; + +// get the named overload + PyObject* pymeth = PyObject_GetAttr(self, mname); + if (!pymeth) + return nullptr; + +// get the '__overload__' method to allow overload selection + PyObject* pydisp = PyObject_GetAttrString(pymeth, const_cast("__overload__")); + if (!pydisp) { + Py_DECREF(pymeth); + return nullptr; + } + +// finally, call dispatch to get the specific overload + PyObject* oload = PyObject_CallFunctionObjArgs(pydisp, sigarg, nullptr); + Py_DECREF(pydisp); + Py_DECREF(pymeth); + return oload; +} + +//= CPyCppyy smart pointer support =========================================== +static PyObject* op_get_smart_ptr(CPPInstance* self) +{ + if (!(self->fFlags & CPPInstance::kIsSmartPtr)) { + // TODO: more likely should raise + Py_RETURN_NONE; + } + + return (PyObject*)CPyCppyy::BindCppObject(self->fObject, self->fSmartPtrType); +} + + +//---------------------------------------------------------------------------- +static PyMethodDef op_methods[] = { + {(char*)"__nonzero__", (PyCFunction)op_nonzero, METH_NOARGS, nullptr}, + {(char*)"__bool__", (PyCFunction)op_nonzero, METH_NOARGS, nullptr}, // for p3 + {(char*)"__destruct__", (PyCFunction)op_destruct, METH_NOARGS, nullptr}, + {(char*)"__dispatch__", (PyCFunction)op_dispatch, METH_VARARGS, + (char*)"dispatch to selected overload"}, + {(char*)"__smartptr__", (PyCFunction)op_get_smart_ptr, METH_NOARGS, + (char*)"get associated smart pointer, if any"}, + {(char*)nullptr, nullptr, 0, nullptr} +}; + + +//= CPyCppyy object proxy construction/destruction =========================== +static CPPInstance* op_new(PyTypeObject* subtype, PyObject*, PyObject*) +{ +// Create a new object proxy (holder only). + CPPInstance* pyobj = (CPPInstance*)subtype->tp_alloc(subtype, 0); + pyobj->fObject = nullptr; + pyobj->fFlags = 0; + pyobj->fSmartPtrType = (Cppyy::TCppType_t)0; + pyobj->fDereferencer = (Cppyy::TCppMethod_t)0; + + return pyobj; +} + +//---------------------------------------------------------------------------- +static void op_dealloc(CPPInstance* pyobj) +{ +// Remove (Python-side) memory held by the object proxy. + op_dealloc_nofree(pyobj); + Py_TYPE(pyobj)->tp_free((PyObject*)pyobj); +} + +//---------------------------------------------------------------------------- +static PyObject* op_richcompare(CPPInstance* self, CPPInstance* other, int op) +{ +// Rich set of comparison objects; only equals and not-equals are defined. + if (op != Py_EQ && op != Py_NE) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + bool bIsEq = false; + +// special case for None to compare True to a null-pointer + if ((PyObject*)other == Py_None && !self->fObject) + bIsEq = true; + +// type + held pointer value defines identity (will cover if other is not +// actually an CPPInstance, as ob_type will be unequal) + else if (Py_TYPE(self) == Py_TYPE(other) && self->GetObject() == other->GetObject()) + bIsEq = true; + + if ((op == Py_EQ && bIsEq) || (op == Py_NE && !bIsEq)) { + Py_RETURN_TRUE; + } + + Py_RETURN_FALSE; +} + +//---------------------------------------------------------------------------- +static PyObject* op_repr(CPPInstance* pyobj) +{ +// Build a representation string of the object proxy that shows the address +// of the C++ object that is held, as well as its type. + PyObject* pyclass = (PyObject*)Py_TYPE(pyobj); + PyObject* modname = PyObject_GetAttr(pyclass, PyStrings::gModule); + Py_DECREF(pyclass); + + Cppyy::TCppType_t klass = pyobj->ObjectIsA(); + std::string clName = klass ? Cppyy::GetFinalName(klass) : ""; + if (pyobj->fFlags & CPPInstance::kIsReference) + clName.append("*"); + + PyObject* repr = nullptr; + if (pyobj->fFlags & CPPInstance::kIsSmartPtr) { + Cppyy::TCppType_t smartPtrType = pyobj->fSmartPtrType; + std::string smartPtrName = smartPtrType ? + Cppyy::GetFinalName(smartPtrType) : "unknown smart pointer"; + repr = CPyCppyy_PyUnicode_FromFormat( + const_cast("<%s.%s object at %p held by %s at %p>"), + CPyCppyy_PyUnicode_AsString(modname), clName.c_str(), + pyobj->GetObject(), smartPtrName.c_str(), pyobj->fObject); + } else { + repr = CPyCppyy_PyUnicode_FromFormat(const_cast("<%s.%s object at %p>"), + CPyCppyy_PyUnicode_AsString(modname), clName.c_str(), pyobj->GetObject()); + } + + Py_DECREF(modname); + return repr; +} + + +//----------------------------------------------------------------------------- +static PyObject* op_getownership(CPPInstance* pyobj, void*) +{ + return PyBool_FromLong((long)(pyobj->fFlags & CPPInstance::kIsOwner)); +} + +//----------------------------------------------------------------------------- +static int op_setownership(CPPInstance* pyobj, PyObject* value, void*) +{ +// Set the ownership (True is python-owns) for the given object. + long shouldown = PyLong_AsLong(value); + if (shouldown == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "__python_owns__ should be either True or False"); + return -1; + } + + (bool)shouldown ? pyobj->PythonOwns() : pyobj->CppOwns(); + + return 0; +} + + +//----------------------------------------------------------------------------- +static PyGetSetDef op_getset[] = { + {(char*)"__python_owns__", (getter)op_getownership, (setter)op_setownership, + (char*)"If true, python manages the life time of this object", nullptr}, + {(char*)nullptr, nullptr, nullptr, nullptr, nullptr} +}; + + +//= CPyCppyy type number stubs to allow dynamic overrides ===================== +#define CPYCPPYY_STUB(name, op, pystring) \ +static PyObject* op_##name##_stub(PyObject* left, PyObject* right) \ +{ \ + if (!CPPInstance_Check(left)) { \ + if (CPPInstance_Check(right)) { \ + std::swap(left, right); \ + } else { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } \ + } \ +/* place holder to lazily install __name__ if a global overload is available */\ + if (!Utility::AddBinaryOperator( \ + left, right, #op, "__"#name"__", "__r"#name"__")) { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } \ + \ +/* redo the call, which will now go to the newly installed method */ \ + return PyObject_CallMethodObjArgs(left, pystring, right, nullptr); \ +} + +CPYCPPYY_STUB(add, +, PyStrings::gAdd) +CPYCPPYY_STUB(sub, -, PyStrings::gSub) +CPYCPPYY_STUB(mul, *, PyStrings::gMul) +CPYCPPYY_STUB(div, /, PyStrings::gDiv) + +//----------------------------------------------------------------------------- +static PyNumberMethods op_as_number = { + (binaryfunc)op_add_stub, // nb_add + (binaryfunc)op_sub_stub, // nb_subtract + (binaryfunc)op_mul_stub, // nb_multiply +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc)op_div_stub, // nb_divide +#endif + 0, // nb_remainder + 0, // nb_divmod + 0, // nb_power + 0, // nb_negative + 0, // nb_positive + 0, // nb_absolute + 0, // tp_nonzero (nb_bool in p3) + 0, // nb_invert + 0, // nb_lshift + 0, // nb_rshift + 0, // nb_and + 0, // nb_xor + 0, // nb_or +#if PY_VERSION_HEX < 0x03000000 + 0, // nb_coerce +#endif + 0, // nb_int + 0, // nb_long (nb_reserved in p3) + 0, // nb_float +#if PY_VERSION_HEX < 0x03000000 + 0, // nb_oct + 0, // nb_hex +#endif + 0, // nb_inplace_add + 0, // nb_inplace_subtract + 0, // nb_inplace_multiply +#if PY_VERSION_HEX < 0x03000000 + 0, // nb_inplace_divide +#endif + 0, // nb_inplace_remainder + 0, // nb_inplace_power + 0, // nb_inplace_lshift + 0, // nb_inplace_rshift + 0, // nb_inplace_and + 0, // nb_inplace_xor + 0 // nb_inplace_or +#if PY_VERSION_HEX >= 0x02020000 + , 0 // nb_floor_divide +#if PY_VERSION_HEX < 0x03000000 + , 0 // nb_true_divide +#else + , (binaryfunc)op_div_stub // nb_true_divide +#endif + , 0 // nb_inplace_floor_divide + , 0 // nb_inplace_true_divide +#endif +#if PY_VERSION_HEX >= 0x02050000 + , 0 // nb_index +#endif +#if PY_VERSION_HEX >= 0x03050000 + , 0 // nb_matrix_multiply + , 0 // nb_inplace_matrix_multiply +#endif +}; + + +//= CPyCppyy object proxy type =============================================== +PyTypeObject CPPInstance_Type = { + PyVarObject_HEAD_INIT(&CPPScope_Type, 0) + (char*)"cppyy.CPPInstance", // tp_name + sizeof(CPPInstance), // tp_basicsize + 0, // tp_itemsize + (destructor)op_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + (reprfunc)op_repr, // tp_repr + &op_as_number, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + PyBaseObject_Type.tp_hash, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_CHECKTYPES, // tp_flags + (char*)"cppyy object proxy (internal)", // tp_doc + 0, // tp_traverse + 0, // tp_clear + (richcmpfunc)op_richcompare, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + op_methods, // tp_methods + 0, // tp_members + op_getset, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + (newfunc)op_new, // tp_new + 0, // tp_free + 0, // tp_is_gc + 0, // tp_bases + 0, // tp_mro + 0, // tp_cache + 0, // tp_subclasses + 0 // tp_weaklist +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +} // namespace CPyCppyy diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPInstance.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPInstance.h new file mode 100644 index 0000000000000..811fde4250899 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPInstance.h @@ -0,0 +1,113 @@ +#ifndef CPYCPPYY_CPPINSTANCE_H +#define CPYCPPYY_CPPINSTANCE_H + +////////////////////////////////////////////////////////////////////////////// +// // +// CpyCppyy::CPPInstance // +// // +// Python-side proxy, encapsulaties a C++ object. // +// // +////////////////////////////////////////////////////////////////////////////// + + +// Bindings +#include "CPPScope.h" +#include "Cppyy.h" +#include "CallContext.h" // for Parameter + + +// TODO: have an CPPInstance derived or alternative type for smart pointers + +namespace CPyCppyy { + +class CPPInstance { +public: + enum EFlags { + kNone = 0x0, + kIsOwner = 0x0001, + kIsReference = 0x0002, + kIsRValue = 0x0004, + kIsValue = 0x0008, + kIsSmartPtr = 0x0010, + kIsPtrPtr = 0x0020 }; + +public: + void Set(void* address, EFlags flags = kNone) + { + // Initialize the proxy with the pointer value 'address.' + fObject = address; + fFlags = flags; + fSmartPtrType = (Cppyy::TCppType_t)0; + fDereferencer = (Cppyy::TCppMethod_t)0; + } + + void SetSmartPtr(Cppyy::TCppType_t ptrtype, Cppyy::TCppMethod_t deref) + { + fFlags |= kIsSmartPtr; + fSmartPtrType = ptrtype; + fDereferencer = deref; + } + + void* GetObject() const + { + // Retrieve a pointer to the held C++ object. + + // We get the raw pointer from the smart pointer each time, in case + // it has changed or has been freed. + if (fFlags & kIsSmartPtr) { + std::vector args; + return Cppyy::CallR(fDereferencer, fObject, &args); + } + + if (fObject && (fFlags & kIsReference)) + return *(reinterpret_cast(const_cast(fObject))); + else + return const_cast(fObject); // may be null + } + + Cppyy::TCppType_t ObjectIsA() const + { + // Retrieve a pointer to the C++ type; may return nullptr. + return ((CPPClass*)Py_TYPE(this))->fCppType; + } + + void PythonOwns() { fFlags |= kIsOwner; } + void CppOwns() { fFlags &= ~kIsOwner; } + +public: // public, as the python C-API works with C structs + PyObject_HEAD + void* fObject; + int fFlags; + +// TODO: should be its own version of CPPInstance so as not to clutter the +// normal instances + Cppyy::TCppType_t fSmartPtrType; + Cppyy::TCppMethod_t fDereferencer; + +private: + CPPInstance() = delete; +}; + + +//- object proxy type and type verification ---------------------------------- +extern PyTypeObject CPPInstance_Type; + +template +inline bool CPPInstance_Check(T* object) +{ + return object && PyObject_TypeCheck(object, &CPPInstance_Type); +} + +template +inline bool CPPInstance_CheckExact(T* object) +{ + return object && Py_TYPE(object) == &CPPInstance_Type; +} + + +//- helper for memory regulation (no PyTypeObject equiv. member in p2.2) ----- +void op_dealloc_nofree(CPPInstance*); + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CPPINSTANCE_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPMethod.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPMethod.cxx new file mode 100644 index 0000000000000..351de34bb0c8c --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPMethod.cxx @@ -0,0 +1,594 @@ +// Bindings +#include "CPyCppyy.h" +#include "CPPMethod.h" +#include "CPPInstance.h" +#include "Converters.h" +#include "Executors.h" +#include "ProxyWrappers.h" +#include "PyStrings.h" +#include "TPyException.h" +#include "Utility.h" + +// Standard +#include +#include +#include +#include +#include +#include +#include + + +//- data and local helpers --------------------------------------------------- +namespace CPyCppyy { + extern PyObject* gThisModule; +} + + +//- private helpers ---------------------------------------------------------- +inline void CPyCppyy::CPPMethod::Copy_(const CPPMethod& /* other */) +{ +// fScope and fMethod handled separately + +// do not copy caches + fExecutor = nullptr; + fArgsRequired = -1; + +// being uninitialized will trigger setting up caches as appropriate + fIsInitialized = false; +} + +//---------------------------------------------------------------------------- +inline void CPyCppyy::CPPMethod::Destroy_() const +{ +// destroy executor and argument converters + delete fExecutor; + + for (int i = 0; i < (int)fConverters.size(); ++i) + delete fConverters[i]; +} + +//---------------------------------------------------------------------------- +inline PyObject* CPyCppyy::CPPMethod::CallFast( + void* self, ptrdiff_t offset, CallContext* ctxt) +{ +// Helper code to prevent some duplication; this is called from CallSafe() as well +// as directly from CPPMethod::Execute in fast mode. + PyObject* result = nullptr; + + try { // C++ try block + result = fExecutor->Execute(fMethod, (Cppyy::TCppObject_t)((Long_t)self+offset), ctxt); + } catch (TPyException&) { + result = nullptr; // error already set + } catch (std::exception& e) { + /* TODO: figure out what this is about ... ? + if (gInterpreter->DiagnoseIfInterpreterException(e)) { + return result; + } + + // TODO: write w/ot use of TClass + + // map user exceptions .. this needs to move to Cppyy.cxx + TClass* cl = TClass::GetClass(typeid(e)); + + PyObject* pyUserExcepts = PyObject_GetAttrString(gThisModule, "UserExceptions"); + std::string exception_type; + if (cl) exception_type = cl->GetName(); + else { + int errorCode; + std::unique_ptr demangled(TClassEdit::DemangleTypeIdName(typeid(e),errorCode)); + if (errorCode) exception_type = typeid(e).name(); + else exception_type = demangled.get(); + } + PyObject* pyexc = PyDict_GetItemString(pyUserExcepts, exception_type.c_str()); + if (!pyexc) { + PyErr_Clear(); + pyexc = PyDict_GetItemString(pyUserExcepts, ("std::"+exception_type).c_str()); + } + Py_DECREF(pyUserExcepts); + + if (pyexc) { + PyErr_Format(pyexc, "%s", e.what()); + } else { + PyErr_Format(PyExc_Exception, "%s (C++ exception of type %s)", e.what(), exception_type.c_str()); + } + */ + + PyErr_Format(PyExc_Exception, "%s (C++ exception)", e.what()); + result = nullptr; + } catch (...) { + PyErr_SetString(PyExc_Exception, "unhandled, unknown C++ exception"); + result = nullptr; + } + return result; +} + +//---------------------------------------------------------------------------- +inline PyObject* CPyCppyy::CPPMethod::CallSafe( + void* self, ptrdiff_t offset, CallContext* ctxt) +{ +// Helper code to prevent some code duplication; this code embeds a "try/catch" +// block that saves the stack for restoration in case of an otherwise fatal signal. + PyObject* result = 0; + +// TRY { // ROOT "try block" + result = CallFast(self, offset, ctxt); + // } CATCH(excode) { + // PyErr_SetString(PyExc_SystemError, "problem in C++; program state has been reset"); + // result = 0; + // Throw(excode); + // } ENDTRY; + + return result; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::CPPMethod::InitConverters_() +{ +// build buffers for argument dispatching + const size_t nArgs = Cppyy::GetMethodNumArgs(fMethod); + fConverters.resize(nArgs); + +// setup the dispatch cache + for (size_t iarg = 0; iarg < nArgs; ++iarg) { + const std::string& fullType = Cppyy::GetMethodArgType(fMethod, iarg); + // CLING WORKAROUND -- std::string can not use kExactMatch as that will + // fail, but if no exact match is used, the const-ref + // std::string arguments will mask the const char* ones, + // even though the extra default arguments differ + if (Cppyy::GetFinalName(fScope) == "string" && \ + Cppyy::GetMethodName(fMethod) == "string" && + // Note with the improve naming normalization we should see only + // the spelling "const string&" (and will be "const std::string&") + (fullType == "const std::string&" || fullType == "const std::string &" + || fullType == "const string&" || fullType == "const string &")) { + fConverters[iarg] = new StrictCppObjectConverter( + Cppyy::GetScope("string"), false); // TODO: this is sooo wrong + // -- CLING WORKAROUND + } else + fConverters[iarg] = CreateConverter(fullType); + + if (!fConverters[iarg]) { + PyErr_Format(PyExc_TypeError, "argument type %s not handled", fullType.c_str()); + return false; + } + } + + return true; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::CPPMethod::InitExecutor_(Executor*& executor, CallContext* ctxt) +{ +// install executor conform to the return type + executor = CreateExecutor( + (bool)fMethod == true ? Cppyy::ResolveName(Cppyy::GetMethodResultType(fMethod))\ + : Cppyy::GetScopedFinalName(fScope), + ctxt ? ManagesSmartPtr(ctxt) : false); + + if (!executor) + return false; + + return true; +} + +//---------------------------------------------------------------------------- +std::string CPyCppyy::CPPMethod::GetSignatureString(bool fa) +{ +// built a signature representation (used for doc strings) + std::stringstream sig; sig << "("; + int count = 0; + const size_t nArgs = Cppyy::GetMethodNumArgs(fMethod); + for (size_t iarg = 0; iarg < nArgs; ++iarg) { + if (count) sig << (fa ? ", " : ","); + + sig << Cppyy::GetMethodArgType(fMethod, iarg); + + if (fa) { + const std::string& parname = Cppyy::GetMethodArgName(fMethod, iarg); + if (!parname.empty()) + sig << " " << parname; + + const std::string& defvalue = Cppyy::GetMethodArgDefault(fMethod, iarg); + if (!defvalue.empty()) + sig << " = " << defvalue; + } + count++; + } + sig << ")"; + return sig.str(); +} + +//---------------------------------------------------------------------------- +void CPyCppyy::CPPMethod::SetPyError_(PyObject* msg) +{ +// helper to report errors in a consistent format (derefs msg) + PyObject *etype, *evalue, *etrace; + PyErr_Fetch(&etype, &evalue, &etrace); + + std::string details = ""; + if (evalue) { + PyObject* descr = PyObject_Str(evalue); + if (descr) { + details = CPyCppyy_PyUnicode_AsString(descr); + Py_DECREF(descr); + } + } + + Py_XDECREF(evalue); Py_XDECREF(etrace); + + PyObject* doc = GetDocString(); + PyObject* errtype = etype; + if (!errtype) { + Py_INCREF(PyExc_TypeError); + errtype = PyExc_TypeError; + } + PyObject* pyname = PyObject_GetAttr(errtype, PyStrings::gName); + const char* cname = pyname ? CPyCppyy_PyUnicode_AsString(pyname) : "Exception"; + + if (details.empty()) { + PyErr_Format(errtype, "%s =>\n %s: %s", CPyCppyy_PyUnicode_AsString(doc), + cname, msg ? CPyCppyy_PyUnicode_AsString(msg) : ""); + } else if (msg) { + PyErr_Format(errtype, "%s =>\n %s: %s (%s)", + CPyCppyy_PyUnicode_AsString(doc), cname, CPyCppyy_PyUnicode_AsString(msg), + details.c_str()); + } else { + PyErr_Format(errtype, "%s =>\n %s: %s", + CPyCppyy_PyUnicode_AsString(doc), cname, details.c_str()); + } + + Py_XDECREF(pyname); + Py_XDECREF(etype); + Py_DECREF(doc); + Py_XDECREF(msg); +} + +//- constructors and destructor ---------------------------------------------- +CPyCppyy::CPPMethod::CPPMethod( + Cppyy::TCppScope_t scope, Cppyy::TCppMethod_t method) : + fMethod(method), fScope(scope), fExecutor(nullptr), fArgsRequired(-1), + fIsInitialized(false) +{ + // empty +} + +//---------------------------------------------------------------------------- +CPyCppyy::CPPMethod::CPPMethod(const CPPMethod& other) : + PyCallable(other), fMethod(other.fMethod), fScope(other.fScope) +{ + Copy_(other); +} + +//---------------------------------------------------------------------------- +CPyCppyy::CPPMethod& CPyCppyy::CPPMethod::operator=(const CPPMethod& other) +{ + if (this != &other) { + Destroy_(); + Copy_(other); + fScope = other.fScope; + fMethod = other.fMethod; + } + + return *this; +} + +//---------------------------------------------------------------------------- +CPyCppyy::CPPMethod::~CPPMethod() +{ + Destroy_(); +} + + +//- public members ----------------------------------------------------------- +PyObject* CPyCppyy::CPPMethod::GetPrototype(bool fa) +{ +// construct python string from the method's prototype + return CPyCppyy_PyUnicode_FromFormat("%s%s %s::%s%s", + (Cppyy::IsStaticMethod(fMethod) ? "static " : ""), + Cppyy::GetMethodResultType(fMethod).c_str(), + Cppyy::GetScopedFinalName(fScope).c_str(), Cppyy::GetMethodName(fMethod).c_str(), + GetSignatureString(fa).c_str()); +} + +//---------------------------------------------------------------------------- +int CPyCppyy::CPPMethod::GetPriority() +{ +// Method priorities exist (in lieu of true overloading) there to prevent +// void* or * from usurping otherwise valid calls. TODO: extend this +// to favour classes that are not bases. + int priority = 0; + + const size_t nArgs = Cppyy::GetMethodNumArgs(fMethod); + for (size_t iarg = 0; iarg < nArgs; ++iarg) { + const std::string aname = Cppyy::GetMethodArgType(fMethod, iarg); + + // the following numbers are made up and may cause problems in specific + // situations: use ..disp() for choice of exact dispatch + if (Cppyy::IsBuiltin(aname)) { + // happens for builtin types (and namespaces, but those can never be an + // argument), NOT for unknown classes as that concept no longer exists + if (strstr(aname.c_str(), "void*")) + // TODO: figure out in general all void* converters + priority -= 10000; // void*/void** shouldn't be too greedy + else if (strstr(aname.c_str(), "float")) + priority -= 1000; // double preferred (no float in python) + else if (strstr(aname.c_str(), "long double")) + priority -= 100; // id, but better than float + else if (strstr(aname.c_str(), "double")) + priority -= 10; // char, int, long can't convert float, + // but vv. works, so prefer the int types + else if (strstr(aname.c_str(), "bool")) + priority += 1; // bool over int (does accept 1 and 0) + + } else if (aname.rfind("&&", aname.size()-2) != std::string::npos) { + priority += 100; + } else if (!aname.empty() && !Cppyy::IsComplete(aname)) { + // class is known, but no dictionary available, 2 more cases: * and & + if (aname[ aname.size() - 1 ] == '&') + priority -= 1000000; + else + priority -= 100000; // prefer pointer passing over reference + } + } + +// add a small penalty to prefer non-const methods over const ones for +// getitem/setitem + if (Cppyy::IsConstMethod(fMethod) && Cppyy::GetMethodName(fMethod) == "operator[]") + priority -= 1; + + return priority; +} + +//---------------------------------------------------------------------------- +int CPyCppyy::CPPMethod::GetMaxArgs() +{ + return Cppyy::GetMethodNumArgs(fMethod); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CPPMethod::GetCoVarNames() +{ +// Build a tuple of the argument types/names. + int co_argcount = (int)GetMaxArgs() /* +1 for self */; + +// TODO: static methods need no 'self' (but is harmless otherwise) + + PyObject* co_varnames = PyTuple_New(co_argcount+1 /* self */); + PyTuple_SET_ITEM(co_varnames, 0, CPyCppyy_PyUnicode_FromString("self")); + for (int iarg = 0; iarg < co_argcount; ++iarg) { + std::string argrep = Cppyy::GetMethodArgType(fMethod, iarg); + const std::string& parname = Cppyy::GetMethodArgName(fMethod, iarg); + if (!parname.empty()) { + argrep += " "; + argrep += parname; + } + + PyObject* pyspec = CPyCppyy_PyUnicode_FromString(argrep.c_str()); + PyTuple_SET_ITEM(co_varnames, iarg+1, pyspec); + } + + return co_varnames; +} + +PyObject* CPyCppyy::CPPMethod::GetArgDefault(int iarg) +{ +// get the default value (if any) of argument iarg of this method + if (iarg >= (int)GetMaxArgs()) + return nullptr; + + const std::string& defvalue = Cppyy::GetMethodArgDefault(fMethod, iarg); + if (!defvalue.empty()) { + + // attempt to evaluate the string representation (will work for all builtin types) + PyObject* pyval = (PyObject*)PyRun_String( + (char*)defvalue.c_str(), Py_eval_input, gThisModule, gThisModule); + if (!pyval && PyErr_Occurred()) { + PyErr_Clear(); + return CPyCppyy_PyUnicode_FromString(defvalue.c_str()); + } + + return pyval; + } + + return nullptr; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CPPMethod::GetScopeProxy() +{ +// Get or build the scope of this method. + return CreateScopeProxy(fScope); +} + + +//---------------------------------------------------------------------------- +Cppyy::TCppFuncAddr_t CPyCppyy::CPPMethod::GetFunctionAddress() +{ +// Return the C++ pointer of this function + return Cppyy::GetFunctionAddress(fMethod); +} + + +//---------------------------------------------------------------------------- +bool CPyCppyy::CPPMethod::Initialize(CallContext* ctxt) +{ +// done if cache is already setup + if (fIsInitialized == true) + return true; + + if (!InitConverters_()) + return false; + + if (!InitExecutor_(fExecutor, ctxt)) + return false; + +// minimum number of arguments when calling + fArgsRequired = (bool)fMethod == true ? Cppyy::GetMethodReqArgs(fMethod) : 0; + +// init done + fIsInitialized = true; + + return true; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CPPMethod::PreProcessArgs( + CPPInstance*& self, PyObject* args, PyObject*) +{ +// verify existence of self, return if ok + if (self) { + Py_INCREF(args); + return args; + } + +// otherwise, check for a suitable 'self' in args and update accordingly + if (PyTuple_GET_SIZE(args) != 0) { + CPPInstance* pyobj = (CPPInstance*)PyTuple_GET_ITEM(args, 0); + + // demand CPyCppyy object, and an argument that may match down the road + if (CPPInstance_Check(pyobj) && + (fScope == Cppyy::gGlobalScope || // free global + (pyobj->ObjectIsA() == 0) || // null pointer or ctor call + (Cppyy::IsSubtype(pyobj->ObjectIsA(), fScope)))) { // matching types + + // reset self + self = pyobj; + Py_INCREF(self); // corresponding Py_DECREF is in CPPOverload + + // offset args by 1 (new ref) + return PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args)); + } + } + +// no self, set error and lament + SetPyError_(CPyCppyy_PyUnicode_FromFormat( + "unbound method %s::%s must be called with a %s instance as first argument", + Cppyy::GetFinalName(fScope).c_str(), Cppyy::GetMethodName(fMethod).c_str(), + Cppyy::GetFinalName(fScope).c_str())); + return nullptr; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::CPPMethod::ConvertAndSetArgs(PyObject* args, CallContext* ctxt) +{ + int argc = PyTuple_GET_SIZE(args); + int argMax = fConverters.size(); + +// argc must be between min and max number of arguments + if (argc < fArgsRequired) { + SetPyError_(CPyCppyy_PyUnicode_FromFormat( + "takes at least %d arguments (%d given)", fArgsRequired, argc)); + return false; + } else if (argMax < argc) { + SetPyError_(CPyCppyy_PyUnicode_FromFormat( + "takes at most %d arguments (%d given)", argMax, argc)); + return false; + } + +// convert the arguments to the method call array + ctxt->fArgs.resize(argc); + for (int i = 0; i < argc; ++i) { + if (!fConverters[i]->SetArg( + PyTuple_GET_ITEM(args, i), ctxt->fArgs[i], ctxt)) { + SetPyError_(CPyCppyy_PyUnicode_FromFormat("could not convert argument %d", i+1)); + return false; + } + } + + return true; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CPPMethod::Execute(void* self, ptrdiff_t offset, CallContext* ctxt) +{ +// call the interface method + PyObject* result = 0; + + if (CallContext::sSignalPolicy == CallContext::kFast) { + // bypasses try block (i.e. segfaults will abort) + result = CallFast(self, offset, ctxt); + } else { + // at the cost of ~10% performance, don't abort the interpreter on any signal + result = CallSafe(self, offset, ctxt); + } + + if (result && Utility::PyErr_Occurred_WithGIL()) { + // can happen in the case of a CINT error: trigger exception processing + Py_DECREF(result); + result = 0; + } else if (!result && PyErr_Occurred()) + SetPyError_(0); + + return result; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CPPMethod::Call( + CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* ctxt) +{ +// preliminary check in case keywords are accidently used (they are ignored otherwise) + if (kwds && PyDict_Size(kwds)) { + PyErr_SetString(PyExc_TypeError, "keyword arguments are not yet supported"); + return nullptr; + } + +// setup as necessary + if (!Initialize(ctxt)) + return nullptr; + +// fetch self, verify, and put the arguments in usable order + if (!(args = PreProcessArgs(self, args, kwds))) + return nullptr; + +// translate the arguments + if (!ConvertAndSetArgs(args, ctxt)) { + Py_DECREF(args); + return nullptr; + } + +// get the C++ object that this object proxy is a handle for + void* object = self->GetObject(); + +// validity check that should not fail + if (!object) { + PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer"); + Py_DECREF(args); + return nullptr; + } + +// get its class + Cppyy::TCppType_t derived = self->ObjectIsA(); + +// calculate offset (the method expects 'this' to be an object of fScope) + ptrdiff_t offset = 0; + if (derived && derived != fScope) + offset = Cppyy::GetBaseOffset(derived, fScope, object, 1 /* up-cast */); + +// actual call; recycle self instead of returning new object for same address objects + CPPInstance* pyobj = (CPPInstance*)Execute(object, offset, ctxt); + Py_DECREF(args); + + if (CPPInstance_Check(pyobj) && + derived && pyobj->ObjectIsA() == derived && + pyobj->GetObject() == object) { + Py_INCREF((PyObject*)self); + Py_DECREF(pyobj); + return (PyObject*)self; + } + + return (PyObject*)pyobj; +} + +//- protected members -------------------------------------------------------- +PyObject* CPyCppyy::CPPMethod::GetSignature(bool fa) +{ +// construct python string from the method's signature + return CPyCppyy_PyUnicode_FromString(GetSignatureString(fa).c_str()); +} + +//---------------------------------------------------------------------------- +std::string CPyCppyy::CPPMethod::GetReturnTypeName() +{ + return Cppyy::GetMethodResultType(fMethod); +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPMethod.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPMethod.h new file mode 100644 index 0000000000000..90f800cb2494c --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPMethod.h @@ -0,0 +1,84 @@ +#ifndef CPYCPPYY_CPPMETHOD_H +#define CPYCPPYY_CPPMETHOD_H + +// Bindings +#include "PyCallable.h" + +// Standard +#include +#include + + +namespace CPyCppyy { + +class Executor; +class Converter; + +class CPPMethod : public PyCallable { +public: + CPPMethod(Cppyy::TCppScope_t scope, Cppyy::TCppMethod_t method); + CPPMethod(const CPPMethod&); + CPPMethod& operator=(const CPPMethod&); + virtual ~CPPMethod(); + +public: + virtual PyObject* GetSignature(bool show_formalargs = true); + virtual PyObject* GetPrototype(bool show_formalargs = true); + virtual int GetPriority(); + + virtual int GetMaxArgs(); + virtual PyObject* GetCoVarNames(); + virtual PyObject* GetArgDefault(int iarg); + virtual PyObject* GetScopeProxy(); + virtual Cppyy::TCppFuncAddr_t GetFunctionAddress(); + + virtual PyCallable* Clone() { return new CPPMethod(*this); } + +public: + virtual PyObject* Call( + CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* ctxt = nullptr); + + virtual bool Initialize(CallContext* ctxt = nullptr); + virtual PyObject* PreProcessArgs(CPPInstance*& self, PyObject* args, PyObject* kwds); + virtual bool ConvertAndSetArgs(PyObject* args, CallContext* ctxt = nullptr); + virtual PyObject* Execute(void* self, ptrdiff_t offset, CallContext* ctxt = nullptr); + +protected: + Cppyy::TCppMethod_t GetMethod() { return fMethod; } + Cppyy::TCppScope_t GetScope() { return fScope; } + Executor* GetExecutor() { return fExecutor; } + std::string GetSignatureString(bool show_formalargs = true); + std::string GetReturnTypeName(); + + virtual bool InitExecutor_(Executor*&, CallContext* ctxt = nullptr); + +private: + void Copy_(const CPPMethod&); + void Destroy_() const; + + PyObject* CallFast(void*, ptrdiff_t, CallContext*); + PyObject* CallSafe(void*, ptrdiff_t, CallContext*); + + bool InitConverters_(); + + void SetPyError_(PyObject* msg); + +private: +// representation + Cppyy::TCppMethod_t fMethod; + Cppyy::TCppScope_t fScope; + Executor* fExecutor; + +// call dispatch buffers + std::vector fConverters; + +// cached values + int fArgsRequired; + +// admin + bool fIsInitialized; +}; + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CPPMETHOD_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPOverload.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPOverload.cxx new file mode 100644 index 0000000000000..6ec1aeba0ad60 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPOverload.cxx @@ -0,0 +1,887 @@ +// Bindings +#include "CPyCppyy.h" +#include "structmember.h" // from Python +#if PY_VERSION_HEX >= 0x02050000 +#include "code.h" // from Python +#else +#include "compile.h" // from Python +#endif +#ifndef CO_NOFREE +// python2.2 does not have CO_NOFREE defined +#define CO_NOFREE 0x0040 +#endif +#include "CPPOverload.h" +#include "CPPInstance.h" +#include "CallContext.h" +#include "TPyException.h" +#include "PyStrings.h" +#include "Utility.h" + +// Standard +#include +#include + + +namespace CPyCppyy { + +namespace { + +// TODO: only used here, but may be better off integrated with Pythonize.cxx callbacks +class TPythonCallback : public PyCallable { +public: + PyObject* fCallable; + + TPythonCallback(PyObject* callable) : fCallable(nullptr) + { + if (!PyCallable_Check(callable)) { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); + return; + } + fCallable = callable; + Py_INCREF(fCallable); + } + + virtual ~TPythonCallback() { + Py_DECREF(fCallable); + fCallable = nullptr; + } + + virtual PyObject* GetSignature(bool /*show_formalargs*/ = true) { + return CPyCppyy_PyUnicode_FromString("*args, **kwargs"); + } + virtual PyObject* GetPrototype(bool /*show_formalargs*/ = true) { + return CPyCppyy_PyUnicode_FromString(""); + } + virtual PyObject* GetDocString() { + if (PyObject_HasAttrString(fCallable, "__doc__")) { + return PyObject_GetAttrString(fCallable, "__doc__"); + } else { + return GetPrototype(); + } + } + + virtual int GetPriority() { return 100; }; + + virtual int GetMaxArgs() { return 100; }; + virtual PyObject* GetCoVarNames() { // TODO: pick these up from the callable + Py_RETURN_NONE; + } + virtual PyObject* GetArgDefault(int /* iarg */) { // TODO: pick these up from the callable + Py_RETURN_NONE; + } + + virtual PyObject* GetScopeProxy() { // should this be the module ?? + Py_RETURN_NONE; + } + + virtual Cppyy::TCppFuncAddr_t GetFunctionAddress() { + return (Cppyy::TCppFuncAddr_t)nullptr; + } + + virtual PyCallable* Clone() { return new TPythonCallback(*this); } + + virtual PyObject* Call( + CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* /* ctxt = 0 */) { + + PyObject* newArgs = nullptr; + if (self) { + Py_ssize_t nargs = PyTuple_Size(args); + newArgs = PyTuple_New(nargs+1); + Py_INCREF(self); + PyTuple_SET_ITEM(newArgs, 0, (PyObject*)self); + for (Py_ssize_t iarg = 0; iarg < nargs; ++iarg) { + PyObject* pyarg = PyTuple_GET_ITEM(args, iarg); + Py_INCREF(pyarg); + PyTuple_SET_ITEM(newArgs, iarg+1, pyarg); + } + } else { + Py_INCREF(args); + newArgs = args; + } + return PyObject_Call(fCallable, newArgs, kwds); + } +}; + +// helper to test whether a method is used in a pseudo-function modus +static inline bool IsPseudoFunc(CPPOverload* pymeth) +{ + return (void*)pymeth == (void*)pymeth->fSelf; +} + +// helper to hash tuple (using tuple hash would cause self-tailing loops) +static inline uint64_t HashSignature(PyObject* args) +{ +// Build a hash from the types of the given python function arguments. + uint64_t hash = 0; + + int nargs = PyTuple_GET_SIZE(args); + for (int i = 0; i < nargs; ++i) { + // TODO: hashing in the ref-count is for moves; resolve this together with the + // improved overloads for implicit conversions + PyObject* pyobj = PyTuple_GET_ITEM(args, i); + hash += (uint64_t)Py_TYPE(pyobj); + if (pyobj->ob_refcnt == 1) + hash += (uint64_t)pyobj->ob_refcnt; + hash += (hash << 10); hash ^= (hash >> 6); + } + + hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); + + return hash; +} + +// helper to sort on method priority +static int PriorityCmp(PyCallable* left, PyCallable* right) +{ + return left->GetPriority() > right->GetPriority(); +} + +// return helper +static inline void ResetCallState(CPPInstance*& selfnew, CPPInstance* selfold, bool clear) +{ + if (selfnew != selfold) { + Py_XDECREF(selfnew); + selfnew = selfold; + } + + if (clear) + PyErr_Clear(); +} + +// helper to factor out return logic of mp_call +static inline PyObject* HandleReturn( + CPPOverload* pymeth, CPPInstance* oldSelf, PyObject* result) +{ + +// special case for python exceptions, propagated through C++ layer + if (result) { + + // if this method creates new objects, always take ownership + if (IsCreator(pymeth->fMethodInfo->fFlags)) { + + // either be a constructor with a fresh object proxy self ... + if (IsConstructor(pymeth->fMethodInfo->fFlags)) { + if (pymeth->fSelf) + pymeth->fSelf->PythonOwns(); + } + + // ... or be a method with an object proxy return value + else if (CPPInstance_Check(result)) + ((CPPInstance*)result)->PythonOwns(); + } + + // if this new object falls inside self, make sure its lifetime is proper + if (CPPInstance_Check(pymeth->fSelf) && CPPInstance_Check(result)) { + ptrdiff_t offset = (ptrdiff_t)( + (CPPInstance*)result)->GetObject() - (ptrdiff_t)pymeth->fSelf->GetObject(); + if (0 <= offset && offset < (ptrdiff_t)Cppyy::SizeOf(pymeth->fSelf->ObjectIsA())) { + if (PyObject_SetAttr(result, PyStrings::gLifeLine, (PyObject*)pymeth->fSelf) == -1) + PyErr_Clear(); // ignored + } + } + } + +// reset self as necessary to allow re-use of the CPPOverload + ResetCallState(pymeth->fSelf, oldSelf, false); + + return result; +} + + +//= CPyCppyy method proxy object behaviour =================================== +static PyObject* mp_name(CPPOverload* pymeth, void*) +{ + return CPyCppyy_PyUnicode_FromString(pymeth->GetName().c_str()); +} + +//----------------------------------------------------------------------------- +static PyObject* mp_module(CPPOverload* /* pymeth */, void*) +{ + Py_INCREF(PyStrings::gThisModule); + return PyStrings::gThisModule; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_doc(CPPOverload* pymeth, void*) +{ +// Build python document string ('__doc__') from all C++-side overloads. + CPPOverload::Methods_t& methods = pymeth->fMethodInfo->fMethods; + +// collect doc strings + int nMethods = methods.size(); + if (nMethods == 0) // from template proxy with no instantiations + return nullptr; + PyObject* doc = methods[0]->GetDocString(); + +// simple case + if (nMethods == 1) + return doc; + +// overloaded method + PyObject* separator = CPyCppyy_PyUnicode_FromString("\n"); + for (int i = 1; i < nMethods; ++i) { + CPyCppyy_PyUnicode_Append(&doc, separator); + CPyCppyy_PyUnicode_AppendAndDel(&doc, methods[i]->GetDocString()); + } + Py_DECREF(separator); + + return doc; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_meth_func(CPPOverload* pymeth, void*) +{ +// Create a new method proxy to be returned. + CPPOverload* newPyMeth = (CPPOverload*)CPPOverload_Type.tp_alloc(&CPPOverload_Type, 0); + +// method info is shared, as it contains the collected overload knowledge + *pymeth->fMethodInfo->fRefCount += 1; + newPyMeth->fMethodInfo = pymeth->fMethodInfo; + +// new method is unbound, use of 'meth' is for keeping track whether this +// proxy is used in the capacity of a method or a function + newPyMeth->fSelf = (CPPInstance*)newPyMeth; + + return (PyObject*)newPyMeth; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_meth_self(CPPOverload* pymeth, void*) +{ +// Return the bound self, if any; in case of pseudo-function role, pretend +// that the data member im_self does not exist. + if (IsPseudoFunc(pymeth)) { + PyErr_Format(PyExc_AttributeError, + "function %s has no attribute \'im_self\'", pymeth->fMethodInfo->fName.c_str()); + return nullptr; + } else if (pymeth->fSelf != 0) { + Py_INCREF((PyObject*)pymeth->fSelf); + return (PyObject*)pymeth->fSelf; + } + + Py_RETURN_NONE; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_meth_class(CPPOverload* pymeth, void*) +{ +// Return scoping class; in case of pseudo-function role, pretend that there +// is no encompassing class (i.e. global scope). + if (!IsPseudoFunc(pymeth) && pymeth->fMethodInfo->fMethods.size()) { + PyObject* pyclass = pymeth->fMethodInfo->fMethods[0]->GetScopeProxy(); + if (!pyclass) + PyErr_Format(PyExc_AttributeError, + "function %s has no attribute \'im_class\'", pymeth->fMethodInfo->fName.c_str()); + return pyclass; + } + + Py_RETURN_NONE; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_func_closure(CPPOverload* /* pymeth */, void*) +{ +// Stub only, to fill out the python function interface. + Py_RETURN_NONE; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_func_code(CPPOverload* pymeth, void*) +{ +// Code details are used in module inspect to fill out interactive help() +#if PY_VERSION_HEX < 0x03000000 + CPPOverload::Methods_t& methods = pymeth->fMethodInfo->fMethods; + +// collect arguments only if there is just 1 overload, otherwise put in a +// fake *args (see below for co_varnames) + PyObject* co_varnames = methods.size() == 1 ? methods[0]->GetCoVarNames() : nullptr; + if (!co_varnames) { + // TODO: static methods need no 'self' (but is harmless otherwise) + co_varnames = PyTuple_New(1 /* self */ + 1 /* fake */); + PyTuple_SET_ITEM(co_varnames, 0, CPyCppyy_PyUnicode_FromString("self")); + PyTuple_SET_ITEM(co_varnames, 1, CPyCppyy_PyUnicode_FromString("*args")); + } + + int co_argcount = PyTuple_Size(co_varnames); + +// for now, code object representing the statement 'pass' + PyObject* co_code = PyString_FromStringAndSize("d\x00\x00S", 4); + +// tuples with all the const literals used in the function + PyObject* co_consts = PyTuple_New(0); + PyObject* co_names = PyTuple_New(0); + +// names, freevars, and cellvars go unused + PyObject* co_unused = PyTuple_New(0); + +// filename is made-up + PyObject* co_filename = PyString_FromString("cppyy.py"); + +// name is the function name, also through __name__ on the function itself + PyObject* co_name = PyString_FromString(pymeth->GetName().c_str()); + +// firstlineno is the line number of first function code in the containing scope + +// lnotab is a packed table that maps instruction count and line number + PyObject* co_lnotab = PyString_FromString("\x00\x01\x0c\x01"); + + PyObject* code = (PyObject*)PyCode_New( + co_argcount, // argcount + co_argcount+1, // nlocals + 2, // stacksize + CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE, // flags + co_code, // code + co_consts, // consts + co_names, // names + co_varnames, // varnames + co_unused, // freevars + co_unused, // cellvars + co_filename, // filename + co_name, // name + 1, // firstlineno + co_lnotab); // lnotab + + Py_DECREF(co_lnotab); + Py_DECREF(co_name); + Py_DECREF(co_unused); + Py_DECREF(co_filename); + Py_DECREF(co_varnames); + Py_DECREF(co_names); + Py_DECREF(co_consts); + Py_DECREF(co_code); + + return code; +#else +// not important for functioning of most code, so not implemented for p3 for now (TODO) + pymeth = 0; + Py_RETURN_NONE; +#endif +} + +//----------------------------------------------------------------------------- +static PyObject* mp_func_defaults(CPPOverload* pymeth, void*) +{ +// Create a tuple of default values, if there is only one method (otherwise +// leave undefined: this is only used by inspect for interactive help()) + CPPOverload::Methods_t& methods = pymeth->fMethodInfo->fMethods; + + if (methods.size() != 1) + return PyTuple_New(0); + + int maxarg = methods[0]->GetMaxArgs(); + + PyObject* defaults = PyTuple_New(maxarg); + + int itup = 0; + for (int iarg = 0; iarg < maxarg; ++iarg) { + PyObject* defvalue = methods[0]->GetArgDefault(iarg); + if (defvalue) + PyTuple_SET_ITEM(defaults, itup++, defvalue); + } + _PyTuple_Resize(&defaults, itup); + + return defaults; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_func_globals(CPPOverload* /* pymeth */, void*) +{ +// Return this function's global dict (hard-wired to be the cppyy module); used +// for lookup of names from co_code indexing into co_names. + PyObject* pyglobal = PyModule_GetDict(PyImport_AddModule((char*)"cppyy")); + Py_XINCREF(pyglobal); + return pyglobal; +} + +//----------------------------------------------------------------------------- +PyObject* mp_getcreates(CPPOverload* pymeth, void*) +{ +// Get '_creates' boolean, which determines ownership of return values. + return PyInt_FromLong((long)IsCreator(pymeth->fMethodInfo->fFlags)); +} + +//----------------------------------------------------------------------------- +static int mp_setcreates(CPPOverload* pymeth, PyObject* value, void*) +{ +// Set '_creates' boolean, which determines ownership of return values. + if (!value) { // means that _creates is being deleted + pymeth->fMethodInfo->fFlags &= ~CallContext::kIsCreator; + return 0; + } + + long iscreator = PyLong_AsLong(value); + if (iscreator == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "a boolean 1 or 0 is required for _creates"); + return -1; + } + + if (iscreator) + pymeth->fMethodInfo->fFlags |= CallContext::kIsCreator; + else + pymeth->fMethodInfo->fFlags &= ~CallContext::kIsCreator; + + return 0; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_getmempolicy(CPPOverload* pymeth, void*) +{ +// Get '_mempolicy' enum, which determines ownership of call arguments. + if (pymeth->fMethodInfo->fFlags & CallContext::kUseHeuristics) + return PyInt_FromLong(CallContext::kUseHeuristics); + + if (pymeth->fMethodInfo->fFlags & CallContext::kUseStrict) + return PyInt_FromLong(CallContext::kUseStrict); + + return PyInt_FromLong(-1); +} + +//----------------------------------------------------------------------------- +static int mp_setmempolicy(CPPOverload* pymeth, PyObject* value, void*) +{ +// Set '_mempolicy' enum, which determines ownership of call arguments. + long mempolicy = PyLong_AsLong(value); + if (mempolicy == CallContext::kUseHeuristics) { + pymeth->fMethodInfo->fFlags |= CallContext::kUseHeuristics; + pymeth->fMethodInfo->fFlags &= ~CallContext::kUseStrict; + } else if (mempolicy == CallContext::kUseStrict) { + pymeth->fMethodInfo->fFlags |= CallContext::kUseStrict; + pymeth->fMethodInfo->fFlags &= ~CallContext::kUseHeuristics; + } else { + PyErr_SetString(PyExc_ValueError, + "expected kMemoryStrict or kMemoryHeuristics as value for _mempolicy"); + return -1; + } + + return 0; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_get_manage_smart_ptr(CPPOverload* pymeth, void*) +{ +// Get '_manage_smart_ptr' boolean, which determines whether or not to +// manage returned smart pointers intelligently. + return PyInt_FromLong( + (long)(pymeth->fMethodInfo->fFlags & CallContext::kManageSmartPtr)); +} + +//----------------------------------------------------------------------------- +static int mp_set_manage_smart_ptr(CPPOverload* pymeth, PyObject* value, void*) +{ +// Set '_manage_smart_ptr' boolean, which determines whether or not to +// manage returned smart pointers intelligently. + long policy = PyLong_AsLong(value); + if (policy == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "a boolean 1 or 0 is required for _manage_smart_ptr"); + return -1; + } + + pymeth->fMethodInfo->fFlags |= CallContext::kManageSmartPtr; + + return 0; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_getthreaded(CPPOverload* pymeth, void*) +{ +// Get '_threaded' boolean, which determines whether the GIL will be released. + return PyInt_FromLong( + (long)(pymeth->fMethodInfo->fFlags & CallContext::kReleaseGIL)); +} + +//----------------------------------------------------------------------------- +static int mp_setthreaded(CPPOverload* pymeth, PyObject* value, void*) +{ +// Set '_threaded' boolean, which determines whether the GIL will be released. + long isthreaded = PyLong_AsLong(value); + if (isthreaded == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "a boolean 1 or 0 is required for _creates"); + return -1; + } + + if (isthreaded) + pymeth->fMethodInfo->fFlags |= CallContext::kReleaseGIL; + else + pymeth->fMethodInfo->fFlags &= ~CallContext::kReleaseGIL; + + return 0; +} + + +//----------------------------------------------------------------------------- +static PyGetSetDef mp_getset[] = { + {(char*)"__name__", (getter)mp_name, nullptr, nullptr, nullptr}, + {(char*)"__module__", (getter)mp_module, nullptr, nullptr, nullptr}, + {(char*)"__doc__", (getter)mp_doc, nullptr, nullptr, nullptr}, + +// to be more python-like, where these are duplicated as well; to actually +// derive from the python method or function type is too memory-expensive, +// given that most of the members of those types would not be used + {(char*)"im_func", (getter)mp_meth_func, nullptr, nullptr, nullptr}, + {(char*)"im_self", (getter)mp_meth_self, nullptr, nullptr, nullptr}, + {(char*)"im_class", (getter)mp_meth_class, nullptr, nullptr, nullptr}, + + {(char*)"func_closure", (getter)mp_func_closure, nullptr, nullptr, nullptr}, + {(char*)"func_code", (getter)mp_func_code, nullptr, nullptr, nullptr}, + {(char*)"func_defaults", (getter)mp_func_defaults, nullptr, nullptr, nullptr}, + {(char*)"func_globals", (getter)mp_func_globals, nullptr, nullptr, nullptr}, + {(char*)"func_doc", (getter)mp_doc, nullptr, nullptr, nullptr}, + {(char*)"func_name", (getter)mp_name, nullptr, nullptr, nullptr}, + + {(char*)"_creates", (getter)mp_getcreates, (setter)mp_setcreates, + (char*)"For ownership rules of result: if true, objects are python-owned", nullptr}, + {(char*)"_mempolicy", (getter)mp_getmempolicy, (setter)mp_setmempolicy, + (char*)"For argument ownership rules: like global, either heuristic or strict", nullptr}, + {(char*)"_manage_smart_ptr", (getter)mp_get_manage_smart_ptr, (setter)mp_set_manage_smart_ptr, + (char*)"If a smart pointer is returned, determines management policy.", nullptr}, + {(char*)"_threaded", (getter)mp_getthreaded, (setter)mp_setthreaded, + (char*)"If true, releases GIL on call into C++", nullptr}, + {(char*)nullptr, nullptr, nullptr, nullptr, nullptr} +}; + +//= CPyCppyy method proxy function behavior ================================== +static PyObject* mp_call(CPPOverload* pymeth, PyObject* args, PyObject* kwds) +{ +// Call the appropriate overload of this method. + +// if called through im_func pseudo-representation (this can be gamed if the +// user really wants to ...) + if (IsPseudoFunc(pymeth)) + pymeth->fSelf = nullptr; + + CPPInstance* oldSelf = pymeth->fSelf; + +// get local handles to proxy internals + auto& methods = pymeth->fMethodInfo->fMethods; + auto& dispatchMap = pymeth->fMethodInfo->fDispatchMap; + auto& mflags = pymeth->fMethodInfo->fFlags; + + int nMethods = methods.size(); + + CallContext ctxt = {0}; + ctxt.fFlags |= (mflags & CallContext::kUseHeuristics); + ctxt.fFlags |= (mflags & CallContext::kUseStrict); + ctxt.fFlags |= (mflags & CallContext::kManageSmartPtr); + if (!ctxt.fFlags) ctxt.fFlags |= CallContext::sMemoryPolicy; + ctxt.fFlags |= (mflags & CallContext::kReleaseGIL); + +// simple case + if (nMethods == 1) { + PyObject* result = methods[0]->Call(pymeth->fSelf, args, kwds, &ctxt); + return HandleReturn(pymeth, oldSelf, result); + } + +// otherwise, handle overloading + uint64_t sighash = HashSignature(args); + +// look for known signatures ... + CPPOverload::DispatchMap_t::iterator m = dispatchMap.find(sighash); + if (m != dispatchMap.end()) { + int index = m->second; + PyObject* result = methods[index]->Call(pymeth->fSelf, args, kwds, &ctxt); + result = HandleReturn(pymeth, oldSelf, result); + + if (result != 0) + return result; + + // fall through: python is dynamic, and so, the hashing isn't infallible + ResetCallState(pymeth->fSelf, oldSelf, true); + } + +// ... otherwise loop over all methods and find the one that does not fail + if (!IsSorted(mflags)) { + std::stable_sort(methods.begin(), methods.end(), PriorityCmp); + mflags |= CallContext::kIsSorted; + } + + std::vector errors; + for (int i = 0; i < nMethods; ++i) { + PyObject* result = methods[i]->Call(pymeth->fSelf, args, kwds, &ctxt); + + if (result != 0) { + // success: update the dispatch map for subsequent calls + dispatchMap[sighash] = i; + std::for_each(errors.begin(), errors.end(), Utility::PyError_t::Clear); + return HandleReturn(pymeth, oldSelf, result); + } + + // failure: collect error message/trace (automatically clears exception, too) + if (!PyErr_Occurred()) { + // this should not happen; set an error to prevent core dump and report + PyObject* sig = methods[i]->GetPrototype(); + PyErr_Format(PyExc_SystemError, "%s =>\n %s", + CPyCppyy_PyUnicode_AsString(sig), (char*)"nullptr result without error in mp_call"); + Py_DECREF(sig); + } + Utility::FetchError(errors); + ResetCallState(pymeth->fSelf, oldSelf, false); + } + +// first summarize, then add details + PyObject* topmsg = CPyCppyy_PyUnicode_FromFormat( + "none of the %d overloaded methods succeeded. Full details:", nMethods); + SetDetailedException(errors, topmsg /* steals */, PyExc_TypeError /* default error */); + +// report failure + return nullptr; +} + +//----------------------------------------------------------------------------- +static CPPOverload* mp_descrget(CPPOverload* pymeth, CPPInstance* pyobj, PyObject*) +{ +// Descriptor; create and return a new bound method proxy (language requirement). + CPPOverload* newPyMeth = (CPPOverload*)CPPOverload_Type.tp_alloc(&CPPOverload_Type, 0); + +// method info is shared, as it contains the collected overload knowledge + *pymeth->fMethodInfo->fRefCount += 1; + newPyMeth->fMethodInfo = pymeth->fMethodInfo; + +// new method is to be bound to current object (may be nullptr) + Py_XINCREF((PyObject*)pyobj); + newPyMeth->fSelf = pyobj; + + return newPyMeth; +} + + +//= CPyCppyy method proxy construction/destruction =========================== +static CPPOverload* mp_new(PyTypeObject*, PyObject*, PyObject*) +{ +// Create a new method proxy object. + CPPOverload* pymeth = PyObject_GC_New(CPPOverload, &CPPOverload_Type); + pymeth->fSelf = nullptr; + pymeth->fMethodInfo = new CPPOverload::MethodInfo_t; + + PyObject_GC_Track(pymeth); + return pymeth; +} + +//----------------------------------------------------------------------------- +static void mp_dealloc(CPPOverload* pymeth) +{ +// Deallocate memory held by method proxy object. + PyObject_GC_UnTrack(pymeth); + + if (!IsPseudoFunc(pymeth)) + Py_CLEAR(pymeth->fSelf); + pymeth->fSelf = nullptr; + + if (--(*pymeth->fMethodInfo->fRefCount) <= 0) { + delete pymeth->fMethodInfo; + } + + PyObject_GC_Del(pymeth); +} + +//----------------------------------------------------------------------------- +static Py_ssize_t mp_hash(CPPOverload* pymeth) +{ +// Hash of method proxy object for insertion into dictionaries; with actual +// method (fMethodInfo) shared, its address is best suited. + return _Py_HashPointer(pymeth->fMethodInfo); +} + +//----------------------------------------------------------------------------- +static int mp_traverse(CPPOverload* pymeth, visitproc visit, void* args) +{ +// Garbage collector traverse of held python member objects. + if (pymeth->fSelf && ! IsPseudoFunc(pymeth)) + return visit((PyObject*)pymeth->fSelf, args); + + return 0; +} + +//----------------------------------------------------------------------------- +static int mp_clear(CPPOverload* pymeth) +{ +// Garbage collector clear of held python member objects. + if (!IsPseudoFunc(pymeth)) + Py_CLEAR(pymeth->fSelf); + pymeth->fSelf = nullptr; + + return 0; +} + +//----------------------------------------------------------------------------- +static PyObject* mp_richcompare(CPPOverload* self, CPPOverload* other, int op) +{ +// Rich set of comparison objects; only equals is defined. + if (op != Py_EQ) + return PyType_Type.tp_richcompare((PyObject*)self, (PyObject*)other, op); + +// defined by type + (shared) MethodInfo + bound self, with special case for +// fSelf (i.e. pseudo-function) + if ((Py_TYPE(self) == Py_TYPE(other) && self->fMethodInfo == other->fMethodInfo) && \ + ((IsPseudoFunc(self) && IsPseudoFunc(other)) || self->fSelf == other->fSelf)) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + + +//= CPyCppyy method proxy access to internals ================================ +static PyObject* mp_overload(CPPOverload* pymeth, PyObject* sigarg) +{ +// Select and call a specific C++ overload, based on its signature. + if (!CPyCppyy_PyUnicode_Check(sigarg)) { + PyErr_Format(PyExc_TypeError, "__overload__() argument 1 must be string, not %.50s", + sigarg == Py_None ? "None" : Py_TYPE(sigarg)->tp_name); + return nullptr; + } + + PyObject* sig1 = CPyCppyy_PyUnicode_FromFormat("(%s)", CPyCppyy_PyUnicode_AsString(sigarg)); + + CPPOverload::Methods_t& methods = pymeth->fMethodInfo->fMethods; + for (auto& meth : methods) { + + PyObject* sig2 = meth->GetSignature(false); + if (PyObject_RichCompareBool(sig1, sig2, Py_EQ)) { + Py_DECREF(sig2); + + CPPOverload* newmeth = mp_new(nullptr, nullptr, nullptr); + CPPOverload::Methods_t vec; vec.push_back(meth->Clone()); + newmeth->Set(pymeth->fMethodInfo->fName, vec); + + if (pymeth->fSelf && !IsPseudoFunc(pymeth)) { + Py_INCREF(pymeth->fSelf); + newmeth->fSelf = pymeth->fSelf; + } + + Py_DECREF(sig1); + return (PyObject*)newmeth; + } + + Py_DECREF(sig2); + } + + Py_DECREF(sig1); + PyErr_Format(PyExc_LookupError, + "signature \"%s\" not found", CPyCppyy_PyUnicode_AsString(sigarg)); + return nullptr; +} + +//= CPyCppyy method proxy access to internals ================================ +static PyObject* mp_add_overload(CPPOverload* pymeth, PyObject* new_overload) +{ + TPythonCallback* cb = new TPythonCallback(new_overload); + pymeth->AddMethod(cb); + Py_RETURN_NONE; +} + +static PyMethodDef mp_methods[] = { + {(char*)"__overload__", (PyCFunction)mp_overload, METH_O, + (char*)"select overload for dispatch" }, + {(char*)"__add_overload__", (PyCFunction)mp_add_overload, METH_O, + (char*)"add a new overload" }, + {(char*)nullptr, nullptr, 0, nullptr } +}; + +} // unnamed namespace + + +//= CPyCppyy method proxy type =============================================== +PyTypeObject CPPOverload_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + (char*)"cppyy.CPPOverload", // tp_name + sizeof(CPPOverload), // tp_basicsize + 0, // tp_itemsize + (destructor)mp_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + (hashfunc)mp_hash, // tp_hash + (ternaryfunc)mp_call, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags + (char*)"cppyy method proxy (internal)", // tp_doc + (traverseproc)mp_traverse, // tp_traverse + (inquiry)mp_clear, // tp_clear + (richcmpfunc)mp_richcompare, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + mp_methods, // tp_methods + 0, // tp_members + mp_getset, // tp_getset + 0, // tp_base + 0, // tp_dict + (descrgetfunc)mp_descrget, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + (newfunc)mp_new, // tp_new + 0, // tp_free + 0, // tp_is_gc + 0, // tp_bases + 0, // tp_mro + 0, // tp_cache + 0, // tp_subclasses + 0 // tp_weaklist +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +} // namespace CPyCppyy + + +//- public members ----------------------------------------------------------- +void CPyCppyy::CPPOverload::Set(const std::string& name, std::vector& methods) +{ +// Fill in the data of a freshly created method proxy. + fMethodInfo->fName = name; + fMethodInfo->fMethods.swap(methods); + fMethodInfo->fFlags &= ~CallContext::kIsSorted; + fMethodInfo->fFlags |= CallContext::kManageSmartPtr; + +// special case: all constructors are considered creators by default + if (name == "__init__") + fMethodInfo->fFlags |= (CallContext::kIsCreator | CallContext::kIsConstructor); + +// special case, in heuristics mode also tag *Clone* methods as creators + if (CallContext::sMemoryPolicy == CallContext::kUseHeuristics && \ + name.find("Clone") != std::string::npos) + fMethodInfo->fFlags |= CallContext::kIsCreator; +} + +//----------------------------------------------------------------------------- +void CPyCppyy::CPPOverload::AddMethod(PyCallable* pc) +{ +// Fill in the data of a freshly created method proxy. + fMethodInfo->fMethods.push_back(pc); + fMethodInfo->fFlags &= ~CallContext::kIsSorted; +} + +//----------------------------------------------------------------------------- +void CPyCppyy::CPPOverload::AddMethod(CPPOverload* meth) +{ + fMethodInfo->fMethods.insert(fMethodInfo->fMethods.end(), + meth->fMethodInfo->fMethods.begin(), meth->fMethodInfo->fMethods.end()); + fMethodInfo->fFlags &= ~CallContext::kIsSorted; +} + +//----------------------------------------------------------------------------- +CPyCppyy::CPPOverload::MethodInfo_t::~MethodInfo_t() +{ +// Destructor (this object is reference counted). + for (Methods_t::iterator it = fMethods.begin(); it != fMethods.end(); ++it) { + delete *it; + } + fMethods.clear(); + delete fRefCount; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPOverload.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPOverload.h new file mode 100644 index 0000000000000..ae9845b300eb7 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPOverload.h @@ -0,0 +1,88 @@ +#ifndef CPYCPPYY_CPPOVERLOAD_H +#define CPYCPPYY_CPPOVERLOAD_H + +// Bindings +#include "PyCallable.h" + +// Standard +#include +#include +#include + + +namespace CPyCppyy { + +class CPPOverload { +public: + typedef std::map DispatchMap_t; + typedef std::vector Methods_t; + + struct MethodInfo_t { + MethodInfo_t() : fFlags(CallContext::kNone) { fRefCount = new int(1); } + ~MethodInfo_t(); + + std::string fName; + CPPOverload::DispatchMap_t fDispatchMap; + CPPOverload::Methods_t fMethods; + uint64_t fFlags; + + int* fRefCount; + + private: + MethodInfo_t(const MethodInfo_t&) = delete; + MethodInfo_t& operator=(const MethodInfo_t&) = delete; + }; + +public: + void Set(const std::string& name, std::vector& methods); + + const std::string& GetName() const { return fMethodInfo->fName; } + void AddMethod(PyCallable* pc); + void AddMethod(CPPOverload* meth); + +public: // public, as the python C-API works with C structs + PyObject_HEAD + CPPInstance* fSelf; // must be first (same layout as TemplateProxy) + MethodInfo_t* fMethodInfo; + +private: + CPPOverload() = delete; +}; + + +//- method proxy type and type verification ---------------------------------- +extern PyTypeObject CPPOverload_Type; + +template +inline bool CPPOverload_Check(T* object) +{ + return object && PyObject_TypeCheck(object, &CPPOverload_Type); +} + +template +inline bool CPPOverload_CheckExact(T* object) +{ + return object && Py_TYPE(object) == &CPPOverload_Type; +} + +//- creation ----------------------------------------------------------------- +inline CPPOverload* CPPOverload_New( + const std::string& name, std::vector& methods) +{ +// Create and initialize a new method proxy from the overloads. + CPPOverload* pymeth = (CPPOverload*)CPPOverload_Type.tp_new(&CPPOverload_Type, nullptr, nullptr); + pymeth->Set(name, methods); + return pymeth; +} + +inline CPPOverload* CPPOverload_New(const std::string& name, PyCallable* method) +{ +// Create and initialize a new method proxy from the method. + std::vector p; + p.push_back(method); + return CPPOverload_New(name, p); +} + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CPPOVERLOAD_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPScope.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPScope.cxx new file mode 100644 index 0000000000000..4dd0664505c35 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPScope.cxx @@ -0,0 +1,394 @@ +// Bindings +#include "CPyCppyy.h" +#include "CPPScope.h" +#include "CPPDataMember.h" +#include "CPPFunction.h" +#include "CPPOverload.h" +#include "ProxyWrappers.h" +#include "PyStrings.h" +#include "TemplateProxy.h" +#include "TypeManip.h" +#include "Utility.h" + +// Standard +#include +#include // for for_each +#include +#include +#include + + +namespace CPyCppyy { + +extern PyTypeObject CPPInstance_Type; + +//= CPyCppyy type proxy construction/destruction ============================= +static PyObject* meta_alloc(PyTypeObject* metatype, Py_ssize_t nitems) +{ + return PyType_Type.tp_alloc(metatype, nitems); +} + +//---------------------------------------------------------------------------- +static void meta_dealloc(CPPScope* metatype) +{ + delete metatype->fCppObjects; metatype->fCppObjects = nullptr; + free(metatype->fModuleName); + return PyType_Type.tp_dealloc((PyObject*)metatype); +} + +//----------------------------------------------------------------------------- +static PyObject* meta_getcppname(CPPScope* meta, void*) +{ + if ((void*)meta == (void*)&CPPInstance_Type) + return CPyCppyy_PyUnicode_FromString("CPPInstance_Type"); + return CPyCppyy_PyUnicode_FromString(Cppyy::GetScopedFinalName(meta->fCppType).c_str()); +} + +//----------------------------------------------------------------------------- +static PyObject* meta_getmodule(CPPScope* meta, void*) +{ + if ((void*)meta == (void*)&CPPInstance_Type) + return CPyCppyy_PyUnicode_FromString("cppyy.gbl"); + + if (meta->fModuleName) + return CPyCppyy_PyUnicode_FromString(meta->fModuleName); + + std::string modname = Cppyy::GetScopedFinalName(meta->fCppType); + std::string::size_type pos1 = modname.rfind("::"); + if (modname.empty() || pos1 == std::string::npos) + return CPyCppyy_PyUnicode_FromString(const_cast("cppyy.gbl")); + + PyObject* pymodule = nullptr; + std::string::size_type pos2 = modname.rfind("::", pos1-1); + pos2 = (pos2 == std::string::npos) ? 0 : pos2 + 2; + PyObject* pyscope = CPyCppyy::GetScopeProxy(Cppyy::GetScope(modname.substr(0, pos1))); + if (pyscope) { + pymodule = PyObject_GetAttr(pyscope, PyStrings::gModule); + CPyCppyy_PyUnicode_AppendAndDel(&pymodule, + CPyCppyy_PyUnicode_FromString(('.'+modname.substr(pos2, pos1-pos2)).c_str())); + + Py_DECREF(pyscope); + } + + if (pymodule) + return pymodule; + PyErr_Clear(); + + TypeManip::cppscope_to_pyscope(modname); + return CPyCppyy_PyUnicode_FromString(("cppyy.gbl."+modname.substr(0, pos1)).c_str()); +} + +//----------------------------------------------------------------------------- +static int meta_setmodule(CPPScope* meta, PyObject* value, void*) +{ + if ((void*)meta == (void*)&CPPInstance_Type) { + PyErr_SetString(PyExc_AttributeError, + "attribute \'__module__\' of 'cppyy.CPPScope\' objects is not writable"); + return -1; + } + + const char* newname = CPyCppyy_PyUnicode_AsStringChecked(value); + if (!value) + return -1; + + free(meta->fModuleName); + Py_ssize_t sz = CPyCppyy_PyUnicode_GET_SIZE(value); + meta->fModuleName = (char*)malloc(sz+1); + memcpy(meta->fModuleName, newname, sz+1); + + return 0; +} + +//---------------------------------------------------------------------------- +static PyObject* meta_repr(CPPScope* metatype) +{ +// Specialized b/c type_repr expects __module__ to live in the dictionary, +// whereas it is a property (to save memory). + if ((void*)metatype == (void*)&CPPInstance_Type) + return CPyCppyy_PyUnicode_FromFormat( + const_cast(""), metatype); + + PyObject* modname = meta_getmodule(metatype, nullptr); + std::string clName = Cppyy::GetFinalName(metatype->fCppType); + const char* kind = Cppyy::IsNamespace(metatype->fCppType) ? "namespace" : "class"; + + PyObject* repr = CPyCppyy_PyUnicode_FromFormat("<%s %s.%s at %p>", + kind, CPyCppyy_PyUnicode_AsString(modname), clName.c_str(), metatype); + + Py_DECREF(modname); + return repr; +} + + +//= CPyCppyy type metaclass behavior ========================================= +static PyObject* pt_new(PyTypeObject* subtype, PyObject* args, PyObject* kwds) +{ +// Called when CPPScope acts as a metaclass; since type_new always resets +// tp_alloc, and since it does not call tp_init on types, the metaclass is +// being fixed up here, and the class is initialized here as well. + +// fixup of metaclass (left permanent, and in principle only called once b/c +// cppyy caches python classes) + subtype->tp_alloc = (allocfunc)meta_alloc; + subtype->tp_dealloc = (destructor)meta_dealloc; + +// creation of the python-side class + CPPScope* result = (CPPScope*)PyType_Type.tp_new(subtype, args, kwds); + if (!result) + return nullptr; + + result->fCppObjects = new CppToPyMap_t; + result->fModuleName = nullptr; + +// initialization of class (based on metatype) + const char* mp = strstr(subtype->tp_name, "_meta"); + if (!mp || !CPPScope_CheckExact(subtype)) { + // there has been a user meta class override in a derived class, so do + // the consistent thing, thus allowing user control over naming + result->fCppType = Cppyy::GetScope( + CPyCppyy_PyUnicode_AsString(PyTuple_GET_ITEM(args, 0))); + } else { + // coming here from cppyy or from sub-classing in python; take the + // C++ type from the meta class to make sure that the latter category + // has fCppType properly set (it inherits the meta class, but has an + // otherwise unknown (or wrong) C++ type) + result->fCppType = ((CPPScope*)subtype)->fCppType; + } + + return (PyObject*)result; +} + +//---------------------------------------------------------------------------- +static PyObject* meta_getattro(PyObject* pyclass, PyObject* pyname) +{ +// normal type-based lookup + PyObject* attr = PyType_Type.tp_getattro(pyclass, pyname); + if (attr || pyclass == (PyObject*)&CPPInstance_Type) + return attr; + + if (!CPyCppyy_PyUnicode_CheckExact(pyname) || !CPPScope_Check(pyclass)) + return nullptr; + +// filter for python specials + std::string name = CPyCppyy_PyUnicode_AsString(pyname); + if (name.size() >= 2 && name.compare(0, 2, "__") == 0 && + name.compare(name.size()-2, name.size(), "__") == 0) + return nullptr; + +// more elaborate search in case of failure (eg. for inner classes on demand) + std::vector errors; + Utility::FetchError(errors); + attr = CreateScopeProxy(name, pyclass); + + if (!attr) { + Utility::FetchError(errors); + Cppyy::TCppScope_t scope = ((CPPScope*)pyclass)->fCppType; + + // namespaces may have seen updates in their list of global functions, which + // are available as "methods" even though they're not really that + if (Cppyy::IsNamespace(scope)) { + // tickle lazy lookup of functions + const std::vector methods = + Cppyy::GetMethodIndicesFromName(scope, name); + if (!methods.empty()) { + // function exists, now collect overloads + std::vector overloads; + for (auto idx : methods) { + overloads.push_back( + new CPPFunction(scope, Cppyy::GetMethod(scope, idx))); + } + + // Note: can't re-use Utility::AddClass here, as there's the risk of + // a recursive call. Simply add method directly, as we're guaranteed + // that it doesn't exist yet. + attr = (PyObject*)CPPOverload_New(name, overloads); + + // If both templated and not, the templated one needs to be user-facing + // in order to expose the instantiation mechanims. + if (Cppyy::ExistsMethodTemplate(scope, name)) { + TemplateProxy* pytmpl = TemplateProxy_New(name, name, pyclass); + pytmpl->AddOverload((CPPOverload*)attr); + attr = (PyObject*)pytmpl; + } + } + + // tickle lazy lookup of data members + if (!attr) { + Cppyy::TCppIndex_t dmi = Cppyy::GetDatamemberIndex(scope, name); + if (0 <= dmi) attr = (PyObject*)CPPDataMember_New(scope, dmi); + } + } + + // function templates that have not been instantiated + if (!attr && Cppyy::ExistsMethodTemplate(scope, name)) { + attr = (PyObject*)TemplateProxy_New(name, name, pyclass); + } else { + // for completeness in error reporting + PyErr_Format(PyExc_TypeError, "\'%s\' is not a known C++ template", name.c_str()); + Utility::FetchError(errors); + } + + // enums types requested as type (rather than the constants) + // TODO: IsEnum should deal with the scope, using klass->GetListOfEnums()->FindObject() + if (!attr && Cppyy::IsEnum(scope == Cppyy::gGlobalScope ? name : Cppyy::GetScopedFinalName(scope)+"::"+name)) { + // special case; enum types; for now, pretend int + // TODO: although fine for C++98, this isn't correct in C++11 + Py_INCREF(&PyInt_Type); + attr = (PyObject*)&PyInt_Type; + } else { + // for completeness in error reporting + PyErr_Format(PyExc_TypeError, "\'%s\' is not a known C++ enum", name.c_str()); + Utility::FetchError(errors); + } + + if (attr) { + // cache the result + if (CPPDataMember_Check(attr)) { + PyObject_SetAttr((PyObject*)Py_TYPE(pyclass), pyname, attr); + Py_DECREF(attr); + attr = PyType_Type.tp_getattro(pyclass, pyname); + } else + PyObject_SetAttr(pyclass, pyname, attr); + + } else { + Utility::FetchError(errors); + } + } + + if (attr) + std::for_each(errors.begin(), errors.end(), Utility::PyError_t::Clear); + else { + // not found: prepare a full error report + PyObject* topmsg = nullptr; + PyObject* sklass = PyObject_Str(pyclass); + if (sklass) { + topmsg = CPyCppyy_PyUnicode_FromFormat("%s has no attribute \'%s\'. Full details:", + CPyCppyy_PyUnicode_AsString(sklass), CPyCppyy_PyUnicode_AsString(pyname)); + Py_DECREF(sklass); + } else { + topmsg = CPyCppyy_PyUnicode_FromFormat("no such attribute \'%s\'. Full details:", + CPyCppyy_PyUnicode_AsString(pyname)); + } + SetDetailedException(errors, topmsg /* steals */, PyExc_AttributeError /* default error */); + } + + return attr; +} + + +//---------------------------------------------------------------------------- +// p2.7 does not have a __dir__ in object, and object.__dir__ in p3 does not +// quite what I'd expected of it, so the following pulls in the internal code +#include "PyObjectDir27.inc" + +static PyObject* meta_dir(CPPScope* klass) +{ +// Collect a list of everything (currently) available in the namespace. +// The backend can filter by returning empty strings. Special care is +// taken for functions, which need not be unique (overloading). + using namespace Cppyy; + + if ((void*)klass == (void*)&CPPInstance_Type) + return PyList_New(0); + + if (!CPyCppyy::CPPScope_Check((PyObject*)klass)) { + PyErr_SetString(PyExc_TypeError, "C++ proxy scope expected"); + return nullptr; + } + + PyObject* dirlist = _generic_dir((PyObject*)klass); + if (!IsNamespace(klass->fCppType)) + return dirlist; + + std::set cppnames; + Cppyy::GetAllCppNames(klass->fCppType, cppnames); + +// get rid of duplicates + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(dirlist); ++i) + cppnames.insert(CPyCppyy_PyUnicode_AsString(PyList_GET_ITEM(dirlist, i))); + + Py_DECREF(dirlist); + dirlist = PyList_New(cppnames.size()); + +// copy total onto python list + Py_ssize_t i = 0; + for (const auto& name : cppnames) { + PyList_SET_ITEM(dirlist, i++, CPyCppyy_PyUnicode_FromString(name.c_str())); + } + return dirlist; +} + +//----------------------------------------------------------------------------- +static PyMethodDef meta_methods[] = { + {(char*)"__dir__", (PyCFunction)meta_dir, METH_NOARGS, nullptr}, + {(char*)nullptr, nullptr, 0, nullptr} +}; + + +//----------------------------------------------------------------------------- +static PyGetSetDef meta_getset[] = { + {(char*)"__cppname__", (getter)meta_getcppname, nullptr, nullptr, nullptr}, + {(char*)"__module__", (getter)meta_getmodule, (setter)meta_setmodule, nullptr, nullptr}, + {(char*)nullptr, nullptr, nullptr, nullptr, nullptr} +}; + + +//= CPyCppyy object proxy type type ========================================== +PyTypeObject CPPScope_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + (char*)"cppyy.CPPScope", // tp_name + sizeof(CPyCppyy::CPPScope), // tp_basicsize + 0, // tp_itemsize + 0, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + (reprfunc)meta_repr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + (getattrofunc)meta_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags + (char*)"CPyCppyy metatype (internal)", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + meta_methods, // tp_methods + 0, // tp_members + meta_getset, // tp_getset + &PyType_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + (newfunc)pt_new, // tp_new + 0, // tp_free + 0, // tp_is_gc + 0, // tp_bases + 0, // tp_mro + 0, // tp_cache + 0, // tp_subclasses + 0 // tp_weaklist +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +} // namespace CPyCppyy diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPScope.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPScope.h new file mode 100644 index 0000000000000..f707fdfb12846 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPScope.h @@ -0,0 +1,66 @@ +#ifndef CPYCPPYY_CPPSCOPE_H +#define CPYCPPYY_CPPSCOPE_H + +#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION == 2 + +// In p2.2, PyHeapTypeObject is not yet part of the interface +#include "structmember.h" + +typedef struct { + PyTypeObject type; + PyNumberMethods as_number; + PySequenceMethods as_sequence; + PyMappingMethods as_mapping; + PyBufferProcs as_buffer; + PyObject *name, *slots; + PyMemberDef members[1]; +} PyHeapTypeObject; + +#endif + +// Standard +#include + + +namespace CPyCppyy { + +/** Type object to hold class reference (this is only semantically a presentation + of CPPScope instances, not in a C++ sense) + @author WLAV + @date 07/06/2017 + @version 2.0 + */ + +typedef std::map CppToPyMap_t; + +class CPPScope { +public: + PyHeapTypeObject fType; + Cppyy::TCppType_t fCppType; + CppToPyMap_t* fCppObjects; + char* fModuleName; + +private: + CPPScope() = delete; +}; + +typedef CPPScope CPPClass; + +//- metatype type and type verification -------------------------------------- +extern PyTypeObject CPPScope_Type; + +template +inline bool CPPScope_Check(T* object) +{ + return object && PyObject_TypeCheck(object, &CPPScope_Type); +} + +template +inline bool CPPScope_CheckExact(T* object) +{ + return object && Py_TYPE(object) == &CPPScope_Type; +} + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CPPSCOPE_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPSetItem.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPSetItem.cxx new file mode 100644 index 0000000000000..1f94abfbd5396 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPSetItem.cxx @@ -0,0 +1,73 @@ +// Bindings +#include "CPyCppyy.h" +#include "CPPSetItem.h" +#include "Executors.h" + + +//- protected members --------------------------------------------------------- +bool CPyCppyy::CPPSetItem::InitExecutor_(Executor*& executor, CallContext*) +{ +// basic call will do + if (!CPPMethod::InitExecutor_(executor)) + return false; + +// check to make sure we're dealing with a RefExecutor + if (!dynamic_cast(executor)) { + PyErr_Format(PyExc_NotImplementedError, + "no __setitem__ handler for return type (%s)", + this->GetReturnTypeName().c_str()); + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +PyObject* CPyCppyy::CPPSetItem::PreProcessArgs( + CPPInstance*& self, PyObject* args, PyObject* kwds) +{ +// Prepare executor with a buffer for the return value. + int nArgs = PyTuple_GET_SIZE(args); + if (nArgs <= 1) { + PyErr_SetString(PyExc_TypeError, "insufficient arguments to __setitem__"); + return nullptr; + } + +// strip the last element of args to be used on return + ((RefExecutor*)this->GetExecutor())->SetAssignable(PyTuple_GET_ITEM(args, nArgs-1)); + PyObject* subset = PyTuple_GetSlice(args, 0, nArgs-1); + +// see whether any of the arguments is a tuple itself + Py_ssize_t realsize = 0; + for (int i = 0; i < nArgs - 1; ++i) { + PyObject* item = PyTuple_GetItem(subset, i); + realsize += PyTuple_Check(item) ? PyTuple_GET_SIZE(item) : 1; + } + +// unroll any tuples, if present in the arguments + PyObject* unrolled = 0; + if (realsize != nArgs-1) { + unrolled = PyTuple_New(realsize); + + int current = 0; + for (int i = 0; i < nArgs - 1; ++i, ++current) { + PyObject* item = PyTuple_GetItem(subset, i); + if (PyTuple_Check(item)) { + for (int j = 0; j < PyTuple_GET_SIZE(item); ++j, ++current) { + PyObject* subitem = PyTuple_GetItem(item, j); + Py_INCREF(subitem); + PyTuple_SetItem(unrolled, current, subitem); + } + } else { + Py_INCREF(item); + PyTuple_SetItem(unrolled, current, item); + } + } + } + +// actual call into C++ + PyObject* result = CPPMethod::PreProcessArgs(self, unrolled ? unrolled : subset, kwds); + Py_XDECREF(unrolled); + Py_DECREF(subset); + return result; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPSetItem.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPSetItem.h new file mode 100644 index 0000000000000..fe2dea75aa8ab --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPPSetItem.h @@ -0,0 +1,24 @@ +#ifndef CPYCPPYY_CPPSETITEM_H +#define CPYCPPYY_CPPSETITEM_H + +// Bindings +#include "CPPMethod.h" + + +namespace CPyCppyy { + +class CPPSetItem : public CPPMethod { +public: + using CPPMethod::CPPMethod; + +public: + virtual PyCallable* Clone() { return new CPPSetItem(*this); } + virtual PyObject* PreProcessArgs(CPPInstance*& self, PyObject* args, PyObject* kwds); + +protected: + virtual bool InitExecutor_(Executor*&, CallContext* ctxt = nullptr); +}; + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CPPSETITEM_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPyCppyy.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPyCppyy.h new file mode 100644 index 0000000000000..c63c4f4aa5af3 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPyCppyy.h @@ -0,0 +1,253 @@ +#ifndef CPYCPPYY_CPYCPPYY_H +#define CPYCPPYY_CPYCPPYY_H + +#ifdef _WIN32 +// Disable warning C4275: non dll-interface class +#pragma warning (disable : 4275) +// Disable warning C4251: needs to have dll-interface to be used by clients +#pragma warning (disable : 4251) +// Disable warning C4800: 'int' : forcing value to bool +#pragma warning (disable : 4800) +// Avoid that pyconfig.h decides using a #pragma what library python library to use +//#define MS_NO_COREDLL 1 +#endif + +// to prevent problems with fpos_t and redefinition warnings +#if defined(linux) + +#include + +#ifdef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif + +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif + +#ifdef _XOPEN_SOURCE +#undef _XOPEN_SOURCE +#endif + +#endif // linux + + +#include "Python.h" +#include + +// selected ROOT types from RtypesCore.h +#ifdef R__INT16 +typedef long Int_t; //Signed integer 4 bytes +typedef unsigned long UInt_t; //Unsigned integer 4 bytes +#else +typedef int Int_t; //Signed integer 4 bytes (int) +typedef unsigned int UInt_t; //Unsigned integer 4 bytes (unsigned int) +#endif +#ifdef R__B64 // Note: Long_t and ULong_t are currently not portable types +typedef long Long_t; //Signed long integer 8 bytes (long) +typedef unsigned long ULong_t; //Unsigned long integer 8 bytes (unsigned long) +#else +typedef long Long_t; //Signed long integer 4 bytes (long) +typedef unsigned long ULong_t; //Unsigned long integer 4 bytes (unsigned long) +#endif +typedef float Float16_t; //Float 4 bytes written with a truncated mantissa +typedef double Double32_t; //Double 8 bytes in memory, written as a 4 bytes float +typedef long double LongDouble_t;//Long Double +#if defined(R__WIN32) && !defined(__CINT__) +typedef __int64 Long64_t; //Portable signed long integer 8 bytes +typedef unsigned __int64 ULong64_t; //Portable unsigned long integer 8 bytes +#else +typedef long long Long64_t; //Portable signed long integer 8 bytes +typedef unsigned long long ULong64_t;//Portable unsigned long integer 8 bytes +#endif + + +// for 3.3 support +#if PY_VERSION_HEX < 0x03030000 + typedef PyDictEntry* (*dict_lookup_func)(PyDictObject*, PyObject*, long); +#else +#if PY_VERSION_HEX >= 0x03060000 + typedef Py_ssize_t (*dict_lookup_func)( + PyDictObject*, PyObject*, Py_hash_t, PyObject***, Py_ssize_t*); +#else + struct PyDictKeyEntry; + typedef PyDictKeyEntry* (*dict_lookup_func)(PyDictObject*, PyObject*, Py_hash_t, PyObject***); +#define PyDictEntry PyDictKeyEntry +#endif +#endif + +// for 3.0 support (backwards compatibility, really) +#if PY_VERSION_HEX < 0x03000000 +#define PyBytes_Check PyString_Check +#define PyBytes_CheckExact PyString_CheckExact +#define PyBytes_AS_STRING PyString_AS_STRING +#define PyBytes_AsString PyString_AsString +#define PyBytes_GET_SIZE PyString_GET_SIZE +#define PyBytes_Size PyString_Size +#define PyBytes_FromFormat PyString_FromFormat +#define PyBytes_FromString PyString_FromString +#define PyBytes_FromStringAndSize PyString_FromStringAndSize + +#define PyBytes_Type PyString_Type + +#define CPyCppyy_PyUnicode_Check PyString_Check +#define CPyCppyy_PyUnicode_CheckExact PyString_CheckExact +#define CPyCppyy_PyUnicode_AsString PyString_AS_STRING +#define CPyCppyy_PyUnicode_AsStringChecked PyString_AsString +#define CPyCppyy_PyUnicode_GET_SIZE PyString_GET_SIZE +#define CPyCppyy_PyUnicode_GetSize PyString_Size +#define CPyCppyy_PyUnicode_FromFormat PyString_FromFormat +#define CPyCppyy_PyUnicode_FromString PyString_FromString +#define CPyCppyy_PyUnicode_InternFromString PyString_InternFromString +#define CPyCppyy_PyUnicode_Append PyString_Concat +#define CPyCppyy_PyUnicode_AppendAndDel PyString_ConcatAndDel +#define CPyCppyy_PyUnicode_FromStringAndSize PyString_FromStringAndSize + +#define CPyCppyy_PyUnicode_Type PyString_Type + +static inline PyObject* CPyCppyy_PyCapsule_New( + void* cobj, const char* /* name */, void (*destr)(void*)) +{ + return PyCObject_FromVoidPtr(cobj, destr); +} +#define CPyCppyy_PyCapsule_CheckExact PyCObject_Check +static inline void* CPyCppyy_PyCapsule_GetPointer(PyObject* capsule, const char* /* name */) +{ + return (void*)PyCObject_AsVoidPtr(capsule); +} + +#define CPPYY__long__ "__long__" +#define CPPYY__idiv__ "__idiv__" +#define CPPYY__div__ "__div__" +#define CPPYY__next__ "next" + +#endif // ! 3.0 + +// for 3.0 support (backwards compatibility, really) +#if PY_VERSION_HEX >= 0x03000000 +#define CPyCppyy_PyUnicode_Check PyUnicode_Check +#define CPyCppyy_PyUnicode_CheckExact PyUnicode_CheckExact +#define CPyCppyy_PyUnicode_AsString _PyUnicode_AsString +#define CPyCppyy_PyUnicode_AsStringChecked _PyUnicode_AsString +#define CPyCppyy_PyUnicode_GetSize PyUnicode_GetSize +#define CPyCppyy_PyUnicode_GET_SIZE PyUnicode_GET_SIZE +#define CPyCppyy_PyUnicode_FromFormat PyUnicode_FromFormat +#define CPyCppyy_PyUnicode_FromString PyUnicode_FromString +#define CPyCppyy_PyUnicode_InternFromString PyUnicode_InternFromString +#define CPyCppyy_PyUnicode_Append PyUnicode_Append +#define CPyCppyy_PyUnicode_AppendAndDel PyUnicode_AppendAndDel +#define CPyCppyy_PyUnicode_FromStringAndSize PyUnicode_FromStringAndSize + +#define CPyCppyy_PyUnicode_Type PyUnicode_Type + +#define PyIntObject PyLongObject +#define PyInt_Check PyLong_Check +#define PyInt_AsLong PyLong_AsLong +#define PyInt_AS_LONG PyLong_AsLong +#define PyInt_AsSsize_t PyLong_AsSsize_t +#define PyInt_CheckExact PyLong_CheckExact +#define PyInt_FromLong PyLong_FromLong +#define PyInt_FromSsize_t PyLong_FromSsize_t + +#define PyInt_Type PyLong_Type + +#define CPyCppyy_PyCapsule_New PyCapsule_New +#define CPyCppyy_PyCapsule_CheckExact PyCapsule_CheckExact +#define CPyCppyy_PyCapsule_GetPointer PyCapsule_GetPointer + +#define CPPYY__long__ "__int__" +#define CPPYY__idiv__ "__itruediv__" +#define CPPYY__div__ "__truediv__" +#define CPPYY__next__ "__next__" + +#define Py_TPFLAGS_HAVE_RICHCOMPARE 0 +#define Py_TPFLAGS_CHECKTYPES 0 + +#define PyClass_Check PyType_Check + +#define PyBuffer_Type PyMemoryView_Type +#endif // ! 3.0 + +#if PY_VERSION_HEX >= 0x03020000 +#define CPyCppyy_PySliceCast PyObject* +#else +#define CPyCppyy_PySliceCast PySliceObject* +#endif // >= 3.2 + +// feature of 3.0 not in 2.5 and earlier +#if PY_VERSION_HEX < 0x02060000 +#define PyVarObject_HEAD_INIT(type, size) \ + PyObject_HEAD_INIT(type) size, +#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) +#endif + +// backwards compatibility, pre python 2.5 +#if PY_VERSION_HEX < 0x02050000 +typedef int Py_ssize_t; +#define PyInt_AsSsize_t PyInt_AsLong +#define PyInt_FromSsize_t PyInt_FromLong +# define PY_SSIZE_T_FORMAT "%d" +# if !defined(PY_SSIZE_T_MIN) +# define PY_SSIZE_T_MAX INT_MAX +# define PY_SSIZE_T_MIN INT_MIN +# endif +#define ssizeobjargproc intobjargproc +#define lenfunc inquiry +#define ssizeargfunc intargfunc + +#define PyIndex_Check(obj) \ + (PyInt_Check(obj) || PyLong_Check(obj)) + +inline Py_ssize_t PyNumber_AsSsize_t(PyObject* obj, PyObject*) { + return (Py_ssize_t)PyLong_AsLong(obj); +} + +#else +# ifdef R__MACOSX +# if SIZEOF_SIZE_T == SIZEOF_INT +# if defined(MAC_OS_X_VERSION_10_4) +# define PY_SSIZE_T_FORMAT "%ld" +# else +# define PY_SSIZE_T_FORMAT "%d" +# endif +# elif SIZEOF_SIZE_T == SIZEOF_LONG +# define PY_SSIZE_T_FORMAT "%ld" +# endif +# else +# define PY_SSIZE_T_FORMAT "%zd" +# endif +#endif + +#if PY_VERSION_HEX < 0x02020000 +#define PyBool_FromLong PyInt_FromLong +#endif + +#if PY_VERSION_HEX < 0x03000000 +// the following should quiet Solaris +#ifdef Py_False +#undef Py_False +#define Py_False ((PyObject*)(void*)&_Py_ZeroStruct) +#endif + +#ifdef Py_True +#undef Py_True +#define Py_True ((PyObject*)(void*)&_Py_TrueStruct) +#endif +#endif + +#ifndef Py_RETURN_NONE +#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif + +#ifndef Py_RETURN_TRUE +#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True +#endif + +#ifndef Py_RETURN_FALSE +#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False +#endif + +// C++ version of the cppyy API +#include "Cppyy.h" + +#endif // !CPYCPPYY_CPYCPPYY_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPyCppyyModule.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPyCppyyModule.cxx new file mode 100644 index 0000000000000..35dc460281b31 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CPyCppyyModule.cxx @@ -0,0 +1,840 @@ +// Bindings +#include "CPyCppyy.h" +#include "CallContext.h" +#include "CPPDataMember.h" +#include "CPPInstance.h" +#include "CPPOverload.h" +#include "CPPScope.h" +#include "CustomPyTypes.h" +#include "LowLevelViews.h" +#include "MemoryRegulator.h" +#include "ProxyWrappers.h" +#include "PyStrings.h" +#include "TemplateProxy.h" +#include "TupleOfInstances.h" +#include "Utility.h" + +// Standard +#include +#include +#include +#include +#include +#include +#include + + +//- from Python's dictobject.c ------------------------------------------------- +#if PY_VERSION_HEX >= 0x03030000 + typedef struct PyDictKeyEntry { + /* Cached hash code of me_key. */ + Py_hash_t me_hash; + PyObject *me_key; + PyObject *me_value; /* This field is only meaningful for combined tables */ + } PyDictEntry; + + typedef struct _dictkeysobject { + Py_ssize_t dk_refcnt; + Py_ssize_t dk_size; + dict_lookup_func dk_lookup; + Py_ssize_t dk_usable; +#if PY_VERSION_HEX >= 0x03060000 + Py_ssize_t dk_nentries; + union { + int8_t as_1[8]; + int16_t as_2[4]; + int32_t as_4[2]; +#if SIZEOF_VOID_P > 4 + int64_t as_8[1]; +#endif + } dk_indices; +#else + PyDictKeyEntry dk_entries[1]; +#endif + } PyDictKeysObject; + +#define CPYCPPYY_GET_DICT_LOOKUP(mp) \ + ((dict_lookup_func&)mp->ma_keys->dk_lookup) + +#else + +#define CPYCPPYY_GET_DICT_LOOKUP(mp) \ + ((dict_lookup_func&)mp->ma_lookup) + +#endif + +//- data ----------------------------------------------------------------------- +static PyObject* nullptr_repr(PyObject*) +{ + return CPyCppyy_PyUnicode_FromString("nullptr"); +} + +static void nullptr_dealloc(PyObject*) +{ + Py_FatalError("deallocating nullptr"); +} + +static int nullptr_nonzero(PyObject*) +{ + return 0; +} + +static PyNumberMethods nullptr_as_number = { + 0, 0, 0, +#if PY_VERSION_HEX < 0x03000000 + 0, +#endif + 0, 0, 0, 0, 0, 0, + (inquiry)nullptr_nonzero, // tp_nonzero (nb_bool in p3) + 0, 0, 0, 0, 0, 0, +#if PY_VERSION_HEX < 0x03000000 + 0, // nb_coerce +#endif + 0, 0, 0, +#if PY_VERSION_HEX < 0x03000000 + 0, 0, +#endif + 0, 0, 0, +#if PY_VERSION_HEX < 0x03000000 + 0, // nb_inplace_divide +#endif + 0, 0, 0, 0, 0, 0, 0 +#if PY_VERSION_HEX >= 0x02020000 + , 0 // nb_floor_divide +#if PY_VERSION_HEX < 0x03000000 + , 0 // nb_true_divide +#else + , 0 // nb_true_divide +#endif + , 0, 0 +#endif +#if PY_VERSION_HEX >= 0x02050000 + , 0 // nb_index +#endif +#if PY_VERSION_HEX >= 0x03050000 + , 0 // nb_matrix_multiply + , 0 // nb_inplace_matrix_multiply +#endif +}; + +static PyTypeObject PyNullPtr_t_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "nullptr_t", // tp_name + sizeof(PyObject), // tp_basicsize + 0, // tp_itemsize + nullptr_dealloc, // tp_dealloc (never called) + 0, 0, 0, 0, + nullptr_repr, // tp_repr + &nullptr_as_number, // tp_as_number + 0, 0, + (hashfunc)_Py_HashPointer, // tp_hash + 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +namespace { + +PyObject _CPyCppyy_NullPtrStruct = { + _PyObject_EXTRA_INIT + 1, &PyNullPtr_t_Type +}; + +} // unnamed namespace + +namespace CPyCppyy { + PyObject* gThisModule = nullptr; + PyObject* gNullPtrObject = nullptr; + std::map> gPythonizations; + std::set gPinnedTypes; +} + + +//- private helpers ------------------------------------------------------------ +namespace { + +using namespace CPyCppyy; + +//---------------------------------------------------------------------------- +namespace { + +class GblGetter { +public: + GblGetter() { + PyObject* cppyy = PyImport_AddModule((char*)"cppyy"); + fGbl = PyObject_GetAttrString(cppyy, (char*)"gbl"); + } + ~GblGetter() { Py_DECREF(fGbl); } + + PyObject* operator*() { return fGbl; } + +private: + PyObject* fGbl; +}; + +} // unnamed namespace + +#if PY_VERSION_HEX >= 0x03060000 +inline Py_ssize_t OrgDictLookup(PyDictObject* mp, PyObject* key, + Py_hash_t hash, PyObject*** value_addr, Py_ssize_t* hashpos) +{ + return (*gDictLookupOrg)(mp, key, hash, value_addr, hashpos); +} +#define CPYCPPYY_ORGDICT_LOOKUP(mp, key, hash, value_addr, hashpos) \ + OrgDictLookup(mp, key, hash, value_addr, hashpos) + +Py_ssize_t CPyCppyyLookDictString(PyDictObject* mp, PyObject* key, + Py_hash_t hash, PyObject*** value_addr, Py_ssize_t* hashpos) + +#elif PY_VERSION_HEX >= 0x03030000 +inline PyDictKeyEntry* OrgDictLookup( + PyDictObject* mp, PyObject* key, Py_hash_t hash, PyObject*** value_addr) +{ + return (*gDictLookupOrg)(mp, key, hash, value_addr); +} + +#define CPYCPPYY_ORGDICT_LOOKUP(mp, key, hash, value_addr, hashpos) \ + OrgDictLookup(mp, key, hash, value_addr) + +PyDictKeyEntry* CPyCppyyLookDictString( + PyDictObject* mp, PyObject* key, Py_hash_t hash, PyObject*** value_addr) + +#else /* < 3.3 */ + +inline PyDictEntry* OrgDictLookup(PyDictObject* mp, PyObject* key, Long_t hash) +{ + return (*gDictLookupOrg)(mp, key, hash); +} + +#define CPYCPPYY_ORGDICT_LOOKUP(mp, key, hash, value_addr, hashpos) \ + OrgDictLookup(mp, key, hash) + +PyDictEntry* CPyCppyyLookDictString(PyDictObject* mp, PyObject* key, Long_t hash) +#endif +{ + static GblGetter gbl; +#if PY_VERSION_HEX >= 0x03060000 + Py_ssize_t ep; +#else + PyDictEntry* ep; +#endif + +// first search dictionary itself + ep = CPYCPPYY_ORGDICT_LOOKUP(mp, key, hash, value_addr, hashpos); + if (gDictLookupActive) + return ep; + +#if PY_VERSION_HEX >= 0x03060000 + if (ep >= 0) +#else + if (!ep || (ep->me_key && ep->me_value)) +#endif + return ep; + +// filter for builtins + if (PyDict_GetItem(PyEval_GetBuiltins(), key) != 0) + return ep; + +// normal lookup failed, attempt to get C++ enum/global/class from top-level + gDictLookupActive = true; + +// attempt to get C++ enum/global/class from top-level + PyObject* val = PyObject_GetAttr(*gbl, key); + + if (val) { + // success ... + + if (CPPDataMember_CheckExact(val)) { + // don't want to add to dictionary (the proper place would be the + // dictionary of the (meta)class), but modifying ep will be noticed no + // matter what; just return the actual value and live with the copy in + // the dictionary (mostly, this is correct) + PyObject* actual_val = Py_TYPE(val)->tp_descr_get(val, nullptr, nullptr); + Py_DECREF(val); + val = actual_val; + } + + // add reference to C++ entity in the given dictionary + CPYCPPYY_GET_DICT_LOOKUP(mp) = gDictLookupOrg; // prevent recursion + if (PyDict_SetItem((PyObject*)mp, key, val) == 0) { + ep = CPYCPPYY_ORGDICT_LOOKUP(mp, key, hash, value_addr, hashpos); + } else { +#if PY_VERSION_HEX >= 0x03060000 + ep = -1; +#else + ep->me_key = nullptr; + ep->me_value = nullptr; +#endif + } + CPYCPPYY_GET_DICT_LOOKUP(mp) = CPyCppyyLookDictString; // restore + + // done with val + Py_DECREF(val); + } else + PyErr_Clear(); + +#if PY_VERSION_HEX >= 0x03030000 + if (mp->ma_keys->dk_usable <= 0) { + // big risk that this lookup will result in a resize, so force it here + // to be able to reset the lookup function; of course, this is nowhere + // near fool-proof, but should cover interactive usage ... + CPYCPPYY_GET_DICT_LOOKUP(mp) = gDictLookupOrg; + const int maxinsert = 5; + PyObject* buf[maxinsert]; + for (int varmax = 1; varmax <= maxinsert; ++varmax) { + for (int ivar = 0; ivar < varmax; ++ivar) { + buf[ivar] = CPyCppyy_PyUnicode_FromFormat("__CPYCPPYY_FORCE_RESIZE_%d", ivar); + PyDict_SetItem((PyObject*)mp, buf[ivar], Py_None); + } + for (int ivar = 0; ivar < varmax; ++ivar) { + PyDict_DelItem((PyObject*)mp, buf[ivar]); + Py_DECREF(buf[ivar]); + } + if (0 < mp->ma_keys->dk_usable) + break; + } + + // make sure the entry pointer is still valid by re-doing the lookup + ep = CPYCPPYY_ORGDICT_LOOKUP(mp, key, hash, value_addr, hashpos); + + // full reset of all lookup functions + gDictLookupOrg = CPYCPPYY_GET_DICT_LOOKUP(mp); + CPYCPPYY_GET_DICT_LOOKUP(mp) = CPyCppyyLookDictString; // restore + } +#endif + +// stopped calling into the reflection system + gDictLookupActive = false; + return ep; +} + +//---------------------------------------------------------------------------- +PyObject* SetCppLazyLookup(PyObject*, PyObject* args) +{ +// Modify the given dictionary to install the lookup function that also +// tries the global C++ namespace before failing. Called on a module's dictionary, +// this allows for lazy lookups. This works fine for p3.2 and earlier, but should +// not be used beyond interactive code for p3.3 and later b/c resizing causes the +// lookup function to revert to the default (lookdict_unicode_nodummy). + PyDictObject* dict = nullptr; + if (!PyArg_ParseTuple(args, const_cast("O!"), &PyDict_Type, &dict)) + return nullptr; + + CPYCPPYY_GET_DICT_LOOKUP(dict) = CPyCppyyLookDictString; + + Py_RETURN_NONE; +} + +//---------------------------------------------------------------------------- +PyObject* MakeCppTemplateClass(PyObject*, PyObject* args) +{ +// Create a binding for a templated class instantiation. + +// args is class name + template arguments; build full instantiation + Py_ssize_t nArgs = PyTuple_GET_SIZE(args); + if (nArgs < 2) { + PyErr_Format(PyExc_TypeError, "too few arguments for template instantiation"); + return nullptr; + } + +// build "< type, type, ... >" part of class name (modifies pyname) + const std::string& tmpl_name = + Utility::ConstructTemplateArgs(PyTuple_GET_ITEM(args, 0), args, 1); + if (!tmpl_name.size()) + return nullptr; + + return CreateScopeProxy(tmpl_name); +} + +//---------------------------------------------------------------------------- +void* GetCPPInstanceAddress(PyObject*, PyObject* args) +{ +// Helper to get the address (address-of-address) of various object proxy types. + CPPInstance* pyobj = 0; + PyObject* pyname = 0; + if (PyArg_ParseTuple(args, const_cast("O|O!"), &pyobj, + &CPyCppyy_PyUnicode_Type, &pyname) && CPPInstance_Check(pyobj)) { + + if (pyname != 0) { + // locate property proxy for offset info + CPPDataMember* pyprop = nullptr; + + PyObject* pyclass = PyObject_GetAttr((PyObject*)pyobj, PyStrings::gClass); + + if (pyclass) { + PyObject* dict = PyObject_GetAttr(pyclass, PyStrings::gDict); + pyprop = (CPPDataMember*)PyObject_GetItem(dict, pyname); + Py_DECREF(dict); + } + Py_XDECREF(pyclass); + + if (CPPDataMember_Check(pyprop)) { + // this is an address of a value (i.e. &myobj->prop) + void* addr = (void*)pyprop->GetAddress(pyobj); + Py_DECREF(pyprop); + return addr; + } + + Py_XDECREF(pyprop); + + PyErr_Format(PyExc_TypeError, + "%s is not a valid data member", CPyCppyy_PyUnicode_AsString(pyname)); + return nullptr; + } + + // this is an address of an address (i.e. &myobj, with myobj of type MyObj*) + // note that pyobject->fObject may be null + return (void*)&pyobj->fObject; + } + + PyErr_SetString(PyExc_ValueError, "invalid argument for addressof()"); + return nullptr; +} + +//---------------------------------------------------------------------------- +PyObject* addressof(PyObject* pyobj, PyObject* args) +{ +// Return object proxy address as a value (cppyy-style), or the same for an array. + void* addr = GetCPPInstanceAddress(pyobj, args); + if (addr) + return PyLong_FromLong(*(ptrdiff_t*)addr); + else if (!PyErr_Occurred()) { + return PyLong_FromLong(0); + } else if (PyTuple_Size(args)) { + PyErr_Clear(); + PyObject* arg0 = PyTuple_GetItem(args, 0); + if (arg0 == gNullPtrObject || (PyInt_Check(arg0) && PyInt_AsLong(arg0) == 0)) + return PyLong_FromLong(0); + Utility::GetBuffer(arg0, '*', 1, addr, false); + if (addr) return PyLong_FromLong((Long_t)addr); + } + +// error message + PyObject* str = PyObject_Str(pyobj); + if (str && CPyCppyy_PyUnicode_Check(str)) + PyErr_Format(PyExc_TypeError, "unknown object %s", PyBytes_AS_STRING(str)); + else + PyErr_Format(PyExc_TypeError, "unknown object at %p", (void*)pyobj); + Py_XDECREF(str); + return nullptr; +} + +//---------------------------------------------------------------------------- +PyObject* AsCObject(PyObject* dummy, PyObject* args) +{ +// Return object proxy as an opaque CObject. + void* addr = GetCPPInstanceAddress(dummy, args); + if (addr) + return CPyCppyy_PyCapsule_New((void*)(*(Long_t*)addr), nullptr, nullptr); + + return nullptr; +} + +//---------------------------------------------------------------------------- +PyObject* BindObject(PyObject*, PyObject* args, PyObject* kwds) +{ +// From a long representing an address or a PyCapsule/CObject, bind to a class. + Py_ssize_t argc = PyTuple_GET_SIZE(args); + if (argc != 2) { + PyErr_Format(PyExc_TypeError, + "BindObject takes exactly 2 argumenst (" PY_SSIZE_T_FORMAT " given)", argc); + return nullptr; + } + +// try to convert first argument: either PyCapsule/CObject or long integer + PyObject* pyaddr = PyTuple_GET_ITEM(args, 0); + + void* addr = nullptr; + if (pyaddr != &_CPyCppyy_NullPtrStruct) { + addr = CPyCppyy_PyCapsule_GetPointer(pyaddr, nullptr); + if (PyErr_Occurred()) { + PyErr_Clear(); + + addr = PyLong_AsVoidPtr(pyaddr); + if (PyErr_Occurred()) { + PyErr_Clear(); + + // last chance, perhaps it's a buffer/array (return from void*) + int buflen = Utility::GetBuffer(PyTuple_GetItem(args, 0), '*', 1, addr, false); + if (!addr || !buflen) { + PyErr_SetString(PyExc_TypeError, + "BindObject requires a CObject or long integer as first argument"); + return nullptr; + } + } + } + } + + Cppyy::TCppType_t klass = 0; + PyObject* pyname = PyTuple_GET_ITEM(args, 1); + if (!CPyCppyy_PyUnicode_Check(pyname)) { // not string, then class + if (CPPScope_Check(pyname)) + klass = ((CPPClass*)pyname)->fCppType; + else + pyname = PyObject_GetAttr(pyname, PyStrings::gName); + } else + Py_INCREF(pyname); + + if (!klass && pyname) { + klass = (Cppyy::TCppType_t)Cppyy::GetScope(CPyCppyy_PyUnicode_AsString(pyname)); + Py_DECREF(pyname); + } + + if (!klass) { + PyErr_SetString(PyExc_TypeError, + "BindObject expects a valid class or class name as an argument"); + return nullptr; + } + + bool do_cast = false; + if (kwds) { + PyObject* cast = PyDict_GetItemString(kwds, "cast"); + do_cast = cast && PyObject_IsTrue(cast); + } + + if (do_cast) + return BindCppObject(addr, klass); + + return BindCppObjectNoCast(addr, klass); +} + +//---------------------------------------------------------------------------- +static PyObject* Move(PyObject*, PyObject* pyobject) +{ +// Prepare the given C++ object for moving. + if (!CPPInstance_Check(pyobject)) { + PyErr_SetString(PyExc_TypeError, "C++ object expected"); + return nullptr; + } + + ((CPPInstance*)pyobject)->fFlags |= CPPInstance::kIsRValue; + Py_INCREF(pyobject); + return pyobject; +} + + +//---------------------------------------------------------------------------- +static PyObject* AddPythonization(PyObject*, PyObject* args) +{ +// Remove a previously registered pythonizor from the given scope. + PyObject* pythonizor = nullptr; const char* scope; + if (!PyArg_ParseTuple(args, const_cast("Os"), &pythonizor, &scope)) + return nullptr; + + if (!PyCallable_Check(pythonizor)) { + PyObject* pystr = PyObject_Str(pythonizor); + PyErr_Format(PyExc_TypeError, + "given \'%s\' object is not callable", CPyCppyy_PyUnicode_AsString(pystr)); + Py_DECREF(pystr); + return nullptr; + } + + Py_INCREF(pythonizor); + gPythonizations[scope].push_back(pythonizor); + + Py_RETURN_NONE; +} + + +//---------------------------------------------------------------------------- +static PyObject* RemovePythonization(PyObject*, PyObject* args) +{ +// Remove a previously registered pythonizor from the given scope. + PyObject* pythonizor = nullptr; const char* scope; + if (!PyArg_ParseTuple(args, const_cast("Os"), &pythonizor, &scope)) + return nullptr; + + auto p1 = gPythonizations.find(scope); + if (p1 != gPythonizations.end()) { + auto p2 = std::find(p1->second.begin(), p1->second.end(), pythonizor); + if (p2 != p1->second.end()) { + p1->second.erase(p2); + Py_RETURN_TRUE; + } + } + + Py_RETURN_FALSE; +} + +//---------------------------------------------------------------------------- +PyObject* SetMemoryPolicy(PyObject*, PyObject* args) +{ +// Set the global memory policy, which affects object ownership when objects +// are passed as function arguments. + PyObject* policy = nullptr; + if (!PyArg_ParseTuple(args, const_cast("O!"), &PyInt_Type, &policy)) + return nullptr; + + Long_t l = PyInt_AS_LONG(policy); + if (CallContext::SetMemoryPolicy((CallContext::ECallFlags)l)) { + Py_RETURN_NONE; + } + + PyErr_Format(PyExc_ValueError, "Unknown policy %ld", l); + return nullptr; +} + +//---------------------------------------------------------------------------- +PyObject* SetSignalPolicy(PyObject*, PyObject* args) +{ +// Set the global signal policy, which determines whether a jmp address +// should be saved to return to after a C++ segfault. + PyObject* policy = 0; + if (!PyArg_ParseTuple(args, const_cast("O!"), &PyInt_Type, &policy)) + return nullptr; + + Long_t l = PyInt_AS_LONG(policy); + if (CallContext::SetSignalPolicy((CallContext::ECallFlags)l)) { + Py_RETURN_NONE; + } + + PyErr_Format(PyExc_ValueError, "Unknown policy %ld", l); + return nullptr; +} + +//---------------------------------------------------------------------------- +PyObject* SetOwnership(PyObject*, PyObject* args) +{ +// Set the ownership (True is python-owns) for the given object. + CPPInstance* pyobj = nullptr; PyObject* pykeep = nullptr; + if (!PyArg_ParseTuple(args, const_cast("O!O!"), + &CPPInstance_Type, (void*)&pyobj, &PyInt_Type, &pykeep)) + return nullptr; + + (bool)PyLong_AsLong(pykeep) ? pyobj->PythonOwns() : pyobj->CppOwns(); + + Py_RETURN_NONE; +} + +//---------------------------------------------------------------------------- +PyObject* AddSmartPtrType(PyObject*, PyObject* args) +{ +// Add a smart pointer to the list of known smart pointer types. + const char* type_name; + if (!PyArg_ParseTuple(args, const_cast("s"), &type_name)) + return nullptr; + + Cppyy::AddSmartPtrType(type_name); + + Py_RETURN_NONE; +} + +//---------------------------------------------------------------------------- +PyObject* PinType(PyObject*, PyObject* pyclass) +{ +// Add a pinning so that objects of type `derived' are interpreted as +// objects of type `base'. + if (!CPPScope_Check(pyclass)) { + PyErr_SetString(PyExc_TypeError, "C++ class expected"); + return nullptr; + } + + gPinnedTypes.insert(((CPPClass*)pyclass)->fCppType); + + Py_RETURN_NONE; +} + +//---------------------------------------------------------------------------- +PyObject* Cast(PyObject*, PyObject* args) +{ +// Cast `obj' to type `type'. + CPPInstance* obj = nullptr; + CPPClass* type = nullptr; + if (!PyArg_ParseTuple(args, const_cast("O!O!"), + &CPPInstance_Type, &obj, + &CPPScope_Type, &type)) + return nullptr; +// TODO: this misses an offset calculation, and reference type must not +// be cast ... + return BindCppObjectNoCast(obj->GetObject(), type->fCppType, + obj->fFlags & CPPInstance::kIsReference); +} + +} // unnamed namespace + + +//- data ----------------------------------------------------------------------- +static PyMethodDef gCPyCppyyMethods[] = { + {(char*) "CreateScopeProxy", (PyCFunction)CPyCppyy::CreateScopeProxy, + METH_VARARGS, (char*)"cppyy internal function"}, + {(char*) "MakeCppTemplateClass", (PyCFunction)MakeCppTemplateClass, + METH_VARARGS, (char*)"cppyy internal function"}, + {(char*) "_set_cpp_lazy_lookup", (PyCFunction)SetCppLazyLookup, + METH_VARARGS, (char*)"cppyy internal function"}, + {(char*) "_DestroyPyStrings", (PyCFunction)CPyCppyy::DestroyPyStrings, + METH_NOARGS, (char*)"cppyy internal function"}, + {(char*) "addressof", (PyCFunction)addressof, + METH_VARARGS, (char*)"Retrieve address of held object as a value"}, + {(char*) "AsCObject", (PyCFunction)AsCObject, + METH_VARARGS, (char*)"Retrieve held object in a CObject"}, + {(char*)"bind_object", (PyCFunction)BindObject, + METH_VARARGS | METH_KEYWORDS, (char*) "Create an object of given type, from given address"}, + {(char*) "move", (PyCFunction)Move, + METH_O, (char*)"Cast the C++ object to become movable"}, + {(char*) "add_pythonization", (PyCFunction)AddPythonization, + METH_VARARGS, (char*)"Add a pythonizor"}, + {(char*) "remove_pythonization", (PyCFunction)RemovePythonization, + METH_VARARGS, (char*)"Remove a pythonizor"}, + {(char*) "SetMemoryPolicy", (PyCFunction)SetMemoryPolicy, + METH_VARARGS, (char*)"Determines object ownership model"}, + {(char*) "SetSignalPolicy", (PyCFunction)SetSignalPolicy, + METH_VARARGS, (char*)"Trap signals in safe mode to prevent interpreter abort"}, + {(char*) "SetOwnership", (PyCFunction)SetOwnership, + METH_VARARGS, (char*)"Modify held C++ object ownership"}, + {(char*) "AddSmartPtrType", (PyCFunction)AddSmartPtrType, + METH_VARARGS, (char*) "Add a smart pointer to the list of known smart pointer types"}, + {(char*) "_pin_type", (PyCFunction)PinType, + METH_O, (char*)"Install a type pinning"}, + {(char*) "Cast", (PyCFunction)Cast, + METH_VARARGS, (char*)"Cast the given object to the given type"}, + {nullptr, nullptr, 0, nullptr} +}; + + +#if PY_VERSION_HEX >= 0x03000000 +struct module_state { + PyObject *error; +}; + +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) + +static int cpycppyymodule_traverse(PyObject* m, visitproc visit, void* arg) +{ + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int cpycppyymodule_clear(PyObject* m) +{ + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "libcppyy", + nullptr, + sizeof(struct module_state), + gCPyCppyyMethods, + nullptr, + cpycppyymodule_traverse, + cpycppyymodule_clear, + nullptr +}; + + +//---------------------------------------------------------------------------- +#define CPYCPPYY_INIT_ERROR return nullptr +extern "C" PyObject* PyInit_libcppyy() +#else +#define CPYCPPYY_INIT_ERROR return +extern "C" void initlibcppyy() +#endif +{ +// Initialization of extension module libcppyy. + +// load commonly used python strings + if (!CPyCppyy::CreatePyStrings()) + CPYCPPYY_INIT_ERROR; + +// setup interpreter + PyEval_InitThreads(); + +// prepare for lazyness + PyObject* dict = PyDict_New(); +#if PY_VERSION_HEX >= 0x03030000 + gDictLookupOrg = (dict_lookup_func)((PyDictObject*)dict)->ma_keys->dk_lookup; +#else + gDictLookupOrg = (dict_lookup_func)((PyDictObject*)dict)->ma_lookup; +#endif + Py_DECREF(dict); + +// setup this module +#if PY_VERSION_HEX >= 0x03000000 + gThisModule = PyModule_Create(&moduledef); +#else + gThisModule = Py_InitModule(const_cast("libcppyy"), gCPyCppyyMethods); +#endif + if (!gThisModule) + CPYCPPYY_INIT_ERROR; + +// keep gThisModule, but do not increase its reference count even as it is borrowed, +// or a self-referencing cycle would be created + +// Pythonizations ... + PyModule_AddObject(gThisModule, "UserExceptions", PyDict_New()); + +// inject meta type + if (!Utility::InitProxy(gThisModule, &CPPScope_Type, "CPPScope")) + CPYCPPYY_INIT_ERROR; + +// inject object proxy type + if (!Utility::InitProxy(gThisModule, &CPPInstance_Type, "CPPInstance")) + CPYCPPYY_INIT_ERROR; + +// inject method proxy type + if (!Utility::InitProxy(gThisModule, &CPPOverload_Type, "CPPOverload")) + CPYCPPYY_INIT_ERROR; + +// inject template proxy type + if (!Utility::InitProxy(gThisModule, &TemplateProxy_Type, "TemplateProxy")) + CPYCPPYY_INIT_ERROR; + +// inject property proxy type + if (!Utility::InitProxy(gThisModule, &CPPDataMember_Type, "CPPDataMember")) + CPYCPPYY_INIT_ERROR; + +// inject custom data types + if (!Utility::InitProxy(gThisModule, &RefFloat_Type, "Double")) + CPYCPPYY_INIT_ERROR; + + if (!Utility::InitProxy(gThisModule, &RefInt_Type, "Long")) + CPYCPPYY_INIT_ERROR; + + if (!Utility::InitProxy(gThisModule, &CustomInstanceMethod_Type, "InstanceMethod")) + CPYCPPYY_INIT_ERROR; + + if (!Utility::InitProxy(gThisModule, &TupleOfInstances_Type, "InstancesArray")) + CPYCPPYY_INIT_ERROR; + + if (!Utility::InitProxy(gThisModule, &PyNullPtr_t_Type, "nullptr_t")) + CPYCPPYY_INIT_ERROR; + +// initialize low level ptr type, but do not inject in gThisModule + if (PyType_Ready(&LowLevelView_Type) < 0) + CPYCPPYY_INIT_ERROR; + +// inject identifiable nullptr + gNullPtrObject = (PyObject*)&_CPyCppyy_NullPtrStruct; + Py_INCREF(gNullPtrObject); + PyModule_AddObject(gThisModule, (char*)"nullptr", gNullPtrObject); + +// policy labels + PyModule_AddObject(gThisModule, (char*)"kMemoryHeuristics", + PyInt_FromLong((int)CallContext::kUseHeuristics)); + PyModule_AddObject(gThisModule, (char*)"kMemoryStrict", + PyInt_FromLong((int)CallContext::kUseStrict)); + PyModule_AddObject(gThisModule, (char*)"kSignalFast", + PyInt_FromLong((int)CallContext::kFast)); + PyModule_AddObject(gThisModule, (char*)"kSignalSafe", + PyInt_FromLong((int)CallContext::kSafe)); + +// gbl namespace is injected in cppyy.py + +// create the memory regulator + static MemoryRegulator s_memory_regulator; + +#if PY_VERSION_HEX >= 0x03000000 + Py_INCREF(gThisModule); + return gThisModule; +#endif +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CallContext.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CallContext.cxx new file mode 100644 index 0000000000000..0626c56a305a0 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CallContext.cxx @@ -0,0 +1,39 @@ +// Bindings +#include "CPyCppyy.h" +#include "CallContext.h" + + +//- data _____________________________________________________________________ +namespace CPyCppyy { + + CallContext::ECallFlags CallContext::sMemoryPolicy = CallContext::kUseStrict; +// this is just a data holder for linking; actual value is set in CPyCppyyModule.cxx + CallContext::ECallFlags CallContext::sSignalPolicy = CallContext::kSafe; + +} // namespace CPyCppyy + + +//----------------------------------------------------------------------------- +bool CPyCppyy::CallContext::SetMemoryPolicy(ECallFlags e) +{ +// Set the global memory policy, which affects object ownership when objects +// are passed as function arguments. + if (kUseHeuristics == e || e == kUseStrict) { + sMemoryPolicy = e; + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +bool CPyCppyy::CallContext::SetSignalPolicy(ECallFlags e) +{ +// Set the global signal policy, which determines whether a jmp address +// should be saved to return to after a C++ segfault. + if (kFast == e || e == kSafe) { + sSignalPolicy = e; + return true; + } + return false; +} + diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CallContext.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CallContext.h new file mode 100644 index 0000000000000..da63e758e916e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CallContext.h @@ -0,0 +1,96 @@ +#ifndef CPYCPPYY_CALLCONTEXT_H +#define CPYCPPYY_CALLCONTEXT_H + +// Standard +#include + + +namespace CPyCppyy { + +// general place holder for function parameters +struct Parameter { + union Value { + bool fBool; + short fShort; + unsigned short fUShort; + Int_t fInt; + UInt_t fUInt; + Long_t fLong; + ULong_t fULong; + Long64_t fLongLong; + ULong64_t fULongLong; + float fFloat; + double fDouble; + LongDouble_t fLongDouble; + void* fVoidp; + } fValue; + void* fRef; + char fTypeCode; +}; + +// extra call information +struct CallContext { + CallContext(std::vector::size_type sz = 0) : fArgs(sz), fFlags(0) {} + + enum ECallFlags { + kNone = 0, + kIsSorted = 1, // if method overload priority determined + kIsCreator = 2, // if method creates python-owned objects + kIsConstructor = 4, // if method is a C++ constructor + kUseHeuristics = 8, // if method applies heuristics memory policy + kUseStrict = 16, // if method applies strict memory policy + kManageSmartPtr = 32, // if executor should manage smart pointers + kReleaseGIL = 64, // if method should release the GIL + kFast = 128, // if method should NOT handle signals + kSafe = 256 // if method should return on signals + }; + +// memory handling + static ECallFlags sMemoryPolicy; + static bool SetMemoryPolicy(ECallFlags e); + +// signal safety + static ECallFlags sSignalPolicy; + static bool SetSignalPolicy(ECallFlags e); + +// payload + std::vector fArgs; + uint64_t fFlags; +}; + +inline bool IsSorted(uint64_t flags) { + return flags & CallContext::kIsSorted; +} + +inline bool IsCreator(uint64_t flags) { + return flags & CallContext::kIsCreator; +} + +inline bool IsConstructor(uint64_t flags) { + return flags & CallContext::kIsConstructor; +} + +inline bool ManagesSmartPtr(CallContext* ctxt) { + return ctxt->fFlags & CallContext::kManageSmartPtr; +} + +inline bool ReleasesGIL(uint64_t flags) { + return flags & CallContext::kReleaseGIL; +} + +inline bool ReleasesGIL(CallContext* ctxt) { + return ctxt ? (ctxt->fFlags & CallContext::kReleaseGIL) : false; +} + +inline bool UseStrictOwnership(CallContext* ctxt) { + if (ctxt && (ctxt->fFlags & CallContext::kUseStrict)) + return true; + if (ctxt && (ctxt->fFlags & CallContext::kUseHeuristics)) + return false; + + return CallContext::sMemoryPolicy == CallContext::kUseStrict; +} + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CALLCONTEXT_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Converters.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Converters.cxx new file mode 100644 index 0000000000000..5f032600c1a57 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Converters.cxx @@ -0,0 +1,1666 @@ +// Bindings +#include "CPyCppyy.h" +#include "DeclareConverters.h" +#include "CallContext.h" +#include "CPPInstance.h" +#include "CPPOverload.h" +#include "CustomPyTypes.h" +#include "LowLevelViews.h" +#include "MemoryRegulator.h" +#include "ProxyWrappers.h" +#include "PyStrings.h" +#include "TupleOfInstances.h" +#include "TypeManip.h" +#include "Utility.h" + +// Standard +#include +#include // for ptrdiff_t +#include +#include +#include +#if __cplusplus > 201402L +#include +#endif + +// FIXME: Should refer to CPyCppyy::Parameter in the code. +#ifdef R__CXXMODULES + #define Parameter CPyCppyy::Parameter +#endif + + +//- data _____________________________________________________________________ +namespace CPyCppyy { + +// factories + typedef Converter* (*cf_t)(long size); + typedef std::map ConvFactories_t; + static ConvFactories_t gConvFactories; + extern PyObject* gNullPtrObject; + +} + +//- pretend-ctypes helpers --------------------------------------------------- +#if PY_VERSION_HEX >= 0x02050000 + +struct CPyCppyy_tagCDataObject { // non-public (but so far very stable) + PyObject_HEAD + char* b_ptr; +}; + +static inline PyTypeObject* GetCTypesType(const char* name) { + PyObject* ct = PyImport_ImportModule("ctypes"); + if (!ct) return nullptr; + PyTypeObject* ct_t = (PyTypeObject*)PyObject_GetAttrString(ct, name); + Py_DECREF(ct); + return ct_t; +} + +#endif + +//- custom helpers to check ranges ------------------------------------------- +static inline bool CPyCppyy_PyLong_AsBool(PyObject* pyobject) +{ +// range-checking python integer to C++ bool conversion + long l = PyLong_AsLong(pyobject); +// fail to pass float -> bool; the problem is rounding (0.1 -> 0 -> False) + if (!(l == 0|| l == 1) || PyFloat_Check(pyobject)) { + PyErr_SetString(PyExc_ValueError, "boolean value should be bool, or integer 1 or 0"); + return (bool)-1; + } + return (bool)l; +} + +static inline char CPyCppyy_PyUnicode_AsChar(PyObject* pyobject) { +// python string to C++ char conversion + return (char)CPyCppyy_PyUnicode_AsString(pyobject)[0]; +} + +static inline unsigned short CPyCppyy_PyLong_AsUShort(PyObject* pyobject) +{ +// range-checking python integer to C++ unsigend short int conversion + +// prevent p2.7 silent conversions and do a range check + if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) { + PyErr_SetString(PyExc_TypeError, "unsigned short conversion expects an integer object"); + return (unsigned short)-1; + } + long l = PyLong_AsLong(pyobject); + if (l < 0 || USHRT_MAX < l) { + PyErr_Format(PyExc_ValueError, "integer %ld out of range for unsigned short", l); + return (unsigned short)-1; + + } + return (unsigned short)l; +} + +static inline short CPyCppyy_PyLong_AsShort(PyObject* pyobject) +{ +// range-checking python integer to C++ short int conversion +// prevent p2.7 silent conversions and do a range check + if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) { + PyErr_SetString(PyExc_TypeError, "short int conversion expects an integer object"); + return (short)-1; + } + long l = PyLong_AsLong(pyobject); + if (l < SHRT_MIN || SHRT_MAX < l) { + PyErr_Format(PyExc_ValueError, "integer %ld out of range for short int", l); + return (short)-1; + + } + return (short)l; +} + +static inline int CPyCppyy_PyLong_AsStrictInt(PyObject* pyobject) +{ +// strict python integer to C++ integer conversion + +// p2.7 and later silently converts floats to long, therefore require this +// check; earlier pythons may raise a SystemError which should be avoided as +// it is confusing + if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) { + PyErr_SetString(PyExc_TypeError, "int/long conversion expects an integer object"); + return -1; + } + long l = PyLong_AsLong(pyobject); + if (l < INT_MIN || INT_MAX < l) { + PyErr_Format(PyExc_ValueError, "integer %ld out of range for int", l); + return (int)-1; + + } + return (int)l; +} + +static inline long CPyCppyy_PyLong_AsStrictLong(PyObject* pyobject) +{ +// strict python integer to C++ long integer conversion + +// prevent float -> long (see CPyCppyy_PyLong_AsStrictInt) + if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) { + PyErr_SetString(PyExc_TypeError, "int/long conversion expects an integer object"); + return (long)-1; + } + return (long)PyLong_AsLong(pyobject); +} + + +//- base converter implementation -------------------------------------------- +PyObject* CPyCppyy::Converter::FromMemory(void*) +{ +// could happen if no derived class override + PyErr_SetString(PyExc_TypeError, "C++ type can not be converted from memory"); + return nullptr; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::Converter::ToMemory(PyObject*, void*) +{ +// could happen if no derived class override + PyErr_SetString(PyExc_TypeError, "C++ type can not be converted to memory"); + return false; +} + + +//- helper macro's ----------------------------------------------------------- +#define CPPYY_IMPL_BASIC_CONVERTER(name, type, stype, F1, F2, tc) \ +bool CPyCppyy::name##Converter::SetArg( \ + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \ +{ \ +/* convert to C++ 'type', set arg for call */ \ + type val = (type)F2(pyobject); \ + if (val == (type)-1 && PyErr_Occurred()) \ + return false; \ + para.fValue.f##name = val; \ + para.fTypeCode = tc; \ + return true; \ +} \ + \ +PyObject* CPyCppyy::name##Converter::FromMemory(void* address) \ +{ \ + return F1((stype)*((type*)address)); \ +} \ + \ +bool CPyCppyy::name##Converter::ToMemory(PyObject* value, void* address) \ +{ \ + type s = (type)F2(value); \ + if (s == (type)-1 && PyErr_Occurred()) \ + return false; \ + *((type*)address) = (type)s; \ + return true; \ +} + +//---------------------------------------------------------------------------- +static inline Int_t ExtractChar(PyObject* pyobject, const char* tname, Int_t low, Int_t high) +{ + Int_t lchar = -1; + if (CPyCppyy_PyUnicode_Check(pyobject)) { + if (CPyCppyy_PyUnicode_GET_SIZE(pyobject) == 1) + lchar = (Int_t)CPyCppyy_PyUnicode_AsChar(pyobject); + else + PyErr_Format(PyExc_ValueError, "%s expected, got string of size " PY_SSIZE_T_FORMAT, + tname, CPyCppyy_PyUnicode_GET_SIZE(pyobject)); + } else if (!PyFloat_Check(pyobject)) { // don't allow truncating conversion + lchar = PyLong_AsLong(pyobject); + if (lchar == -1 && PyErr_Occurred()) + ; // empty, as error already set + else if (!(low <= lchar && lchar <= high)) { + PyErr_Format(PyExc_ValueError, + "integer to character: value %d not in range [%d,%d]", lchar, low, high); + lchar = -1; + } + } else + PyErr_SetString(PyExc_TypeError, "char or small int type expected"); + + return lchar; +} + +//---------------------------------------------------------------------------- +#define CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(name, type, F1) \ +bool CPyCppyy::Const##name##RefConverter::SetArg( \ + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \ +{ \ + type val = (type)F1(pyobject); \ + if (val == (type)-1 && PyErr_Occurred()) \ + return false; \ + para.fValue.f##name = val; \ + para.fRef = ¶.fValue.f##name; \ + para.fTypeCode = 'r'; \ + return true; \ +} + +//---------------------------------------------------------------------------- +#define CPPYY_IMPL_BASIC_CONST_CHAR_REF_CONVERTER(name, type, low, high) \ +bool CPyCppyy::Const##name##RefConverter::SetArg( \ + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \ +{ \ +/* convert to C++ <>, set arg for call, allow int -> char */\ + type val = (type)ExtractChar(pyobject, #type, low, high); \ + if (val == (type)-1 && PyErr_Occurred()) \ + return false; \ + para.fValue.fLong = val; \ + para.fTypeCode = 'l'; \ + return true; \ +} + +//---------------------------------------------------------------------------- +#define CPPYY_IMPL_BASIC_CHAR_CONVERTER(name, type, low, high) \ +bool CPyCppyy::name##Converter::SetArg( \ + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \ +{ \ +/* convert to C++ <>, set arg for call, allow int -> char */\ + long val = ExtractChar(pyobject, #type, low, high); \ + if (val == -1 && PyErr_Occurred()) \ + return false; \ + para.fValue.fLong = val; \ + para.fTypeCode = 'l'; \ + return true; \ +} \ + \ +PyObject* CPyCppyy::name##Converter::FromMemory(void* address) \ +{ \ + return CPyCppyy_PyUnicode_FromFormat("%c", *((type*)address)); \ +} \ + \ +bool CPyCppyy::name##Converter::ToMemory(PyObject* value, void* address) \ +{ \ + if (CPyCppyy_PyUnicode_Check(value)) { \ + const char* buf = CPyCppyy_PyUnicode_AsString(value); \ + if (PyErr_Occurred()) \ + return false; \ + int len = CPyCppyy_PyUnicode_GET_SIZE(value); \ + if (len != 1) { \ + PyErr_Format(PyExc_TypeError, #type" expected, got string of size %d", len);\ + return false; \ + } \ + *((type*)address) = (type)buf[0]; \ + } else { \ + long l = PyLong_AsLong(value); \ + if (l == -1 && PyErr_Occurred()) \ + return false; \ + if (!(low <= l && l <= high)) { \ + PyErr_Format(PyExc_ValueError, \ + "integer to character: value %ld not in range [%d,%d]", l, low, high);\ + return false; \ + } \ + *((type*)address) = (type)l; \ + } \ + return true; \ +} + + +//- converters for built-ins ------------------------------------------------- +CPPYY_IMPL_BASIC_CONVERTER(Long, long, long, PyLong_FromLong, CPyCppyy_PyLong_AsStrictLong, 'l') + +//---------------------------------------------------------------------------- +bool CPyCppyy::LongRefConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// convert to C++ long&, set arg for call +#if PY_VERSION_HEX < 0x03000000 + if (RefInt_CheckExact(pyobject)) { + para.fValue.fVoidp = (void*)&((PyIntObject*)pyobject)->ob_ival; + para.fTypeCode = 'V'; + return true; + } +#endif + +#if PY_VERSION_HEX < 0x02050000 + PyErr_SetString(PyExc_TypeError, "use cppyy.Long for pass-by-ref of longs"); + return false; +#endif + +// TODO: this keeps a refcount to the type .. it should be okay to drop that + static PyTypeObject* c_long_type = GetCTypesType("c_long"); + if (Py_TYPE(pyobject) == c_long_type) { + para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr; + para.fTypeCode = 'V'; + return true; + } + + PyErr_SetString(PyExc_TypeError, "use ctypes.c_long for pass-by-ref of longs"); + return false; +} + +//---------------------------------------------------------------------------- +CPPYY_IMPL_BASIC_CONST_CHAR_REF_CONVERTER(Char, char, CHAR_MIN, CHAR_MAX) +CPPYY_IMPL_BASIC_CONST_CHAR_REF_CONVERTER(UChar, unsigned char, 0, UCHAR_MAX) + +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(Bool, bool, CPyCppyy_PyLong_AsBool) +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(Short, short, CPyCppyy_PyLong_AsShort) +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(UShort, unsigned short, CPyCppyy_PyLong_AsUShort) +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(Int, Int_t, CPyCppyy_PyLong_AsStrictInt) +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(UInt, UInt_t, PyLongOrInt_AsULong) +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(Long, Long_t, CPyCppyy_PyLong_AsStrictLong) +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(ULong, ULong_t, PyLongOrInt_AsULong) +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(LongLong, Long64_t, PyLong_AsLongLong) +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(ULongLong, ULong64_t, PyLongOrInt_AsULong64) + +//---------------------------------------------------------------------------- +bool CPyCppyy::IntRefConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// convert to C++ (pseudo)int&, set arg for call +#if PY_VERSION_HEX < 0x03000000 + if (RefInt_CheckExact(pyobject)) { + para.fValue.fVoidp = (void*)&((PyIntObject*)pyobject)->ob_ival; + para.fTypeCode = 'V'; + return true; + } +#endif + +#if PY_VERSION_HEX >= 0x02050000 +// TODO: this keeps a refcount to the type .. it should be okay to drop that + static PyTypeObject* c_int_type = GetCTypesType("c_int"); + if (Py_TYPE(pyobject) == c_int_type) { + para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr; + para.fTypeCode = 'V'; + return true; + } +#endif + +// alternate, pass pointer from buffer + int buflen = Utility::GetBuffer(pyobject, 'i', sizeof(int), para.fValue.fVoidp); + if (para.fValue.fVoidp && buflen) { + para.fTypeCode = 'V'; + return true; + }; + +#if PY_VERSION_HEX < 0x02050000 + PyErr_SetString(PyExc_TypeError, "use cppyy.Long for pass-by-ref of ints"); +#else + PyErr_SetString(PyExc_TypeError, "use ctypes.c_int for pass-by-ref of ints"); +#endif + return false; +} + +//---------------------------------------------------------------------------- +// convert to C++ bool, allow int/long -> bool, set arg for call +CPPYY_IMPL_BASIC_CONVERTER( + Bool, bool, long, PyInt_FromLong, CPyCppyy_PyLong_AsBool, 'l') + +//---------------------------------------------------------------------------- +CPPYY_IMPL_BASIC_CHAR_CONVERTER(Char, char, CHAR_MIN, CHAR_MAX) +CPPYY_IMPL_BASIC_CHAR_CONVERTER(UChar, unsigned char, 0, UCHAR_MAX) + +PyObject* CPyCppyy::UCharAsIntConverter::FromMemory(void* address) +{ +// special case to be used with arrays: return a Python int instead of str +// (following the same convention as module array.array) + return PyInt_FromLong((long)*((unsigned char*)address)); +} + + +//---------------------------------------------------------------------------- +CPPYY_IMPL_BASIC_CONVERTER( + Short, short, long, PyInt_FromLong, CPyCppyy_PyLong_AsShort, 'l') +CPPYY_IMPL_BASIC_CONVERTER( + UShort, unsigned short, long, PyInt_FromLong, CPyCppyy_PyLong_AsUShort, 'l') +CPPYY_IMPL_BASIC_CONVERTER( + Int, Int_t, long, PyInt_FromLong, CPyCppyy_PyLong_AsStrictInt, 'l') + +//---------------------------------------------------------------------------- +bool CPyCppyy::ULongConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// convert to C++ unsigned long, set arg for call + para.fValue.fULong = PyLongOrInt_AsULong(pyobject); + if (PyErr_Occurred()) + return false; + para.fTypeCode = 'L'; + return true; +} + +PyObject* CPyCppyy::ULongConverter::FromMemory(void* address) +{ +// construct python object from C++ unsigned long read at
+ return PyLong_FromUnsignedLong(*((unsigned long*)address)); +} + +bool CPyCppyy::ULongConverter::ToMemory(PyObject* value, void* address) +{ +// convert to C++ unsigned long, write it at
+ unsigned long u = PyLongOrInt_AsULong(value); + if (PyErr_Occurred()) + return false; + *((unsigned long*)address) = u; + return true; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::UIntConverter::FromMemory(void* address) +{ +// construct python object from C++ unsigned int read at
+ return PyLong_FromUnsignedLong(*((UInt_t*)address)); +} + +bool CPyCppyy::UIntConverter::ToMemory(PyObject* value, void* address) +{ +// convert to C++ unsigned int, write it at
+ ULong_t u = PyLongOrInt_AsULong(value); + if (PyErr_Occurred()) + return false; + + if (u > (ULong_t)UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, "value too large for unsigned int"); + return false; + } + + *((UInt_t*)address) = (UInt_t)u; + return true; +} + +//- floating point converters ------------------------------------------------ +CPPYY_IMPL_BASIC_CONVERTER( + Float, float, double, PyFloat_FromDouble, PyFloat_AsDouble, 'f') +CPPYY_IMPL_BASIC_CONVERTER( + Double, double, double, PyFloat_FromDouble, PyFloat_AsDouble, 'd') + +CPPYY_IMPL_BASIC_CONVERTER( + LongDouble, LongDouble_t, LongDouble_t, PyFloat_FromDouble, PyFloat_AsDouble, 'g') + +//---------------------------------------------------------------------------- +bool CPyCppyy::DoubleRefConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// convert to C++ double&, set arg for call + if (RefFloat_CheckExact(pyobject)) { + para.fValue.fVoidp = (void*)&((PyFloatObject*)pyobject)->ob_fval; + para.fTypeCode = 'V'; + return true; + } + +// alternate, pass pointer from buffer + int buflen = Utility::GetBuffer(pyobject, 'd', sizeof(double), para.fValue.fVoidp); + if (para.fValue.fVoidp && buflen) { + para.fTypeCode = 'V'; + return true; + } + + PyErr_SetString(PyExc_TypeError, "use cppyy.Double for pass-by-ref of doubles"); + return false; +} + +//---------------------------------------------------------------------------- +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(Float, float, PyFloat_AsDouble) +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(Double, double, PyFloat_AsDouble) +CPPYY_IMPL_BASIC_CONST_REF_CONVERTER(LongDouble, LongDouble_t, PyFloat_AsDouble) + +//---------------------------------------------------------------------------- +bool CPyCppyy::VoidConverter::SetArg(PyObject*, Parameter&, CallContext*) +{ +// can't happen (unless a type is mapped wrongly), but implemented for completeness + PyErr_SetString(PyExc_SystemError, "void/unknown arguments can\'t be set"); + return false; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::LongLongConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// convert to C++ long long, set arg for call + if (PyFloat_Check(pyobject)) { + // special case: float implements nb_int, but allowing rounding conversions + // interferes with overloading + PyErr_SetString(PyExc_ValueError, "can not convert float to long long"); + return false; + } + + para.fValue.fLongLong = PyLong_AsLongLong(pyobject); + if (PyErr_Occurred()) + return false; + para.fTypeCode = 'q'; + return true; +} + +PyObject* CPyCppyy::LongLongConverter::FromMemory(void* address) +{ +// construct python object from C++ long long read at
+ return PyLong_FromLongLong(*(Long64_t*)address); +} + +bool CPyCppyy::LongLongConverter::ToMemory(PyObject* value, void* address) +{ +// convert to C++ long long, write it at
+ Long64_t ll = PyLong_AsLongLong(value); + if (ll == -1 && PyErr_Occurred()) + return false; + *((Long64_t*)address) = ll; + return true; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::ULongLongConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// convert to C++ unsigned long long, set arg for call + para.fValue.fULongLong = PyLongOrInt_AsULong64(pyobject); + if (PyErr_Occurred()) + return false; + para.fTypeCode = 'Q'; + return true; +} + +PyObject* CPyCppyy::ULongLongConverter::FromMemory(void* address) +{ +// construct python object from C++ unsigned long long read at
+ return PyLong_FromUnsignedLongLong(*(ULong64_t*)address); +} + +bool CPyCppyy::ULongLongConverter::ToMemory(PyObject* value, void* address) +{ +// convert to C++ unsigned long long, write it at
+ Long64_t ull = PyLongOrInt_AsULong64(value); + if (PyErr_Occurred()) + return false; + *((ULong64_t*)address) = ull; + return true; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::CStringConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// construct a new string and copy it in new memory + const char* s = CPyCppyy_PyUnicode_AsStringChecked(pyobject); + if (PyErr_Occurred()) + return false; + + fBuffer = std::string(s, CPyCppyy_PyUnicode_GET_SIZE(pyobject)); + +// verify (too long string will cause truncation, no crash) + if (fMaxSize != -1 && fMaxSize < (long)fBuffer.size()) + PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for char array (truncated)"); + else if (fMaxSize != -1) + fBuffer.resize(fMaxSize, '\0'); // padd remainder of buffer as needed + +// set the value and declare success + para.fValue.fVoidp = (void*)fBuffer.c_str(); + para.fTypeCode = 'p'; + return true; +} + +PyObject* CPyCppyy::CStringConverter::FromMemory(void* address) +{ +// construct python object from C++ const char* read at
+ if (address && *(char**)address) { + if (fMaxSize != -1) { // need to prevent reading beyond boundary + std::string buf(*(char**)address, fMaxSize); // cut on fMaxSize + return CPyCppyy_PyUnicode_FromString(buf.c_str()); // cut on \0 + } + + return CPyCppyy_PyUnicode_FromString(*(char**)address); + } + +// empty string in case there's no address + Py_INCREF(PyStrings::gEmptyString); + return PyStrings::gEmptyString; +} + +bool CPyCppyy::CStringConverter::ToMemory(PyObject* value, void* address) +{ +// convert to C++ const char*, write it at
+ const char* s = CPyCppyy_PyUnicode_AsStringChecked(value); + if (PyErr_Occurred()) + return false; + +// verify (too long string will cause truncation, no crash) + if (fMaxSize < (UInt_t)CPyCppyy_PyUnicode_GET_SIZE(value)) + PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for char array (truncated)"); + + if (fMaxSize != -1) + strncpy(*(char**)address, s, fMaxSize); // padds remainder + else + // coverity[secure_coding] - can't help it, it's intentional. + strcpy(*(char**)address, s); + + return true; +} + + +//- pointer/array conversions ------------------------------------------------ +namespace { + +using namespace CPyCppyy; + +inline bool CArraySetArg(PyObject* pyobject, Parameter& para, char tc, int size) +{ +// general case of loading a C array pointer (void* + type code) as function argument + if (pyobject == gNullPtrObject || (PyInt_Check(pyobject) && PyInt_AsLong(pyobject) == 0)) { + para.fValue.fVoidp = nullptr; + } else { + int buflen = Utility::GetBuffer(pyobject, tc, size, para.fValue.fVoidp); + if (!para.fValue.fVoidp || buflen == 0) + return false; + } + para.fTypeCode = 'p'; + return true; +} + +} // unnamed namespace + + +//---------------------------------------------------------------------------- +bool CPyCppyy::NonConstCStringConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* ctxt) +{ +// attempt base class first (i.e. passing a string), but if that fails, try a buffer + if (this->CStringConverter::SetArg(pyobject, para, ctxt)) + return true; + +// apparently failed, try char buffer + PyErr_Clear(); + return CArraySetArg(pyobject, para, 'c', sizeof(char)); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::NonConstCStringConverter::FromMemory(void* address) +{ +// assume this is a buffer access if the size is known; otherwise assume string + if (fMaxSize != -1) + return CPyCppyy_PyUnicode_FromStringAndSize(*(char**)address, fMaxSize); + return this->CStringConverter::FromMemory(address); +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::VoidArrayConverter::GetAddressSpecialCase(PyObject* pyobject, void*& address) +{ +// (1): C++11 style "null pointer" + if (pyobject == gNullPtrObject) { + address = nullptr; + return true; + } + +// (2): allow integer zero to act as a null pointer (C NULL), no deriveds + if (PyInt_CheckExact(pyobject) || PyLong_CheckExact(pyobject)) { + long val = (long)PyLong_AsLong(pyobject); + if (val == 0l) { + address = (void*)val; + return true; + } + + return false; + } + +// (3): opaque PyCapsule (CObject in older pythons) from somewhere + if (CPyCppyy_PyCapsule_CheckExact(pyobject)) { + address = (void*)CPyCppyy_PyCapsule_GetPointer(pyobject, nullptr); + return true; + } + + return false; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::VoidArrayConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* ctxt) +{ +// just convert pointer if it is a C++ object + if (CPPInstance_Check(pyobject)) { + // depending on memory policy, some objects are no longer owned when passed to C++ + if (!fKeepControl && !UseStrictOwnership(ctxt)) + ((CPPInstance*)pyobject)->CppOwns(); + + // set pointer (may be null) and declare success + para.fValue.fVoidp = ((CPPInstance*)pyobject)->GetObject(); + para.fTypeCode = 'p'; + return true; + } + +// handle special cases + if (GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) { + para.fTypeCode = 'p'; + return true; + } + +// final try: attempt to get buffer + int buflen = Utility::GetBuffer(pyobject, '*', 1, para.fValue.fVoidp, false); + +// ok if buffer exists (can't perform any useful size checks) + if (para.fValue.fVoidp && buflen != 0) { + para.fTypeCode = 'p'; + return true; + } + +// give up + return false; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::VoidArrayConverter::FromMemory(void* address) +{ +// nothing sensible can be done, just return
as pylong + if (!address || *(ptrdiff_t*)address == 0) { + Py_INCREF(gNullPtrObject); + return gNullPtrObject; + } + return CreatePointerView(*(ptrdiff_t**)address); +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::VoidArrayConverter::ToMemory(PyObject* value, void* address) +{ +// just convert pointer if it is a C++ object + if (CPPInstance_Check(value)) { + // depending on memory policy, some objects are no longer owned when passed to C++ + if (!fKeepControl && CallContext::sMemoryPolicy != CallContext::kUseStrict) + ((CPPInstance*)value)->CppOwns(); + + // set pointer (may be null) and declare success + *(void**)address = ((CPPInstance*)value)->GetObject(); + return true; + } + +// handle special cases + void* ptr = nullptr; + if (GetAddressSpecialCase(value, ptr)) { + *(void**)address = ptr; + return true; + } + +// final try: attempt to get buffer + void* buf = nullptr; + int buflen = Utility::GetBuffer(value, '*', 1, buf, false); + if (!buf || buflen == 0) + return false; + + *(void**)address = buf; + return true; +} + +//---------------------------------------------------------------------------- +#define CPPYY_IMPL_ARRAY_CONVERTER(name, type, code) \ +bool CPyCppyy::name##ArrayConverter::SetArg( \ + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \ +{ \ + return CArraySetArg(pyobject, para, code, sizeof(type)); \ +} \ + \ +PyObject* CPyCppyy::name##ArrayConverter::FromMemory(void* address) \ +{ \ + Py_ssize_t shape[] = {1, fSize}; \ + return CreateLowLevelView(*(type**)address, shape); \ +} \ + \ +bool CPyCppyy::name##ArrayConverter::ToMemory(PyObject* value, void* address)\ +{ \ + void* buf = nullptr; \ + int buflen = Utility::GetBuffer(value, code, sizeof(type), buf); \ + if (!buf || buflen == 0) \ + return false; \ + if (0 <= fSize) { \ + if (fSize < buflen/(int)sizeof(type)) { \ + PyErr_SetString(PyExc_ValueError, "buffer too large for value"); \ + return false; \ + } \ + memcpy(*(type**)address, buf, 0 < buflen ? ((size_t)buflen) : sizeof(type));\ + } else \ + *(type**)address = (type*)buf; \ + return true; \ +} + +#define CPPYY_IMPL_ARRAY_CONVERTER2(name, type, code) \ +CPPYY_IMPL_ARRAY_CONVERTER(name, type, code) \ + \ +bool CPyCppyy::name##ArrayRefConverter::SetArg( \ + PyObject* pyobject, Parameter& para, CallContext* ctxt) \ +{ \ + bool result = name##ArrayConverter::SetArg(pyobject, para, ctxt); \ + para.fTypeCode = 'V'; \ + return result; \ +} + + +//---------------------------------------------------------------------------- +CPPYY_IMPL_ARRAY_CONVERTER2(Bool, bool, 'b') // signed char +CPPYY_IMPL_ARRAY_CONVERTER (UChar, unsigned char, 'B') +CPPYY_IMPL_ARRAY_CONVERTER2(Short, short, 'h') +CPPYY_IMPL_ARRAY_CONVERTER2(UShort, unsigned short, 'H') +CPPYY_IMPL_ARRAY_CONVERTER (Int, int, 'i') +CPPYY_IMPL_ARRAY_CONVERTER2(UInt, unsigned int, 'I') +CPPYY_IMPL_ARRAY_CONVERTER (Long, long, 'l') +CPPYY_IMPL_ARRAY_CONVERTER2(ULong, unsigned long, 'L') +CPPYY_IMPL_ARRAY_CONVERTER2(LLong, long long, 'q') +CPPYY_IMPL_ARRAY_CONVERTER2(ULLong, unsigned long long, 'Q') +CPPYY_IMPL_ARRAY_CONVERTER2(Float, float, 'f') +CPPYY_IMPL_ARRAY_CONVERTER (Double, double, 'd') + + +//- converters for special cases --------------------------------------------- +#define CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(name, type, F1, F2) \ +CPyCppyy::name##Converter::name##Converter(bool keepControl) : \ + CppObjectConverter(Cppyy::GetScope(#type), keepControl) {} \ + \ +bool CPyCppyy::name##Converter::SetArg( \ + PyObject* pyobject, Parameter& para, CallContext* ctxt) \ +{ \ + if (CPyCppyy_PyUnicode_Check(pyobject)) { \ + fBuffer = type(CPyCppyy_PyUnicode_AsString(pyobject), \ + CPyCppyy_PyUnicode_GET_SIZE(pyobject)); \ + para.fValue.fVoidp = &fBuffer; \ + para.fTypeCode = 'V'; \ + return true; \ + } \ + \ + if (!(PyInt_Check(pyobject) || PyLong_Check(pyobject))) { \ + bool result = CppObjectConverter::SetArg(pyobject, para, ctxt); \ + para.fTypeCode = 'V'; \ + return result; \ + } \ + return false; \ +} \ + \ +PyObject* CPyCppyy::name##Converter::FromMemory(void* address) \ +{ \ + if (address) \ + return CPyCppyy_PyUnicode_FromStringAndSize(((type*)address)->F1(), ((type*)address)->F2()); \ + Py_INCREF(PyStrings::gEmptyString); \ + return PyStrings::gEmptyString; \ +} \ + \ +bool CPyCppyy::name##Converter::ToMemory(PyObject* value, void* address) \ +{ \ + if (CPyCppyy_PyUnicode_Check(value)) { \ + *((type*)address) = CPyCppyy_PyUnicode_AsString(value); \ + return true; \ + } \ + \ + return CppObjectConverter::ToMemory(value, address); \ +} + +CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(STLString, std::string, c_str, size) +#if __cplusplus > 201402L +CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(STLStringView, std::string_view, data, size) +#endif + +//---------------------------------------------------------------------------- +bool CPyCppyy::CppObjectConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* ctxt) +{ +// convert to C++ instance*, set arg for call + if (!CPPInstance_Check(pyobject)) { + if (GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) { + para.fTypeCode = 'p'; // allow special cases such as nullptr + return true; + } + + // not a cppyy object (TODO: handle SWIG etc.) + return false; + } + + CPPInstance* pyobj = (CPPInstance*)pyobject; + if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) { + // depending on memory policy, some objects need releasing when passed into functions + if (!KeepControl() && !UseStrictOwnership(ctxt)) + ((CPPInstance*)pyobject)->CppOwns(); + + // calculate offset between formal and actual arguments + para.fValue.fVoidp = pyobj->GetObject(); + if (pyobj->ObjectIsA() != fClass) { + para.fValue.fLong += Cppyy::GetBaseOffset( + pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */); + } + + // set pointer (may be null) and declare success + para.fTypeCode = 'p'; + return true; + } + + return false; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CppObjectConverter::FromMemory(void* address) +{ +// construct python object from C++ instance read at
+ return BindCppObject(address, fClass); +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::CppObjectConverter::ToMemory(PyObject* value, void* address) +{ +// convert to C++ instance, write it at
+ if (!CPPInstance_Check(value)) { + void* ptr = nullptr; + if (GetAddressSpecialCase(value, ptr)) { + *(void**)address = ptr; // allow special cases such as nullptr + return true; + } + + // not a cppyy object (TODO: handle SWIG etc.) + return false; + } + + if (Cppyy::IsSubtype(((CPPInstance*)value)->ObjectIsA(), fClass)) { + // depending on memory policy, some objects need releasing when passed into functions + if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict) + ((CPPInstance*)value)->CppOwns(); + + // call assignment operator through a temporarily wrapped object proxy + PyObject* pyobj = BindCppObjectNoCast(address, fClass); + ((CPPInstance*)pyobj)->CppOwns(); // TODO: might be recycled (?) + PyObject* result = PyObject_CallMethod(pyobj, (char*)"__assign__", (char*)"O", value); + Py_DECREF(pyobj); + if (result) { + Py_DECREF(result); + return true; + } + } + + return false; +} + +// TODO: CONSOLIDATE ValueCpp, RefCpp, and CppObject ... + +//---------------------------------------------------------------------------- +bool CPyCppyy::ValueCppObjectConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// convert to C++ instance, set arg for call + if (!CPPInstance_Check(pyobject)) + return false; + + CPPInstance* pyobj = (CPPInstance*)pyobject; + if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) { + // calculate offset between formal and actual arguments + para.fValue.fVoidp = pyobj->GetObject(); + if (!para.fValue.fVoidp) + return false; + + if (pyobj->ObjectIsA() != fClass) { + para.fValue.fLong += Cppyy::GetBaseOffset( + pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */); + } + + para.fTypeCode = 'V'; + return true; + } + + return false; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::RefCppObjectConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// convert to C++ instance&, set arg for call + if (!CPPInstance_Check(pyobject)) + return false; + CPPInstance* pyobj = (CPPInstance*)pyobject; + +// reject moves + if (pyobj->fFlags & CPPInstance::kIsRValue) + return false; + + if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) { + // calculate offset between formal and actual arguments + para.fValue.fVoidp = pyobj->GetObject(); + if (pyobj->ObjectIsA() != fClass) { + para.fValue.fLong += Cppyy::GetBaseOffset( + pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */); + } + + para.fTypeCode = 'V'; + return true; + } + + return false; +} + +//---------------------------------------------------------------------------- +#if PY_VERSION_HEX < 0x03000000 +const size_t refcount_cutoff = 1; +#else +// p3 has at least 2 ref-counts, as contrary to p2, it will create a descriptor +// copy for the method holding self in the case of __init__; but there can also +// be a reference held by the frame object, which is indistinguishable from a +// local variable reference, so the cut-off has to remain 2. +const size_t refcount_cutoff = 2; +#endif + +bool CPyCppyy::MoveCppObjectConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* ctxt) +{ +// convert to C++ instance&&, set arg for call + if (!CPPInstance_Check(pyobject)) + return false; + CPPInstance* pyobj = (CPPInstance*)pyobject; + +// moving is same as by-ref, but have to check that move is allowed + int moveit_reason = 0; + if (pyobj->fFlags & CPPInstance::kIsRValue) { + pyobj->fFlags &= ~CPPInstance::kIsRValue; + moveit_reason = 2; + } else if (pyobject->ob_refcnt == refcount_cutoff) { + moveit_reason = 1; + } + + if (moveit_reason) { + bool result = this->RefCppObjectConverter::SetArg(pyobject, para, ctxt); + if (!result && moveit_reason == 2) // restore the movability flag? + ((CPPInstance*)pyobject)->fFlags |= CPPInstance::kIsRValue; + return result; + } + + PyErr_SetString(PyExc_ValueError, "object is not an rvalue"); + return false; // not a temporary or movable object +} + +//---------------------------------------------------------------------------- +template +bool CPyCppyy::CppObjectPtrConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* ctxt) +{ +// convert to C++ instance**, set arg for call + if (!CPPInstance_Check(pyobject)) + return false; // not a cppyy object (TODO: handle SWIG etc.) + + CPPInstance* pyobj = (CPPInstance*)pyobject; + if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) { + // depending on memory policy, some objects need releasing when passed into functions + if (!KeepControl() && !UseStrictOwnership(ctxt)) + pyobj->CppOwns(); + + // set pointer (may be null) and declare success + if (pyobj->fFlags & CPPInstance::kIsReference) + para.fValue.fVoidp = pyobj->fObject; // already a ptr to object + else + para.fValue.fVoidp = &pyobj->fObject; + para.fTypeCode = ISREFERENCE ? 'V' : 'p'; + return true; + } + + return false; +} + +//---------------------------------------------------------------------------- +template +PyObject* CPyCppyy::CppObjectPtrConverter::FromMemory(void* address) +{ +// construct python object from C++ instance* read at
+ return BindCppObject(address, fClass, CPPInstance::kIsReference); +} + +//---------------------------------------------------------------------------- +template +bool CPyCppyy::CppObjectPtrConverter::ToMemory(PyObject* value, void* address) +{ +// convert to C++ instance*, write it at
+ if (!CPPInstance_Check(value)) + return false; // not a cppyy object (TODO: handle SWIG etc.) + + if (Cppyy::IsSubtype(((CPPInstance*)value)->ObjectIsA(), fClass)) { + // depending on memory policy, some objects need releasing when passed into functions + if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict) + ((CPPInstance*)value)->CppOwns(); + + // register the value for potential recycling + MemoryRegulator::RegisterPyObject((CPPInstance*)value, ((CPPInstance*)value)->GetObject()); + + // set pointer (may be null) and declare success + *(void**)address = ((CPPInstance*)value)->GetObject(); + return true; + } + + return false; +} + + +namespace CPyCppyy { +// Instantiate the templates + template class CPyCppyy::CppObjectPtrConverter; + template class CPyCppyy::CppObjectPtrConverter; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::CppObjectArrayConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* txt */) +{ +// convert to C++ instance**, set arg for call + if (!TupleOfInstances_CheckExact(pyobject)) + return false; // no guarantee that the tuple is okay + +// treat the first instance of the tuple as the start of the array, and pass it +// by pointer (TODO: store and check sizes) + if (PyTuple_Size(pyobject) < 1) + return false; + + PyObject* first = PyTuple_GetItem(pyobject, 0); + if (!CPPInstance_Check(first)) + return false; // should not happen + + if (Cppyy::IsSubtype(((CPPInstance*)first)->ObjectIsA(), fClass)) { + // no memory policies supported; set pointer (may be null) and declare success + para.fValue.fVoidp = ((CPPInstance*)first)->fObject; + para.fTypeCode = 'p'; + return true; + } + + return false; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CppObjectArrayConverter::FromMemory(void* address) +{ +// construct python tuple of instances from C++ array read at
+ if (m_size <= 0) // if size unknown, just hand out the first object + return BindCppObjectNoCast(address, fClass); + + return BindCppObjectArray(address, fClass, m_size); +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::CppObjectArrayConverter::ToMemory(PyObject* /* value */, void* /* address */) +{ +// convert to C++ array of instances, write it at
+ +// TODO: need to have size both for the array and from the input + PyErr_SetString(PyExc_NotImplementedError, + "access to C-arrays of objects not yet implemented!"); + return false; +} + +//___________________________________________________________________________ +// CLING WORKAROUND -- classes for STL iterators are completely undefined in that +// they come in a bazillion different guises, so just do whatever +bool CPyCppyy::STLIteratorConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ + if (!CPPInstance_Check(pyobject)) + return false; + +// just set the pointer value, no check + CPPInstance* pyobj = (CPPInstance*)pyobject; + para.fValue.fVoidp = pyobj->GetObject(); + para.fTypeCode = 'V'; + return true; +} +// -- END CLING WORKAROUND + +//---------------------------------------------------------------------------- +bool CPyCppyy::VoidPtrRefConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// convert to C++ void*&, set arg for call + if (CPPInstance_Check(pyobject)) { + para.fValue.fVoidp = &((CPPInstance*)pyobject)->fObject; + para.fTypeCode = 'V'; + return true; + } + + return false; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::VoidPtrPtrConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// convert to C++ void**, set arg for call + if (CPPInstance_Check(pyobject)) { + // this is a C++ object, take and set its address + para.fValue.fVoidp = &((CPPInstance*)pyobject)->fObject; + para.fTypeCode = 'p'; + return true; + } + +// buffer objects are allowed under "user knows best" + int buflen = Utility::GetBuffer(pyobject, '*', 1, para.fValue.fVoidp, false); + +// ok if buffer exists (can't perform any useful size checks) + if (para.fValue.fVoidp && buflen != 0) { + para.fTypeCode = 'p'; + return true; + } + + return false; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::VoidPtrPtrConverter::FromMemory(void* address) +{ +// read a void** from address; since this is unknown, long is used (user can cast) + if (!address || *(ptrdiff_t*)address == 0) { + Py_INCREF(gNullPtrObject); + return gNullPtrObject; + } + return CreatePointerView(*(ptrdiff_t**)address); +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::PyObjectConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) +{ +// by definition: set and declare success + para.fValue.fVoidp = pyobject; + para.fTypeCode = 'p'; + return true; +} + +PyObject* CPyCppyy::PyObjectConverter::FromMemory(void* address) +{ +// construct python object from C++ PyObject* read at
+ PyObject* pyobject = *((PyObject**)address); + + if (!pyobject) { + Py_RETURN_NONE; + } + + Py_INCREF(pyobject); + return pyobject; +} + +bool CPyCppyy::PyObjectConverter::ToMemory(PyObject* value, void* address) +{ +// no conversion needed, write at
+ Py_INCREF(value); + *((PyObject**)address) = value; + return true; +} + + +//- function pointer converter ----------------------------------------------- +bool CPyCppyy::FunctionPointerConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /*ctxt*/) +{ + if (!CPPOverload_Check(pyobject)) + return false; + + CPPOverload* ol = (CPPOverload*)pyobject; + if (!ol->fMethodInfo || ol->fMethodInfo->fMethods.empty()) + return false; + +// find the overload with matching signature + for (auto& m : ol->fMethodInfo->fMethods) { + PyObject* sig = m->GetSignature(false); + bool found = fSignature == CPyCppyy_PyUnicode_AsString(sig); + Py_DECREF(sig); + if (found) { + para.fValue.fVoidp = (void*)m->GetFunctionAddress(); + if (!para.fValue.fVoidp) + return false; + para.fTypeCode = 'p'; + return true; + } + } + + return false; +} + + +//- smart pointer converters ------------------------------------------------- +bool CPyCppyy::SmartPtrCppObjectConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* ctxt) +{ + char typeCode = fIsRef ? 'p' : 'V'; + + if (!CPPInstance_Check(pyobject)) { + if (fIsRef && GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) { + para.fTypeCode = typeCode; // allow special cases such as nullptr + return true; + } + + return false; + } + + CPPInstance* pyobj = (CPPInstance*)pyobject; + +// for the case where we have a 'hidden' smart pointer: + if ((pyobj->fFlags & CPPInstance::kIsSmartPtr) && + Cppyy::IsSubtype(pyobj->fSmartPtrType, fSmartPtrType)) { + // depending on memory policy, some objects need releasing when passed into functions + if (fKeepControl && !UseStrictOwnership(ctxt)) + ((CPPInstance*)pyobject)->CppOwns(); + + // calculate offset between formal and actual arguments + para.fValue.fVoidp = pyobj->fObject; + if (pyobj->fSmartPtrType != fSmartPtrType) { + para.fValue.fLong += Cppyy::GetBaseOffset( + pyobj->fSmartPtrType, fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */); + } + + // set pointer (may be null) and declare success + para.fTypeCode = typeCode; + return true; + } + +// for the case where we have an 'exposed' smart pointer: + if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fSmartPtrType)) { + // calculate offset between formal and actual arguments + para.fValue.fVoidp = pyobj->GetObject(); + if (pyobj->ObjectIsA() != fSmartPtrType) { + para.fValue.fLong += Cppyy::GetBaseOffset( + pyobj->ObjectIsA(), fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */); + } + + // set pointer (may be null) and declare success + para.fTypeCode = typeCode; + return true; + } + + return false; +} + +PyObject* CPyCppyy::SmartPtrCppObjectConverter::FromMemory(void* address) +{ + if (!address || !fSmartPtrType) + return nullptr; + +// TODO: note the mismatch between address, which is the smart pointer, and the +// declared type, which is the raw pointer + CPPInstance* pyobj = (CPPInstance*)BindCppObjectNoCast(address, fRawPtrType); + if (pyobj) + pyobj->SetSmartPtr(fSmartPtrType, fDereferencer); + + return (PyObject*)pyobj; +} + + +//---------------------------------------------------------------------------- +namespace { + +// clang libcpp and gcc use the same structure (ptr, size) +#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__) +struct faux_initlist +{ + typedef size_t size_type; + typedef void* iterator; + iterator _M_array; + size_type _M_len; +}; +#else +#define NO_KNOWN_INITIALIZER_LIST 1 +#endif + +} // unnamed namespace + +bool CPyCppyy::InitializerListConverter::SetArg( + PyObject* pyobject, Parameter& para, CallContext* /*ctxt*/) +{ +#ifdef NO_KNOWN_INITIALIZER_LIST + return false; +#else +// convert the given argument to an initializer list temporary + if (!PySequence_Check(pyobject)) + return false; + +// can only construct empty lists, so use a fake initializer list + size_t len = (size_t)PySequence_Size(pyobject); + faux_initlist* fake = (faux_initlist*)malloc(sizeof(faux_initlist)+fValueSize*len); + fake->_M_len = (faux_initlist::size_type)len; + fake->_M_array = (faux_initlist::iterator)((char*)fake+sizeof(faux_initlist)); + + for (faux_initlist::size_type i = 0; i < fake->_M_len; ++i) { + PyObject* item = PySequence_GetItem(pyobject, i); + if (!fConverter->ToMemory(item, (char*)fake->_M_array + i*fValueSize)) { + Py_DECREF(item); + free((void*)fake); + return false; + } + Py_DECREF(item); + } + +// TODO: this passes, but how to clean up? + para.fValue.fVoidp = (void*)fake; + para.fTypeCode = 'X'; + return true; +#endif +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::NotImplementedConverter::SetArg(PyObject*, Parameter&, CallContext*) +{ +// raise a NotImplemented exception to take a method out of overload resolution + PyErr_SetString(PyExc_NotImplementedError, "this method can not (yet) be called"); + return false; +} + + +//- factories ---------------------------------------------------------------- +CPyCppyy::Converter* CPyCppyy::CreateConverter(const std::string& fullType, long size) +{ +// The matching of the fulltype to a converter factory goes through up to five levels: +// 1) full, exact match +// 2) match of decorated, unqualified type +// 3) accept const ref as by value +// 4) accept ref as pointer +// 5) generalized cases (covers basically all C++ classes) +// +// If all fails, void is used, which will generate a run-time warning when used. + +// an exactly matching converter is best + ConvFactories_t::iterator h = gConvFactories.find(fullType); + if (h != gConvFactories.end()) + return (h->second)(size); + +// resolve typedefs etc. + const std::string& resolvedType = Cppyy::ResolveName(fullType); + +// a full, qualified matching converter is preferred + if (resolvedType != fullType) { + h = gConvFactories.find(resolvedType); + if (h != gConvFactories.end()) + return (h->second)(size); + } + +//-- nothing? ok, collect information about the type and possible qualifiers/decorators + bool isConst = strncmp(resolvedType.c_str(), "const", 5) == 0; + const std::string& cpd = Utility::Compound(resolvedType); + std::string realType = TypeManip::clean_type(resolvedType, false, true); + +// accept unqualified type (as python does not know about qualifiers) + h = gConvFactories.find(realType + cpd); + if (h != gConvFactories.end()) + return (h->second)(size); + +// drop const, as that is mostly meaningless to python (with the exception +// of c-strings, but those are specialized in the converter map) + if (isConst) { + realType = TypeManip::remove_const(realType); + h = gConvFactories.find(realType + cpd); + if (h != gConvFactories.end()) + return (h->second)(size); + } + +// CLING WORKAROUND -- if the type is a fixed-size array, it will have a funky +// resolved type like MyClass(&)[N], which TClass::GetClass() fails on. So, strip +// it down: +/* TODO: remove TClassEdit usage + if (cpd == "[]") + realType = TClassEdit::CleanType(realType.substr(0, realType.rfind("(")).c_str(), 1); +*/ +// -- CLING WORKAROUND + +//-- still nothing? try pointer instead of array (for builtins) + if (cpd == "[]") { + h = gConvFactories.find(realType + "*"); + if (h != gConvFactories.end()) + return (h->second)(size); + } + +//-- special case: initializer list + auto pos = realType.find("initializer_list"); + if (pos == 0 /* no std:: */ || pos == 5 /* with std:: */) { + // get the type of the list and create a converter (TODO: get hold of value_type?) + auto pos2 = realType.find('<'); + std::string value_type = realType.substr(pos2+1, realType.size()-pos2-2); + Converter* cnv = CreateConverter(value_type); + if (cnv) + return new InitializerListConverter(cnv, Cppyy::SizeOf(value_type)); + } + +//-- still nothing? use a generalized converter + bool control = cpd == "&" || isConst; + +// converters for known C++ classes and default (void*) + Converter* result = nullptr; + if (Cppyy::TCppScope_t klass = Cppyy::GetScope(realType)) { + Cppyy::TCppType_t raw; Cppyy::TCppMethod_t deref; + if (Cppyy::GetSmartPtrInfo(realType, raw, deref)) { + if (cpd == "") { + result = new SmartPtrCppObjectConverter(klass, raw, deref, control); + } else if (cpd == "&") { + result = new SmartPtrCppObjectConverter(klass, raw, deref); + } else if (cpd == "*" && size <= 0) { + result = new SmartPtrCppObjectConverter(klass, raw, deref, control, true); + } + } + + if (!result) { + // CLING WORKAROUND -- special case for STL iterators + if (realType.find("__gnu_cxx::__normal_iterator", 0) /* vector */ == 0) + result = new STLIteratorConverter(); + else + // -- CLING WORKAROUND + if (cpd == "**" || cpd == "*[]" || cpd == "&*") + result = new CppObjectPtrConverter(klass, control); + else if (cpd == "*&") + result = new CppObjectPtrConverter(klass, control); + else if (cpd == "*" && size <= 0) + result = new CppObjectConverter(klass, control); + else if (cpd == "&") + result = new RefCppObjectConverter(klass); + else if (cpd == "&&") + result = new MoveCppObjectConverter(klass); + else if (cpd == "[]" || size > 0) + result = new CppObjectArrayConverter(klass, size, false); + else if (cpd == "") // by value + result = new ValueCppObjectConverter(klass, true); + } + } else if (resolvedType.find("(*)") != std::string::npos || + (resolvedType.find("::*)") != std::string::npos)) { + // this is a function function pointer + // TODO: find better way of finding the type + // TODO: a converter that generates wrappers as appropriate + auto pos2 = resolvedType.find("*)"); + result = new FunctionPointerConverter(resolvedType.substr(pos2+2)); + } + + if (!result && cpd == "&&") // unhandled moves + result = new NotImplementedConverter(); + + if (!result && h != gConvFactories.end()) + // converter factory available, use it to create converter + result = (h->second)(size); + else if (!result) { + if (cpd != "") { + result = new VoidArrayConverter(); // "user knows best" + } else { + result = new VoidConverter(); // fails on use + } + } + + return result; +} + +//---------------------------------------------------------------------------- +namespace { + +using namespace CPyCppyy; + +static struct InitConvFactories_t { +public: + InitConvFactories_t() { + // load all converter factories in the global map 'gConvFactories' + CPyCppyy::ConvFactories_t& gf = gConvFactories; + + // factories for built-ins + gf["bool"] = (cf_t)+[](long) { return new BoolConverter{}; }; + gf["const bool&"] = (cf_t)+[](long) { return new ConstBoolRefConverter{}; }; + gf["char"] = (cf_t)+[](long) { return new CharConverter{}; }; + gf["const char&"] = (cf_t)+[](long) { return new ConstCharRefConverter{}; }; + gf["signed char"] = (cf_t)+[](long) { return new CharConverter{}; }; + gf["const signed char&"] = (cf_t)+[](long) { return new ConstCharRefConverter{}; }; + gf["unsigned char"] = (cf_t)+[](long) { return new UCharConverter{}; }; + gf["const unsigned char&"] = (cf_t)+[](long) { return new ConstUCharRefConverter{}; }; + gf["UCharAsInt"] = (cf_t)+[](long) { return new UCharAsIntConverter{}; }; + gf["short"] = (cf_t)+[](long) { return new ShortConverter{}; }; + gf["const short&"] = (cf_t)+[](long) { return new ConstShortRefConverter{}; }; + gf["unsigned short"] = (cf_t)+[](long) { return new UShortConverter{}; }; + gf["const unsigned short&"] = (cf_t)+[](long) { return new ConstUShortRefConverter{}; }; + gf["int"] = (cf_t)+[](long) { return new IntConverter{}; }; + gf["int&"] = (cf_t)+[](long) { return new IntRefConverter{}; }; + gf["const int&"] = (cf_t)+[](long) { return new ConstIntRefConverter{}; }; + gf["unsigned int"] = (cf_t)+[](long) { return new UIntConverter{}; }; + gf["const unsigned int&"] = (cf_t)+[](long) { return new ConstUIntRefConverter{}; }; + gf["internal_enum_type_t"] = (cf_t)+[](long) { return new IntConverter{}; }; + gf["internal_enum_type_t&"] = (cf_t)+[](long) { return new IntRefConverter{}; }; + gf["long"] = (cf_t)+[](long) { return new LongConverter{}; }; + gf["long&"] = (cf_t)+[](long) { return new LongRefConverter{}; }; + gf["const long&"] = (cf_t)+[](long) { return new ConstLongRefConverter{}; }; + gf["unsigned long"] = (cf_t)+[](long) { return new ULongConverter{}; }; + gf["const unsigned long&"] = (cf_t)+[](long) { return new ConstULongRefConverter{}; }; + gf["long long"] = (cf_t)+[](long) { return new LongLongConverter{}; }; + gf["const long long&"] = (cf_t)+[](long) { return new ConstLongLongRefConverter{}; }; + gf["unsigned long long"] = (cf_t)+[](long) { return new ULongLongConverter{}; }; + gf["const unsigned long long&"] = (cf_t)+[](long) { return new ConstULongLongRefConverter{}; }; + + gf["float"] = (cf_t)+[](long) { return new FloatConverter{}; }; + gf["const float&"] = (cf_t)+[](long) { return new ConstFloatRefConverter{}; }; + gf["double"] = (cf_t)+[](long) { return new DoubleConverter{}; }; + gf["double&"] = (cf_t)+[](long) { return new DoubleRefConverter{}; }; + gf["const double&"] = (cf_t)+[](long) { return new ConstDoubleRefConverter{}; }; + gf["long double"] = (cf_t)+[](long) { return new LongDoubleConverter{}; }; + gf["const long double&"] = (cf_t)+[](long) { return new ConstLongDoubleRefConverter{}; }; + gf["void"] = (cf_t)+[](long) { return new VoidConverter{}; }; + + // pointer/array factories + gf["bool*"] = (cf_t)+[](long sz) { return new BoolArrayConverter{sz}; }; + gf["bool&"] = (cf_t)+[](long sz) { return new BoolArrayRefConverter{sz}; }; + gf["const unsigned char*"] = (cf_t)+[](long sz) { return new UCharArrayConverter{sz}; }; + gf["unsigned char*"] = (cf_t)+[](long sz) { return new UCharArrayConverter{sz}; }; + gf["short*"] = (cf_t)+[](long sz) { return new ShortArrayConverter{sz}; }; + gf["short&"] = (cf_t)+[](long sz) { return new ShortArrayRefConverter{sz}; }; + gf["unsigned short*"] = (cf_t)+[](long sz) { return new UShortArrayConverter{sz}; }; + gf["unsigned short&"] = (cf_t)+[](long sz) { return new UShortArrayRefConverter{sz}; }; + gf["int*"] = (cf_t)+[](long sz) { return new IntArrayConverter{sz}; }; + gf["unsigned int*"] = (cf_t)+[](long sz) { return new UIntArrayConverter{sz}; }; + gf["unsigned int&"] = (cf_t)+[](long sz) { return new UIntArrayRefConverter{sz}; }; + gf["long*"] = (cf_t)+[](long sz) { return new LongArrayConverter{sz}; }; + gf["unsigned long*"] = (cf_t)+[](long sz) { return new ULongArrayConverter{sz}; }; + gf["unsigned long&"] = (cf_t)+[](long sz) { return new ULongArrayRefConverter{sz}; }; + gf["float*"] = (cf_t)+[](long sz) { return new FloatArrayConverter{sz}; }; + gf["float&"] = (cf_t)+[](long sz) { return new FloatArrayRefConverter{sz}; }; + gf["double*"] = (cf_t)+[](long sz) { return new DoubleArrayConverter{sz}; }; + gf["long long*"] = (cf_t)+[](long sz) { return new LLongArrayConverter{sz}; }; + gf["long long&"] = (cf_t)+[](long sz) { return new LLongArrayRefConverter{sz}; }; + gf["unsigned long long*"] = (cf_t)+[](long sz) { return new ULLongArrayConverter{sz}; }; + gf["unsigned long long&"] = (cf_t)+[](long sz) { return new ULLongArrayRefConverter{sz}; }; + gf["void*"] = (cf_t)+[](long sz) { return new VoidArrayConverter{static_cast(sz)}; }; + + // aliases + gf["Long64_t"] = gf["long long"]; + gf["Long64_t*"] = gf["long long*"]; + gf["Long64_t&"] = gf["long long&"]; + gf["const Long64_t&"] = gf["const long long&"]; + gf["ULong64_t"] = gf["unsigned long long"]; + gf["ULong64_t*"] = gf["unsigned long long*"]; + gf["ULong64_t&"] = gf["unsigned long long&"]; + gf["const ULong64_t&"] = gf["const unsigned long long&"]; + + // factories for special cases + gf["const char*"] = (cf_t)+[](long) { return new CStringConverter{}; }; + gf["const char[]"] = (cf_t)+[](long) { return new CStringConverter{}; }; + gf["char*"] = (cf_t)+[](long) { return new NonConstCStringConverter{}; }; + gf["std::string"] = (cf_t)+[](long) { return new STLStringConverter{}; }; + gf["string"] = (cf_t)+[](long) { return new STLStringConverter{}; }; + gf["const std::string&"] = (cf_t)+[](long) { return new STLStringConverter{}; }; + gf["const string&"] = (cf_t)+[](long) { return new STLStringConverter{}; }; +#if __cplusplus > 201402L + gf["std::string_view"] = (cf_t)+[](long) { return new STLStringViewConverter{}; }; + gf["string_view"] = (cf_t)+[](long) { return new STLStringViewConverter{}; }; + gf["experimental::basic_string_view >"] = (cf_t)+[](long) { return new STLStringViewConverter{}; }; +#endif + gf["void*&"] = (cf_t)+[](long) { return new VoidPtrRefConverter{}; }; + gf["void**"] = (cf_t)+[](long) { return new VoidPtrPtrConverter{}; }; + gf["void*[]"] = (cf_t)+[](long) { return new VoidPtrPtrConverter{}; }; + gf["PyObject*"] = (cf_t)+[](long) { return new PyObjectConverter{}; }; + gf["_object*"] = (cf_t)+[](long) { return new PyObjectConverter{}; }; + gf["FILE*"] = (cf_t)+[](long) { return new VoidArrayConverter{}; }; + gf["Float16_t"] = (cf_t)+[](long) { return new FloatConverter{}; }; + gf["const Float16_t&"] = (cf_t)+[](long) { return new ConstFloatRefConverter{}; }; + gf["Double32_t"] = (cf_t)+[](long) { return new DoubleConverter{}; }; + gf["Double32_t&"] = (cf_t)+[](long) { return new DoubleRefConverter{}; }; + gf["const Double32_t&"] = (cf_t)+[](long) { return new ConstDoubleRefConverter{}; }; + } +} initConvFactories_; + +} // unnamed namespace diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Converters.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Converters.h new file mode 100644 index 0000000000000..d1e9637b1a01e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Converters.h @@ -0,0 +1,69 @@ +#ifndef CPYCPPYY_CONVERTERS_H +#define CPYCPPYY_CONVERTERS_H + +// Standard +#include + + +namespace CPyCppyy { + +struct Parameter; +struct CallContext; + +class Converter { +public: + virtual ~Converter() {} + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr) = 0; + virtual PyObject* FromMemory(void* address); + virtual bool ToMemory(PyObject* value, void* address); +}; + +// create converter from fully qualified type +Converter* CreateConverter(const std::string& fullType, Long_t size = -1); + + +// converters for special cases (only here b/c of external use of StrictCppObjectConverter) +class VoidArrayConverter : public Converter { +public: + VoidArrayConverter(bool keepControl = true) { fKeepControl = keepControl; } + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + virtual PyObject* FromMemory(void* address); + virtual bool ToMemory(PyObject* value, void* address); + +protected: + virtual bool GetAddressSpecialCase(PyObject* pyobject, void*& address); + bool KeepControl() { return fKeepControl; } + +private: + bool fKeepControl; +}; + +class CppObjectConverter : public VoidArrayConverter { +public: + CppObjectConverter(Cppyy::TCppType_t klass, bool keepControl = false) : + VoidArrayConverter(keepControl), fClass(klass) {} + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + virtual PyObject* FromMemory(void* address); + virtual bool ToMemory(PyObject* value, void* address); + +protected: + Cppyy::TCppType_t fClass; +}; + +class StrictCppObjectConverter : public CppObjectConverter { +public: + using CppObjectConverter::CppObjectConverter; + +protected: + virtual bool GetAddressSpecialCase(PyObject*, void*&) { return false; } +}; + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CONVERTERS_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Cppyy.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Cppyy.h new file mode 100644 index 0000000000000..1e13cc9a58d34 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Cppyy.h @@ -0,0 +1,139 @@ +#ifndef CPYCPPYY_CPPYY_H +#define CPYCPPYY_CPPYY_H + +// Standard +#include +#include +#include +#include + + +namespace Cppyy { + + typedef ptrdiff_t TCppScope_t; + typedef TCppScope_t TCppType_t; + typedef void* TCppObject_t; + typedef ptrdiff_t TCppMethod_t; + + typedef long TCppIndex_t; + typedef void* TCppFuncAddr_t; + +// name to opaque C++ scope representation ----------------------------------- + std::string ResolveName(const std::string& cppitem_name); + std::string ResolveEnum(const std::string& enum_type); + TCppScope_t GetScope(const std::string& scope_name); + TCppType_t GetActualClass(TCppType_t klass, TCppObject_t obj); + size_t SizeOf(TCppType_t klass); + size_t SizeOf(const std::string& type_name); + + bool IsBuiltin(const std::string& type_name); + bool IsComplete(const std::string& type_name); + + extern TCppScope_t gGlobalScope; // for fast access + +// memory management --------------------------------------------------------- + TCppObject_t Allocate(TCppType_t type); + void Deallocate(TCppType_t type, TCppObject_t instance); + TCppObject_t Construct(TCppType_t type); + void Destruct(TCppType_t type, TCppObject_t instance); + +// method/function dispatching ----------------------------------------------- + void CallV(TCppMethod_t method, TCppObject_t self, void* args); + unsigned char CallB(TCppMethod_t method, TCppObject_t self, void* args); + char CallC(TCppMethod_t method, TCppObject_t self, void* args); + short CallH(TCppMethod_t method, TCppObject_t self, void* args); + int CallI(TCppMethod_t method, TCppObject_t self, void* args); + long CallL(TCppMethod_t method, TCppObject_t self, void* args); + Long64_t CallLL(TCppMethod_t method, TCppObject_t self, void* args); + float CallF(TCppMethod_t method, TCppObject_t self, void* args); + double CallD(TCppMethod_t method, TCppObject_t self, void* args); + LongDouble_t CallLD(TCppMethod_t method, TCppObject_t self, void* args); + void* CallR(TCppMethod_t method, TCppObject_t self, void* args); + char* CallS(TCppMethod_t method, TCppObject_t self, void* args, size_t* length); + TCppObject_t CallConstructor(TCppMethod_t method, TCppType_t type, void* args); + void CallDestructor(TCppType_t type, TCppObject_t self); + TCppObject_t CallO(TCppMethod_t method, TCppObject_t self, void* args, TCppType_t result_type); + + TCppFuncAddr_t GetFunctionAddress(TCppScope_t scope, TCppIndex_t imeth); + TCppFuncAddr_t GetFunctionAddress(TCppMethod_t method); + +// handling of function argument buffer -------------------------------------- + void* AllocateFunctionArgs(size_t nargs); + void DeallocateFunctionArgs(void* args); + size_t GetFunctionArgSizeof(); + size_t GetFunctionArgTypeoffset(); + +// scope reflection information ---------------------------------------------- + bool IsNamespace(TCppScope_t scope); + bool IsTemplate(const std::string& template_name); + bool IsAbstract(TCppType_t type); + bool IsEnum(const std::string& type_name); + + void GetAllCppNames(TCppScope_t scope, std::set& cppnames); + +// class reflection information ---------------------------------------------- + std::string GetFinalName(TCppType_t type); + std::string GetScopedFinalName(TCppType_t type); + bool HasComplexHierarchy(TCppType_t type); + TCppIndex_t GetNumBases(TCppType_t type); + std::string GetBaseName(TCppType_t type, TCppIndex_t ibase); + bool IsSubtype(TCppType_t derived, TCppType_t base); + bool GetSmartPtrInfo(const std::string&, TCppType_t& raw, TCppMethod_t& deref); + void AddSmartPtrType(const std::string&); + +// calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 + ptrdiff_t GetBaseOffset( + TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror = false); + +// method/function reflection information ------------------------------------ + TCppIndex_t GetNumMethods(TCppScope_t scope); + std::vector GetMethodIndicesFromName( + TCppScope_t scope, const std::string& name); + + TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth); + + std::string GetMethodName(TCppMethod_t); + std::string GetMethodMangledName(TCppMethod_t); + std::string GetMethodResultType(TCppMethod_t); + TCppIndex_t GetMethodNumArgs(TCppMethod_t); + TCppIndex_t GetMethodReqArgs(TCppMethod_t); + std::string GetMethodArgName(TCppMethod_t, int iarg); + std::string GetMethodArgType(TCppMethod_t, int iarg); + std::string GetMethodArgDefault(TCppMethod_t, int iarg); + std::string GetMethodSignature(TCppScope_t scope, TCppIndex_t imeth, bool show_formalargs); + std::string GetMethodPrototype(TCppScope_t scope, TCppIndex_t imeth, bool show_formalargs); + bool IsConstMethod(TCppMethod_t); + + bool ExistsMethodTemplate(TCppScope_t scope, const std::string& name); + bool IsMethodTemplate(TCppScope_t scope, TCppIndex_t imeth); + TCppIndex_t GetMethodNumTemplateArgs(TCppScope_t scope, TCppIndex_t imeth); + std::string GetMethodTemplateArgName(TCppScope_t scope, TCppIndex_t imeth, TCppIndex_t iarg); + + TCppMethod_t GetMethodTemplate( + TCppScope_t scope, const std::string& name, const std::string& proto); + TCppIndex_t GetGlobalOperator( + TCppType_t scope, TCppType_t lc, TCppScope_t rc, const std::string& op); + +// method properties --------------------------------------------------------- + bool IsPublicMethod(TCppMethod_t method); + bool IsConstructor(TCppMethod_t method); + bool IsDestructor(TCppMethod_t method); + bool IsStaticMethod(TCppMethod_t method); + +// data member reflection information ---------------------------------------- + TCppIndex_t GetNumDatamembers(TCppScope_t scope); + std::string GetDatamemberName(TCppScope_t scope, TCppIndex_t idata); + std::string GetDatamemberType(TCppScope_t scope, TCppIndex_t idata); + ptrdiff_t GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata); + TCppIndex_t GetDatamemberIndex(TCppScope_t scope, const std::string& name); + +// data member properties ---------------------------------------------------- + bool IsPublicData(TCppScope_t scope, TCppIndex_t idata); + bool IsStaticData(TCppScope_t scope, TCppIndex_t idata); + bool IsConstData(TCppScope_t scope, TCppIndex_t idata); + bool IsEnumData(TCppScope_t scope, TCppIndex_t idata); + int GetDimensionSize(TCppScope_t scope, TCppIndex_t idata, int dimension); + +} // namespace Cppyy + +#endif // !CPYCPPYY_CPPYY_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CustomPyTypes.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CustomPyTypes.cxx new file mode 100644 index 0000000000000..52b5d66c6d02b --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CustomPyTypes.cxx @@ -0,0 +1,327 @@ +// Bindings +#include "CPyCppyy.h" +#include "CustomPyTypes.h" + +#if PY_VERSION_HEX >= 0x03000000 +// TODO: this will break functionality +#define PyMethod_GET_CLASS(meth) Py_None +#endif + + +namespace CPyCppyy { + +//= float type allowed for reference passing ================================= +PyTypeObject RefFloat_Type = { // python float is a C/C++ double + PyVarObject_HEAD_INIT(&PyType_Type, 0) + (char*)"cppyy.Double", // tp_name + 0, // tp_basicsize + 0, // tp_itemsize + 0, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, // tp_flags + (char*)"CPyCppyy float object for pass by reference", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyFloat_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + 0, // tp_new + 0, // tp_free + 0, // tp_is_gc + 0, // tp_bases + 0, // tp_mro + 0, // tp_cache + 0, // tp_subclasses + 0 // tp_weaklist +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +//= long type allowed for reference passing ================================== +PyTypeObject RefInt_Type = { // python int is a C/C++ long + PyVarObject_HEAD_INIT(&PyType_Type, 0) + (char*)"cppyy.Long", // tp_name + 0, // tp_basicsize + 0, // tp_itemsize + 0, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, // tp_flags + (char*)"CPyCppyy long object for pass by reference", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyInt_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + 0, // tp_new + 0, // tp_free + 0, // tp_is_gc + 0, // tp_bases + 0, // tp_mro + 0, // tp_cache + 0, // tp_subclasses + 0 // tp_weaklist +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +//= instancemethod object with a more efficient call function ================ +static PyMethodObject* free_list; +static int numfree = 0; +#ifndef PyMethod_MAXFREELIST +#define PyMethod_MAXFREELIST 256 +#endif + +//----------------------------------------------------------------------------- +PyObject* CustomInstanceMethod_New(PyObject* func, PyObject* self, PyObject* +#if PY_VERSION_HEX < 0x03000000 + pyclass +#endif + ) +{ +// from instancemethod, but with custom type (at issue is that instancemethod is not +// meant to be derived from) + PyMethodObject* im; + if (!PyCallable_Check(func)) { + PyErr_Format(PyExc_SystemError, + "%s:%d: bad argument to internal function", __FILE__, __LINE__); + return nullptr; + } + + im = free_list; + if (im != nullptr) { + free_list = (PyMethodObject*)(im->im_self); + (void)PyObject_INIT(im, &CustomInstanceMethod_Type); + } + else { + im = PyObject_GC_New(PyMethodObject, &CustomInstanceMethod_Type); + if (im == nullptr) + return nullptr; + } + + im->im_weakreflist = nullptr; + Py_INCREF(func); + im->im_func = func; + Py_XINCREF(self); + im->im_self = self; +#if PY_VERSION_HEX < 0x03000000 + Py_XINCREF(pyclass); + im->im_class = pyclass; +#endif + PyObject_GC_Track(im); + return (PyObject*)im; +} + +//----------------------------------------------------------------------------- +static void im_dealloc(PyMethodObject* im) +{ +// from instancemethod, but with custom type (at issue is that instancemethod is not +// meant to be derived from) + PyObject_GC_UnTrack(im); + + if (im->im_weakreflist != nullptr) + PyObject_ClearWeakRefs((PyObject*)im); + + Py_DECREF(im->im_func); + Py_XDECREF(im->im_self); +#if PY_VERSION_HEX < 0x03000000 + Py_XDECREF(im->im_class); +#endif + + if (numfree < PyMethod_MAXFREELIST) { + im->im_self = (PyObject*)free_list; + free_list = im; + numfree++; + } else { + PyObject_GC_Del(im); + } +} + +//----------------------------------------------------------------------------- +static PyObject* im_call(PyObject* meth, PyObject* args, PyObject* kw) +{ +// The mapping from a method to a function involves reshuffling of self back +// into the list of arguments. However, the pythonized methods will then have +// to undo that shuffling, which is inefficient. This method is the same as +// the one for the instancemethod object, except for the shuffling. + PyObject* self = PyMethod_GET_SELF(meth); + + if (!self) { + // unbound methods must be called with an instance of the class (or a + // derived class) as first argument + Py_ssize_t argc = PyTuple_GET_SIZE(args); + PyObject* pyclass = PyMethod_GET_CLASS(meth); + if (1 <= argc && PyObject_IsInstance(PyTuple_GET_ITEM(args, 0), pyclass) == 1) { + self = PyTuple_GET_ITEM(args, 0); + + PyObject* newArgs = PyTuple_New(argc-1); + for (int i = 1; i < argc; ++i) { + PyObject* v = PyTuple_GET_ITEM(args, i); + Py_INCREF(v); + PyTuple_SET_ITEM(newArgs, i-1, v); + } + + args = newArgs; + + } else + return PyMethod_Type.tp_call(meth, args, kw); // will set proper error msg + + } else + Py_INCREF(args); + + PyCFunctionObject* func = (PyCFunctionObject*)PyMethod_GET_FUNCTION(meth); + +// the function is globally shared, so set and reset its "self" (ok, b/c of GIL) + Py_INCREF(self); + func->m_self = self; + PyObject* result = PyCFunction_Call((PyObject*)func, args, kw); + func->m_self = nullptr; + Py_DECREF(self); + Py_DECREF(args); + return result; +} + +//----------------------------------------------------------------------------- +static PyObject* im_descr_get(PyObject* meth, PyObject* obj, PyObject* pyclass) +{ +// from instancemethod: don't rebind an already bound method, or an unbound method +// of a class that's not a base class of pyclass + if (PyMethod_GET_SELF(meth) +#if PY_VERSION_HEX < 0x03000000 + || (PyMethod_GET_CLASS(meth) && + !PyObject_IsSubclass(pyclass, PyMethod_GET_CLASS(meth))) +#endif + ) { + Py_INCREF(meth); + return meth; + } + + if (obj == Py_None) + obj = nullptr; + + return CustomInstanceMethod_New(PyMethod_GET_FUNCTION(meth), obj, pyclass); +} + +//= CPyCppyy custom instance method type ===================================== +PyTypeObject CustomInstanceMethod_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + (char*)"cppyy.InstanceMethod", // tp_name + 0, // tp_basicsize + 0, // tp_itemsize + (destructor)im_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + im_call, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, // tp_flags + (char*)"CPyCppyy custom instance method (internal)", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyMethod_Type, // tp_base + 0, // tp_dict + im_descr_get, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + 0, // tp_new + 0, // tp_free + 0, // tp_is_gc + 0, // tp_bases + 0, // tp_mro + 0, // tp_cache + 0, // tp_subclasses + 0 // tp_weaklist +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +} // namespace CPyCppyy diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CustomPyTypes.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CustomPyTypes.h new file mode 100644 index 0000000000000..7078ad491c17e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/CustomPyTypes.h @@ -0,0 +1,59 @@ +#ifndef CPYCPPYY_CUSTOMPYTYPES_H +#define CPYCPPYY_CUSTOMPYTYPES_H + +namespace CPyCppyy { + +/** Custom "builtins," detectable by type, for pass by ref and improved + performance. + */ + +//- reference float object type and type verification ------------------------ +extern PyTypeObject RefFloat_Type; + +template +inline bool RefFloat_Check(T* object) +{ + return object && PyObject_TypeCheck(object, &RefFloat_Type); +} + +template +inline bool RefFloat_CheckExact(T* object) +{ + return object && Py_TYPE(object) == &RefFloat_Type; +} + +//- reference long object type and type verification ------------------------- +extern PyTypeObject RefInt_Type; + +template +inline bool RefInt_Check(T* object) +{ + return object && PyObject_TypeCheck(object, &RefInt_Type); +} + +template +inline bool RefInt_CheckExact(T* object) +{ + return object && Py_TYPE(object) == &RefInt_Type; +} + +//- custom instance method object type and type verification ----------------- +extern PyTypeObject CustomInstanceMethod_Type; + +template +inline bool CustomInstanceMethod_Check(T* object) +{ + return object && PyObject_TypeCheck(object, &CustomInstanceMethod_Type); +} + +template +inline bool CustomInstanceMethod_CheckExact(T* object) +{ + return object && Py_TYPE(object) == &CustomInstanceMethod_Type; +} + +PyObject* CustomInstanceMethod_New(PyObject* func, PyObject* self, PyObject* pyclass); + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CUSTOMPYTYPES_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/DeclareConverters.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/DeclareConverters.h new file mode 100644 index 0000000000000..264ecbdc53f54 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/DeclareConverters.h @@ -0,0 +1,291 @@ +#ifndef CPYCPPYY_DECLARECONVERTERS_H +#define CPYCPPYY_DECLARECONVERTERS_H + +// Bindings +#include "Converters.h" + +// Standard +#include + + +namespace CPyCppyy { + +namespace { + +#define CPPYY_DECLARE_BASIC_CONVERTER(name) \ +class name##Converter : public Converter { \ +public: \ + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); \ + virtual PyObject* FromMemory(void*); \ + virtual bool ToMemory(PyObject*, void*); \ +}; \ + \ +class Const##name##RefConverter : public Converter { \ +public: \ + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); \ +} + + +#define CPPYY_DECLARE_BASIC_CONVERTER2(name, base) \ +class name##Converter : public base##Converter { \ +public: \ + virtual PyObject* FromMemory(void*); \ + virtual bool ToMemory(PyObject*, void*); \ +}; \ + \ +class Const##name##RefConverter : public Converter { \ +public: \ + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); \ +} + +#define CPPYY_DECLARE_REF_CONVERTER(name) \ +class name##RefConverter : public Converter { \ +public: \ + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); \ +}; + +#define CPPYY_DECLARE_ARRAY_CONVERTER(name) \ +class name##Converter : public Converter { \ +public: \ + name##Converter(Py_ssize_t size = -1) { fSize = size; } \ + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); \ + virtual PyObject* FromMemory(void*); \ + virtual bool ToMemory(PyObject*, void*); \ +private: \ + Py_ssize_t fSize; \ +}; \ + \ +class name##RefConverter : public name##Converter { \ +public: \ + using name##Converter::name##Converter; \ + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); \ +} + +// converters for built-ins +CPPYY_DECLARE_BASIC_CONVERTER(Long); +CPPYY_DECLARE_BASIC_CONVERTER(Bool); +CPPYY_DECLARE_BASIC_CONVERTER(Char); +CPPYY_DECLARE_BASIC_CONVERTER(UChar); +class UCharAsIntConverter : public UCharConverter { +public: + using UCharConverter::UCharConverter; + virtual PyObject* FromMemory(void*); +}; +CPPYY_DECLARE_BASIC_CONVERTER(Short); +CPPYY_DECLARE_BASIC_CONVERTER(UShort); +CPPYY_DECLARE_BASIC_CONVERTER(Int); +CPPYY_DECLARE_BASIC_CONVERTER(ULong); +CPPYY_DECLARE_BASIC_CONVERTER2(UInt, ULong); +CPPYY_DECLARE_BASIC_CONVERTER(LongLong); +CPPYY_DECLARE_BASIC_CONVERTER(ULongLong); +CPPYY_DECLARE_BASIC_CONVERTER(Double); +CPPYY_DECLARE_BASIC_CONVERTER(Float); +CPPYY_DECLARE_BASIC_CONVERTER(LongDouble); + +CPPYY_DECLARE_REF_CONVERTER(Int); +CPPYY_DECLARE_REF_CONVERTER(Long); +CPPYY_DECLARE_REF_CONVERTER(Double); + +class VoidConverter : public Converter { +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); +}; + +class CStringConverter : public Converter { +public: + CStringConverter(long maxSize = -1) : fMaxSize(maxSize) {} + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + virtual PyObject* FromMemory(void* address); + virtual bool ToMemory(PyObject* value, void* address); + +protected: + std::string fBuffer; + long fMaxSize; +}; + +class NonConstCStringConverter : public CStringConverter { +public: + NonConstCStringConverter(long maxSize = -1) : CStringConverter(maxSize) {} + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + virtual PyObject* FromMemory(void* address); +}; + +// pointer/array conversions +CPPYY_DECLARE_ARRAY_CONVERTER(BoolArray); +CPPYY_DECLARE_ARRAY_CONVERTER(UCharArray); +CPPYY_DECLARE_ARRAY_CONVERTER(ShortArray); +CPPYY_DECLARE_ARRAY_CONVERTER(UShortArray); +CPPYY_DECLARE_ARRAY_CONVERTER(IntArray); +CPPYY_DECLARE_ARRAY_CONVERTER(UIntArray); +CPPYY_DECLARE_ARRAY_CONVERTER(LongArray); +CPPYY_DECLARE_ARRAY_CONVERTER(ULongArray); +CPPYY_DECLARE_ARRAY_CONVERTER(LLongArray); +CPPYY_DECLARE_ARRAY_CONVERTER(ULLongArray); +CPPYY_DECLARE_ARRAY_CONVERTER(FloatArray); +CPPYY_DECLARE_ARRAY_CONVERTER(DoubleArray); + +class LongLongArrayConverter : public VoidArrayConverter { +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); +}; + +// converters for special cases +class ValueCppObjectConverter : public StrictCppObjectConverter { +public: + using StrictCppObjectConverter::StrictCppObjectConverter; + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); +}; + +class RefCppObjectConverter : public Converter { +public: + RefCppObjectConverter(Cppyy::TCppType_t klass) : fClass(klass) {} + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + +protected: + Cppyy::TCppType_t fClass; +}; + +class MoveCppObjectConverter : public RefCppObjectConverter { +public: + using RefCppObjectConverter::RefCppObjectConverter; + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); +}; + +template +class CppObjectPtrConverter : public CppObjectConverter { +public: + using CppObjectConverter::CppObjectConverter; + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + virtual PyObject* FromMemory(void* address); + virtual bool ToMemory(PyObject* value, void* address); +}; + +extern template class CppObjectPtrConverter; +extern template class CppObjectPtrConverter; + +class CppObjectArrayConverter : public CppObjectConverter { +public: + CppObjectArrayConverter(Cppyy::TCppType_t klass, size_t size, bool keepControl = false) : + CppObjectConverter(klass, keepControl), m_size(size) {} + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + virtual PyObject* FromMemory(void* address); + virtual bool ToMemory(PyObject* value, void* address); + +protected: + size_t m_size; +}; + +// CLING WORKAROUND -- classes for STL iterators are completely undefined in that +// they come in a bazillion different guises, so just do whatever +class STLIteratorConverter : public Converter { +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); +}; +// -- END CLING WORKAROUND + +class VoidPtrRefConverter : public Converter { +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); +}; + +class VoidPtrPtrConverter : public Converter { +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + virtual PyObject* FromMemory(void* address); +}; + +CPPYY_DECLARE_BASIC_CONVERTER(PyObject); + +#define CPPYY_DECLARE_STRING_CONVERTER(name, strtype) \ +class name##Converter : public CppObjectConverter { \ +public: \ + name##Converter(bool keepControl = true); \ +public: \ + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); \ + virtual PyObject* FromMemory(void* address); \ + virtual bool ToMemory(PyObject* value, void* address); \ +private: \ + strtype fBuffer; \ +} + +CPPYY_DECLARE_STRING_CONVERTER(STLString, std::string); +#if __cplusplus > 201402L +CPPYY_DECLARE_STRING_CONVERTER(STLStringView, std::string_view); +#endif + +// function pointers +class FunctionPointerConverter : public Converter { +public: + FunctionPointerConverter(const std::string& sig) : fSignature(sig) {} + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + +protected: + std::string fSignature; +}; + +// smart pointer converter +class SmartPtrCppObjectConverter : public Converter { +public: + SmartPtrCppObjectConverter(Cppyy::TCppType_t smart, + Cppyy::TCppType_t raw, + Cppyy::TCppMethod_t deref, + bool keepControl = false, + bool isRef = false) + : fSmartPtrType(smart), fRawPtrType(raw), fDereferencer(deref), + fKeepControl(keepControl), fIsRef(isRef) {} + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + virtual PyObject* FromMemory(void* address); + //virtual bool ToMemory(PyObject* value, void* address); + +protected: + virtual bool GetAddressSpecialCase(PyObject*, void*&) { return false; } + + Cppyy::TCppType_t fSmartPtrType; + Cppyy::TCppType_t fRawPtrType; + Cppyy::TCppMethod_t fDereferencer; + bool fKeepControl; + bool fIsRef; +}; + +// initializer lists +class InitializerListConverter : public Converter { +public: + InitializerListConverter(Converter* cnv, size_t sz) : + fConverter(cnv), fValueSize(sz) {} + ~InitializerListConverter() { + delete fConverter; + } + +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); + +protected: + Converter* fConverter; + size_t fValueSize; +}; + +// raising converter to take out overloads +class NotImplementedConverter : public Converter { +public: + virtual bool SetArg(PyObject*, Parameter&, CallContext* = nullptr); +}; + +} // unnamed namespace + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_DECLARECONVERTERS_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/DeclareExecutors.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/DeclareExecutors.h new file mode 100644 index 0000000000000..fc89188f3cb7e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/DeclareExecutors.h @@ -0,0 +1,178 @@ +#ifndef CPYCPPYY_DECLAREEXECUTORS_H +#define CPYCPPYY_DECLAREEXECUTORS_H + +// Bindings +#include "Executors.h" +#include "CallContext.h" + + +namespace CPyCppyy { + +namespace { + +#define CPPYY_DECL_EXEC(name) \ +class name##Executor : public Executor { \ +public: \ + virtual PyObject* Execute( \ + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); \ +} + +// executors for built-ins +CPPYY_DECL_EXEC(Bool); +CPPYY_DECL_EXEC(BoolConstRef); +CPPYY_DECL_EXEC(Char); +CPPYY_DECL_EXEC(CharConstRef); +CPPYY_DECL_EXEC(UChar); +CPPYY_DECL_EXEC(UCharConstRef); +CPPYY_DECL_EXEC(Short); +CPPYY_DECL_EXEC(Int); +CPPYY_DECL_EXEC(Long); +CPPYY_DECL_EXEC(ULong); +CPPYY_DECL_EXEC(LongLong); +CPPYY_DECL_EXEC(ULongLong); +CPPYY_DECL_EXEC(Float); +CPPYY_DECL_EXEC(Double); +CPPYY_DECL_EXEC(LongDouble); +CPPYY_DECL_EXEC(Void); +CPPYY_DECL_EXEC(CString); + +// pointer/array executors +CPPYY_DECL_EXEC(VoidArray); +CPPYY_DECL_EXEC(BoolArray); +CPPYY_DECL_EXEC(UCharArray); +CPPYY_DECL_EXEC(ShortArray); +CPPYY_DECL_EXEC(UShortArray); +CPPYY_DECL_EXEC(IntArray); +CPPYY_DECL_EXEC(UIntArray); +CPPYY_DECL_EXEC(LongArray); +CPPYY_DECL_EXEC(ULongArray); +CPPYY_DECL_EXEC(LLongArray); +CPPYY_DECL_EXEC(ULLongArray); +CPPYY_DECL_EXEC(FloatArray); +CPPYY_DECL_EXEC(DoubleArray); + +// special cases +CPPYY_DECL_EXEC(STLString); + +class CppObjectExecutor : public Executor { +public: + CppObjectExecutor(Cppyy::TCppType_t klass) : fClass(klass) {} + virtual PyObject* Execute( + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); + +protected: + Cppyy::TCppType_t fClass; +}; + +class CppObjectByValueExecutor : public CppObjectExecutor { +public: + using CppObjectExecutor::CppObjectExecutor; + virtual PyObject* Execute( + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); +}; + +CPPYY_DECL_EXEC(Constructor); +CPPYY_DECL_EXEC(PyObject); + +#define CPPYY_DECL_REFEXEC(name) \ +class name##RefExecutor : public RefExecutor { \ +public: \ + virtual PyObject* Execute( \ + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); \ +} + +CPPYY_DECL_REFEXEC(Bool); +CPPYY_DECL_REFEXEC(Char); +CPPYY_DECL_REFEXEC(UChar); +CPPYY_DECL_REFEXEC(Short); +CPPYY_DECL_REFEXEC(UShort); +CPPYY_DECL_REFEXEC(Int); +CPPYY_DECL_REFEXEC(UInt); +CPPYY_DECL_REFEXEC(Long); +CPPYY_DECL_REFEXEC(ULong); +CPPYY_DECL_REFEXEC(LongLong); +CPPYY_DECL_REFEXEC(ULongLong); +CPPYY_DECL_REFEXEC(Float); +CPPYY_DECL_REFEXEC(Double); +CPPYY_DECL_REFEXEC(LongDouble); +CPPYY_DECL_REFEXEC(STLString); + +// special cases +class CppObjectRefExecutor : public RefExecutor { +public: + CppObjectRefExecutor(Cppyy::TCppType_t klass) : fClass(klass) {} + virtual PyObject* Execute( + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); + +protected: + Cppyy::TCppType_t fClass; +}; + +class CppObjectPtrPtrExecutor : public CppObjectRefExecutor { +public: + using CppObjectRefExecutor::CppObjectRefExecutor; + virtual PyObject* Execute( + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); +}; + +class CppObjectPtrRefExecutor : public CppObjectRefExecutor { +public: + using CppObjectRefExecutor::CppObjectRefExecutor; + virtual PyObject* Execute( + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); +}; + +class CppObjectArrayExecutor : public CppObjectExecutor { +public: + CppObjectArrayExecutor(Cppyy::TCppType_t klass, Py_ssize_t array_size) + : CppObjectExecutor(klass), fArraySize(array_size) {} + virtual PyObject* Execute( + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); + +protected: + Py_ssize_t fArraySize; +}; + +// smart pointer executors +class CppObjectBySmartPtrExecutor : public Executor { +public: + CppObjectBySmartPtrExecutor(Cppyy::TCppType_t smart, + Cppyy::TCppType_t raw, Cppyy::TCppMethod_t deref) + : fSmartPtrType(smart), fRawPtrType(raw), fDereferencer(deref) {} + + virtual PyObject* Execute( + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); + +protected: + Cppyy::TCppType_t fSmartPtrType; + Cppyy::TCppType_t fRawPtrType; + Cppyy::TCppMethod_t fDereferencer; +}; + +class CppObjectBySmartPtrPtrExecutor : public CppObjectBySmartPtrExecutor { +public: + using CppObjectBySmartPtrExecutor::CppObjectBySmartPtrExecutor; + virtual PyObject* Execute( + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); +}; + +class CppObjectBySmartPtrRefExecutor : public RefExecutor { +public: + CppObjectBySmartPtrRefExecutor(Cppyy::TCppType_t smart, + Cppyy::TCppType_t raw, Cppyy::TCppMethod_t deref) + : fSmartPtrType(smart), fRawPtrType(raw), fDereferencer(deref) {} + + virtual PyObject* Execute( + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*); + +protected: + Cppyy::TCppType_t fSmartPtrType; + Cppyy::TCppType_t fRawPtrType; + Cppyy::TCppMethod_t fDereferencer; +}; + +} // unnamed namespace + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_DECLAREEXECUTORS_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Executors.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Executors.cxx new file mode 100644 index 0000000000000..e9d0075c89d76 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Executors.cxx @@ -0,0 +1,839 @@ +// Bindings +#include "CPyCppyy.h" +#include "DeclareExecutors.h" +#include "CPPInstance.h" +#include "LowLevelViews.h" +#include "ProxyWrappers.h" +#include "PyStrings.h" +#include "TypeManip.h" +#include "Utility.h" + +// Standard +#include +#include +#include +#include +#include + + +//- data _____________________________________________________________________ +namespace CPyCppyy { + + typedef Executor* (*ef_t) (); + typedef std::map ExecFactories_t; + static ExecFactories_t gExecFactories; + + extern PyObject* gNullPtrObject; +} + + +//- helpers ------------------------------------------------------------------ +namespace { + + class GILControl { + public: + GILControl(CPyCppyy::CallContext* ctxt) : + fSave(nullptr), fRelease(ReleasesGIL(ctxt)) { +#ifdef WITH_THREAD + if (fRelease) fSave = PyEval_SaveThread(); +#endif + } + ~GILControl() { +#ifdef WITH_THREAD + if (fRelease) PyEval_RestoreThread(fSave); +#endif + } + private: + PyThreadState* fSave; + bool fRelease; + }; + +} // unnamed namespace + +#define CPPYY_IMPL_GILCALL(rtype, tcode) \ +static inline rtype GILCall##tcode( \ + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CPyCppyy::CallContext* ctxt)\ +{ \ + GILControl gc(ctxt); \ + return Cppyy::Call##tcode(method, self, &ctxt->fArgs); \ +} + +CPPYY_IMPL_GILCALL(void, V) +CPPYY_IMPL_GILCALL(unsigned char, B) +CPPYY_IMPL_GILCALL(char, C) +CPPYY_IMPL_GILCALL(short, H) +CPPYY_IMPL_GILCALL(Int_t, I) +CPPYY_IMPL_GILCALL(Long_t, L) +CPPYY_IMPL_GILCALL(Long64_t, LL) +CPPYY_IMPL_GILCALL(float, F) +CPPYY_IMPL_GILCALL(double, D) +CPPYY_IMPL_GILCALL(LongDouble_t, LD) +CPPYY_IMPL_GILCALL(void*, R) + +/* +// TODO: CallS may not have a use here; CallO is used instead for std::string +static inline char* GILCallS( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CPyCppyy::CallContext* ctxt) +{ + GILControl gc(ctxt); +// TODO: make use of getting the string length returned ... + size_t len; + return Cppyy::CallS(method, self, &ctxt->fArgs, &len); +} +*/ + +static inline Cppyy::TCppObject_t GILCallO(Cppyy::TCppMethod_t method, + Cppyy::TCppObject_t self, CPyCppyy::CallContext* ctxt, Cppyy::TCppType_t klass) +{ + GILControl gc(ctxt); + return Cppyy::CallO(method, self, &ctxt->fArgs, klass); +} + +static inline Cppyy::TCppObject_t GILCallConstructor( + Cppyy::TCppMethod_t method, Cppyy::TCppType_t klass, CPyCppyy::CallContext* ctxt) +{ + GILControl gc(ctxt); + return Cppyy::CallConstructor(method, klass, &ctxt->fArgs); +} + +static inline PyObject* CPyCppyy_PyUnicode_FromInt(int c) +{ +// python chars are range(256) + if (c < 0) return CPyCppyy_PyUnicode_FromFormat("%c", 256 - std::abs(c)); + return CPyCppyy_PyUnicode_FromFormat("%c", c); +} + +static inline PyObject* CPyCppyy_PyBool_FromInt(int b) +{ + PyObject* result = (bool)b ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + + +//- executors for built-ins -------------------------------------------------- +PyObject* CPyCppyy::BoolExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python bool return value + bool retval = GILCallB(method, self, ctxt); + PyObject* result = retval ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::BoolConstRefExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python bool return value + return CPyCppyy_PyBool_FromInt(*((bool*)GILCallR(method, self, ctxt))); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CharExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute , construct python string return value +// with the single char + return CPyCppyy_PyUnicode_FromInt((int)GILCallC(method, self, ctxt)); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CharConstRefExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python string return value +// with the single char + return CPyCppyy_PyUnicode_FromInt(*((char*)GILCallR(method, self, ctxt))); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::UCharExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python string return value +// with the single char + return CPyCppyy_PyUnicode_FromInt((unsigned char)GILCallB(method, self, ctxt)); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::UCharConstRefExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python string return value +// with the single char from the pointer return + return CPyCppyy_PyUnicode_FromInt(*((unsigned char*)GILCallR(method, self, ctxt))); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::IntExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python int return value + return PyInt_FromLong((int)GILCallI(method, self, ctxt)); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::ShortExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python int return value + return PyInt_FromLong((short)GILCallH(method, self, ctxt)); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::LongExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python long return value + return PyLong_FromLong((Long_t)GILCallL(method, self, ctxt)); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::ULongExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python unsigned long return value + return PyLong_FromUnsignedLong((ULong_t)GILCallLL(method, self, ctxt)); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::LongLongExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python long long return value + Long64_t result = GILCallLL(method, self, ctxt); + return PyLong_FromLongLong(result); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::ULongLongExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python unsigned long long return value + ULong64_t result = (ULong64_t)GILCallLL(method, self, ctxt); + return PyLong_FromUnsignedLongLong(result); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::FloatExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python float return value + return PyFloat_FromDouble((double)GILCallF(method, self, ctxt)); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::DoubleExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python float return value + return PyFloat_FromDouble((double)GILCallD(method, self, ctxt)); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::LongDoubleExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python float return value + return PyFloat_FromDouble((double)GILCallLD(method, self, ctxt)); +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::RefExecutor::SetAssignable(PyObject* pyobject) +{ +// prepare "buffer" for by-ref returns, used with __setitem__ + if (pyobject) { + Py_INCREF(pyobject); + fAssignable = pyobject; + return true; + } + + fAssignable = nullptr; + return false; +} + +//---------------------------------------------------------------------------- +#define CPPYY_IMPL_REFEXEC(name, type, stype, F1, F2) \ +PyObject* CPyCppyy::name##RefExecutor::Execute( \ + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) \ +{ \ + type* ref = (type*)GILCallR(method, self, ctxt); \ + if (!fAssignable) \ + return F1((stype)*ref); \ + else { \ + *ref = (type)F2(fAssignable); \ + Py_DECREF(fAssignable); \ + fAssignable = nullptr; \ + Py_INCREF(Py_None); \ + return Py_None; \ + } \ +} + +CPPYY_IMPL_REFEXEC(Bool, bool, Long_t, CPyCppyy_PyBool_FromInt, PyLong_AsLong) +CPPYY_IMPL_REFEXEC(Char, char, Long_t, CPyCppyy_PyUnicode_FromInt, PyLong_AsLong) +CPPYY_IMPL_REFEXEC(UChar, unsigned char, ULong_t, CPyCppyy_PyUnicode_FromInt, PyLongOrInt_AsULong) +CPPYY_IMPL_REFEXEC(Short, short, Long_t, PyInt_FromLong, PyLong_AsLong) +CPPYY_IMPL_REFEXEC(UShort, unsigned short, ULong_t, PyInt_FromLong, PyLongOrInt_AsULong) +CPPYY_IMPL_REFEXEC(Int, Int_t, Long_t, PyInt_FromLong, PyLong_AsLong) +CPPYY_IMPL_REFEXEC(UInt, UInt_t, ULong_t, PyLong_FromUnsignedLong, PyLongOrInt_AsULong) +CPPYY_IMPL_REFEXEC(Long, Long_t, Long_t, PyLong_FromLong, PyLong_AsLong) +CPPYY_IMPL_REFEXEC(ULong, ULong_t, ULong_t, PyLong_FromUnsignedLong, PyLongOrInt_AsULong) +CPPYY_IMPL_REFEXEC(LongLong, Long64_t, Long64_t, PyLong_FromLongLong, PyLong_AsLongLong) +CPPYY_IMPL_REFEXEC(ULongLong, ULong64_t, ULong64_t, PyLong_FromUnsignedLongLong, PyLongOrInt_AsULong64) +CPPYY_IMPL_REFEXEC(Float, float, double, PyFloat_FromDouble, PyFloat_AsDouble) +CPPYY_IMPL_REFEXEC(Double, double, double, PyFloat_FromDouble, PyFloat_AsDouble) +CPPYY_IMPL_REFEXEC(LongDouble, LongDouble_t, LongDouble_t, PyFloat_FromDouble, PyFloat_AsDouble) + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::STLStringRefExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , return python string return value + std::string* result = (std::string*)GILCallR(method, self, ctxt); + if (!fAssignable) + return CPyCppyy_PyUnicode_FromStringAndSize(result->c_str(), result->size()); + + *result = std::string( + CPyCppyy_PyUnicode_AsString(fAssignable), CPyCppyy_PyUnicode_GET_SIZE(fAssignable)); + + Py_DECREF(fAssignable); + fAssignable = nullptr; + + Py_RETURN_NONE; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::VoidExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , return None + GILCallV(method, self, ctxt); + Py_RETURN_NONE; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CStringExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python string return value + char* result = (char*)GILCallR(method, self, ctxt); + if (!result) { + Py_INCREF(PyStrings::gEmptyString); + return PyStrings::gEmptyString; + } + + return CPyCppyy_PyUnicode_FromString(result); +} + + +//- pointer/array executors -------------------------------------------------- +PyObject* CPyCppyy::VoidArrayExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python long return value + Long_t* result = (Long_t*)GILCallR(method, self, ctxt); + if (!result) { + Py_INCREF(gNullPtrObject); + return gNullPtrObject; + } + return CreatePointerView(result); +} + +//---------------------------------------------------------------------------- +#define CPPYY_IMPL_ARRAY_EXEC(name, type) \ +PyObject* CPyCppyy::name##ArrayExecutor::Execute( \ + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) \ +{ \ + return CreateLowLevelView((type*)GILCallR(method, self, ctxt)); \ +} + +CPPYY_IMPL_ARRAY_EXEC(Bool, bool) +CPPYY_IMPL_ARRAY_EXEC(UChar, unsigned char) +CPPYY_IMPL_ARRAY_EXEC(Short, short) +CPPYY_IMPL_ARRAY_EXEC(UShort, unsigned short) +CPPYY_IMPL_ARRAY_EXEC(Int, int) +CPPYY_IMPL_ARRAY_EXEC(UInt, unsigned int) +CPPYY_IMPL_ARRAY_EXEC(Long, long) +CPPYY_IMPL_ARRAY_EXEC(ULong, unsigned long) +CPPYY_IMPL_ARRAY_EXEC(LLong, long long) +CPPYY_IMPL_ARRAY_EXEC(ULLong, unsigned long long) +CPPYY_IMPL_ARRAY_EXEC(Float, float) +CPPYY_IMPL_ARRAY_EXEC(Double, double) + + +//- special cases ------------------------------------------------------------ +PyObject* CPyCppyy::STLStringExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python string return value + +// TODO: make use of GILLCallS (?!) + static Cppyy::TCppScope_t sSTLStringScope = Cppyy::GetScope("std::string"); + std::string* result = (std::string*)GILCallO(method, self, ctxt, sSTLStringScope); + if (!result) { + Py_INCREF(PyStrings::gEmptyString); + return PyStrings::gEmptyString; + } + + PyObject* pyresult = + CPyCppyy_PyUnicode_FromStringAndSize(result->c_str(), result->size()); + ::operator delete(result); // calls Cppyy::CallO which calls ::operator new + + return pyresult; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CppObjectExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python proxy object return value + return BindCppObject((void*)GILCallR(method, self, ctxt), fClass); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CppObjectByValueExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execution will bring a temporary in existence + Cppyy::TCppObject_t value = GILCallO(method, self, ctxt, fClass); + + if (!value) { + if (!PyErr_Occurred()) // callee may have set a python error itself + PyErr_SetString(PyExc_ValueError, "nullptr result where temporary expected"); + return nullptr; + } + +// the result can then be bound + PyObject* pyobj = BindCppObjectNoCast(value, fClass, CPPInstance::kIsValue); + if (!pyobj) + return nullptr; + +// python ref counting will now control this object's life span + ((CPPInstance*)pyobj)->PythonOwns(); + return pyobj; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CppObjectRefExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// executor binds the result to the left-hand side, overwriting if an old object + PyObject* result = BindCppObject((void*)GILCallR(method, self, ctxt), fClass); + if (!result || !fAssignable) + return result; + else { + // this generic code is quite slow compared to its C++ equivalent ... + PyObject* assign = PyObject_GetAttr(result, PyStrings::gAssign); + if (!assign) { + PyErr_Clear(); + PyObject* descr = PyObject_Str(result); + if (descr && CPyCppyy_PyUnicode_CheckExact(descr)) { + PyErr_Format(PyExc_TypeError, "can not assign to return object (%s)", + CPyCppyy_PyUnicode_AsString(descr)); + } else { + PyErr_SetString(PyExc_TypeError, "can not assign to result"); + } + Py_XDECREF(descr); + Py_DECREF(result); + Py_DECREF(fAssignable); fAssignable = nullptr; + return nullptr; + } + + PyObject* res2 = PyObject_CallFunction(assign, const_cast("O"), fAssignable); + + Py_DECREF(assign); + Py_DECREF(result); + Py_DECREF(fAssignable); fAssignable = nullptr; + + if (res2) { + Py_DECREF(res2); // typically, *this from operator=() + Py_RETURN_NONE; + } + + return nullptr; + } +} + +//---------------------------------------------------------------------------- +static inline PyObject* SetInstanceCheckError(PyObject* pyobj) { + PyObject* pystr = PyObject_Str(pyobj); + if (pystr) { + PyErr_Format(PyExc_TypeError, + "C++ object expected, got %s", CPyCppyy_PyUnicode_AsString(pystr)); + Py_DECREF(pystr); + } else + PyErr_SetString(PyExc_TypeError, "C++ object expected"); + return nullptr; +} + +PyObject* CPyCppyy::CppObjectPtrPtrExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python C++ proxy object +// return ptr value + if (fAssignable && !CPPInstance_Check(fAssignable)) + return SetInstanceCheckError(fAssignable); + + void** result = (void**)GILCallR(method, self, ctxt); + if (!fAssignable) + return BindCppObject((void*)result, fClass, + CPPInstance::kIsPtrPtr | CPPInstance::kIsReference); + + CPPInstance* cppinst = (CPPInstance*)fAssignable; + *result = cppinst->fObject; + + Py_DECREF(fAssignable); + fAssignable = nullptr; + + Py_RETURN_NONE; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CppObjectPtrRefExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct python C++ proxy object +// ignoring ref) return ptr value + if (fAssignable && !CPPInstance_Check(fAssignable)) + return SetInstanceCheckError(fAssignable); + + void** result = (void**)GILCallR(method, self, ctxt); + if (!fAssignable) + return BindCppObject(*result, fClass); + + CPPInstance* cppinst = (CPPInstance*)fAssignable; + *result = cppinst->fObject; + + Py_DECREF(fAssignable); + fAssignable = nullptr; + + Py_RETURN_NONE; +} + + +//- smart pointers ----------------------------------------------------------- +PyObject* CPyCppyy::CppObjectBySmartPtrExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// smart pointer executor + Cppyy::TCppObject_t value = GILCallO(method, self, ctxt, fSmartPtrType); + + if (!value) { + if (!PyErr_Occurred()) // callee may have set a python error itself + PyErr_SetString(PyExc_ValueError, "NULL result where temporary expected"); + return nullptr; + } + +// fixme? - why doesn't this do the same as `self.__smartptr__().get()' + CPPInstance* pyobj = (CPPInstance*)BindCppObjectNoCast(value, fRawPtrType); + + if (pyobj) { + pyobj->SetSmartPtr(fSmartPtrType, fDereferencer); + pyobj->PythonOwns(); // life-time control by python ref-counting + } + + return (PyObject*)pyobj; +} + +PyObject* CPyCppyy::CppObjectBySmartPtrPtrExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ + Cppyy::TCppObject_t value = GILCallR(method, self, ctxt); + if (!value) + return nullptr; + +// todo: why doesn't this do the same as `self.__smartptr__().get()' + CPPInstance* pyobj = (CPPInstance*)BindCppObjectNoCast(value, fRawPtrType); + + if (pyobj) + pyobj->SetSmartPtr(fSmartPtrType, fDereferencer); + + return (PyObject*)pyobj; +} + +PyObject* CPyCppyy::CppObjectBySmartPtrRefExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ + Cppyy::TCppObject_t value = GILCallR(method, self, ctxt); + if (!value) + return nullptr; + + //if (!fAssignable) { + +// fixme? - why doesn't this do the same as `self.__smartptr__().get()' + CPPInstance* pyobj = (CPPInstance*)BindCppObjectNoCast(value, fRawPtrType); + + if (pyobj) + pyobj->SetSmartPtr(fSmartPtrType, fDereferencer); + + return (PyObject*)pyobj; + + // todo: assignment not done yet + // + /*} else { + + PyObject* result = BindCppObject((void*)value, fClass); + + // this generic code is quite slow compared to its C++ equivalent ... + PyObject* assign = PyObject_GetAttrString(result, const_cast("__assign__")); + if (!assign) { + PyErr_Clear(); + PyObject* descr = PyObject_Str(result); + if (descr && PyBytes_CheckExact(descr)) { + PyErr_Format(PyExc_TypeError, "can not assign to return object (%s)", + PyBytes_AS_STRING(descr)); + } else { + PyErr_SetString(PyExc_TypeError, "can not assign to result"); + } + Py_XDECREF(descr); + Py_DECREF(result); + Py_DECREF(fAssignable); fAssignable = nullptr; + return nullptr; + } + + PyObject* res2 = PyObject_CallFunction( + assign, const_cast("O"), fAssignable); + + + Py_DECREF(assign); + Py_DECREF(result); + Py_DECREF(fAssignable); fAssignable = nullptr; + + if (res2) { + Py_DECREF(res2); // typically, *this from operator=() + Py_RETURN_NONE; + } + + return nullptr; + } + */ +} + + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CppObjectArrayExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , construct TupleOfInstances from +// return value + return BindCppObjectArray((void*)GILCallR(method, self, ctxt), fClass, fArraySize); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::ConstructorExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t klass, CallContext* ctxt) +{ +// package return address in PyObject* for caller to handle appropriately (see +// CPPConstructor for the actual build of the PyObject) + return (PyObject*)GILCallConstructor(method, (Cppyy::TCppType_t)klass, ctxt); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::PyObjectExecutor::Execute( + Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, CallContext* ctxt) +{ +// execute with argument , return python object + return (PyObject*)GILCallR(method, self, ctxt); +} + + +//- factories ---------------------------------------------------------------- +CPyCppyy::Executor* CPyCppyy::CreateExecutor( + const std::string& fullType, bool manage_smart_ptr) +{ +// The matching of the fulltype to an executor factory goes through up to 4 levels: +// 1) full, qualified match +// 2) drop '&' as by ref/full type is often pretty much the same python-wise +// 3) C++ classes, either by ref/ptr or by value +// 4) additional special case for enums +// +// If all fails, void is used, which will cause the return type to be ignored on use + +// an exactly matching executor is best + ExecFactories_t::iterator h = gExecFactories.find(fullType); + if (h != gExecFactories.end()) + return (h->second)(); + +// resolve typedefs etc. + const std::string& resolvedType = Cppyy::ResolveName(fullType); + +// a full, qualified matching executor is preferred + if (resolvedType != fullType) { + h = gExecFactories.find(resolvedType); + if (h != gExecFactories.end()) + return (h->second)(); + } + +//-- nothing? ok, collect information about the type and possible qualifiers/decorators + bool isConst = strncmp(resolvedType.c_str(), "const", 5) == 0; + const std::string& cpd = Utility::Compound(resolvedType); + std::string realType = TypeManip::clean_type(resolvedType, false); + +// accept unqualified type (as python does not know about qualifiers) + h = gExecFactories.find(realType + cpd); + if (h != gExecFactories.end()) + return (h->second)(); + +// drop const, as that is mostly meaningless to python (with the exception +// of c-strings, but those are specialized in the converter map) + if (isConst) { + realType = TypeManip::remove_const(realType); + h = gExecFactories.find(realType + cpd); + if (h != gExecFactories.end()) + return (h->second)(); + } + +//-- still nothing? try pointer instead of array (for builtins) + if (cpd == "[]") { + /* // CLING WORKAROUND -- if the type is a fixed-size array, it will have a funky + // resolved type like MyClass(&)[N], which TClass::GetClass() fails on. So, strip + // it down: + realType = TClassEdit::CleanType(realType.substr(0, realType.rfind("(")).c_str(), 1); + // -- CLING WORKAROUND */ + h = gExecFactories.find(realType + "*"); + if (h != gExecFactories.end()) + return (h->second)(); // TODO: use array size + } + +// C++ classes and special cases (enum) + Executor* result = 0; + if (Cppyy::TCppType_t klass = Cppyy::GetScope(realType)) { + Cppyy::TCppType_t raw; Cppyy::TCppMethod_t deref; + if (manage_smart_ptr && Cppyy::GetSmartPtrInfo(realType, raw, deref)) { + if (cpd == "") { + result = new CppObjectBySmartPtrExecutor(klass, raw, deref); + } else if (cpd == "*") { + result = new CppObjectBySmartPtrPtrExecutor(klass, raw, deref); + } else if (cpd == "&") { + result = new CppObjectBySmartPtrRefExecutor(klass, raw, deref); + } + } + + if (!result) { + if (cpd == "") + result = new CppObjectByValueExecutor(klass); + else if (cpd == "&") + result = new CppObjectRefExecutor(klass); + else if (cpd == "**" || cpd == "*[]" || cpd == "&*") + result = new CppObjectPtrPtrExecutor(klass); + else if (cpd == "*&") + result = new CppObjectPtrRefExecutor(klass); + else if (cpd == "[]") { + Py_ssize_t asize = Utility::ArraySize(resolvedType); + if (0 < asize) + result = new CppObjectArrayExecutor(klass, asize); + else + result = new CppObjectPtrRefExecutor(klass); + } else + result = new CppObjectExecutor(klass); + } + } else { + // unknown: void* may work ("user knows best"), void will fail on use of return value + h = (cpd == "") ? gExecFactories.find("void") : gExecFactories.find("void*"); + } + + if (!result && h != gExecFactories.end()) + // executor factory available, use it to create executor + result = (h->second)(); + + return result; // may still be null +} + + +//---------------------------------------------------------------------------- +namespace { + +using namespace CPyCppyy; + +struct InitExecFactories_t { +public: + InitExecFactories_t() { + // load all executor factories in the global map 'gExecFactories' + CPyCppyy::ExecFactories_t& gf = gExecFactories; + + // factories for built-ins + gf["bool"] = (ef_t)+[]() { return new BoolExecutor{}; }; + gf["bool&"] = (ef_t)+[]() { return new BoolRefExecutor{}; }; + gf["const bool&"] = (ef_t)+[]() { return new BoolConstRefExecutor{}; }; + gf["char"] = (ef_t)+[]() { return new CharExecutor{}; }; + gf["signed char"] = (ef_t)+[]() { return new CharExecutor{}; }; + gf["unsigned char"] = (ef_t)+[]() { return new UCharExecutor{}; }; + gf["char&"] = (ef_t)+[]() { return new CharRefExecutor{}; }; + gf["signed char&"] = (ef_t)+[]() { return new CharRefExecutor{}; }; + gf["unsigned char&"] = (ef_t)+[]() { return new UCharRefExecutor{}; }; + gf["const char&"] = (ef_t)+[]() { return new CharConstRefExecutor{}; }; + gf["const signed char&"] = (ef_t)+[]() { return new CharConstRefExecutor{}; }; + gf["const unsigned char&"] = (ef_t)+[]() { return new UCharConstRefExecutor{}; }; + gf["short"] = (ef_t)+[]() { return new ShortExecutor{}; }; + gf["short&"] = (ef_t)+[]() { return new ShortRefExecutor{}; }; + gf["unsigned short"] = (ef_t)+[]() { return new IntExecutor{}; }; + gf["unsigned short&"] = (ef_t)+[]() { return new UShortRefExecutor{}; }; + gf["int"] = (ef_t)+[]() { return new IntExecutor{}; }; + gf["int&"] = (ef_t)+[]() { return new IntRefExecutor{}; }; + gf["unsigned int"] = (ef_t)+[]() { return new ULongExecutor{}; }; + gf["unsigned int&"] = (ef_t)+[]() { return new UIntRefExecutor{}; }; + gf["internal_enum_type_t"] = (ef_t)+[]() { return new IntExecutor{}; }; + gf["internal_enum_type_t&"] = (ef_t)+[]() { return new IntRefExecutor{}; }; + gf["long"] = (ef_t)+[]() { return new LongExecutor{}; }; + gf["long&"] = (ef_t)+[]() { return new LongRefExecutor{}; }; + gf["unsigned long"] = (ef_t)+[]() { return new ULongExecutor{}; }; + gf["unsigned long&"] = (ef_t)+[]() { return new ULongRefExecutor{}; }; + gf["long long"] = (ef_t)+[]() { return new LongLongExecutor{}; }; + gf["Long64_t"] = (ef_t)+[]() { return new LongLongExecutor{}; }; + gf["long long&"] = (ef_t)+[]() { return new LongLongRefExecutor{}; }; + gf["Long64_t&"] = (ef_t)+[]() { return new LongLongRefExecutor{}; }; + gf["unsigned long long"] = (ef_t)+[]() { return new ULongLongExecutor{}; }; + gf["ULong64_t"] = (ef_t)+[]() { return new ULongLongExecutor{}; }; + gf["unsigned long long&"] = (ef_t)+[]() { return new ULongLongRefExecutor{}; }; + gf["ULong64_t&"] = (ef_t)+[]() { return new ULongLongRefExecutor{}; }; + + gf["float"] = (ef_t)+[]() { return new FloatExecutor{}; }; + gf["float&"] = (ef_t)+[]() { return new FloatRefExecutor{}; }; + gf["Float16_t"] = (ef_t)+[]() { return new FloatExecutor{}; }; + gf["Float16_t&"] = (ef_t)+[]() { return new FloatRefExecutor{}; }; + gf["double"] = (ef_t)+[]() { return new DoubleExecutor{}; }; + gf["double&"] = (ef_t)+[]() { return new DoubleRefExecutor{}; }; + gf["Double32_t"] = (ef_t)+[]() { return new DoubleExecutor{}; }; + gf["Double32_t&"] = (ef_t)+[]() { return new DoubleRefExecutor{}; }; + gf["long double"] = (ef_t)+[]() { return new LongDoubleExecutor{}; }; // TODO: lost precision + gf["long double&"] = (ef_t)+[]() { return new LongDoubleRefExecutor{}; }; + gf["void"] = (ef_t)+[]() { return new VoidExecutor{}; }; + + // pointer/array factories + gf["void*"] = (ef_t)+[]() { return new VoidArrayExecutor{}; }; + gf["bool*"] = (ef_t)+[]() { return new BoolArrayExecutor{}; }; + gf["const unsigned char*"] = (ef_t)+[]() { return new UCharArrayExecutor{}; }; + gf["unsigned char*"] = (ef_t)+[]() { return new UCharArrayExecutor{}; }; + gf["short*"] = (ef_t)+[]() { return new ShortArrayExecutor{}; }; + gf["unsigned short*"] = (ef_t)+[]() { return new UShortArrayExecutor{}; }; + gf["int*"] = (ef_t)+[]() { return new IntArrayExecutor{}; }; + gf["unsigned int*"] = (ef_t)+[]() { return new UIntArrayExecutor{}; }; + gf["internal_enum_type_t*"] = (ef_t)+[]() { return new UIntArrayExecutor{}; }; + gf["long*"] = (ef_t)+[]() { return new LongArrayExecutor{}; }; + gf["unsigned long*"] = (ef_t)+[]() { return new ULongArrayExecutor{}; }; + gf["long long*"] = (ef_t)+[]() { return new LLongArrayExecutor{}; }; + gf["Long64_t*"] = (ef_t)+[]() { return new LLongArrayExecutor{}; }; + gf["unsigned long long*"] = (ef_t)+[]() { return new ULLongArrayExecutor{}; }; + gf["ULong64_t*"] = (ef_t)+[]() { return new ULLongArrayExecutor{}; }; + gf["float*"] = (ef_t)+[]() { return new FloatArrayExecutor{}; }; + gf["double*"] = (ef_t)+[]() { return new DoubleArrayExecutor{}; }; + + // factories for special cases + gf["const char*"] = (ef_t)+[]() { return new CStringExecutor{}; }; + gf["char*"] = (ef_t)+[]() { return new CStringExecutor{}; }; + gf["const signed char*"] = (ef_t)+[]() { return new CStringExecutor{}; }; + gf["signed char*"] = (ef_t)+[]() { return new CStringExecutor{}; }; + gf["std::string"] = (ef_t)+[]() { return new STLStringExecutor{}; }; + gf["string"] = (ef_t)+[]() { return new STLStringExecutor{}; }; + gf["std::string&"] = (ef_t)+[]() { return new STLStringRefExecutor{}; }; + gf["string&"] = (ef_t)+[]() { return new STLStringRefExecutor{}; }; + gf["__init__"] = (ef_t)+[]() { return new ConstructorExecutor{}; }; + gf["PyObject*"] = (ef_t)+[]() { return new PyObjectExecutor{}; }; + gf["_object*"] = (ef_t)+[]() { return new PyObjectExecutor{}; }; + gf["FILE*"] = (ef_t)+[]() { return new VoidArrayExecutor{}; }; + } +} initExecvFactories_; + +} // unnamed namespace diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Executors.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Executors.h new file mode 100644 index 0000000000000..cf16dbba2bb4a --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Executors.h @@ -0,0 +1,34 @@ +#ifndef CPYCPPYY_EXECUTORS_H +#define CPYCPPYY_EXECUTORS_H + +// Standard +#include + + +namespace CPyCppyy { + +struct CallContext; + +class Executor { +public: + virtual ~Executor() {} + virtual PyObject* Execute( + Cppyy::TCppMethod_t, Cppyy::TCppObject_t, CallContext*) = 0; +}; + +// special case needed for CPPSetItem +class RefExecutor : public Executor { +public: + RefExecutor() : fAssignable(nullptr) {} + virtual bool SetAssignable(PyObject*); + +protected: + PyObject* fAssignable; +}; + +// create executor from fully qualified type +Executor* CreateExecutor(const std::string& fullType, bool manage_smart_ptr = true); + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_EXECUTORS_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/LowLevelViews.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/LowLevelViews.cxx new file mode 100644 index 0000000000000..d81fdac9bb6a0 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/LowLevelViews.cxx @@ -0,0 +1,836 @@ +// Bindings +#include "CPyCppyy.h" +#include "LowLevelViews.h" +#include "Converters.h" + +// Standard +#include +#include +#include + + +//= memoryview-like object =================================================== +// This is largely setup just like Python builtin memory view objects, with +// the exceptions that there is no need of a "base" object (it views on C++ +// memory, not a Python object with a buffer interface), it uses the CPyCppyy +// converters, and typed results and assignments are supported. Code reused +// under PSF License Version 2. + +namespace CPyCppyy { + +class LowLevelView { +public: + PyObject_HEAD + Py_buffer fBufInfo; + Converter* fConverter; +}; + +} // namespace CPyCppyy + +//= CPyCppyy low level view construction/destruction ========================= +static CPyCppyy::LowLevelView* ll_new(PyTypeObject* subtype, PyObject*, PyObject*) +{ +// Create a new low level ptr type + CPyCppyy::LowLevelView* pyobj = (CPyCppyy::LowLevelView*)subtype->tp_alloc(subtype, 0); + if (!pyobj) PyErr_Print(); + memset(&pyobj->fBufInfo, 0, sizeof(Py_buffer)); + pyobj->fConverter = nullptr; + + return pyobj; +} + +//---------------------------------------------------------------------------- +static void ll_dealloc(CPyCppyy::LowLevelView* pyobj) +{ +// Destruction requires the deletion of the converter (if any) + PyMem_Free(pyobj->fBufInfo.shape); + PyMem_Free(pyobj->fBufInfo.strides); + delete pyobj->fConverter; + Py_TYPE(pyobj)->tp_free((PyObject*)pyobj); +} + + +//--------------------------------------------------------------------------- +static PyObject* ll_typecode(CPyCppyy::LowLevelView* self, void*) +{ + return CPyCppyy_PyUnicode_FromString((char*)self->fBufInfo.format); +} + +//--------------------------------------------------------------------------- +static PyGetSetDef ll_getset[] = { + {(char*)"format", (getter)ll_typecode, nullptr, nullptr, nullptr}, + {(char*)"typecode", (getter)ll_typecode, nullptr, nullptr, nullptr}, + {(char*)nullptr, nullptr, nullptr, nullptr, nullptr } +}; + + +//--------------------------------------------------------------------------- +static PyObject* ll_reshape(CPyCppyy::LowLevelView* self, PyObject* shape) +{ +// Allow the user to fix up the actual (type-strided) size of the buffer. + if (!PyTuple_Check(shape) || PyTuple_GET_SIZE(shape) != 1) { + if (shape) { + PyObject* pystr = PyObject_Str(shape); + if (pystr) { + PyErr_Format(PyExc_TypeError, "tuple object of length 1 expected, received %s", + CPyCppyy_PyUnicode_AsStringChecked(pystr)); + Py_DECREF(pystr); + return nullptr; + } + } + PyErr_SetString(PyExc_TypeError, "tuple object of length 1 expected"); + return nullptr; + } + + Py_ssize_t nlen = PyInt_AsSsize_t(PyTuple_GET_ITEM(shape, 0)); + if (nlen == -1 && PyErr_Occurred()) + return nullptr; + + self->fBufInfo.len = nlen * self->fBufInfo.itemsize; + if (self->fBufInfo.ndim == 1 && self->fBufInfo.shape) + self->fBufInfo.shape[0] = nlen; + else { + PyErr_SetString(PyExc_TypeError, "unsupported buffer dimensions"); + return nullptr; + } + + Py_RETURN_NONE; +} + +//--------------------------------------------------------------------------- +static PyMethodDef ll_methods[] = { + {(char*)"reshape", (PyCFunction)ll_reshape, METH_O, nullptr}, + {(char*)nullptr, nullptr, 0, nullptr} +}; + + +//- Copy memoryview buffers ================================================= + +// The functions in this section take a source and a destination buffer +// with the same logical structure: format, itemsize, ndim and shape +// are identical, with ndim > 0. + +// Check for the presence of suboffsets in the first dimension. +#define HAVE_PTR(suboffsets, dim) (suboffsets && suboffsets[dim] >= 0) +// Adjust ptr if suboffsets are present. +#define ADJUST_PTR(ptr, suboffsets, dim) \ + (HAVE_PTR(suboffsets, dim) ? *((char**)ptr) + suboffsets[dim] : ptr) + +// Assumptions: ndim >= 1. The macro tests for a corner case that should +// perhaps be explicitly forbidden in the PEP. +#define HAVE_SUBOFFSETS_IN_LAST_DIM(view) \ + (view->suboffsets && view->suboffsets[dest->ndim-1] >= 0) + +//--------------------------------------------------------------------------- +static inline int last_dim_is_contiguous(const Py_buffer *dest, const Py_buffer *src) +{ + assert(dest->ndim > 0 && src->ndim > 0); + return (!HAVE_SUBOFFSETS_IN_LAST_DIM(dest) && + !HAVE_SUBOFFSETS_IN_LAST_DIM(src) && + dest->strides[dest->ndim-1] == dest->itemsize && + src->strides[src->ndim-1] == src->itemsize); +} + +//--------------------------------------------------------------------------- +static inline bool equiv_shape(const Py_buffer* dest, const Py_buffer* src) +{ +// Two shapes are equivalent if they are either equal or identical up +// to a zero element at the same position. For example, in NumPy arrays +// the shapes [1, 0, 5] and [1, 0, 7] are equivalent. + if (dest->ndim != src->ndim) + return false; + + for (int i = 0; i < dest->ndim; i++) { + if (dest->shape[i] != src->shape[i]) + return 0; + if (dest->shape[i] == 0) + break; + } + + return true; +} + +//--------------------------------------------------------------------------- +static bool equiv_structure(const Py_buffer* dest, const Py_buffer* src) +{ +// Check that the logical structure of the destination and source buffers +// is identical. + if (strcmp(dest->format, src->format) != 0 || dest->itemsize != src->itemsize || + !equiv_shape(dest, src)) { + PyErr_SetString(PyExc_ValueError, + "low level pointer assignment: lvalue and rvalue have different structures"); + return false; + } + + return true; +} + +//--------------------------------------------------------------------------- +static void copy_base(const Py_ssize_t* shape, Py_ssize_t itemsize, + char* dptr, const Py_ssize_t* dstrides, const Py_ssize_t* dsuboffsets, + char* sptr, const Py_ssize_t* sstrides, const Py_ssize_t* ssuboffsets, + char* mem) +{ +// Base case for recursive multi-dimensional copying. Contiguous arrays are +// copied with very little overhead. Assumptions: ndim == 1, mem == nullptr or +// sizeof(mem) == shape[0] * itemsize. + if (!mem) { // contiguous + Py_ssize_t size = shape[0] * itemsize; + if (dptr + size < sptr || sptr + size < dptr) + memcpy(dptr, sptr, size); // no overlapping + else + memmove(dptr, sptr, size); + } + else { + char *p; + Py_ssize_t i; + for (i=0, p=mem; i < shape[0]; p+=itemsize, sptr+=sstrides[0], i++) { + char *xsptr = ADJUST_PTR(sptr, ssuboffsets, 0); + memcpy(p, xsptr, itemsize); + } + for (i=0, p=mem; i < shape[0]; p+=itemsize, dptr+=dstrides[0], i++) { + char *xdptr = ADJUST_PTR(dptr, dsuboffsets, 0); + memcpy(xdptr, p, itemsize); + } + } + +} + +//--------------------------------------------------------------------------- +static int copy_single(Py_buffer* dest, Py_buffer* src) +{ +// Faster copying of one-dimensional arrays. + char* mem = nullptr; + + assert(dest->ndim == 1); + + if (!equiv_structure(dest, src)) + return -1; + + if (!last_dim_is_contiguous(dest, src)) { + mem = (char*)PyMem_Malloc(dest->shape[0] * dest->itemsize); + if (!mem) { + PyErr_NoMemory(); + return -1; + } + } + + copy_base(dest->shape, dest->itemsize, + (char*)dest->buf, dest->strides, dest->suboffsets, + (char*)src->buf, src->strides, src->suboffsets, + mem); + + if (mem) + PyMem_Free(mem); + + return 0; +} + + +//- Indexing and slicing ---------------------------------------------------- +static char* lookup_dimension(Py_buffer& view, char* ptr, int dim, Py_ssize_t index) +{ + Py_ssize_t nitems; // items in the given dimension + + assert(view.shape); + assert(view.strides); + + nitems = view.shape[dim]; + if (index < 0) + index += nitems; + + if (index < 0 || index >= nitems) { + PyErr_Format(PyExc_IndexError, + "index out of bounds on dimension %d", dim + 1); + return nullptr; + } + + ptr += view.strides[dim] * index; + ptr = ADJUST_PTR(ptr, view.suboffsets, dim); + + return ptr; +} + +// Get the pointer to the item at index. +//--------------------------------------------------------------------------- +static inline void* ptr_from_index(Py_buffer& view, Py_ssize_t index) +{ + return lookup_dimension(view, (char*)view.buf, 0, index); +} + +// Get the pointer to the item at tuple. +//--------------------------------------------------------------------------- +static void* ptr_from_tuple(Py_buffer& view, PyObject* tup) +{ + Py_ssize_t nindices = PyTuple_GET_SIZE(tup); + if (nindices > view.ndim) { + PyErr_Format(PyExc_TypeError, + "cannot index %d-dimension view with %zd-element tuple", view.ndim, nindices); + return nullptr; + } + + char* ptr = (char*)view.buf; + for (Py_ssize_t dim = 0; dim < nindices; dim++) { + Py_ssize_t index; + index = PyNumber_AsSsize_t(PyTuple_GET_ITEM(tup, dim), + PyExc_IndexError); + if (index == -1 && PyErr_Occurred()) + return nullptr; + ptr = lookup_dimension(view, ptr, (int)dim, index); + if (!ptr) + return nullptr; + } + return ptr; +} + + +//= mapping methods ========================================================= +static Py_ssize_t ll_length(CPyCppyy::LowLevelView* self) +{ + if (!self->fBufInfo.buf) + return 0; + return self->fBufInfo.ndim == 0 ? 1 : self->fBufInfo.shape[0]; +} + +//--------------------------------------------------------------------------- +static inline int init_slice(Py_buffer* base, PyObject* key, int dim) +{ + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx( +#if PY_VERSION_HEX < 0x03000000 + (PySliceObject*) +#endif + key, base->shape[dim], &start, &stop, &step, &slicelength) < 0) { + return -1; + } + + if (!base->suboffsets || dim == 0) { + adjust_buf: + base->buf = (char *)base->buf + base->strides[dim] * start; + } + else { + Py_ssize_t n = dim-1; + while (n >= 0 && base->suboffsets[n] < 0) + n--; + if (n < 0) + goto adjust_buf; // all suboffsets are negative + base->suboffsets[n] = base->suboffsets[n] + base->strides[dim] * start; + } + base->shape[dim] = slicelength; + base->strides[dim] = base->strides[dim] * step; + + return 0; +} + +//--------------------------------------------------------------------------- +static bool is_multislice(PyObject* key) +{ + if (!PyTuple_Check(key)) + return false; + + Py_ssize_t size = PyTuple_GET_SIZE(key); + if (size == 0) + return false; + + for (Py_ssize_t i = 0; i < size; i++) { + PyObject *x = PyTuple_GET_ITEM(key, i); + if (!PySlice_Check(x)) + return false; + } + return true; +} + +//--------------------------------------------------------------------------- +static Py_ssize_t is_multiindex(PyObject* key) +{ + if (!PyTuple_Check(key)) + return 0; + + Py_ssize_t size = PyTuple_GET_SIZE(key); + for (Py_ssize_t i = 0; i < size; i++) { + PyObject *x = PyTuple_GET_ITEM(key, i); + if (!PyIndex_Check(x)) + return 0; + } + return 1; +} + + +// Return the item at index. In a one-dimensional view, this is an object +// with the type specified by view->format. Otherwise, the item is a sub-view. +// The function is used in ll_subscript() and ll_as_sequence. +//--------------------------------------------------------------------------- +static PyObject* ll_item(CPyCppyy::LowLevelView* self, Py_ssize_t index) +{ + Py_buffer& view = self->fBufInfo; + + if (!view.buf) { + PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer"); + return nullptr; + } + + if (view.ndim == 0) { + PyErr_SetString(PyExc_TypeError, "invalid indexing of 0-dim memory"); + return nullptr; + } + + if (view.ndim == 1) { + void* ptr = ptr_from_index(view, index); + if (!ptr) + return nullptr; + return self->fConverter->FromMemory(ptr); + } + +// TODO: implement sub-views + PyErr_SetString(PyExc_NotImplementedError, + "multi-dimensional sub-views are not implemented"); + return nullptr; +} + +// Return the item at position *key* (a tuple of indices). +//--------------------------------------------------------------------------- +static PyObject* ll_item_multi(CPyCppyy::LowLevelView* self, PyObject *tup) +{ + Py_buffer& view = self->fBufInfo; + Py_ssize_t nindices = PyTuple_GET_SIZE(tup); + + if (nindices < view.ndim) { + // TODO: implement + PyErr_SetString(PyExc_NotImplementedError, + "sub-views are not implemented"); + return nullptr; + } + + void* ptr = ptr_from_tuple(view, tup); + if (!ptr) + return nullptr; + return self->fConverter->FromMemory(ptr); +} + + +// llp[obj] returns an object holding the data for one element if obj +// fully indexes the lowlevelptr or another lowlevelptr object if it +// does not. +// +// 0-d lowlevelptr objects can be referenced using llp[...] or llp[()] +// but not with anything else. +//--------------------------------------------------------------------------- +static PyObject* ll_subscript(CPyCppyy::LowLevelView* self, PyObject *key) +{ + Py_buffer& view = self->fBufInfo; + + if (view.ndim == 0) { + if (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0) { + return self->fConverter->FromMemory(view.buf); + } + else if (key == Py_Ellipsis) { + Py_INCREF(self); + return (PyObject*)self; + } + else { + PyErr_SetString(PyExc_TypeError, + "invalid indexing of 0-dim memory"); + return nullptr; + } + } + + if (PyIndex_Check(key)) { + Py_ssize_t index = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (index == -1 && PyErr_Occurred()) + return nullptr; + return ll_item(self, index); + } + else if (PySlice_Check(key)) { + // TODO: handle slicing. This should be simpler than the memoryview + // case as there is no Python object holding the buffer. + PyErr_SetString(PyExc_NotImplementedError, + "multi-dimensional slicing is not implemented"); + return nullptr; + } + else if (is_multiindex(key)) { + return ll_item_multi(self, key); + } + else if (is_multislice(key)) { + PyErr_SetString(PyExc_NotImplementedError, + "multi-dimensional slicing is not implemented"); + return nullptr; + } + + PyErr_SetString(PyExc_TypeError, "invalid slice key"); + return nullptr; +} + +//--------------------------------------------------------------------------- +static int ll_ass_sub(CPyCppyy::LowLevelView* self, PyObject* key, PyObject* value) +{ + Py_buffer& view = self->fBufInfo; + Py_buffer src; + + if (view.readonly) { + PyErr_SetString(PyExc_TypeError, "cannot modify read-only memory"); + return -1; + } + + if (value == nullptr) { + PyErr_SetString(PyExc_TypeError, "cannot delete memory"); + return -1; + } + + if (view.ndim == 0) { + if (key == Py_Ellipsis || + (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0)) { + return self->fConverter->ToMemory(value, view.buf) ? 0 : -1; + } + else { + PyErr_SetString(PyExc_TypeError, + "invalid indexing of 0-dim memory"); + return -1; + } + } + + if (PyIndex_Check(key)) { + Py_ssize_t index; + if (1 < view.ndim) { + PyErr_SetString(PyExc_NotImplementedError, + "sub-views are not implemented"); + return -1; + } + index = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (index == -1 && PyErr_Occurred()) + return -1; + void* ptr = ptr_from_index(view, index); + if (ptr == nullptr) + return -1; + return self->fConverter->ToMemory(value, ptr) ? 0 : -1; + } + + // one-dimensional: fast path + if (PySlice_Check(key) && view.ndim == 1) { + Py_buffer dest; // sliced view + Py_ssize_t arrays[3]; + int ret = -1; + + // rvalue must be an exporter + if (PyObject_GetBuffer(value, &src, PyBUF_FULL_RO) < 0) + return ret; + + dest = view; + dest.shape = &arrays[0]; dest.shape[0] = view.shape[0]; + dest.strides = &arrays[1]; dest.strides[0] = view.strides[0]; + if (view.suboffsets) { + dest.suboffsets = &arrays[2]; dest.suboffsets[0] = view.suboffsets[0]; + } + + if (init_slice(&dest, key, 0) < 0) + return -1; + dest.len = dest.shape[0] * dest.itemsize; + + return copy_single(&dest, &src); + } + + if (is_multiindex(key)) { + // TODO: implement + if (PyTuple_GET_SIZE(key) < view.ndim) { + PyErr_SetString(PyExc_NotImplementedError, + "sub-views are not implemented"); + return -1; + } + void* ptr = ptr_from_tuple(view, key); + if (ptr == nullptr) + return -1; + return self->fConverter->ToMemory(value, ptr) ? 0 : -1; + } + + if (PySlice_Check(key) || is_multislice(key)) { + // TODO: implement + PyErr_SetString(PyExc_NotImplementedError, + "LowLevelView slice assignments are currently restricted " + "to ndim = 1"); + return -1; + } + + PyErr_SetString(PyExc_TypeError, "invalid slice key"); + return -1; +} + +#if PY_VERSION_HEX < 0x03000000 +//--------------------------------------------------------------------------- +static Py_ssize_t ll_oldgetbuf(CPyCppyy::LowLevelView* self, Py_ssize_t seg, void** pptr) +{ + if (seg != 0) { + PyErr_SetString(PyExc_TypeError, "accessing non-existent segment"); + return -1; + } + + *pptr = self->fBufInfo.buf; + return self->fBufInfo.len; +} + +//--------------------------------------------------------------------------- +static Py_ssize_t ll_getsegcount(PyObject*, Py_ssize_t* lenp) +{ + if (lenp) *lenp = 1; + return 1; +} +#endif + +//--------------------------------------------------------------------------- +static int ll_getbuf(CPyCppyy::LowLevelView* self, Py_buffer* view, int flags) +{ +// Simplified from memoryobject, as we're always dealing with C arrays. + +// start with full copy + *view = self->fBufInfo; + + if (!(flags & PyBUF_FORMAT)) { + /* NULL indicates that the buffer's data type has been cast to 'B'. + view->itemsize is the _previous_ itemsize. If shape is present, + the equality product(shape) * itemsize = len still holds at this + point. The equality calcsize(format) = itemsize does _not_ hold + from here on! */ + view->format = NULL; + } + + if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) { + PyErr_SetString(PyExc_BufferError, + "underlying buffer is not Fortran contiguous"); + return -1; + } + + if (!(flags & PyBUF_FORMAT)) { + /* PyBUF_SIMPLE or PyBUF_WRITABLE: at this point buf is C-contiguous, + so base->buf = ndbuf->data. */ + if (view->format != NULL) { + /* PyBUF_SIMPLE|PyBUF_FORMAT and PyBUF_WRITABLE|PyBUF_FORMAT do + not make sense. */ + PyErr_Format(PyExc_BufferError, + "cannot cast to unsigned bytes if the format flag is present"); + return -1; + } + /* product(shape) * itemsize = len and calcsize(format) = itemsize + do _not_ hold from here on! */ + view->ndim = 1; + view->shape = NULL; + } + + view->obj = (PyObject*)self; + Py_INCREF(view->obj); + + return 0; +} + + +//- mapping methods --------------------------------------------------------- +static PyMappingMethods ll_as_mapping = { + (lenfunc) ll_length, // mp_length + (binaryfunc) ll_subscript, // mp_subscript + (objobjargproc)ll_ass_sub, // mp_ass_subscript +}; + +//- sequence methods -------------------------------------------------------- +static PySequenceMethods ll_as_sequence = { + (lenfunc)ll_length, // sq_length + 0, // sq_concat + 0, // sq_repeat + (ssizeargfunc)ll_item, // sq_item + 0, // sq_slice + 0, // sq_ass_item + 0, // sq_ass_slice + 0, // sq_contains + 0, // sq_inplace_concat + 0, // sq_inplace_repeat +}; + +//- buffer methods ---------------------------------------------------------- +static PyBufferProcs ll_as_buffer = { +#if PY_VERSION_HEX < 0x03000000 + (readbufferproc)ll_oldgetbuf, // bf_getreadbuffer + (writebufferproc)ll_oldgetbuf, // bf_getwritebuffer + (segcountproc)ll_getsegcount, // bf_getsegcount + 0, // bf_getcharbuffer +#endif + (getbufferproc)ll_getbuf, // bf_getbuffer + 0, // bf_releasebuffer +}; + + +namespace CPyCppyy { + +//= CPyCppyy low level view type ============================================ +PyTypeObject LowLevelView_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + (char*)"cppyy.LowLevelView", // tp_name + sizeof(CPyCppyy::LowLevelView),// tp_basicsize + 0, // tp_itemsize + (destructor)ll_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &ll_as_sequence, // tp_as_sequence + &ll_as_mapping, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + &ll_as_buffer, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, // tp_flags + (char*)"memory view on C++ pointer", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + ll_methods, // tp_methods + 0, // tp_members + ll_getset, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + (newfunc)ll_new, // tp_new + 0, // tp_free + 0, // tp_is_gc + 0, // tp_bases + 0, // tp_mro + 0, // tp_cache + 0, // tp_subclasses + 0 // tp_weaklist +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +} // namespace CPyCppyy + +namespace { + +template struct typecode_traits {}; +template<> struct typecode_traits { + static constexpr const char* format = "?"; static constexpr const char* name = "bool"; }; +template<> struct typecode_traits { + static constexpr const char* format = "B"; static constexpr const char* name = "UCharAsInt"; }; +template<> struct typecode_traits { + static constexpr const char* format = "h"; static constexpr const char* name = "short"; }; +template<> struct typecode_traits { + static constexpr const char* format = "H"; static constexpr const char* name = "unsigned short"; }; +template<> struct typecode_traits { + static constexpr const char* format = "i"; static constexpr const char* name = "int"; }; +template<> struct typecode_traits { + static constexpr const char* format = "I"; static constexpr const char* name = "unsigned int"; }; +template<> struct typecode_traits { + static constexpr const char* format = "l"; static constexpr const char* +#if PY_VERSION_HEX < 0x03000000 + name = "int"; +#else + name = "long"; +#endif +}; +template<> struct typecode_traits { + static constexpr const char* format = "L"; static constexpr const char* name = "unsigned long"; }; +template<> struct typecode_traits { + static constexpr const char* format = "q"; static constexpr const char* name = "long long"; }; +template<> struct typecode_traits { + static constexpr const char* format = "Q"; static constexpr const char* name = "unsigned long long"; }; +template<> struct typecode_traits { + static constexpr const char* format = "f"; static constexpr const char* name = "float"; }; +template<> struct typecode_traits { + static constexpr const char* format = "d"; static constexpr const char* name = "double"; }; + +} // unnamed namespace + + +//--------------------------------------------------------------------------- +template +static inline PyObject* CreateLowLevelViewT(T* address, Py_ssize_t* shape) +{ + using namespace CPyCppyy; + Py_ssize_t nx = (shape && 0 <= shape[1]) ? shape[1] : INT_MAX/sizeof(T); + PyObject* args = PyTuple_New(0); + LowLevelView* llp = + (LowLevelView*)LowLevelView_Type.tp_new(&LowLevelView_Type, args, nullptr); + Py_DECREF(args); + + Py_buffer& view = llp->fBufInfo; + view.buf = address; + view.obj = nullptr; + view.len = nx * sizeof(T); + view.readonly = 0; + view.itemsize = sizeof(T); + view.format = (char*)typecode_traits::format; + view.ndim = shape ? shape[0] : 1; + view.shape = (Py_ssize_t*)PyMem_Malloc(view.ndim * sizeof(Py_ssize_t)); + view.shape[0] = nx; // view.len / view.itemsize + view.strides = (Py_ssize_t*)PyMem_Malloc(view.ndim * sizeof(Py_ssize_t)); + view.strides[0] = view.itemsize; + view.suboffsets = nullptr; + view.internal = nullptr; + + llp->fConverter = CreateConverter(typecode_traits::name); + + return (PyObject*)llp; +} + +//--------------------------------------------------------------------------- +PyObject* CPyCppyy::CreateLowLevelView(bool* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(unsigned char* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(short* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(unsigned short* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(int* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(unsigned int* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(long* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(unsigned long* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(long long* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(unsigned long long* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(float* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} + +PyObject* CPyCppyy::CreateLowLevelView(double* address, Py_ssize_t* shape) { + return CreateLowLevelViewT(address, shape); +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/LowLevelViews.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/LowLevelViews.h new file mode 100644 index 0000000000000..a792bd4cc27a2 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/LowLevelViews.h @@ -0,0 +1,43 @@ +#ifndef CPYCPPYY_LOWLEVELVIEWS_H +#define CPYCPPYY_LOWLEVELVIEWS_H + +#include + +namespace CPyCppyy { + +PyObject* CreateLowLevelView(bool*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(unsigned char*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(short*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(unsigned short*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(int*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(unsigned int*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(long*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(unsigned long*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(long long*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(unsigned long long*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(float*, Py_ssize_t* shape = nullptr); +PyObject* CreateLowLevelView(double*, Py_ssize_t* shape = nullptr); + +inline PyObject* CreatePointerView(void* ptr) { + Py_ssize_t shape[] = {1, 1}; + return CreateLowLevelView((long*)ptr, shape); +} + +//- low level view type and type verification -------------------------------- +extern PyTypeObject LowLevelView_Type; + +template +inline bool LowLevelView_Check(T* object) +{ + return object && PyObject_TypeCheck(object, &LowLevelView_Type); +} + +template +inline bool LowLevelView_CheckExact(T* object) +{ + return object && Py_TYPE(object) == &LowLevelView_Type; +} + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_LOWLEVELVIEWS_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/MemoryRegulator.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/MemoryRegulator.cxx new file mode 100644 index 0000000000000..c7ceef7ebd5dc --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/MemoryRegulator.cxx @@ -0,0 +1,267 @@ +// Bindings +#include "CPyCppyy.h" +#include "MemoryRegulator.h" +#include "CPPInstance.h" +#include "ProxyWrappers.h" + +// Standard +#include +#include +#include + + +// memory regulater callback for deletion of registered objects +static PyMethodDef methoddef_ = { + const_cast("MemoryRegulator_internal_raseCallback"), + (PyCFunction)CPyCppyy::MemoryRegulator::EraseCallback, + METH_O, nullptr +}; + +static PyObject* gEraseCallback = PyCFunction_New(&methoddef_, nullptr); + + +//= pseudo-None type for masking out objects on the python side =============== +static PyTypeObject CPyCppyy_NoneType; + +//----------------------------------------------------------------------------- +static Py_ssize_t AlwaysNullLength(PyObject*) +{ + return 0; +} + +//----------------------------------------------------------------------------- +static PyMappingMethods CPyCppyy_NoneType_mapping = { + AlwaysNullLength, + (binaryfunc) 0, + (objobjargproc) 0 +}; + +// silence warning about some cast operations +#if defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ >= 4 && ((__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ >= 1) || (__GNUC_MINOR__ >= 3)))) && !__INTEL_COMPILER +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + + +//----------------------------------------------------------------------------- +namespace { + +struct InitCPyCppyy_NoneType_t { + InitCPyCppyy_NoneType_t() { + // create a CPyCppyy NoneType (for references that went dodo) from NoneType + memset(&CPyCppyy_NoneType, 0, sizeof(CPyCppyy_NoneType)); + + ((PyObject&)CPyCppyy_NoneType).ob_type = &PyType_Type; + ((PyObject&)CPyCppyy_NoneType).ob_refcnt = 1; + ((PyVarObject&)CPyCppyy_NoneType).ob_size = 0; + + CPyCppyy_NoneType.tp_name = const_cast("CPyCppyy_NoneType"); + CPyCppyy_NoneType.tp_flags = Py_TPFLAGS_HAVE_RICHCOMPARE | Py_TPFLAGS_HAVE_GC; + + CPyCppyy_NoneType.tp_traverse = (traverseproc)0; + CPyCppyy_NoneType.tp_clear = (inquiry)0; + CPyCppyy_NoneType.tp_dealloc = (destructor)&InitCPyCppyy_NoneType_t::DeAlloc; + CPyCppyy_NoneType.tp_repr = Py_TYPE(Py_None)->tp_repr; + CPyCppyy_NoneType.tp_richcompare = (richcmpfunc)&InitCPyCppyy_NoneType_t::RichCompare; +#if PY_VERSION_HEX < 0x03000000 + // tp_compare has become tp_reserved (place holder only) in p3 + CPyCppyy_NoneType.tp_compare = (cmpfunc)&InitCPyCppyy_NoneType_t::Compare; +#endif + CPyCppyy_NoneType.tp_hash = (hashfunc)&InitCPyCppyy_NoneType_t::PtrHash; + + CPyCppyy_NoneType.tp_as_mapping = &CPyCppyy_NoneType_mapping; + + PyType_Ready(&CPyCppyy_NoneType); + } + + static void DeAlloc(PyObject* pyobj) { Py_TYPE(pyobj)->tp_free(pyobj); } + static int PtrHash(PyObject* pyobj) { return (int)ptrdiff_t(pyobj); } + + static PyObject* RichCompare(PyObject*, PyObject* other, int opid) { + return PyObject_RichCompare(other, Py_None, opid); + } + + static int Compare(PyObject*, PyObject* other) { +#if PY_VERSION_HEX < 0x03000000 + return PyObject_Compare(other, Py_None); +#else + // TODO the following isn't correct as it doesn't order, but will do for now ... + return !PyObject_RichCompareBool(other, Py_None, Py_EQ); +#endif + } +}; + +} // unnamed namespace + + +//- ctor/dtor ---------------------------------------------------------------- +CPyCppyy::MemoryRegulator::MemoryRegulator() +{ +// setup NoneType for referencing and create weakref cache + static InitCPyCppyy_NoneType_t initCPyCppyy_NoneType; +} + + +//- public members ----------------------------------------------------------- +bool CPyCppyy::MemoryRegulator::RecursiveRemove( + Cppyy::TCppObject_t cppobj, Cppyy::TCppType_t klass) +{ +// if registerd by the framework, called whenever a cppobj gets destroyed + if (!cppobj) + return false; + + PyObject* pyscope = GetScopeProxy(klass); + if (!CPPScope_Check(pyscope)) + return false; + + CPPClass* pyclass = (CPPClass*)pyscope; + if (!pyclass->fCppObjects) // table may have been deleted on shutdown + return false; + +// see whether we're tracking this object + CppToPyMap_t* cppobjs = pyclass->fCppObjects; + CppToPyMap_t::iterator ppo = cppobjs->find(cppobj); + + if (ppo != cppobjs->end()) { + // get the tracked object and cleanup weak reference + CPPInstance* pyobj = (CPPInstance*)PyWeakref_GetObject(ppo->second); + Py_DECREF(ppo->second); + if (!pyobj) { + cppobjs->erase(ppo); + return false; + } + + // nullify the object + if (!CPyCppyy_NoneType.tp_traverse) { + // take a reference as we're copying its function pointers + Py_INCREF(Py_TYPE(pyobj)); + + // all object that arrive here are expected to be of the same type ("instance") + CPyCppyy_NoneType.tp_traverse = Py_TYPE(pyobj)->tp_traverse; + CPyCppyy_NoneType.tp_clear = Py_TYPE(pyobj)->tp_clear; + CPyCppyy_NoneType.tp_free = Py_TYPE(pyobj)->tp_free; + } else if (CPyCppyy_NoneType.tp_traverse != Py_TYPE(pyobj)->tp_traverse) { + std::cerr << "in CPyCppyy::MemoryRegulater, unexpected object of type: " + << Py_TYPE(pyobj)->tp_name << std::endl; + + // drop object and leave before too much damage is done + cppobjs->erase(ppo); + return false; + } + + // notify any other weak referents by playing dead + int refcnt = ((PyObject*)pyobj)->ob_refcnt; + ((PyObject*)pyobj)->ob_refcnt = 0; + PyObject_ClearWeakRefs((PyObject*)pyobj); + ((PyObject*)pyobj)->ob_refcnt = refcnt; + + // cleanup object internals + pyobj->CppOwns(); // held object is out of scope now anyway + op_dealloc_nofree(pyobj); // normal object cleanup, while keeping memory + + // reset type object + Py_INCREF((PyObject*)(void*)&CPyCppyy_NoneType); + Py_DECREF(Py_TYPE(pyobj)); + ((PyObject*)pyobj)->ob_type = &CPyCppyy_NoneType; + + // erase the object from tracking (weakref table already cleared, above) + cppobjs->erase(ppo); + return true; + } + +// unknown cppobj + return false; +} + +//----------------------------------------------------------------------------- +bool CPyCppyy::MemoryRegulator::RegisterPyObject( + CPPInstance* pyobj, Cppyy::TCppObject_t cppobj) +{ +// start tracking proxied by + if (!(pyobj && cppobj)) + return false; + + CPPClass* pyclass = (CPPClass*)Py_TYPE(pyobj); + CppToPyMap_t* cppobjs = ((CPPClass*)Py_TYPE(pyobj))->fCppObjects; + CppToPyMap_t::iterator ppo = cppobjs->find(cppobj); + if (ppo == pyclass->fCppObjects->end()) { + PyObject* pyref = PyWeakref_NewRef((PyObject*)pyobj, gEraseCallback); + pyclass->fCppObjects->insert(std::make_pair(cppobj, pyref)); + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +bool CPyCppyy::MemoryRegulator::UnregisterPyObject( + Cppyy::TCppObject_t cppobj, Cppyy::TCppType_t klass) +{ +// stop tracking , without notification + if (!(cppobj && klass)) + return false; + + PyObject* pyscope = GetScopeProxy(klass); + if (!CPPScope_Check(pyscope)) + return false; + + CPPClass* pyclass = (CPPClass*)pyscope; + CppToPyMap_t::iterator ppo = pyclass->fCppObjects->find(cppobj); + if (ppo != pyclass->fCppObjects->end()) { + Py_DECREF(ppo->second); + pyclass->fCppObjects->erase(ppo); + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +PyObject* CPyCppyy::MemoryRegulator::RetrievePyObject( + Cppyy::TCppObject_t cppobj, Cppyy::TCppType_t klass) +{ +// lookup , return old proxy if tracked + if (!(cppobj && klass)) + return nullptr; + + PyObject* pyscope = GetScopeProxy(klass); + if (!CPPScope_Check(pyscope)) + return nullptr; + + CPPClass* pyclass = (CPPClass*)pyscope; + CppToPyMap_t::iterator ppo = pyclass->fCppObjects->find(cppobj); + if (ppo != pyclass->fCppObjects->end() ) { + PyObject* pyobj = PyWeakref_GetObject(ppo->second); + if (pyobj == Py_None) { + Py_DECREF(ppo->second); + pyclass->fCppObjects->erase(ppo); + return nullptr; + } + Py_INCREF(pyobj); + return pyobj; + } + + return nullptr; +} + + +//- private static members ------------------------------------------------------ +PyObject* CPyCppyy::MemoryRegulator::EraseCallback(PyObject*, PyObject* pyref) +{ +// called when one of the python objects we've registered is going away + CPPInstance* pyobj = (CPPInstance*)PyWeakref_GetObject(pyref); + if ((PyObject*)pyobj != Py_None) { + CPPClass* pyclass = (CPPClass*)Py_TYPE(pyobj); + if (pyobj->GetObject()) { + // erase if tracked + void* cppobj = pyobj->GetObject(); + CppToPyMap_t::iterator ppo = pyclass->fCppObjects->find(cppobj); + if (ppo != pyclass->fCppObjects->end()) { + Py_DECREF(ppo->second); + pyclass->fCppObjects->erase(ppo); + } + } + } + + Py_INCREF(Py_None); + return Py_None; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/MemoryRegulator.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/MemoryRegulator.h new file mode 100644 index 0000000000000..3828014d58e0f --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/MemoryRegulator.h @@ -0,0 +1,31 @@ +#ifndef CPYCPPYY_MEMORYREGULATOR_H +#define CPYCPPYY_MEMORYREGULATOR_H + + +namespace CPyCppyy { + +class CPPInstance; + +class MemoryRegulator { +public: + MemoryRegulator(); + +// callback from C++-side frameworks + static bool RecursiveRemove(Cppyy::TCppObject_t cppobj, Cppyy::TCppType_t klass); + +// add a python object to the table of managed objects + static bool RegisterPyObject(CPPInstance* pyobj, void* cppobj); + +// remove a python object from the table of managed objects, w/o notification + static bool UnregisterPyObject(Cppyy::TCppObject_t cppobj, Cppyy::TCppType_t klass); + +// new reference to python object matching cppobj, or 0 on failure + static PyObject* RetrievePyObject(Cppyy::TCppObject_t cppobj, Cppyy::TCppType_t klass); + +// callback when weak refs to managed objects are destroyed + static PyObject* EraseCallback(PyObject*, PyObject* pyref); +}; + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_MEMORYREGULATOR_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/ProxyWrappers.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/ProxyWrappers.cxx new file mode 100644 index 0000000000000..6f830c3187aa5 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/ProxyWrappers.cxx @@ -0,0 +1,726 @@ +// Bindings +#include "CPyCppyy.h" +#include "ProxyWrappers.h" +#include "CPPClassMethod.h" +#include "CPPConstructor.h" +#include "CPPDataMember.h" +#include "CPPFunction.h" +#include "CPPInstance.h" +#include "CPPMethod.h" +#include "CPPOverload.h" +#include "CPPScope.h" +#include "CPPSetItem.h" +#include "MemoryRegulator.h" +#include "PyStrings.h" +#include "Pythonize.h" +#include "TemplateProxy.h" +#include "TupleOfInstances.h" +#include "TypeManip.h" +#include "Utility.h" + +// Standard +#include +#include +#include +#include +#include +#include + + +//- data _______________________________________________________________________ +namespace CPyCppyy { + extern PyObject* gThisModule; + extern std::set gPinnedTypes; +} + +// to prevent having to walk scopes, track python classes by C++ class +typedef std::map PyClassMap_t; +static PyClassMap_t gPyClasses; + + +//- helpers -------------------------------------------------------------------- + +namespace CPyCppyy { + +typedef struct { + PyObject_HEAD + PyObject *dict; +} proxyobject; + +// helper for creating new C++ proxy python types +static PyObject* CreateNewCppProxyClass(Cppyy::TCppScope_t klass, PyObject* pybases) +{ +// Create a new python shadow class with the required hierarchy and meta-classes. + Py_XINCREF(pybases); + if (!pybases) { + pybases = PyTuple_New(1); + Py_INCREF((PyObject*)(void*)&CPPInstance_Type); + PyTuple_SET_ITEM(pybases, 0, (PyObject*)(void*)&CPPInstance_Type); + } + + PyObject* pymetabases = PyTuple_New(PyTuple_GET_SIZE(pybases)); + for (int i = 0; i < PyTuple_GET_SIZE(pybases); ++i) { + PyObject* btype = (PyObject*)Py_TYPE(PyTuple_GetItem(pybases, i)); + Py_INCREF(btype); + PyTuple_SET_ITEM(pymetabases, i, btype); + } + + std::string name = Cppyy::GetFinalName(klass); + +// create meta-class, add a dummy __module__ to pre-empt the default setting + PyObject* args = Py_BuildValue((char*)"sO{}", (name+"_meta").c_str(), pymetabases); + PyDict_SetItem(PyTuple_GET_ITEM(args, 2), PyStrings::gModule, Py_True); + Py_DECREF(pymetabases); + + PyObject* pymeta = PyType_Type.tp_new(&CPPScope_Type, args, nullptr); + + Py_DECREF(args); + if (!pymeta) { + PyErr_Print(); + Py_DECREF(pybases); + return nullptr; + } + +// set the klass id, in case there is derivation Python-side + ((CPPClass*)pymeta)->fCppType = klass; + +// alright, and now we really badly want to get rid of the dummy ... + PyObject* dictproxy = PyObject_GetAttr(pymeta, PyStrings::gDict); + PyDict_DelItem(((proxyobject*)dictproxy)->dict, PyStrings::gModule); + +// create actual class + args = Py_BuildValue((char*)"sO{}", name.c_str(), pybases); + PyObject* pyclass = + ((PyTypeObject*)pymeta)->tp_new((PyTypeObject*)pymeta, args, nullptr); + + Py_DECREF(args); + Py_DECREF(pymeta); + Py_DECREF(pybases); + + return pyclass; +} + +static inline +void AddPropertyToClass(PyObject* pyclass, + Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata) +{ + CPyCppyy::CPPDataMember* property = CPyCppyy::CPPDataMember_New(scope, idata); + +// allow access at the instance level + PyObject_SetAttrString(pyclass, + const_cast(property->GetName().c_str()), (PyObject*)property); + +// allow access at the class level (always add after setting instance level) + if (Cppyy::IsStaticData(scope, idata)) { + PyObject_SetAttrString((PyObject*)Py_TYPE(pyclass), + const_cast(property->GetName().c_str()), (PyObject*)property); + } + +// done + Py_DECREF(property); +} + +} // namespace CPyCppyy + + +//- public functions --------------------------------------------------------- +namespace CPyCppyy { + +static int BuildScopeProxyDict(Cppyy::TCppScope_t scope, PyObject* pyclass) { +// Collect methods and data for the given scope, and add them to the given python +// proxy object. + +// some properties that'll affect building the dictionary + bool isNamespace = Cppyy::IsNamespace(scope); + bool hasConstructor = false; + +// load all public methods and data members + typedef std::vector Callables_t; + typedef std::map CallableCache_t; + CallableCache_t cache; + +// bypass custom __getattr__ for efficiency + getattrofunc oldgetattro = Py_TYPE(pyclass)->tp_getattro; + Py_TYPE(pyclass)->tp_getattro = PyType_Type.tp_getattro; + +// functions in namespaces are properly found through lazy lookup, so do not +// create them until needed (the same is not true for data members) + const Cppyy::TCppIndex_t nMethods = + Cppyy::IsNamespace(scope) ? 0 : Cppyy::GetNumMethods(scope); + for (Cppyy::TCppIndex_t imeth = 0; imeth < nMethods; ++imeth) { + Cppyy::TCppMethod_t method = Cppyy::GetMethod(scope, imeth); + + // process the method based on its name + std::string mtCppName = Cppyy::GetMethodName(method); + + // special case trackers + bool setupSetItem = false; + bool isConstructor = Cppyy::IsConstructor(method); + bool isTemplate = isConstructor ? false : Cppyy::IsMethodTemplate(scope, imeth); + + // filter empty names (happens for namespaces, is bug?) + if (mtCppName == "") + continue; + + // filter C++ destructors + if (mtCppName[0] == '~') + continue; + + // translate operators + std::string mtName = Utility::MapOperatorName(mtCppName, Cppyy::GetMethodNumArgs(method)); + + // operator[]/() returning a reference type will be used for __setitem__ + if (mtName == "__call__" || mtName == "__getitem__") { + const std::string& qual_return = Cppyy::ResolveName(Cppyy::GetMethodResultType(method)); + if (qual_return.find("const", 0, 5) == std::string::npos) { + const std::string& cpd = Utility::Compound(qual_return); + if (!cpd.empty() && cpd[cpd.size()- 1] == '&') { + setupSetItem = true; + } + } + } + + // public methods are normally visible, private methods are mangled python-wise + // note the overload implications which are name based, and note that genreflex + // does not create the interface methods for private/protected methods ... + // TODO: check whether Cling allows private method calling; otherwise delete this + if (!Cppyy::IsPublicMethod(method)) { + if (isConstructor) // don't expose private ctors + continue; + else { // mangle private methods + // TODO: drop use of TClassEdit here ... + // const std::string& clName = TClassEdit::ShortType( + // Cppyy::GetFinalName(scope).c_str(), TClassEdit::kDropAlloc); + const std::string& clName = Cppyy::GetFinalName(scope); + mtName = "_" + clName + "__" + mtName; + } + } + + // template members; handled by adding a dispatcher to the class + if (isTemplate) { + // TODO: the following is incorrect if both base and derived have the same + // templated method (but that is an unlikely scenario anyway) + PyObject* attr = PyObject_GetAttrString(pyclass, const_cast(mtName.c_str())); + if (!TemplateProxy_Check(attr)) { + PyErr_Clear(); + TemplateProxy* pytmpl = TemplateProxy_New(mtCppName, mtName, pyclass); + if (CPPOverload_Check(attr)) pytmpl->AddOverload((CPPOverload*)attr); + PyObject_SetAttrString( + pyclass, const_cast(mtName.c_str()), (PyObject*)pytmpl); + Py_DECREF(pytmpl); + } + Py_XDECREF(attr); + // continue processing to actually add the method so that the proxy can find + // it on the class when called explicitly + } + + // construct the holder + PyCallable* pycall = 0; + if (Cppyy::IsStaticMethod(method)) // class method + pycall = new CPPClassMethod(scope, method); + else if (isNamespace) // free function + pycall = new CPPFunction(scope, method); + else if (isConstructor) { // constructor + pycall = new CPPConstructor(scope, method); + mtName = "__init__"; + hasConstructor = true; + } else // member function + pycall = new CPPMethod(scope, method); + + // lookup method dispatcher and store method + Callables_t& md = (*(cache.insert( + std::make_pair(mtName, Callables_t())).first)).second; + md.push_back(pycall); + + // special case for operator[]/() that returns by ref, use for getitem/call and setitem + if (setupSetItem) { + Callables_t& setitem = (*(cache.insert( + std::make_pair(std::string("__setitem__"), Callables_t())).first)).second; + setitem.push_back(new CPPSetItem(scope, method)); + } + + if (isTemplate) { + PyObject* attr = PyObject_GetAttrString(pyclass, const_cast(mtName.c_str())); + ((TemplateProxy*)attr)->AddTemplate(pycall->Clone()); + Py_DECREF(attr); + } + } + +// add a pseudo-default ctor, if none defined + if (!isNamespace && !hasConstructor) + cache["__init__"].push_back(new CPPConstructor(scope, (Cppyy::TCppMethod_t)0)); + +// add the methods to the class dictionary + for (CallableCache_t::iterator imd = cache.begin(); imd != cache.end(); ++imd) { + // in order to prevent removing templated editions of this method (which were set earlier, + // above, as a different proxy object), we'll check and add this method flagged as a generic + // one (to be picked up by the templated one as appropriate) if a template exists + PyObject* attr = PyObject_GetAttrString(pyclass, const_cast(imd->first.c_str())); + if (TemplateProxy_Check(attr)) { + // template exists, supply it with the non-templated method overloads + for (Callables_t::iterator cit = imd->second.begin(); cit != imd->second.end(); ++cit) + ((TemplateProxy*)attr)->AddOverload(*cit); + } else { + if (!attr) PyErr_Clear(); + // normal case, add a new method + CPPOverload* method = CPPOverload_New(imd->first, imd->second); + PyObject_SetAttrString( + pyclass, const_cast(method->GetName().c_str()), (PyObject*)method); + Py_DECREF(method); + } + + Py_XDECREF(attr); // could have be found in base class or non-existent + } + + // collect data members (including enums) + const Cppyy::TCppIndex_t nDataMembers = Cppyy::GetNumDatamembers(scope); + for (Cppyy::TCppIndex_t idata = 0; idata < nDataMembers; ++idata) { + // allow only public members + if (!Cppyy::IsPublicData(scope, idata)) + continue; + + // enum datamembers (this in conjunction with previously collected enums above) + if (Cppyy::IsEnumData(scope, idata) && Cppyy::IsStaticData(scope, idata)) { + // some implementation-specific data members have no address: ignore them + if (!Cppyy::GetDatamemberOffset(scope, idata)) + continue; + + // two options: this is a static variable, or it is the enum value, the latter + // already exists, so check for it and move on if set + PyObject* eset = PyObject_GetAttrString(pyclass, + const_cast(Cppyy::GetDatamemberName(scope, idata).c_str())); + if (eset) { + Py_DECREF(eset); + continue; + } + + PyErr_Clear(); + + // it could still be that this is an anonymous enum, which is not in the list + // provided by the class + if (strstr(Cppyy::GetDatamemberType(scope, idata).c_str(), "(anonymous)") != 0) { + AddPropertyToClass(pyclass, scope, idata); + continue; + } + } + + // properties (aka public (static) data members) + AddPropertyToClass(pyclass, scope, idata); + } + +// restore custom __getattr__ + Py_TYPE(pyclass)->tp_getattro = oldgetattro; + +// all ok, done + return 0; +} + +//---------------------------------------------------------------------------- +static PyObject* BuildCppClassBases(Cppyy::TCppType_t klass) +{ +// Build a tuple of python proxy classes of all the bases of the given 'klass'. + + size_t nbases = Cppyy::GetNumBases(klass); + +// collect bases in acceptable mro order, while removing duplicates (this may +// break the overload resolution in esoteric cases, but otherwise the class can +// not be used at all, as CPython will refuse the mro). + std::deque uqb; + std::deque bids; + for (size_t ibase = 0; ibase < nbases; ++ibase) { + const std::string& name = Cppyy::GetBaseName(klass, ibase); + int decision = 2; + Cppyy::TCppType_t tp = Cppyy::GetScope(name); + for (size_t ibase2 = 0; ibase2 < uqb.size(); ++ibase2) { + if (uqb[ibase2] == name) { // not unique ... skip + decision = 0; + break; + } + + if (Cppyy::IsSubtype(tp, bids[ibase2])) { + // mro requirement: sub-type has to follow base + decision = 1; + break; + } + } + + if (decision == 1) { + uqb.push_front(name); + bids.push_front(tp); + } else if (decision == 2) { + uqb.push_back(name); + bids.push_back(tp); + } + // skipped if decision == 0 (not unique) + } + +// allocate a tuple for the base classes, special case for first base + nbases = uqb.size(); + + PyObject* pybases = PyTuple_New(nbases ? nbases : 1); + if (!pybases) + return nullptr; + +// build all the bases + if (nbases == 0) { + Py_INCREF((PyObject*)(void*)&CPPInstance_Type); + PyTuple_SET_ITEM(pybases, 0, (PyObject*)(void*)&CPPInstance_Type); + } else { + for (std::vector::size_type ibase = 0; ibase < nbases; ++ibase) { + PyObject* pyclass = CreateScopeProxy(uqb[ibase]); + if (!pyclass) { + Py_DECREF(pybases); + return nullptr; + } + + PyTuple_SET_ITEM(pybases, ibase, pyclass); + } + + // special case, if true python types enter the hierarchy, make sure that + // the first base seen is still the CPPInstance_Type + if (!PyObject_IsSubclass(PyTuple_GET_ITEM(pybases, 0), (PyObject*)&CPPInstance_Type)) { + PyObject* newpybases = PyTuple_New(nbases+1); + Py_INCREF((PyObject*)(void*)&CPPInstance_Type); + PyTuple_SET_ITEM(newpybases, 0, (PyObject*)(void*)&CPPInstance_Type); + for (int ibase = 0; ibase < (int)nbases; ++ibase) { + PyObject* pyclass = PyTuple_GET_ITEM(pybases, ibase); + Py_INCREF(pyclass); + PyTuple_SET_ITEM(newpybases, ibase+1, pyclass); + } + Py_DECREF(pybases); + pybases = newpybases; + } + } + + return pybases; +} + +} // namespace CPyCppyy + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::GetScopeProxy(Cppyy::TCppScope_t scope) +{ +// Retrieve scope proxy from the known ones. + PyClassMap_t::iterator pci = gPyClasses.find(scope); + if (pci != gPyClasses.end()) { + PyObject* pyclass = PyWeakref_GetObject(pci->second); + if (pyclass != Py_None) { + Py_INCREF(pyclass); + return pyclass; + } + } + + return nullptr; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CreateScopeProxy(Cppyy::TCppScope_t scope) +{ +// Convenience function with a lookup first through the known existing proxies. + PyObject* pyclass = GetScopeProxy(scope); + if (pyclass) + return pyclass; + + return CreateScopeProxy(Cppyy::GetScopedFinalName(scope)); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CreateScopeProxy(PyObject*, PyObject* args) +{ +// Build a python shadow class for the named C++ class. + std::string cname = CPyCppyy_PyUnicode_AsString(PyTuple_GetItem(args, 0)); + if (PyErr_Occurred()) + return nullptr; + + return CreateScopeProxy(cname); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::CreateScopeProxy(const std::string& scope_name, PyObject* parent) +{ +// Build a python shadow class for the named C++ class or namespace. + +// force building of the class if a parent is specified (prevents loops) + bool force = parent != 0; + +// working copy + std::string name = scope_name; + +// determine complete scope name, if a python parent has been given + std::string scName = ""; + if (parent) { + if (CPPScope_Check(parent)) + scName = Cppyy::GetScopedFinalName(((CPPScope*)parent)->fCppType); + else { + PyObject* parname = PyObject_GetAttr(parent, PyStrings::gName); + if (!parname) { + PyErr_Format(PyExc_SystemError, "given scope has no name for %s", name.c_str()); + return nullptr; + } + + // should be a string + scName = CPyCppyy_PyUnicode_AsString(parname); + Py_DECREF(parname); + if (PyErr_Occurred()) + return nullptr; + } + + // accept this parent scope and use it's name for prefixing + Py_INCREF(parent); + } + +// retrieve C++ class (this verifies name, and is therefore done first) + const std::string& lookup = scName.empty() ? name : (scName+"::"+name); + Cppyy::TCppScope_t klass = Cppyy::GetScope(lookup); + + if (!(bool)klass && Cppyy::IsTemplate(lookup)) { + // a "naked" templated class is requested: return callable proxy for instantiations + PyObject* pytcl = PyObject_GetAttr(gThisModule, PyStrings::gTemplate); + PyObject* pytemplate = PyObject_CallFunction( + pytcl, const_cast("s"), const_cast(lookup.c_str())); + Py_DECREF(pytcl); + + // cache the result + PyObject_SetAttrString(parent ? parent : gThisModule, (char*)name.c_str(), pytemplate); + + // done, next step should be a call into this template + Py_XDECREF(parent); + return pytemplate; + } + + if (!(bool)klass) { // if so, all options have been exhausted: it doesn't exist as such + PyErr_Format(PyExc_TypeError, "\'%s\' is not a known C++ class", lookup.c_str()); + Py_XDECREF(parent); + return nullptr; + } + +// locate class by ID, if possible, to prevent parsing scopes/templates anew + PyObject* pyscope = GetScopeProxy(klass); + if (pyscope) { + if (parent) PyObject_SetAttrString(parent, (char*)scope_name.c_str(), pyscope); + return pyscope; + } + +// locate the parent, if necessary, for building the class if not specified + std::string::size_type last = 0; + if (!parent) { + // TODO: move this to TypeManip + // need to deal with template paremeters that can have scopes themselves + int tpl_open = 0; + for (std::string::size_type pos = 0; pos < name.size(); ++pos) { + std::string::value_type c = name[pos]; + + // count '<' and '>' to be able to skip template contents + if (c == '<') + ++tpl_open; + else if (c == '>') + --tpl_open; + + // by only checking for "::" the last part (class name) is dropped + else if (tpl_open == 0 && \ + c == ':' && pos+1 < name.size() && name[ pos+1 ] == ':') { + // found a new scope part + const std::string& part = name.substr(last, pos-last); + + PyObject* next = PyObject_GetAttrString( + parent ? parent : gThisModule, const_cast(part.c_str())); + + if (!next) { // lookup failed, try to create it + PyErr_Clear(); + next = CreateScopeProxy(part, parent); + } + Py_XDECREF(parent); + + if (!next) // create failed, give up + return nullptr; + + // found scope part + parent = next; + + // done with part (note that pos is moved one ahead here) + last = pos+2; ++pos; + } + + } + + if (parent && !CPPScope_Check(parent)) { + // Special case: parent found is not one of ours (it's e.g. a pure Python module), so + // continuing would fail badly. One final lookup, then out of here ... + std::string unscoped = scope_name.substr(last, std::string::npos); + return PyObject_GetAttrString(parent, unscoped.c_str()); + } + } + +// use the module as a fake cope if no outer scope found + if (!parent) { + parent = gThisModule; + Py_INCREF(parent); + } + +// use actual class name for binding + const std::string& actual = Cppyy::GetFinalName(klass); + +// first try to retrieve an existing class representation + PyObject* pyactual = CPyCppyy_PyUnicode_FromString(actual.c_str()); + PyObject* pyclass = force ? nullptr : PyObject_GetAttr(parent, pyactual); + + bool bClassFound = (bool)pyclass; + +// build if the class does not yet exist + if (!pyclass) { + // ignore error generated from the failed lookup + PyErr_Clear(); + + // construct the base classes + PyObject* pybases = BuildCppClassBases(klass); + if (pybases != 0) { + // create a fresh Python class, given bases, name, and empty dictionary + pyclass = CreateNewCppProxyClass(klass, pybases); + Py_DECREF(pybases); + } + + // fill the dictionary, if successful + if (pyclass) { + if (BuildScopeProxyDict(klass, pyclass)) { + // something failed in building the dictionary + Py_DECREF(pyclass); + pyclass = nullptr; + } else { + PyObject_SetAttr(parent, pyactual, pyclass); + } + } + } + +// give up, if not constructed + if (!pyclass) + return nullptr; + + if (name != actual) // exists, but typedef-ed: simply map reference + PyObject_SetAttrString(parent, const_cast(name.c_str()), pyclass); + +// if this was a recycled class, we're done + if (bClassFound) + return pyclass; + +// store a ref from cppyy scope id to new python class + gPyClasses[klass] = PyWeakref_NewRef(pyclass, nullptr); + + Py_DECREF(pyactual); + Py_DECREF(parent); + + if (!Cppyy::IsNamespace(klass)) { + // add python-style features to classes + if (!Pythonize(pyclass, Cppyy::GetScopedFinalName(klass))) { + Py_XDECREF(pyclass); + pyclass = nullptr; + } + } else { + // add to sys.modules to allow importing from this namespace + PyObject* pyfullname = PyObject_GetAttr(pyclass, PyStrings::gModule); + CPyCppyy_PyUnicode_AppendAndDel( + &pyfullname, CPyCppyy_PyUnicode_FromString(".")); + CPyCppyy_PyUnicode_AppendAndDel( + &pyfullname, PyObject_GetAttr(pyclass, PyStrings::gName)); + PyObject* modules = PySys_GetObject(const_cast("modules")); + if (modules && PyDict_Check(modules)) + PyDict_SetItem(modules, pyfullname, pyclass); + Py_DECREF(pyfullname); + } + +// all done + return pyclass; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::BindCppObjectNoCast(Cppyy::TCppObject_t address, + Cppyy::TCppType_t klass, int flags) +{ +// only known or knowable objects will be bound (null object is ok) + if (!klass) { + PyErr_SetString(PyExc_TypeError, "attempt to bind C++ object w/o class"); + return nullptr; + } + +// retrieve python class + PyObject* pyclass = CreateScopeProxy(klass); + if (!pyclass) + return nullptr; // error has been set in CreateScopeProxy + + bool isRef = flags & CPPInstance::kIsReference; + bool isValue = flags & CPPInstance::kIsValue; + +// TODO: add convenience function to MemoryRegulator to use pyclass directly +// TODO: make sure that a consistent address is used (may have to be done in BindCppObject) + if (address && !isValue /* always fresh */) { + PyObject* oldPyObject = MemoryRegulator::RetrievePyObject( + isRef ? *(void**)address : address, klass); + // ptr-ptr requires old object to be a reference to enable re-use + if (oldPyObject && (!(flags & CPPInstance::kIsPtrPtr) || + ((CPPInstance*)oldPyObject)->fFlags & CPPInstance::kIsReference)) + return oldPyObject; + } + +// instantiate an object of this class + PyObject* args = PyTuple_New(0); + CPPInstance* pyobj = + (CPPInstance*)((PyTypeObject*)pyclass)->tp_new((PyTypeObject*)pyclass, args, nullptr); + Py_DECREF(args); + Py_DECREF(pyclass); + +// bind, register and return if successful + if (pyobj != 0) { // fill proxy value? + unsigned flags = + (isRef ? CPPInstance::kIsReference : 0) | (isValue ? CPPInstance::kIsValue : 0); + pyobj->Set(address, (CPPInstance::EFlags)flags); + + if (address && !isRef) + MemoryRegulator::RegisterPyObject(pyobj, address); + } + +// successful completion + return (PyObject*)pyobj; +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::BindCppObject(Cppyy::TCppObject_t address, + Cppyy::TCppType_t klass, int flags) +{ +// if the object is a null pointer, return a typed one (as needed for overloading) + if (!address) + return BindCppObjectNoCast(address, klass, flags); + +// only known or knowable objects will be bound + if (!klass) { + PyErr_SetString(PyExc_TypeError, "attempt to bind C++ object w/o class"); + return nullptr; + } + + bool isRef = flags & CPPInstance::kIsReference; + +// get actual class for recycling checking and/or downcasting + Cppyy::TCppType_t clActual = isRef ? 0 : Cppyy::GetActualClass(klass, address); + +// downcast to real class for object returns, unless pinned + if (clActual && klass != clActual) { + auto pci = gPinnedTypes.find(klass); + if (pci == gPinnedTypes.end()) { + ptrdiff_t offset = Cppyy::GetBaseOffset( + clActual, klass, address, -1 /* down-cast */, true /* report errors */); + if (offset != -1) { // may fail if clActual not fully defined + address = (void*)((Long_t)address + offset); + klass = clActual; + } + } + } + +// actual binding (returned object may be zero w/ a python exception set) + return BindCppObjectNoCast(address, klass, flags); +} + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::BindCppObjectArray( + Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Int_t size) +{ +// TODO: this function exists for symmetry; need to figure out if it's useful + return TupleOfInstances_New(address, klass, size); +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/ProxyWrappers.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/ProxyWrappers.h new file mode 100644 index 0000000000000..4b7d35068230c --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/ProxyWrappers.h @@ -0,0 +1,27 @@ +#ifndef CPYCPPYY_PROXYWRAPPERS_H +#define CPYCPPYY_PROXYWRAPPERS_H + +// Standard +#include + + +namespace CPyCppyy { + +// construct a Python shadow class for the named C++ class +PyObject* GetScopeProxy(Cppyy::TCppScope_t); +PyObject* CreateScopeProxy(Cppyy::TCppScope_t); +PyObject* CreateScopeProxy(PyObject*, PyObject* args); +PyObject* CreateScopeProxy( + const std::string& scope_name, PyObject* parent = nullptr); + +// bind a C++ object into a Python proxy object +PyObject* BindCppObjectNoCast(Cppyy::TCppObject_t object, + Cppyy::TCppType_t klass, int flags = 0x0); +PyObject* BindCppObject(Cppyy::TCppObject_t object, + Cppyy::TCppType_t klass, int flags = 0x0); +PyObject* BindCppObjectArray( + Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Int_t size); + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_PROXYWRAPPERS_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyCallable.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyCallable.h new file mode 100644 index 0000000000000..ff2b247889264 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyCallable.h @@ -0,0 +1,39 @@ +#ifndef CPYCPPYY_PYCALLABLE_H +#define CPYCPPYY_PYCALLABLE_H + +// Bindings +#include "CallContext.h" + + +namespace CPyCppyy { + +class CPPInstance; + +class PyCallable { +public: + virtual ~PyCallable() {} + +public: + virtual PyObject* GetSignature(bool show_formalargs = true) = 0; + virtual PyObject* GetPrototype(bool show_formalargs = true) = 0; + virtual PyObject* GetDocString() { return GetPrototype(); } + + virtual int GetPriority() = 0; + + virtual int GetMaxArgs() = 0; + virtual PyObject* GetCoVarNames() = 0; + virtual PyObject* GetArgDefault(int /* iarg */) = 0; + + virtual PyObject* GetScopeProxy() = 0; + virtual Cppyy::TCppFuncAddr_t GetFunctionAddress() = 0; + + virtual PyCallable* Clone() = 0; + +public: + virtual PyObject* Call( + CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* ctxt = nullptr) = 0; +}; + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_PYCALLABLE_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyObjectDir27.inc b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyObjectDir27.inc new file mode 100644 index 0000000000000..3274a7559983a --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyObjectDir27.inc @@ -0,0 +1,237 @@ +/* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved + +Copied from Objects/object.c under the PSF License Version 2. + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are retained +in Python alone or in any derivative version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + +*/ + +/* Helper for PyObject_Dir. + Merge the __dict__ of aclass into dict, and recursively also all + the __dict__s of aclass's base classes. The order of merging isn't + defined, as it's expected that only the final set of dict keys is + interesting. + Return 0 on success, -1 on error. +*/ + +static int merge_class_dict(PyObject* dict, PyObject* aclass) +{ + PyObject *classdict; + PyObject *bases; + + assert(PyDict_Check(dict)); + assert(aclass); + + /* Merge in the type's dict (if any). */ + classdict = PyObject_GetAttrString(aclass, "__dict__"); + if (classdict == NULL) + PyErr_Clear(); + else { + int status = PyDict_Update(dict, classdict); + Py_DECREF(classdict); + if (status < 0) + return -1; + } + + /* Recursively merge in the base types' (if any) dicts. */ + bases = PyObject_GetAttrString(aclass, "__bases__"); + if (bases == NULL) + PyErr_Clear(); + else { + /* We have no guarantee that bases is a real tuple */ + Py_ssize_t i, n; + n = PySequence_Size(bases); /* This better be right */ + if (n < 0) + PyErr_Clear(); + else { + for (i = 0; i < n; i++) { + int status; + PyObject *base = PySequence_GetItem(bases, i); + if (base == NULL) { + Py_DECREF(bases); + return -1; + } + status = merge_class_dict(dict, base); + Py_DECREF(base); + if (status < 0) { + Py_DECREF(bases); + return -1; + } + } + } + Py_DECREF(bases); + } + return 0; +} + +#if PY_VERSION_HEX < 0x03000000 + +/* Helper for PyObject_Dir. + If obj has an attr named attrname that's a list, merge its string + elements into keys of dict. + Return 0 on success, -1 on error. Errors due to not finding the attr, + or the attr not being a list, are suppressed. +*/ + +static int +merge_list_attr(PyObject* dict, PyObject* obj, const char *attrname) +{ + PyObject *list; + int result = 0; + + assert(PyDict_Check(dict)); + assert(obj); + assert(attrname); + + list = PyObject_GetAttrString(obj, attrname); + if (list == NULL) + PyErr_Clear(); + + else if (PyList_Check(list)) { + int i; + for (i = 0; i < PyList_GET_SIZE(list); ++i) { + PyObject *item = PyList_GET_ITEM(list, i); + if (PyString_Check(item)) { + result = PyDict_SetItem(dict, item, Py_None); + if (result < 0) + break; + } + } + if (Py_Py3kWarningFlag && + (strcmp(attrname, "__members__") == 0 || + strcmp(attrname, "__methods__") == 0)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "__members__ and __methods__ not " + "supported in 3.x", 1) < 0) { + Py_XDECREF(list); + return -1; + } + } + } + + Py_XDECREF(list); + return result; +} + +#endif + +/* Helper for PyObject_Dir of type objects: returns __dict__ and __bases__. + We deliberately don't suck up its __class__, as methods belonging to the + metaclass would probably be more confusing than helpful. +*/ +static PyObject * +_specialized_dir_type(PyObject *obj) +{ + PyObject *result = NULL; + PyObject *dict = PyDict_New(); + + if (dict != NULL && merge_class_dict(dict, obj) == 0) + result = PyDict_Keys(dict); + + Py_XDECREF(dict); + return result; +} + +static PyObject* _generic_dir(PyObject *obj) +{ + if (PyType_Check(obj) || PyClass_Check(obj)) + return _specialized_dir_type(obj); + + PyObject *result = NULL; + PyObject *dict = NULL; + PyObject *itsclass = NULL; + + /* Get __dict__ (which may or may not be a real dict...) */ + dict = PyObject_GetAttrString(obj, "__dict__"); + if (dict == NULL) { + PyErr_Clear(); + dict = PyDict_New(); + } + else if (!PyDict_Check(dict)) { + Py_DECREF(dict); + dict = PyDict_New(); + } + else { + /* Copy __dict__ to avoid mutating it. */ + PyObject *temp = PyDict_Copy(dict); + Py_DECREF(dict); + dict = temp; + } + + if (dict == NULL) + goto error; + +#if PY_VERSION_HEX < 0x03000000 + /* Merge in __members__ and __methods__ (if any). + * This is removed in Python 3000. */ + if (merge_list_attr(dict, obj, "__members__") < 0) + goto error; + if (merge_list_attr(dict, obj, "__methods__") < 0) + goto error; +#endif + + /* Merge in attrs reachable from its class. */ + itsclass = PyObject_GetAttrString(obj, "__class__"); + if (itsclass == NULL) + /* XXX(tomer): Perhaps fall back to obj->ob_type if no + __class__ exists? */ + PyErr_Clear(); + else { + if (merge_class_dict(dict, itsclass) != 0) + goto error; + } + + result = PyDict_Keys(dict); + /* fall through */ +error: + Py_XDECREF(itsclass); + Py_XDECREF(dict); + return result; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyStrings.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyStrings.cxx new file mode 100644 index 0000000000000..df3c9418ecf01 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyStrings.cxx @@ -0,0 +1,138 @@ +// Bindings +#include "CPyCppyy.h" +#include "PyStrings.h" + + +//- data _____________________________________________________________________ +PyObject* CPyCppyy::PyStrings::gAssign = nullptr; +PyObject* CPyCppyy::PyStrings::gBases = nullptr; +PyObject* CPyCppyy::PyStrings::gBase = nullptr; +PyObject* CPyCppyy::PyStrings::gClass = nullptr; +PyObject* CPyCppyy::PyStrings::gCppEq = nullptr; +PyObject* CPyCppyy::PyStrings::gCppNe = nullptr; +PyObject* CPyCppyy::PyStrings::gDeref = nullptr; +PyObject* CPyCppyy::PyStrings::gDict = nullptr; +PyObject* CPyCppyy::PyStrings::gEmptyString = nullptr; +PyObject* CPyCppyy::PyStrings::gEq = nullptr; +PyObject* CPyCppyy::PyStrings::gFollow = nullptr; +PyObject* CPyCppyy::PyStrings::gGetItem = nullptr; +PyObject* CPyCppyy::PyStrings::gInit = nullptr; +PyObject* CPyCppyy::PyStrings::gIter = nullptr; +PyObject* CPyCppyy::PyStrings::gLen = nullptr; +PyObject* CPyCppyy::PyStrings::gLifeLine = nullptr; +PyObject* CPyCppyy::PyStrings::gModule = nullptr; +PyObject* CPyCppyy::PyStrings::gMRO = nullptr; +PyObject* CPyCppyy::PyStrings::gName = nullptr; +PyObject* CPyCppyy::PyStrings::gNe = nullptr; +PyObject* CPyCppyy::PyStrings::gTypeCode = nullptr; + +PyObject* CPyCppyy::PyStrings::gAdd = nullptr; +PyObject* CPyCppyy::PyStrings::gSub = nullptr; +PyObject* CPyCppyy::PyStrings::gMul = nullptr; +PyObject* CPyCppyy::PyStrings::gDiv = nullptr; + +PyObject* CPyCppyy::PyStrings::gAt = nullptr; +PyObject* CPyCppyy::PyStrings::gBegin = nullptr; +PyObject* CPyCppyy::PyStrings::gEnd = nullptr; +PyObject* CPyCppyy::PyStrings::gFirst = nullptr; +PyObject* CPyCppyy::PyStrings::gSecond = nullptr; +PyObject* CPyCppyy::PyStrings::gSize = nullptr; +PyObject* CPyCppyy::PyStrings::gTemplate = nullptr; +PyObject* CPyCppyy::PyStrings::gVectorAt = nullptr; + +PyObject* CPyCppyy::PyStrings::gThisModule = nullptr; + + +//----------------------------------------------------------------------------- +#define CPPYY_INITIALIZE_STRING(var, str) \ + if (!(PyStrings::var = CPyCppyy_PyUnicode_InternFromString((char*)#str))) \ + return false + +bool CPyCppyy::CreatePyStrings() { +// Build cache of commonly used python strings (the cache is python intern, so +// all strings are shared python-wide, not just in cppyy). + CPPYY_INITIALIZE_STRING(gBases, __assign__); + CPPYY_INITIALIZE_STRING(gBases, __bases__); + CPPYY_INITIALIZE_STRING(gBase, __base__); + CPPYY_INITIALIZE_STRING(gClass, __class__); + CPPYY_INITIALIZE_STRING(gCppEq, __cpp_eq__); + CPPYY_INITIALIZE_STRING(gCppNe, __cpp_ne__); + CPPYY_INITIALIZE_STRING(gDeref, __deref__); + CPPYY_INITIALIZE_STRING(gDict, __dict__); + if (!(PyStrings::gEmptyString = CPyCppyy_PyUnicode_FromString((char*)""))) + return false; + CPPYY_INITIALIZE_STRING(gEq, __eq__); + CPPYY_INITIALIZE_STRING(gFollow, __follow__); + CPPYY_INITIALIZE_STRING(gGetItem, __getitem__); + CPPYY_INITIALIZE_STRING(gInit, __init__); + CPPYY_INITIALIZE_STRING(gIter, __iter__); + CPPYY_INITIALIZE_STRING(gLen, __len__); + CPPYY_INITIALIZE_STRING(gLifeLine, __lifeline); + CPPYY_INITIALIZE_STRING(gModule, __module__); + CPPYY_INITIALIZE_STRING(gMRO, __mro__); + CPPYY_INITIALIZE_STRING(gName, __name__); + CPPYY_INITIALIZE_STRING(gNe, __ne__); + CPPYY_INITIALIZE_STRING(gTypeCode, typecode); + + CPPYY_INITIALIZE_STRING(gAdd, __add__); + CPPYY_INITIALIZE_STRING(gSub, __sub__); + CPPYY_INITIALIZE_STRING(gMul, __mul__); + CPPYY_INITIALIZE_STRING(gDiv, CPPYY__div__); + + CPPYY_INITIALIZE_STRING(gAt, at); + CPPYY_INITIALIZE_STRING(gBegin, begin); + CPPYY_INITIALIZE_STRING(gEnd, end); + CPPYY_INITIALIZE_STRING(gFirst, first); + CPPYY_INITIALIZE_STRING(gSecond, second); + CPPYY_INITIALIZE_STRING(gSize, size); + CPPYY_INITIALIZE_STRING(gTemplate, Template); + CPPYY_INITIALIZE_STRING(gVectorAt, _vector__at); + + CPPYY_INITIALIZE_STRING(gThisModule, cppyy); + + return true; +} + + +//----------------------------------------------------------------------------- +PyObject* CPyCppyy::DestroyPyStrings() { +// Remove all cached python strings. + Py_DECREF(PyStrings::gBases); PyStrings::gBases = nullptr; + Py_DECREF(PyStrings::gBase); PyStrings::gBase = nullptr; + Py_DECREF(PyStrings::gClass); PyStrings::gClass = nullptr; + Py_DECREF(PyStrings::gCppEq); PyStrings::gCppEq = nullptr; + Py_DECREF(PyStrings::gCppNe); PyStrings::gCppNe = nullptr; + Py_DECREF(PyStrings::gDeref); PyStrings::gDeref = nullptr; + Py_DECREF(PyStrings::gDict); PyStrings::gDict = nullptr; + Py_DECREF(PyStrings::gEmptyString); PyStrings::gEmptyString = nullptr; + Py_DECREF(PyStrings::gEq); PyStrings::gEq = nullptr; + Py_DECREF(PyStrings::gFollow); PyStrings::gFollow = nullptr; + Py_DECREF(PyStrings::gGetItem); PyStrings::gGetItem = nullptr; + Py_DECREF(PyStrings::gInit); PyStrings::gInit = nullptr; + Py_DECREF(PyStrings::gIter); PyStrings::gIter = nullptr; + Py_DECREF(PyStrings::gLen); PyStrings::gLen = nullptr; + Py_DECREF(PyStrings::gLifeLine); PyStrings::gLifeLine = nullptr; + Py_DECREF(PyStrings::gModule); PyStrings::gModule = nullptr; + Py_DECREF(PyStrings::gMRO); PyStrings::gMRO = nullptr; + Py_DECREF(PyStrings::gName); PyStrings::gName = nullptr; + Py_DECREF(PyStrings::gNe); PyStrings::gNe = nullptr; + Py_DECREF(PyStrings::gTypeCode); PyStrings::gTypeCode = nullptr; + + Py_DECREF(PyStrings::gAdd); PyStrings::gAdd = nullptr; + Py_DECREF(PyStrings::gSub); PyStrings::gSub = nullptr; + Py_DECREF(PyStrings::gMul); PyStrings::gMul = nullptr; + Py_DECREF(PyStrings::gDiv); PyStrings::gDiv = nullptr; + + Py_DECREF(PyStrings::gAt); PyStrings::gAt = nullptr; + Py_DECREF(PyStrings::gBegin); PyStrings::gBegin = nullptr; + Py_DECREF(PyStrings::gEnd); PyStrings::gEnd = nullptr; + Py_DECREF(PyStrings::gFirst); PyStrings::gFirst = nullptr; + Py_DECREF(PyStrings::gSecond); PyStrings::gSecond = nullptr; + Py_DECREF(PyStrings::gSize); PyStrings::gSize = nullptr; + Py_DECREF(PyStrings::gTemplate); PyStrings::gTemplate = nullptr; + Py_DECREF(PyStrings::gVectorAt); PyStrings::gVectorAt = nullptr; + + Py_DECREF(PyStrings::gThisModule); PyStrings::gThisModule = nullptr; + + Py_RETURN_NONE; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyStrings.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyStrings.h new file mode 100644 index 0000000000000..f7dcbeaf77b3a --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/PyStrings.h @@ -0,0 +1,55 @@ +#ifndef CPYCPPYY_PYSTRINGS_H +#define CPYCPPYY_PYSTRINGS_H + +namespace CPyCppyy { + +// python strings kept for performance reasons + +namespace PyStrings { + + extern PyObject* gAssign; + extern PyObject* gBases; + extern PyObject* gBase; + extern PyObject* gClass; + extern PyObject* gCppEq; + extern PyObject* gCppNe; + extern PyObject* gDeref; + extern PyObject* gDict; + extern PyObject* gEmptyString; + extern PyObject* gEq; + extern PyObject* gFollow; + extern PyObject* gGetItem; + extern PyObject* gInit; + extern PyObject* gIter; + extern PyObject* gLen; + extern PyObject* gLifeLine; + extern PyObject* gModule; + extern PyObject* gMRO; + extern PyObject* gName; + extern PyObject* gNe; + extern PyObject* gTypeCode; + + extern PyObject* gAdd; + extern PyObject* gSub; + extern PyObject* gMul; + extern PyObject* gDiv; + + extern PyObject* gAt; + extern PyObject* gBegin; + extern PyObject* gEnd; + extern PyObject* gFirst; + extern PyObject* gSecond; + extern PyObject* gSize; + extern PyObject* gTemplate; + extern PyObject* gVectorAt; + + extern PyObject* gThisModule; + +} // namespace PyStrings + +bool CreatePyStrings(); +PyObject* DestroyPyStrings(); + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_PYSTRINGS_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Pythonize.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Pythonize.cxx new file mode 100644 index 0000000000000..5c94788e2e969 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Pythonize.cxx @@ -0,0 +1,840 @@ +// Bindings +#include "CPyCppyy.h" +#include "Pythonize.h" +#include "Converters.h" +#include "CPPInstance.h" +#include "CPPOverload.h" +#include "ProxyWrappers.h" +#include "PyCallable.h" +#include "PyStrings.h" +#include "Utility.h" + +// Standard +#include +#include +#include + + +//- data and local helpers --------------------------------------------------- +namespace CPyCppyy { + extern PyObject* gThisModule; + extern std::map> gPythonizations; +} + +namespace { + +// for convenience +using namespace CPyCppyy; + +//----------------------------------------------------------------------------- +bool HasAttrDirect(PyObject* pyclass, PyObject* pyname, bool mustBeCPyCppyy = false) { +// prevents calls to Py_TYPE(pyclass)->tp_getattr, which is unnecessary for our +// purposes here and could tickle problems w/ spurious lookups into ROOT meta + PyObject* attr = PyType_Type.tp_getattro(pyclass, pyname); + if (attr != 0 && (!mustBeCPyCppyy || CPPOverload_Check(attr))) { + Py_DECREF(attr); + return true; + } + + PyErr_Clear(); + return false; +} + +//----------------------------------------------------------------------------- +inline bool IsTemplatedSTLClass(const std::string& name, const std::string& klass) { +// Scan the name of the class and determine whether it is a template instantiation. + const int nsize = (int)name.size(); + const int ksize = (int)klass.size(); + + return ((ksize < nsize && name.substr(0,ksize) == klass) || + (ksize+5 < nsize && name.substr(5,ksize) == klass)) && + name.find("::", name.find(">")) == std::string::npos; +} + +// to prevent compiler warnings about const char* -> char* +inline PyObject* CallPyObjMethod(PyObject* obj, const char* meth) +{ +// Helper; call method with signature: obj->meth(). + Py_INCREF(obj); + PyObject* result = PyObject_CallMethod(obj, const_cast(meth), const_cast("")); + Py_DECREF(obj); + return result; +} + +//----------------------------------------------------------------------------- +inline PyObject* CallPyObjMethod(PyObject* obj, const char* meth, PyObject* arg1) +{ +// Helper; call method with signature: obj->meth(arg1). + Py_INCREF(obj); + PyObject* result = PyObject_CallMethod( + obj, const_cast(meth), const_cast("O"), arg1); + Py_DECREF(obj); + return result; +} + + +//- helpers -------------------------------------------------------------------- +static std::string ExtractNamespace(const std::string& name) +{ +// Find the namespace the named class lives in, take care of templates + int tpl_open = 0; + for (std::string::size_type pos = name.size()-1; 0 < pos; --pos) { + std::string::value_type c = name[pos]; + + // count '<' and '>' to be able to skip template contents + if (c == '>') + ++tpl_open; + else if (c == '<') + --tpl_open; + + // collect name up to "::" + else if (tpl_open == 0 && c == ':' && name[pos-1] == ':') { + // found the extend of the scope ... done + return name.substr(0, pos-1); + } + } + +// no namespace; assume outer scope + return ""; +} + +//----------------------------------------------------------------------------- +PyObject* PyStyleIndex(PyObject* self, PyObject* index) +{ +// Helper; converts python index into straight C index. + Py_ssize_t idx = PyInt_AsSsize_t(index); + if (idx == (Py_ssize_t)-1 && PyErr_Occurred()) + return nullptr; + + Py_ssize_t size = PySequence_Size(self); + if (idx >= size || (idx < 0 && idx < -size)) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return nullptr; + } + + PyObject* pyindex = nullptr; + if (idx >= 0) { + Py_INCREF(index); + pyindex = index; + } else + pyindex = PyLong_FromLong(size+idx); + + return pyindex; +} + +//----------------------------------------------------------------------------- +inline PyObject* CallSelfIndex(CPPInstance* self, PyObject* idx, const char* meth) +{ +// Helper; call method with signature: meth(pyindex). + Py_INCREF((PyObject*)self); + PyObject* pyindex = PyStyleIndex((PyObject*)self, idx); + if (!pyindex) { + Py_DECREF((PyObject*)self); + return nullptr; + } + + PyObject* result = CallPyObjMethod((PyObject*)self, meth, pyindex); + Py_DECREF(pyindex); + Py_DECREF((PyObject*)self); + return result; +} + +//- "smart pointer" behavior --------------------------------------------------- +PyObject* DeRefGetAttr(PyObject* self, PyObject* name) +{ +// Follow operator*() if present (available in python as __deref__), so that +// smart pointers behave as expected. + if (!CPyCppyy_PyUnicode_Check(name)) + PyErr_SetString(PyExc_TypeError, "getattr(): attribute name must be string"); + + PyObject* pyptr = CallPyObjMethod(self, "__deref__"); + if (!pyptr) + return nullptr; + +// prevent a potential infinite loop + if (Py_TYPE(pyptr) == Py_TYPE(self)) { + PyObject* val1 = PyObject_Str(self); + PyObject* val2 = PyObject_Str(name); + PyErr_Format(PyExc_AttributeError, "%s has no attribute \'%s\'", + CPyCppyy_PyUnicode_AsString(val1), CPyCppyy_PyUnicode_AsString(val2)); + Py_DECREF(val2); + Py_DECREF(val1); + + Py_DECREF(pyptr); + return nullptr; + } + + PyObject* result = PyObject_GetAttr(pyptr, name); + Py_DECREF(pyptr); + return result; +} + +//----------------------------------------------------------------------------- +PyObject* FollowGetAttr(PyObject* self, PyObject* name) +{ +// Follow operator->() if present (available in python as __follow__), so that +// smart pointers behave as expected. + if (!CPyCppyy_PyUnicode_Check(name)) + PyErr_SetString(PyExc_TypeError, "getattr(): attribute name must be string"); + + PyObject* pyptr = CallPyObjMethod(self, "__follow__"); + if (!pyptr) + return nullptr; + + PyObject* result = PyObject_GetAttr(pyptr, name); + Py_DECREF(pyptr); + return result; +} + +//----------------------------------------------------------------------------- +PyObject* GenObjectIsEqual(PyObject* self, PyObject* obj) +{ +// Call the C++ operator==() if available, otherwise default. + PyObject* result = CallPyObjMethod(self, "__cpp_eq__", obj); + if (result) + return result; + +// failed: fallback like python would do by reversing the arguments + PyErr_Clear(); + result = CallPyObjMethod(obj, "__cpp_eq__", self); + if (result) + return result; + +// failed: fallback to generic rich comparison + PyErr_Clear(); + return CPPInstance_Type.tp_richcompare(self, obj, Py_EQ); +} + +//----------------------------------------------------------------------------- +PyObject* GenObjectIsNotEqual(PyObject* self, PyObject* obj) +{ +// Reverse of GenObjectIsEqual, if operator!= defined. + PyObject* result = CallPyObjMethod(self, "__cpp_ne__", obj); + if (result) + return result; + +// failed: fallback like python would do by reversing the arguments + PyErr_Clear(); + result = CallPyObjMethod(obj, "__cpp_ne__", self); + if (result) + return result; + +// failed: fallback to generic rich comparison + PyErr_Clear(); + return CPPInstance_Type.tp_richcompare(self, obj, Py_NE); +} + +//- vector behavior as primitives ---------------------------------------------- +typedef struct { + PyObject_HEAD + PyObject* vi_vector; + void* vi_data; + CPyCppyy::Converter* vi_converter; + Py_ssize_t vi_pos; + Py_ssize_t vi_len; + Py_ssize_t vi_stride; +} vectoriterobject; + +static void vectoriter_dealloc(vectoriterobject* vi) { + Py_XDECREF(vi->vi_vector); + delete vi->vi_converter; + PyObject_GC_Del(vi); +} + +static int vectoriter_traverse(vectoriterobject* vi, visitproc visit, void* arg) { + Py_VISIT(vi->vi_vector); + return 0; +} + +static PyObject* vectoriter_iternext(vectoriterobject* vi) { + if (vi->vi_pos >= vi->vi_len) + return nullptr; + + PyObject* result = nullptr; + + if (vi->vi_data && vi->vi_converter) { + void* location = (void*)((ptrdiff_t)vi->vi_data + vi->vi_stride * vi->vi_pos); + result = vi->vi_converter->FromMemory(location); + } else { + PyObject* pyindex = PyLong_FromLong(vi->vi_pos); + result = CallPyObjMethod((PyObject*)vi->vi_vector, "_vector__at", pyindex); + Py_DECREF(pyindex); + } + + vi->vi_pos += 1; + return result; +} + +PyTypeObject VectorIter_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + (char*)"cppyy.vectoriter", // tp_name + sizeof(vectoriterobject), // tp_basicsize + 0, + (destructor)vectoriter_dealloc, // tp_dealloc + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_HAVE_GC, // tp_flags + 0, + (traverseproc)vectoriter_traverse, // tp_traverse + 0, 0, 0, + PyObject_SelfIter, // tp_iter + (iternextfunc)vectoriter_iternext, // tp_iternext + 0, // tp_methods + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +static PyObject* vector_iter(PyObject* v) { + vectoriterobject* vi = PyObject_GC_New(vectoriterobject, &VectorIter_Type); + if (!vi) return nullptr; + + Py_INCREF(v); + vi->vi_vector = v; + + PyObject* pyvalue_type = PyObject_GetAttrString((PyObject*)Py_TYPE(v), "value_type"); + PyObject* pyvalue_size = PyObject_GetAttrString((PyObject*)Py_TYPE(v), "value_size"); + + if (pyvalue_type && pyvalue_size) { + PyObject* pydata = CallPyObjMethod(v, "data"); + if (!pydata || Utility::GetBuffer(pydata, '*', 1, vi->vi_data, false) == 0) + vi->vi_data = nullptr; + Py_XDECREF(pydata); + + vi->vi_converter = CPyCppyy::CreateConverter(CPyCppyy_PyUnicode_AsString(pyvalue_type)); + vi->vi_stride = PyLong_AsLong(pyvalue_size); + } else { + PyErr_Clear(); + vi->vi_data = nullptr; + vi->vi_converter = nullptr; + vi->vi_stride = 0; + } + + Py_XDECREF(pyvalue_size); + Py_XDECREF(pyvalue_type); + + vi->vi_len = vi->vi_pos = 0; + vi->vi_len = PySequence_Size(v); + + _PyObject_GC_TRACK(vi); + return (PyObject*)vi; +} + +PyObject* VectorGetItem(CPPInstance* self, PySliceObject* index) +{ +// Implement python's __getitem__ for std::vector<>s. + if (PySlice_Check(index)) { + if (!self->GetObject()) { + PyErr_SetString(PyExc_TypeError, "unsubscriptable object"); + return nullptr; + } + + PyObject* pyclass = PyObject_GetAttr((PyObject*)self, PyStrings::gClass); + PyObject* nseq = PyObject_CallObject(pyclass, nullptr); + Py_DECREF(pyclass); + + Py_ssize_t start, stop, step; + PySlice_GetIndices((CPyCppyy_PySliceCast)index, PyObject_Length((PyObject*)self), &start, &stop, &step); + for (Py_ssize_t i = start; i < stop; i += step) { + PyObject* pyidx = PyInt_FromSsize_t(i); + CallPyObjMethod(nseq, "push_back", CallPyObjMethod((PyObject*)self, "_vector__at", pyidx)); + Py_DECREF(pyidx); + } + + return nseq; + } + + return CallSelfIndex(self, (PyObject*)index, "_vector__at"); +} + + +static Cppyy::TCppType_t sVectorBoolTypeID = (Cppyy::TCppType_t)0; + +PyObject* VectorBoolGetItem(CPPInstance* self, PyObject* idx) +{ +// std::vector is a special-case in C++, and its return type depends on +// the compiler: treat it special here as well + if (!CPPInstance_Check(self) || self->ObjectIsA() != sVectorBoolTypeID) { + PyErr_Format(PyExc_TypeError, + "require object of type std::vector, but %s given", + Cppyy::GetScopedFinalName(self->ObjectIsA()).c_str()); + return nullptr; + } + + if (!self->GetObject()) { + PyErr_SetString(PyExc_TypeError, "unsubscriptable object"); + return nullptr; + } + + if (PySlice_Check(idx)) { + PyObject* pyclass = PyObject_GetAttr((PyObject*)self, PyStrings::gClass); + PyObject* nseq = PyObject_CallObject(pyclass, nullptr); + Py_DECREF(pyclass); + + Py_ssize_t start, stop, step; + PySlice_GetIndices((CPyCppyy_PySliceCast)idx, PyObject_Length((PyObject*)self), &start, &stop, &step); + for (Py_ssize_t i = start; i < stop; i += step) { + PyObject* pyidx = PyInt_FromSsize_t(i); + CallPyObjMethod(nseq, "push_back", CallPyObjMethod((PyObject*)self, "__getitem__", pyidx)); + Py_DECREF(pyidx); + } + + return nseq; + } + + PyObject* pyindex = PyStyleIndex((PyObject*)self, idx); + if (!pyindex) + return nullptr; + + int index = (int)PyLong_AsLong(pyindex); + Py_DECREF(pyindex); + +// get hold of the actual std::vector (no cast, as vector is never a base) + std::vector* vb = (std::vector*)self->GetObject(); + +// finally, return the value + if (bool((*vb)[index])) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +PyObject* VectorBoolSetItem(CPPInstance* self, PyObject* args) +{ +// std::vector is a special-case in C++, and its return type depends on +// the compiler: treat it special here as well + if (!CPPInstance_Check(self) || self->ObjectIsA() != sVectorBoolTypeID) { + PyErr_Format(PyExc_TypeError, + "require object of type std::vector, but %s given", + Cppyy::GetScopedFinalName(self->ObjectIsA()).c_str()); + return nullptr; + } + + if (!self->GetObject()) { + PyErr_SetString(PyExc_TypeError, "unsubscriptable object"); + return nullptr; + } + + int bval = 0; PyObject* idx = nullptr; + if (!PyArg_ParseTuple(args, const_cast("Oi:__setitem__"), &idx, &bval)) + return nullptr; + + PyObject* pyindex = PyStyleIndex((PyObject*)self, idx); + if (!pyindex) + return nullptr; + + int index = (int)PyLong_AsLong(pyindex); + Py_DECREF(pyindex); + +// get hold of the actual std::vector (no cast, as vector is never a base) + std::vector* vb = (std::vector*)self->GetObject(); + +// finally, set the value + (*vb)[index] = (bool)bval; + + Py_RETURN_NONE; +} + +//- map behavior as primitives ------------------------------------------------ +PyObject* MapContains(PyObject* self, PyObject* obj) +{ +// Implement python's __contains__ for std::map<>s. + PyObject* result = nullptr; + + PyObject* iter = CallPyObjMethod(self, "find", obj); + if (CPPInstance_Check(iter)) { + PyObject* end = CallPyObjMethod(self, "end"); + if (CPPInstance_Check(end)) { + if (!PyObject_RichCompareBool(iter, end, Py_EQ)) { + Py_INCREF(Py_True); + result = Py_True; + } + } + Py_XDECREF(end); + } + Py_XDECREF(iter); + + if (!result) { + PyErr_Clear(); // e.g. wrong argument type, which should always lead to False + Py_INCREF(Py_False); + result = Py_False; + } + + return result; +} + +//- STL container iterator support -------------------------------------------- +PyObject* StlSequenceIter(PyObject* self) +{ +// Implement python's __iter__ for std::iterator<>s. + PyObject* iter = CallPyObjMethod(self, "begin"); + if (iter) { + PyObject* end = CallPyObjMethod(self, "end"); + if (end) + PyObject_SetAttr(iter, PyStrings::gEnd, end); + Py_XDECREF(end); + + // add iterated collection as attribute so its refcount stays >= 1 while it's being iterated over + PyObject_SetAttr(iter, PyUnicode_FromString("_collection"), self); + } + return iter; +} + +//- safe indexing for STL-like vector w/o iterator dictionaries --------------- +/* +PyObject* CheckedGetItem(PyObject* self, PyObject* obj) +{ +// Implement a generic python __getitem__ for std::vector<>s that are missing +// their std::vector<>::iterator dictionary. This is then used for iteration +// by means of consecutive index. + bool inbounds = false; + Py_ssize_t size = PySequence_Size(self); + Py_ssize_t idx = PyInt_AsSsize_t(obj); + if (0 <= idx && 0 <= size && idx < size) + inbounds = true; + + if (inbounds) { + return CallPyObjMethod(self, "_getitem__unchecked", obj); + } else if (PyErr_Occurred()) { + // argument conversion problem: let method itself resolve anew and report + PyErr_Clear(); + return CallPyObjMethod(self, "_getitem__unchecked", obj); + } else { + PyErr_SetString(PyExc_IndexError, "index out of range"); + } + + return nullptr; +} +*/ + +//- pair as sequence to allow tuple unpacking -------------------------------- +PyObject* PairUnpack(PyObject* self, PyObject* pyindex) +{ +// For std::map<> iteration, unpack std::pair<>s into tuples for the loop. + long idx = PyLong_AsLong(pyindex); + if (idx == -1 && PyErr_Occurred()) + return nullptr; + + if (!CPPInstance_Check(self) || !((CPPInstance*)self)->GetObject()) { + PyErr_SetString(PyExc_TypeError, "unsubscriptable object"); + return nullptr; + } + + if ((int)idx == 0) + return PyObject_GetAttr(self, PyStrings::gFirst); + else if ((int)idx == 1) + return PyObject_GetAttr(self, PyStrings::gSecond); + +// still here? Trigger stop iteration + PyErr_SetString(PyExc_IndexError, "out of bounds"); + return nullptr; +} + +//- simplistic len() functions ----------------------------------------------- +PyObject* ReturnTwo(CPPInstance*, PyObject*) { + return PyInt_FromLong(2); +} + +//- string behavior as primitives -------------------------------------------- +#if PY_VERSION_HEX >= 0x03000000 +// TODO: this is wrong, b/c it doesn't order +static int PyObject_Compare(PyObject* one, PyObject* other) { + return !PyObject_RichCompareBool(one, other, Py_EQ); +} +#endif +static inline PyObject* CPyCppyy_PyString_FromCppString(std::string* s) { + return CPyCppyy_PyUnicode_FromStringAndSize(s->c_str(), s->size()); +} + +#define CPPYY_IMPL_STRING_PYTHONIZATION(type, name) \ +inline PyObject* name##GetData(PyObject* self) \ +{ \ + if (CPyCppyy::CPPInstance_Check(self)) { \ + type* obj = ((type*)((CPPInstance*)self)->GetObject()); \ + if (obj) { \ + return CPyCppyy_PyString_FromCppString(obj); \ + } else { \ + return CPPInstance_Type.tp_str(self); \ + } \ + } \ + PyErr_Format(PyExc_TypeError, "object mismatch (%s expected)", #type); \ + return nullptr; \ +} \ + \ +PyObject* name##StringRepr(PyObject* self) \ +{ \ + PyObject* data = name##GetData(self); \ + if (data) { \ + PyObject* repr = CPyCppyy_PyUnicode_FromFormat("\'%s\'", CPyCppyy_PyUnicode_AsString(data));\ + Py_DECREF(data); \ + return repr; \ + } \ + return nullptr; \ +} \ + \ +PyObject* name##StringIsEqual(PyObject* self, PyObject* obj) \ +{ \ + PyObject* data = name##GetData(self); \ + if (data) { \ + PyObject* result = PyObject_RichCompare(data, obj, Py_EQ); \ + Py_DECREF(data); \ + return result; \ + } \ + return nullptr; \ +} \ + \ +PyObject* name##StringIsNotEqual(PyObject* self, PyObject* obj) \ +{ \ + PyObject* data = name##GetData(self); \ + if (data) { \ + PyObject* result = PyObject_RichCompare(data, obj, Py_NE); \ + Py_DECREF(data); \ + return result; \ + } \ + return nullptr; \ +} + +// Only define StlStringCompare: +#define CPPYY_IMPL_STRING_PYTHONIZATION_CMP(type, name) \ +CPPYY_IMPL_STRING_PYTHONIZATION(type, name) \ +PyObject* name##StringCompare(PyObject* self, PyObject* obj) \ +{ \ + PyObject* data = name##GetData(self); \ + int result = 0; \ + if (data) { \ + result = PyObject_Compare(data, obj); \ + Py_DECREF(data); \ + } \ + if (PyErr_Occurred()) \ + return nullptr; \ + return PyInt_FromLong(result); \ +} + +CPPYY_IMPL_STRING_PYTHONIZATION_CMP(std::string, Stl) + + +//- STL iterator behavior ---------------------------------------------------- +PyObject* StlIterNext(PyObject* self) +{ +// Python iterator protocol __next__ for STL forward iterators. + PyObject* next = nullptr; + PyObject* last = PyObject_GetAttr(self, PyStrings::gEnd); + + if (last) { + // handle special case of empty container (i.e. self is end) + if (PyObject_RichCompareBool(last, self, Py_EQ)) { + PyErr_SetString(PyExc_StopIteration, ""); + } else { + PyObject* dummy = PyInt_FromLong(1l); + PyObject* iter = CallPyObjMethod(self, "__postinc__", dummy); + Py_DECREF(dummy); + if (iter != 0) { + if (PyObject_RichCompareBool(last, iter, Py_EQ)) + PyErr_SetString(PyExc_StopIteration, ""); + else + next = CallPyObjMethod(iter, "__deref__"); + } else { + PyErr_SetString(PyExc_StopIteration, ""); + } + Py_XDECREF(iter); + } + } else { + PyErr_SetString(PyExc_StopIteration, ""); + } + + Py_XDECREF(last); + return next; +} + +//---------------------------------------------------------------------------- +PyObject* StlIterIsEqual(PyObject* self, PyObject* other) +{ +// Called if operator== not available (e.g. if a global overload as under gcc). +// An exception is raised as the user should fix the dictionary. + return PyErr_Format(PyExc_LookupError, + "No operator==(const %s&, const %s&) available in the dictionary!", + Utility::ClassName(self).c_str(), Utility::ClassName(other).c_str()); +} + +//---------------------------------------------------------------------------- +PyObject* StlIterIsNotEqual(PyObject* self, PyObject* other) +{ +// Called if operator!= not available (e.g. if a global overload as under gcc). +// An exception is raised as the user should fix the dictionary. + return PyErr_Format(PyExc_LookupError, + "No operator!=(const %s&, const %s&) available in the dictionary!", + Utility::ClassName(self).c_str(), Utility::ClassName(other).c_str()); +} + +} // unnamed namespace + + +//- public functions --------------------------------------------------------- +bool CPyCppyy::Pythonize(PyObject* pyclass, const std::string& name) +{ +// Add pre-defined pythonizations (for STL and ROOT) to classes based on their +// signature and/or class name. + if (!pyclass) + return false; + +//- method name based pythonization ------------------------------------------ + +// for smart pointer style classes (note fall-through) + if (HasAttrDirect(pyclass, PyStrings::gDeref)) { + Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)DeRefGetAttr, METH_O); + } else if (HasAttrDirect(pyclass, PyStrings::gFollow)) { + Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)FollowGetAttr, METH_O); + } + +// for STL containers, and user classes modeled after them + if (HasAttrDirect(pyclass, PyStrings::gSize)) + Utility::AddToClass(pyclass, "__len__", "size"); + + if (!IsTemplatedSTLClass(name, "vector")) { // vector is dealt with below + if (HasAttrDirect(pyclass, PyStrings::gBegin) && HasAttrDirect(pyclass, PyStrings::gEnd)) { + // TODO: check whether iterator type is available + + // if yes: install iterator protocol + ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)StlSequenceIter; + Utility::AddToClass(pyclass, "__iter__", (PyCFunction) StlSequenceIter, METH_NOARGS); + + // if not and if (HasAttrDirect(pyclass, PyStrings::gGetItem) && HasAttrDirect(pyclass, PyStrings::gLen)) { + // install increment until StopIteration "protocol" + //Utility::AddToClass(pyclass, "_getitem__unchecked", "__getitem__"); + //Utility::AddToClass(pyclass, "__getitem__", (PyCFunction) CheckedGetItem, METH_O); + } + } + +// search for global comparator overloads (may fail; not sure whether it isn't better to +// do this lazily just as is done for math operators, but this interplays nicely with the +// generic versions) + Utility::AddBinaryOperator(pyclass, "==", "__eq__"); + Utility::AddBinaryOperator(pyclass, "!=", "__ne__"); + +// map operator==() through GenObjectIsEqual to allow comparison to None (true is to +// require that the located method is a CPPOverload; this prevents circular calls as +// GenObjectIsEqual is no CPPOverload) + if (HasAttrDirect(pyclass, PyStrings::gEq, true)) { + Utility::AddToClass(pyclass, "__cpp_eq__", "__eq__"); + Utility::AddToClass(pyclass, "__eq__", (PyCFunction)GenObjectIsEqual, METH_O); + } + +// map operator!=() through GenObjectIsNotEqual to allow comparison to None (see note +// on true above for __eq__) + if (HasAttrDirect(pyclass, PyStrings::gNe, true)) { + Utility::AddToClass(pyclass, "__cpp_ne__", "__ne__"); + Utility::AddToClass(pyclass, "__ne__", (PyCFunction)GenObjectIsNotEqual, METH_O); + } + + +//- class name based pythonization ------------------------------------------- + + if (IsTemplatedSTLClass(name, "vector")) { + + // std::vector is a special case in C++ + if (!sVectorBoolTypeID) sVectorBoolTypeID = (Cppyy::TCppType_t)Cppyy::GetScope("std::vector"); + if (CPPScope_Check(pyclass) && ((CPPClass*)pyclass)->fCppType == sVectorBoolTypeID) { + Utility::AddToClass(pyclass, "__getitem__", (PyCFunction)VectorBoolGetItem, METH_O); + Utility::AddToClass(pyclass, "__setitem__", (PyCFunction)VectorBoolSetItem); + } else { + + if (HasAttrDirect(pyclass, PyStrings::gLen) && HasAttrDirect(pyclass, PyStrings::gAt)) { + Utility::AddToClass(pyclass, "_vector__at", "at"); + // remove iterator that was set earlier (checked __getitem__ will do the trick) + if (HasAttrDirect(pyclass, PyStrings::gIter)) + PyObject_DelAttr(pyclass, PyStrings::gIter); + } else if (HasAttrDirect(pyclass, PyStrings::gGetItem)) { + Utility::AddToClass(pyclass, "_vector__at", "__getitem__"); // unchecked! + } + + // vector-optimized iterator protocol + ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)vector_iter; + + // helpers for iteration + /*TODO: remove this use of gInterpreter + TypedefInfo_t* ti = gInterpreter->TypedefInfo_Factory((name+"::value_type").c_str()); + if (gInterpreter->TypedefInfo_IsValid(ti)) { + PyObject* pyvalue_size = PyLong_FromLong(gInterpreter->TypedefInfo_Size(ti)); + PyObject_SetAttrString(pyclass, "value_size", pyvalue_size); + Py_DECREF(pyvalue_size); + + PyObject* pyvalue_type = CPyCppyy_PyUnicode_FromString(gInterpreter->TypedefInfo_TrueName(ti)); + PyObject_SetAttrString(pyclass, "value_type", pyvalue_type); + Py_DECREF(pyvalue_type); + } + gInterpreter->TypedefInfo_Delete(ti); + */ + + // provide a slice-able __getitem__, if possible + if (HasAttrDirect(pyclass, PyStrings::gVectorAt)) + Utility::AddToClass(pyclass, "__getitem__", (PyCFunction)VectorGetItem, METH_O); + } + } + + else if (IsTemplatedSTLClass(name, "map")) { + Utility::AddToClass(pyclass, "__contains__", (PyCFunction)MapContains, METH_O); + } + + else if (IsTemplatedSTLClass(name, "pair")) { + Utility::AddToClass(pyclass, "__getitem__", (PyCFunction)PairUnpack, METH_O); + Utility::AddToClass(pyclass, "__len__", (PyCFunction)ReturnTwo, METH_NOARGS); + } + + else if (name.find("iterator") != std::string::npos) { + ((PyTypeObject*)pyclass)->tp_iternext = (iternextfunc)StlIterNext; + Utility::AddToClass(pyclass, CPPYY__next__, (PyCFunction)StlIterNext, METH_NOARGS); + + // special case, if operator== is a global overload and included in the dictionary + if (!HasAttrDirect(pyclass, PyStrings::gCppEq, true)) + Utility::AddToClass(pyclass, "__eq__", (PyCFunction)StlIterIsEqual, METH_O); + if (!HasAttrDirect(pyclass, PyStrings::gCppNe, true)) + Utility::AddToClass(pyclass, "__ne__", (PyCFunction)StlIterIsNotEqual, METH_O); + } + + else if (name == "string" || name == "std::string") { // TODO: ask backend as well + Utility::AddToClass(pyclass, "__repr__", (PyCFunction)StlStringRepr, METH_NOARGS); + Utility::AddToClass(pyclass, "__str__", "c_str"); + Utility::AddToClass(pyclass, "__cmp__", (PyCFunction)StlStringCompare, METH_O); + Utility::AddToClass(pyclass, "__eq__", (PyCFunction)StlStringIsEqual, METH_O); + Utility::AddToClass(pyclass, "__ne__", (PyCFunction)StlStringIsNotEqual, METH_O); + } + + PyObject* args = PyTuple_New(2); + Py_INCREF(pyclass); + PyTuple_SET_ITEM(args, 0, pyclass); + + std::string outer_scope = ExtractNamespace(name); + + bool pstatus = true; + auto p = outer_scope.empty() ? gPythonizations.end() : gPythonizations.find(outer_scope); + if (p == gPythonizations.end()) { + p = gPythonizations.find(""); + PyTuple_SET_ITEM(args, 1, CPyCppyy_PyUnicode_FromString(name.c_str())); + } else { + PyTuple_SET_ITEM(args, 1, CPyCppyy_PyUnicode_FromString( + name.substr(outer_scope.size()+2, std::string::npos).c_str())); + } + + if (p != gPythonizations.end()) { + for (auto pythonizor : p->second) { + PyObject* result = PyObject_CallObject(pythonizor, args); + if (!result) { + // TODO: detail error handling for the pythonizors + pstatus = false; + break; + } + Py_DECREF(result); + } + } + + Py_DECREF(args); + +// phew! all done ... + return pstatus; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Pythonize.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Pythonize.h new file mode 100644 index 0000000000000..cbdec834a24cd --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Pythonize.h @@ -0,0 +1,15 @@ +#ifndef CPYCPPYY_PYTHONIZE_H +#define CPYCPPYY_PYTHONIZE_H + +// Standard +#include + + +namespace CPyCppyy { + +// make the named C++ class more python-like +bool Pythonize(PyObject* pyclass, const std::string& name); + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_PYTHONIZE_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyArg.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyArg.cxx new file mode 100644 index 0000000000000..2061ac5b47e46 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyArg.cxx @@ -0,0 +1,129 @@ +// Bindings +#include "CPyCppyy.h" +#include "TPyArg.h" + + +//______________________________________________________________________________ +// Generic wrapper for arguments +// ============================= +// +// Transport class for bringing C++ values and objects from Cling to Python. It +// provides, from the selected constructor, the proper conversion to a PyObject. +// In principle, there should be no need to use this class directly: it relies +// on implicit conversions. + + +//- constructor dispatcher --------------------------------------------------- +void TPyArg::CallConstructor( + PyObject*& pyself, PyObject* pyclass, const std::vector& args) +{ + int nArgs = args.size(); + PyObject* pyargs = PyTuple_New(nArgs); + for (int i = 0; i < nArgs; ++i) + PyTuple_SET_ITEM(pyargs, i, (PyObject*)args[i]); + pyself = PyObject_Call(pyclass, pyargs, nullptr); + Py_DECREF(pyargs); +} + +//---------------------------------------------------------------------------- +void CallConstructor(PyObject*& pyself, PyObject* pyclass) +{ + PyObject* pyargs = PyTuple_New(0); + pyself = PyObject_Call(pyclass, pyargs, nullptr); + Py_DECREF(pyargs); +} + +//- generic dispatcher ------------------------------------------------------- +PyObject* TPyArg::CallMethod(PyObject* pymeth, const std::vector& args) +{ + int nArgs = args.size(); + PyObject* pyargs = PyTuple_New(nArgs); + for (int i = 0; i < nArgs; ++i) + PyTuple_SET_ITEM(pyargs, i, (PyObject*)args[i]); + PyObject* result = PyObject_Call(pymeth, pyargs, nullptr); + Py_DECREF(pyargs); + return result; +} + +//- destructor dispatcher ---------------------------------------------------- +void TPyArg::CallDestructor(PyObject*& pyself, PyObject*, const std::vector&) +{ + Py_XDECREF(pyself); // calls actual dtor if ref-count down to 0 +} + +//---------------------------------------------------------------------------- +void TPyArg::CallDestructor(PyObject*& pyself) +{ + Py_XDECREF(pyself); +} + +//- constructors/destructor -------------------------------------------------- +TPyArg::TPyArg(PyObject* pyobject) +{ +// Construct a TPyArg from a python object. + Py_XINCREF(pyobject); + fPyObject = pyobject; +} + +//---------------------------------------------------------------------------- +TPyArg::TPyArg(int value) +{ +// Construct a TPyArg from an integer value. + fPyObject = PyInt_FromLong(value); +} + +//---------------------------------------------------------------------------- +TPyArg::TPyArg(long value) +{ +// Construct a TPyArg from an integer value. + fPyObject = PyLong_FromLong(value); +} + +//---------------------------------------------------------------------------- +TPyArg::TPyArg(double value) +{ +// Construct a TPyArg from a double value. + fPyObject = PyFloat_FromDouble(value); +} + +//---------------------------------------------------------------------------- +TPyArg::TPyArg(const char* value) +{ +// Construct a TPyArg from a C-string. + fPyObject = CPyCppyy_PyUnicode_FromString(value); +} + +//---------------------------------------------------------------------------- +TPyArg::TPyArg(const TPyArg& s) +{ +// Copy constructor. + Py_XINCREF(s.fPyObject); + fPyObject = s.fPyObject; +} + +//---------------------------------------------------------------------------- +TPyArg& TPyArg::operator=(const TPyArg& s) +{ +// Assignment operator. + if (this != &s) { + Py_XINCREF(s.fPyObject); + fPyObject = s.fPyObject; + } + return *this; +} + +//---------------------------------------------------------------------------- +TPyArg::~TPyArg() +{ +// Done with held PyObject. + Py_XDECREF(fPyObject); + fPyObject = nullptr; +} + +//- public members ----------------------------------------------------------- +TPyArg::operator PyObject*() const +{ +// Extract the python object. + Py_XINCREF(fPyObject); + return fPyObject; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyClassGenerator.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyClassGenerator.cxx new file mode 100644 index 0000000000000..e07f86af869a7 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyClassGenerator.cxx @@ -0,0 +1,300 @@ +// Bindings +#include "CPyCppyy.h" +#include "PyStrings.h" +#include "TPyClassGenerator.h" +#include "TPyReturn.h" +#include "Utility.h" + +// TODO: not sure if any of this still makes sense ... +#if 0 + +// ROOT +#include "TClass.h" +#include "TInterpreter.h" +#include "TROOT.h" + +// Standard +#include +#include +#include + + +//= helper ================================================================== +namespace { + + class PyGILRAII { + PyGILState_STATE m_GILState; + public: + PyGILRAII() : m_GILState(PyGILState_Ensure()) {} + ~PyGILRAII() { PyGILState_Release(m_GILState); } + }; + +} // unnamed namespace + + +//- public members ----------------------------------------------------------- +TClass* TPyClassGenerator::GetClass( const char* name, bool load ) +{ +// Just forward. + return GetClass( name, load, false ); +} + +//- public members ----------------------------------------------------------- +TClass* TPyClassGenerator::GetClass( const char* name, bool load, bool silent ) +{ +// Class generator to make python classes available to Cling + +// called if all other class generators failed, attempt to build from python class + if ( PyROOT::gDictLookupActive == true ) + return 0; // call originated from python + + if ( ! load || ! name ) + return 0; + + PyGILRAII thePyGILRAII; + +// first, check whether the name is of a module + PyObject* modules = PySys_GetObject( const_cast("modules") ); + PyObject* pyname = PyROOT_PyUnicode_FromString( name ); + PyObject* keys = PyDict_Keys( modules ); + bool isModule = PySequence_Contains( keys, pyname ); + Py_DECREF( keys ); + Py_DECREF( pyname ); + + if ( isModule ) { + // the normal TClass::GetClass mechanism doesn't allow direct returns, so + // do our own check + TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject( name ); + if ( cl ) return cl; + + std::ostringstream nsCode; + nsCode << "namespace " << name << " {\n"; + + // add all free functions + PyObject* mod = PyDict_GetItemString( modules, const_cast(name) ); + PyObject* dct = PyModule_GetDict( mod ); + keys = PyDict_Keys( dct ); + + for ( int i = 0; i < PyList_GET_SIZE( keys ); ++i ) { + PyObject* key = PyList_GET_ITEM( keys, i ); + Py_INCREF( key ); + + PyObject* attr = PyDict_GetItem( dct, key ); + Py_INCREF( attr ); + + // TODO: refactor the code below with the class method code + if ( PyCallable_Check( attr ) && \ + ! (PyClass_Check( attr ) || PyObject_HasAttr( attr, PyROOT::PyStrings::gBases )) ) { + std::string func_name = PyROOT_PyUnicode_AsString( key ); + + // figure out number of variables required + PyObject* func_code = PyObject_GetAttrString( attr, (char*)"func_code" ); + PyObject* var_names = + func_code ? PyObject_GetAttrString( func_code, (char*)"co_varnames" ) : NULL; + int nVars = var_names ? PyTuple_GET_SIZE( var_names ) : 0 /* TODO: probably large number, all default? */; + if ( nVars < 0 ) nVars = 0; + Py_XDECREF( var_names ); + Py_XDECREF( func_code ); + + nsCode << " TPyReturn " << func_name << "("; + for ( int ivar = 0; ivar < nVars; ++ivar ) { + nsCode << "const TPyArg& a" << ivar; + if ( ivar != nVars-1 ) nsCode << ", "; + } + nsCode << ") {\n"; + nsCode << " std::vector v; v.reserve(" << nVars << ");\n"; + + // add the variables + for ( int ivar = 0; ivar < nVars; ++ ivar ) + nsCode << " v.push_back(a" << ivar << ");\n"; + + // call dispatch (method or class pointer hard-wired) + nsCode << " return TPyReturn(TPyArg::CallMethod((PyObject*)" << (void*)attr << ", v)); }\n"; + } + + Py_DECREF( attr ); + Py_DECREF( key ); + } + + Py_DECREF( keys ); + + nsCode << " }"; + + if ( gInterpreter->LoadText( nsCode.str().c_str() ) ) { + TClass* klass = new TClass( name, silent ); + TClass::AddClass( klass ); + return klass; + } + + return nullptr; + } + +// determine module and class name part + std::string clName = name; + std::string::size_type pos = clName.rfind( '.' ); + + if ( pos == std::string::npos ) + return 0; // this isn't a python style class + + std::string mdName = clName.substr( 0, pos ); + clName = clName.substr( pos+1, std::string::npos ); + +// create class in namespace, if it exists (no load, silent) + bool useNS = gROOT->GetListOfClasses()->FindObject( mdName.c_str() ) != 0; + if ( ! useNS ) { + // the class itself may exist if we're using the global scope + TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject( clName.c_str() ); + if ( cl ) return cl; + } + +// locate and get class + PyObject* mod = PyImport_AddModule( const_cast< char* >( mdName.c_str() ) ); + if ( ! mod ) { + PyErr_Clear(); + return 0; // module apparently disappeared + } + + Py_INCREF( mod ); + PyObject* pyclass = + PyDict_GetItemString( PyModule_GetDict( mod ), const_cast< char* >( clName.c_str() ) ); + Py_XINCREF( pyclass ); + Py_DECREF( mod ); + + if ( ! pyclass ) { + PyErr_Clear(); // the class is no longer available?! + return 0; + } + +// get a listing of all python-side members + PyObject* attrs = PyObject_Dir( pyclass ); + if ( ! attrs ) { + PyErr_Clear(); + Py_DECREF( pyclass ); + return 0; + } + +// pre-amble Cling proxy class + std::ostringstream proxyCode; + if ( useNS ) proxyCode << "namespace " << mdName << " { "; + proxyCode << "class " << clName << " {\nprivate:\n PyObject* fPyObject;\npublic:\n"; + +// loop over and add member functions + bool hasConstructor = false, hasDestructor = false; + for ( int i = 0; i < PyList_GET_SIZE( attrs ); ++i ) { + PyObject* label = PyList_GET_ITEM( attrs, i ); + Py_INCREF( label ); + PyObject* attr = PyObject_GetAttr( pyclass, label ); + + // collect only member functions (i.e. callable elements in __dict__) + if ( PyCallable_Check( attr ) ) { + std::string mtName = PyROOT_PyUnicode_AsString( label ); + + if ( mtName == "__del__" ) { + hasDestructor = true; + proxyCode << " ~" << clName << "() { TPyArg::CallDestructor(fPyObject); }\n"; + continue; + } + + bool isConstructor = mtName == "__init__"; + if ( !isConstructor && mtName.find("__", 0, 2) == 0 ) + continue; // skip all other python special funcs + + // figure out number of variables required +#if PY_VERSION_HEX < 0x03000000 + PyObject* im_func = PyObject_GetAttrString( attr, (char*)"im_func" ); + PyObject* func_code = + im_func ? PyObject_GetAttrString( im_func, (char*)"func_code" ) : NULL; +#else + PyObject* func_code = PyObject_GetAttrString( attr, "__code__" ); +#endif + PyObject* var_names = + func_code ? PyObject_GetAttrString( func_code, (char*)"co_varnames" ) : NULL; + if (PyErr_Occurred()) PyErr_Clear(); // happens for slots; default to 0 arguments + + int nVars = var_names ? PyTuple_GET_SIZE( var_names ) - 1 /* self */ : 0 /* TODO: probably large number, all default? */; + if ( nVars < 0 ) nVars = 0; + Py_XDECREF( var_names ); + Py_XDECREF( func_code ); +#if PY_VERSION_HEX < 0x03000000 + Py_XDECREF( im_func ); +#endif + + // method declaration as appropriate + if ( isConstructor ) { + hasConstructor = true; + proxyCode << " " << clName << "("; + } else // normal method + proxyCode << " TPyReturn " << mtName << "("; + for ( int ivar = 0; ivar < nVars; ++ivar ) { + proxyCode << "const TPyArg& a" << ivar; + if ( ivar != nVars-1 ) proxyCode << ", "; + } + proxyCode << ") {\n"; + proxyCode << " std::vector v; v.reserve(" << nVars+(isConstructor ? 0 : 1) << ");\n"; + + // add the 'self' argument as appropriate + if ( ! isConstructor ) + proxyCode << " v.push_back(fPyObject);\n"; + + // then add the remaining variables + for ( int ivar = 0; ivar < nVars; ++ ivar ) + proxyCode << " v.push_back(a" << ivar << ");\n"; + + // call dispatch (method or class pointer hard-wired) + if ( ! isConstructor ) + proxyCode << " return TPyReturn(TPyArg::CallMethod((PyObject*)" << (void*)attr << ", v))"; + else + proxyCode << " TPyArg::CallConstructor(fPyObject, (PyObject*)" << (void*)pyclass << ", v)"; + proxyCode << ";\n }\n"; + } + + // no decref of attr for now (b/c of hard-wired ptr); need cleanup somehow + Py_DECREF( label ); + } + +// special case if no constructor or destructor + if ( ! hasConstructor ) + proxyCode << " " << clName << "() {\n TPyArg::CallConstructor(fPyObject, (PyObject*)" << (void*)pyclass << "); }\n"; + + if ( ! hasDestructor ) + proxyCode << " ~" << clName << "() { TPyArg::CallDestructor(fPyObject); }\n"; + +// for now, don't allow copying (ref-counting wouldn't work as expected anyway) + proxyCode << " " << clName << "(const " << clName << "&) = delete;\n"; + proxyCode << " " << clName << "& operator=(const " << clName << "&) = delete;\n"; + +// closing and building of Cling proxy class + proxyCode << "};"; + if ( useNS ) proxyCode << " }"; + + Py_DECREF( attrs ); +// done with pyclass, decref here, assuming module is kept + Py_DECREF( pyclass ); + +// body compilation + if ( ! gInterpreter->LoadText( proxyCode.str().c_str() ) ) + return nullptr; + +// done, let ROOT manage the new class + TClass* klass = new TClass( useNS ? (mdName+"::"+clName).c_str() : clName.c_str(), silent ); + TClass::AddClass( klass ); + + return klass; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Just forward; based on type name only. + +TClass* TPyClassGenerator::GetClass( const std::type_info& typeinfo, bool load, bool silent ) +{ + return GetClass( typeinfo.name(), load, silent ); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Just forward; based on type name only + +TClass* TPyClassGenerator::GetClass( const std::type_info& typeinfo, bool load ) +{ + return GetClass( typeinfo.name(), load ); +} +#endif diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyClassGenerator.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyClassGenerator.h new file mode 100644 index 0000000000000..ed55fa27fd6fa --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyClassGenerator.h @@ -0,0 +1,21 @@ +#ifndef CPYCPPYY_TPYCLASSGENERATOR +#define CPYCPPYY_TPYCLASSGENERATOR + +// TODO: not sure if any of this still makes sense ... +#if 0 + +// ROOT +#include "TClassGenerator.h" + + +class TPyClassGenerator : public TClassGenerator { +public: + virtual TClass* GetClass(const char* name, bool load); + virtual TClass* GetClass(const std::type_info& typeinfo, bool load); + virtual TClass* GetClass(const char* name, bool load, bool silent); + virtual TClass* GetClass(const std::type_info& typeinfo, bool load, bool silent); +}; + +#endif + +#endif // !CPYCPPYY_TPYCLASSGENERATOR diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyException.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyException.cxx new file mode 100644 index 0000000000000..1641cd10e14a2 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyException.cxx @@ -0,0 +1,36 @@ +// Bindings +#include "CPyCppyy.h" +#include "TPyException.h" + + +//______________________________________________________________________________ +// C++ exception for throwing python exceptions +// ============================================ +// Purpose: A C++ exception class for throwing python exceptions +// through C++ code. +// Created: Apr, 2004, Scott Snyder, from the version in D0's python_util. +// +// Note: Don't be tempted to declare the virtual functions defined here +// as inline. +// If you do, you may not be able to properly throw these +// exceptions across shared libraries. + + +//- constructors/destructor -------------------------------------------------- +CPyCppyy::TPyException::TPyException() +{ +// default constructor +} + +CPyCppyy::TPyException::~TPyException() noexcept +{ +// destructor +} + + +//- public members ----------------------------------------------------------- +const char* CPyCppyy::TPyException::what() const noexcept +{ +// Return reason for throwing this exception: a python exception was raised. + return "python exception"; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyReturn.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyReturn.cxx new file mode 100644 index 0000000000000..402cd6e3bf102 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPyReturn.cxx @@ -0,0 +1,174 @@ +// Bindings +#include "CPyCppyy.h" +#include "TPyReturn.h" +#include "CPPInstance.h" + +// Standard +#include + + +//______________________________________________________________________________ +// Python expression eval result +// ============================= +// +// Transport class for bringing objects from python (dynamically typed) to Cling +// (statically typed). It is best to immediately cast a TPyReturn to the real +// type, either implicitly (for builtin types) or explicitly (through a void* +// cast for pointers to ROOT objects). +// +// Examples: +// +// root [0] TBrowser* b = (void*)TPython::Eval("ROOT.TBrowser()"); +// root [1] int i = TPython::Eval("1+1"); +// root [2] i +// (int)2 +// root [3] double d = TPython::Eval("1+3.1415"); +// root [4] d +// (double)4.14150000000000063e+00 + + +//- constructors/destructor -------------------------------------------------- +TPyReturn::TPyReturn() +{ +// Construct a TPyReturn object from Py_None. + Py_INCREF(Py_None); + fPyObject = Py_None; +} + +//////////////////////////////////////////////////////////////////////////////// +//---------------------------------------------------------------------------- +TPyReturn::TPyReturn(PyObject* pyobject) +{ +// Construct a TPyReturn from a python object. The python object may represent +// a ROOT object. Steals reference to given python object. + if (!pyobject) { + Py_INCREF(Py_None); + fPyObject = Py_None; + } else + fPyObject = pyobject; // steals reference +} + +//---------------------------------------------------------------------------- +TPyReturn::TPyReturn(const TPyReturn& other) +{ +// Copy constructor. Applies python object reference counting. + Py_INCREF(other.fPyObject); + fPyObject = other.fPyObject; +} + +//---------------------------------------------------------------------------- +TPyReturn& TPyReturn::operator=(const TPyReturn& other) +{ +// Assignment operator. Applies python object reference counting. + if (this != &other) { + Py_INCREF(other.fPyObject); + Py_DECREF(fPyObject); + fPyObject = other.fPyObject; + } + + return *this; +} + +//---------------------------------------------------------------------------- +TPyReturn::~TPyReturn() +{ +// Destructor. Reference counting for the held python object is in effect. + Py_DECREF(fPyObject); +} + + +//- public members ----------------------------------------------------------- +TPyReturn::operator char*() const +{ +// Cast python return value to C-style string (may fail). + return (char*)((const char*)*this); +} + +//---------------------------------------------------------------------------- +TPyReturn::operator const char*() const +{ +// Cast python return value to C-style string (may fail). + if (fPyObject == Py_None) // for void returns + return nullptr; + + const char* s = CPyCppyy_PyUnicode_AsString(fPyObject); + if (PyErr_Occurred()) { + PyErr_Print(); + return nullptr; + } + + return s; +} + +//---------------------------------------------------------------------------- +TPyReturn::operator char() const +{ +// Cast python return value to C++ char (may fail). + std::string s = operator const char*(); + if (s.size()) + return s[0]; + + return '\0'; +} + +//---------------------------------------------------------------------------- +TPyReturn::operator long() const +{ +// Cast python return value to C++ long (may fail). + long l = PyLong_AsLong(fPyObject); + + if (PyErr_Occurred()) + PyErr_Print(); + + return l; +} + +//---------------------------------------------------------------------------- +TPyReturn::operator unsigned long() const +{ +// Cast python return value to C++ unsigned long (may fail). + unsigned long ul = PyLong_AsUnsignedLong(fPyObject); + + if (PyErr_Occurred()) + PyErr_Print(); + + return ul; +} + +//---------------------------------------------------------------------------- +TPyReturn::operator double() const +{ +// Cast python return value to C++ double (may fail). + double d = PyFloat_AsDouble(fPyObject); + + if (PyErr_Occurred()) + PyErr_Print(); + + return d; +} + +//---------------------------------------------------------------------------- +TPyReturn::operator void*() const +{ +// Cast python return value to ROOT object with dictionary (may fail; note that +// you have to use the void* converter, as CINT will not call any other). + if (fPyObject == Py_None) + return nullptr; + + if (CPyCppyy::CPPInstance_Check(fPyObject)) { + ((CPyCppyy::CPPInstance*)fPyObject)->CppOwns(); + return ((CPyCppyy::CPPInstance*)fPyObject)->GetObject(); + } else + return fPyObject; // borrows reference +} + +//---------------------------------------------------------------------------- +TPyReturn::operator PyObject*() const +{ +// Direct return of the held PyObject; note the new reference. + if (fPyObject == Py_None) + return nullptr; + + Py_INCREF(fPyObject); + return fPyObject; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPython.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPython.cxx new file mode 100644 index 0000000000000..a60a34b1c8734 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TPython.cxx @@ -0,0 +1,499 @@ +// Bindings +#include "CPyCppyy.h" +#include "TPython.h" +#include "CPPInstance.h" +#include "CPPOverload.h" +#include "ProxyWrappers.h" +#include "PyStrings.h" + +// Standard +#include +#include +#include + +//______________________________________________________________________________ +// Python interpreter access +// ========================= +// +// The TPython class allows for access to python objects from Cling. The current +// functionality is only basic: cppyy objects and builtin types can freely cross +// the boundary between the two interpreters, python objects can be instantiated +// and their methods can be called. All other cross-coding is based on strings +// that are run on the python interpreter. +// +// Examples: +// +// $ cat MyPyClass.py +// print 'creating class MyPyClass ... ' +// +// class MyPyClass: +// def __init__(self): +// print 'in MyPyClass.__init__' +// +// def gime(self, what): +// return what +// +// $ root -l +// // Execute a string of python code. +// root [0] TPython::Exec("print \'Hello World!\'"); +// Hello World! +// +// // Create a TBrowser on the python side, and transfer it back and forth. +// // Note the required explicit (void*) cast! +// root [1] TBrowser* b = (void*)TPython::Eval("ROOT.TBrowser()"); +// root [2] TPython::Bind(b, "b"); +// root [3] b == (void*) TPython::Eval("b") +// (int)1 +// +// // Builtin variables can cross-over by using implicit casts. +// root [4] int i = TPython::Eval("1 + 1"); +// root [5] i +// (int)2 +// +// // Load a python module with a class definition, and use it. Casts are +// // necessary as the type information can not be otherwise derived. +// root [6] TPython::LoadMacro("MyPyClass.py"); +// creating class MyPyClass ... +// root [7] MyPyClass m; +// in MyPyClass.__init__ +// root [8] std::string s = (char*)m.gime("aap"); +// root [9] s +// (class TString)"aap" +// +// It is possible to switch between interpreters by calling "TPython::Prompt()" +// on the Cling side, while returning with ^D (EOF). State is preserved between +// successive switches. +// +// The API part provides (direct) C++ access to the bindings functionality of +// CPyCppyy. It allows verifying that you deal with a CPyCppyy pyobject in the +// first place (CPPInstance_Check for CPPInstance and any derived types, as well +// as CPPInstance_CheckExact for CPPInstance's only); and it allows conversions +// of void* to an CPPInstance and vice versa. + + +//- data --------------------------------------------------------------------- +static PyObject* gMainDict = nullptr; + +namespace CPyCppyy { + extern PyObject* gThisModule; +} + + +//- static public members ---------------------------------------------------- +bool TPython::Initialize() +{ +// Private initialization method: setup the python interpreter and load the +// cppyy module. + + static bool isInitialized = false; + if (isInitialized) + return true; + + if (!Py_IsInitialized()) { + // this happens if Cling comes in first +#if PY_VERSION_HEX < 0x03020000 + PyEval_InitThreads(); +#endif + Py_Initialize(); +#if PY_VERSION_HEX >= 0x03020000 + PyEval_InitThreads(); +#endif + + // try again to see if the interpreter is initialized + if (!Py_IsInitialized()) { + // give up ... + std::cerr << "Error: python has not been intialized; returning." << std::endl; + return false; + } + + // set the command line arguments on python's sys.argv +#if PY_VERSION_HEX < 0x03000000 + char* argv[] = {const_cast("cppyy")}; +#else + wchar_t* argv[] = {const_cast(L"cppyy")}; +#endif + PySys_SetArgv(sizeof(argv)/sizeof(argv[0]), argv); + + // force loading of the cppyy module + PyRun_SimpleString(const_cast("import cppyy")); + } + + if (!gMainDict) { + // retrieve the main dictionary + gMainDict = PyModule_GetDict( + PyImport_AddModule(const_cast("__main__"))); + Py_INCREF(gMainDict); + } + +// declare success ... + isInitialized = true; + return true; +} + +//----------------------------------------------------------------------------- +bool TPython::Import(const char* mod_name) +{ +// Import the named python module and create Cling equivalents for its classes +// and methods. + if (!Initialize()) + return false; + + PyObject* mod = PyImport_ImportModule(mod_name); + if (!mod) { + PyErr_Print(); + return false; + } + +// allow finding to prevent creation of a python proxy for the C++ proxy + Py_INCREF(mod); + PyModule_AddObject(CPyCppyy::gThisModule, mod_name, mod); + +// force creation of the module as a namespace +// TODO: the following is broken (and should live in Cppyy.cxx) +// TClass::GetClass(mod_name, true); + + PyObject* dct = PyModule_GetDict(mod); + +// create Cling classes for all new python classes + PyObject* values = PyDict_Values(dct); + for (int i = 0; i < PyList_GET_SIZE(values); ++i) { + PyObject* value = PyList_GET_ITEM(values, i); + Py_INCREF(value); + + // collect classes + if (PyClass_Check(value) || PyObject_HasAttr(value, CPyCppyy::PyStrings::gBases)) { + // get full class name (including module) + PyObject* pyClName = PyObject_GetAttr(value, CPyCppyy::PyStrings::gName); + if (PyErr_Occurred()) + PyErr_Clear(); + + // build full, qualified name + std::string fullname = mod_name; + fullname += "."; + fullname += CPyCppyy_PyUnicode_AsString(pyClName); + + // force class creation (this will eventually call TPyClassGenerator) + // TODO: the following is broken (and should live in Cppyy.cxx) to + // TClass::GetClass(fullname.c_str(), true); + + Py_XDECREF(pyClName); + } + + Py_DECREF(value); + } + + Py_DECREF(values); + +// TODO: mod "leaks" here + if (PyErr_Occurred()) + return false; + return true; +} + +//----------------------------------------------------------------------------- +void TPython::LoadMacro(const char* name) +{ +// Execute the give python script as if it were a macro (effectively an +// execfile in __main__), and create Cling equivalents for any newly available +// python classes. + if (!Initialize()) + return; + +// obtain a reference to look for new classes later + PyObject* old = PyDict_Values(gMainDict); + +// actual execution +#if PY_VERSION_HEX < 0x03000000 + Exec((std::string("execfile(\"") + name + "\")").c_str()); +#else + Exec((std::string("__cpycppyy_f = open(\"") + name + "\"); " + "exec(__cpycppyy_f.read()); " + "__cpycppyy_f.close(); del __cpycppyy_f").c_str()); +#endif + +// obtain new __main__ contents + PyObject* current = PyDict_Values(gMainDict); + +// create Cling classes for all new python classes + for (int i = 0; i < PyList_GET_SIZE(current); ++i) { + PyObject* value = PyList_GET_ITEM(current, i); + Py_INCREF(value); + + if (!PySequence_Contains(old, value)) { + // collect classes + if (PyClass_Check(value) || PyObject_HasAttr(value, CPyCppyy::PyStrings::gBases)) { + // get full class name (including module) + PyObject* pyModName = PyObject_GetAttr(value, CPyCppyy::PyStrings::gModule); + PyObject* pyClName = PyObject_GetAttr(value, CPyCppyy::PyStrings::gName); + + if (PyErr_Occurred()) + PyErr_Clear(); + + // need to check for both exact and derived (differences exist between older and newer + // versions of python ... bug?) + if ((pyModName && pyClName) && \ + ((CPyCppyy_PyUnicode_CheckExact(pyModName) && \ + CPyCppyy_PyUnicode_CheckExact(pyClName)) || \ + (CPyCppyy_PyUnicode_Check(pyModName) && \ + CPyCppyy_PyUnicode_Check(pyClName)) \ + )) { + // build full, qualified name + std::string fullname = CPyCppyy_PyUnicode_AsString(pyModName); + fullname += '.'; + fullname += CPyCppyy_PyUnicode_AsString(pyClName); + + // force class creation (this will eventually call TPyClassGenerator) + // the following is broken (and should live in Cppyy.cxx) + // TClass::GetClass(fullname.c_str(), true); + } + + Py_XDECREF(pyClName); + Py_XDECREF(pyModName); + } + } + + Py_DECREF(value); + } + + Py_DECREF(current); + Py_DECREF(old); +} + +//----------------------------------------------------------------------------- +void TPython::ExecScript(const char* name, int argc, const char** +#if PY_VERSION_HEX < 0x03000000 + argv +#endif + ) +{ +// Execute a python stand-alone script, with argv CLI arguments. +// +// example of use: +// const char* argv[] = {"1", "2", "3"}; +// TPython::ExecScript("test.py", sizeof(argv)/sizeof(argv[0]), argv); + if (!Initialize()) + return; + +// verify arguments + if (!name) { + std::cerr << "Error: no file name specified." << std::endl; + return; + } + + FILE* fp = fopen(name, "r"); + if (!fp) { + std::cerr << "Error: could not open file \"" << name << "\"." << std::endl; + return; + } + +// store a copy of the old cli for restoration + PyObject* oldargv = PySys_GetObject(const_cast("argv")); // borrowed + if (!oldargv) // e.g. apache + PyErr_Clear(); + else { + PyObject* l = PyList_New(PyList_GET_SIZE(oldargv)); + for (int i = 0; i < PyList_GET_SIZE(oldargv); ++i) { + PyObject* item = PyList_GET_ITEM(oldargv, i); + Py_INCREF(item); + PyList_SET_ITEM(l, i, item); // steals ref + } + oldargv = l; + } + +// create and set (add progam name) the new command line + argc += 1; +#if PY_VERSION_HEX < 0x03000000 + const char** argv2 = new const char*[argc]; + for (int i = 1; i < argc; ++i) argv2[i] = argv[i-1]; + argv2[0] = Py_GetProgramName(); + PySys_SetArgv(argc, const_cast(argv2)); + delete [] argv2; +#else +// TODO: fix this to work like above ... +#endif + +// actual script execution + PyObject* gbl = PyDict_Copy(gMainDict); + PyObject* result = // PyRun_FileEx closes fp (b/c of last argument "1") + PyRun_FileEx(fp, const_cast(name), Py_file_input, gbl, gbl, 1); + if (!result) + PyErr_Print(); + Py_XDECREF(result); + Py_DECREF(gbl); + +// restore original command line + if (oldargv) { + PySys_SetObject(const_cast("argv"), oldargv); + Py_DECREF(oldargv); + } +} + +//----------------------------------------------------------------------------- +bool TPython::Exec(const char* cmd) +{ +// Execute a python statement (e.g. "import noddy"). + if (!Initialize()) + return false; + +// execute the command + PyObject* result = + PyRun_String(const_cast(cmd), Py_file_input, gMainDict, gMainDict); + +// test for error + if (result) { + Py_DECREF(result); + return true; + } + + PyErr_Print(); + return false; +} + +//----------------------------------------------------------------------------- +const TPyReturn TPython::Eval(const char* expr) +{ +// Evaluate a python expression. +// +// Caution: do not hold on to the return value: either store it in a builtin +// type (implicit casting will work), or in a pointer to a cppyy object (explicit +// casting to a void* is required). + if (!Initialize()) + return TPyReturn(); + +// evaluate the expression + PyObject* result = + PyRun_String(const_cast(expr), Py_eval_input, gMainDict, gMainDict); + +// report errors as appropriate; return void + if (!result) { + PyErr_Print(); + return TPyReturn(); + } + +// results that require no convserion + if (result == Py_None || CPyCppyy::CPPInstance_Check(result) || + PyBytes_Check(result) || + PyFloat_Check(result) || PyLong_Check(result) || PyInt_Check(result)) + return TPyReturn(result); + +// explicit conversion for python type required + PyObject* pyclass = PyObject_GetAttr(result, CPyCppyy::PyStrings::gClass); + if (pyclass) { + // retrieve class name and the module in which it resides + PyObject* name = PyObject_GetAttr(pyclass, CPyCppyy::PyStrings::gName); + PyObject* module = PyObject_GetAttr(pyclass, CPyCppyy::PyStrings::gModule); + + // concat name + std::string qname = + std::string(CPyCppyy_PyUnicode_AsString(module)) + \ + '.' + CPyCppyy_PyUnicode_AsString(name); + Py_DECREF(module); + Py_DECREF(name); + Py_DECREF(pyclass); + + // locate cppyy style class with this name + // TODO: use Cppyy.cxx ... + //TClass* klass = TClass::GetClass(qname.c_str()); + void* klass = nullptr; + + // construct general cppyy python object that pretends to be of class 'klass' + if (klass) + return TPyReturn(result); + } else + PyErr_Clear(); + +// no conversion, return null pointer object + Py_DECREF(result); + return TPyReturn(); +} + +//----------------------------------------------------------------------------- +void TPython::Prompt() { +// Enter an interactive python session (exit with ^D). State is preserved +// between successive calls. + if (!Initialize()) { + return; + } + +// enter i/o interactive mode + PyRun_InteractiveLoop(stdin, const_cast("\0")); +} + +//----------------------------------------------------------------------------- +bool TPython::CPPInstance_Check(PyObject* pyobject) +{ +// Test whether the type of the given pyobject is of CPPInstance type or any +// derived type. + if (!Initialize()) + return false; + +// detailed walk through inheritance hierarchy + return CPyCppyy::CPPInstance_Check(pyobject); +} + +//----------------------------------------------------------------------------- +bool TPython::CPPInstance_CheckExact(PyObject* pyobject) +{ +// Test whether the type of the given pyobject is CPPInstance type. + if (!Initialize()) + return false; + +// direct pointer comparison of type member + return CPyCppyy::CPPInstance_CheckExact(pyobject); +} + +//----------------------------------------------------------------------------- +bool TPython::CPPOverload_Check(PyObject* pyobject) +{ +// Test whether the type of the given pyobject is of CPPOverload type or any +// derived type. + if (!Initialize()) + return false; + +// detailed walk through inheritance hierarchy + return CPyCppyy::CPPOverload_Check(pyobject); +} + +//----------------------------------------------------------------------------- +bool TPython::CPPOverload_CheckExact(PyObject* pyobject) +{ +// Test whether the type of the given pyobject is CPPOverload type. + if (!Initialize()) + return false; + +// direct pointer comparison of type member + return CPyCppyy::CPPOverload_CheckExact(pyobject); +} + +//----------------------------------------------------------------------------- +void* TPython::CPPInstance_AsVoidPtr(PyObject* pyobject) +{ +// Extract the object pointer held by the CPPInstance pyobject. + if (!Initialize()) + return nullptr; + +// check validity of cast + if (!CPyCppyy::CPPInstance_Check(pyobject)) + return nullptr; + +// get held object (may be null) + return ((CPyCppyy::CPPInstance*)pyobject)->GetObject(); +} + +//----------------------------------------------------------------------------- +PyObject* TPython::CPPInstance_FromVoidPtr( + void* addr, const char* classname, bool python_owns) +{ +// Bind the addr to a python object of class defined by classname. + if (!Initialize()) + return nullptr; + +// perform cast (the call will check TClass and addr, and set python errors) + PyObject* pyobject = CPyCppyy::BindCppObjectNoCast(addr, Cppyy::GetScope(classname), false); + +// give ownership, for ref-counting, to the python side, if so requested + if (python_owns && CPyCppyy::CPPInstance_Check(pyobject)) + ((CPyCppyy::CPPInstance*)pyobject)->PythonOwns(); + + return pyobject; +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TemplateProxy.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TemplateProxy.cxx new file mode 100644 index 0000000000000..282a66822712d --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TemplateProxy.cxx @@ -0,0 +1,449 @@ +// Bindings +#include "CPyCppyy.h" +#include "TemplateProxy.h" +#include "CPPClassMethod.h" +#include "CPPConstructor.h" +#include "CPPFunction.h" +#include "CPPMethod.h" +#include "CPPOverload.h" +#include "PyCallable.h" +#include "PyStrings.h" +#include "Utility.h" + + +namespace CPyCppyy { + +//---------------------------------------------------------------------------- +void TemplateProxy::Set(const std::string& cppname, const std::string& pyname, PyObject* pyclass) +{ +// Initialize the proxy for the given 'pyclass.' + fCppName = CPyCppyy_PyUnicode_FromString(const_cast(cppname.c_str())); + fPyName = CPyCppyy_PyUnicode_FromString(const_cast(pyname.c_str())); + fTemplateArgs = nullptr; + Py_XINCREF(pyclass); + fPyClass = pyclass; + fSelf = nullptr; + std::vector dummy; + fNonTemplated = CPPOverload_New(pyname, dummy); + fTemplated = CPPOverload_New(pyname, dummy); +} + +//---------------------------------------------------------------------------- +void TemplateProxy::AddOverload(CPPOverload* mp) { +// Store overloads of this templated method. + fNonTemplated->AddMethod(mp); +} + +void TemplateProxy::AddOverload(PyCallable* pc) { +// Store overload of this templated method. + fNonTemplated->AddMethod(pc); +} + +void TemplateProxy::AddTemplate(PyCallable* pc) +{ +// Store know template methods. + fTemplated->AddMethod(pc); +} + +//---------------------------------------------------------------------------- +PyCallable* TemplateProxy::Instantiate(const std::string& fullname, PyObject* args) +{ +// Instantiate (and cache) templated methods, return method if any + std::string proto = ""; + + Py_ssize_t nArgs = PyTuple_GET_SIZE(args); + if (nArgs != 0) { + PyObject* tpArgs = PyTuple_New(nArgs); + for (int i = 0; i < nArgs; ++i) { + PyObject* itemi = PyTuple_GET_ITEM(args, i); + + // special case for arrays + PyObject* pytc = PyObject_GetAttr(itemi, PyStrings::gTypeCode); + if (!(pytc && CPyCppyy_PyUnicode_Check(pytc))) { + // normal case (not an array) + PyErr_Clear(); + PyObject* tp = (PyObject*)Py_TYPE(itemi); + Py_INCREF(tp); + PyTuple_SET_ITEM(tpArgs, i, tp); + } else { + // array, build up a pointer type + char tc = ((char*)CPyCppyy_PyUnicode_AsString(pytc))[0]; + const char* ptrname = 0; + switch (tc) { + case 'b': ptrname = "char*"; break; + case 'h': ptrname = "short*"; break; + case 'H': ptrname = "unsigned short*"; break; + case 'i': ptrname = "int*"; break; + case 'I': ptrname = "unsigned int*"; break; + case 'l': ptrname = "long*"; break; + case 'L': ptrname = "unsigned long*"; break; + case 'f': ptrname = "float*"; break; + case 'd': ptrname = "double*"; break; + default: ptrname = "void*"; // TODO: verify if this is right + } + if (ptrname) { + PyObject* pyptrname = PyBytes_FromString(ptrname); + PyTuple_SET_ITEM(tpArgs, i, pyptrname); + // string added, but not counted towards nStrings + } else { + // this should cleanly fail instantiation + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tpArgs, i, Py_None); + } + } + Py_XDECREF(pytc); + } + + const std::string& name_v1 = Utility::ConstructTemplateArgs(nullptr, tpArgs, 0); + Py_DECREF(tpArgs); + if (name_v1.size()) + proto = name_v1.substr(1, name_v1.size()-2); + } + +// the following causes instantiation as necessary + Cppyy::TCppScope_t scope = ((CPPClass*)fPyClass)->fCppType; + Cppyy::TCppMethod_t cppmeth = Cppyy::GetMethodTemplate(scope, fullname, proto); + if (cppmeth) { // overload stops here + PyCallable* meth = nullptr; + if (Cppyy::IsNamespace(scope)) + meth = new CPPFunction(scope, cppmeth); + else if (Cppyy::IsStaticMethod(cppmeth)) + meth = new CPPClassMethod(scope, cppmeth); + else if (Cppyy::IsConstructor(cppmeth)) + meth = new CPPConstructor(scope, cppmeth); + else + meth = new CPPMethod(scope, cppmeth); + + // add to overload of instantiated templates + AddTemplate(meth); + + return meth; + } + + return nullptr; +} + + +//= CPyCppyy template proxy construction/destruction ========================= +static TemplateProxy* tpp_new(PyTypeObject*, PyObject*, PyObject*) +{ +// Create a new empty template method proxy. + TemplateProxy* pytmpl = PyObject_GC_New(TemplateProxy, &TemplateProxy_Type); + pytmpl->fCppName = nullptr; + pytmpl->fPyName = nullptr; + pytmpl->fTemplateArgs = nullptr; + pytmpl->fPyClass = nullptr; + pytmpl->fSelf = nullptr; + pytmpl->fNonTemplated = nullptr; + pytmpl->fTemplated = nullptr; + + PyObject_GC_Track(pytmpl); + return pytmpl; +} + +//---------------------------------------------------------------------------- +static int tpp_clear(TemplateProxy* pytmpl) +{ +// Garbage collector clear of held python member objects. + Py_CLEAR(pytmpl->fCppName); + Py_CLEAR(pytmpl->fPyName); + Py_CLEAR(pytmpl->fTemplateArgs); + Py_CLEAR(pytmpl->fPyClass); + Py_CLEAR(pytmpl->fSelf); + Py_CLEAR(pytmpl->fNonTemplated); + Py_CLEAR(pytmpl->fTemplated); + + return 0; +} + +//---------------------------------------------------------------------------- +static void tpp_dealloc(TemplateProxy* pytmpl) +{ +// Destroy the given template method proxy. + PyObject_GC_UnTrack(pytmpl); + tpp_clear(pytmpl); + PyObject_GC_Del(pytmpl); +} + +//---------------------------------------------------------------------------- +static PyObject* tpp_doc(TemplateProxy* pytmpl, void*) +{ +// Forward to method proxies to doc all overloads + PyObject* doc = nullptr; + if (pytmpl->fNonTemplated) + doc = PyObject_GetAttrString((PyObject*)pytmpl->fNonTemplated, "__doc__"); + if (pytmpl->fTemplated) { + PyObject* doc2 = PyObject_GetAttrString((PyObject*)pytmpl->fTemplated, "__doc__"); + if (doc && doc2) { + CPyCppyy_PyUnicode_AppendAndDel(&doc, CPyCppyy_PyUnicode_FromString("\n")); + CPyCppyy_PyUnicode_AppendAndDel(&doc, doc2); + } else if (!doc && doc2) { + doc = doc2; + } + } + + if (doc) + return doc; + + return CPyCppyy_PyUnicode_FromString(TemplateProxy_Type.tp_doc); +} + +//---------------------------------------------------------------------------- +static int tpp_traverse(TemplateProxy* pytmpl, visitproc visit, void* arg) +{ +// Garbage collector traverse of held python member objects. + Py_VISIT(pytmpl->fCppName); + Py_VISIT(pytmpl->fPyName); + Py_VISIT(pytmpl->fTemplateArgs); + Py_VISIT(pytmpl->fPyClass); + Py_VISIT(pytmpl->fSelf); + Py_VISIT(pytmpl->fNonTemplated); + Py_VISIT(pytmpl->fTemplated); + + return 0; +} + +//= CPyCppyy template proxy callable behavior ================================ +static PyObject* tpp_call(TemplateProxy* pytmpl, PyObject* args, PyObject* kwds) +{ +// Dispatcher to the actual member method, several uses possible; in order: +// +// case 1: explicit template previously selected through subscript +// +// case 2: select known non-template overload +// +// obj.method(a0, a1, ...) +// => obj->method(a0, a1, ...) // non-template +// +// case 3: select known template overload +// +// obj.method(a0, a1, ...) +// => obj->method(a0, a1, ...) // all known templates +// +// case 4: auto-instantiation from types of arguments +// +// obj.method(a0, a1, ...) +// => obj->method(a0, a1, ...) +// +// Note: explicit instantiation needs to use [] syntax: +// +// obj.method[type, type, ...](a0, a1, ...) +// + +// case 1: explicit template previously selected through subscript + + if (pytmpl->fTemplateArgs) { + // instantiate explicitly + PyObject* pyfullname = CPyCppyy_PyUnicode_FromString(CPyCppyy_PyUnicode_AsString(pytmpl->fCppName)); + CPyCppyy_PyUnicode_Append(&pyfullname, pytmpl->fTemplateArgs); + PyCallable* meth = pytmpl->Instantiate(CPyCppyy_PyUnicode_AsString(pyfullname), args); + if (meth) { + // store overload + PyObject* pymeth = (PyObject*)CPPOverload_New(CPyCppyy_PyUnicode_AsString(pyfullname), meth); + PyObject_SetAttr(pytmpl->fPyClass, pyfullname, pymeth); + Py_DECREF(pymeth); + pymeth = PyObject_GetAttr(pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, pyfullname); + Py_DECREF(pyfullname); + PyObject* result = CPPOverload_Type.tp_call(pymeth, args, kwds); + Py_DECREF(pymeth); + return result; + } else { + Py_DECREF(pyfullname); + // debatable ... should this drop through? + } + } + +// case 2: select known non-template overload + +// simply forward the call: all non-templated methods are defined on class definition +// and thus already available + PyObject* pymeth = CPPOverload_Type.tp_descr_get( + (PyObject*)pytmpl->fNonTemplated, pytmpl->fSelf, (PyObject*)&CPPOverload_Type); +// now call the method with the arguments (loops internally) + PyObject* result = CPPOverload_Type.tp_call(pymeth, args, kwds); + Py_DECREF(pymeth); pymeth = nullptr; + if (result) + return result; +// TODO: collect error here, as the failure may be either an overload +// failure after which we should continue; or a real failure, which should +// be reported. + PyErr_Clear(); + +// case 3: select known template overload + pymeth = CPPOverload_Type.tp_descr_get( + (PyObject*)pytmpl->fTemplated, pytmpl->fSelf, (PyObject*)&CPPOverload_Type); +// now call the method with the arguments (loops internally) + result = CPPOverload_Type.tp_call(pymeth, args, kwds); + Py_DECREF(pymeth); pymeth = nullptr; + if (result) + return result; +// TODO: collect error here, as the failure may be either an overload +// failure after which we should continue; or a real failure, which should +// be reported. + PyErr_Clear(); + +// case 4: auto-instantiation from types of arguments + PyCallable* meth = pytmpl->Instantiate(CPyCppyy_PyUnicode_AsString(pytmpl->fCppName), args); + if (meth) { + // re-retrieve the cached method to bind it, then call it + PyObject* pymeth = CPPOverload_Type.tp_descr_get( + (PyObject*)pytmpl->fTemplated, pytmpl->fSelf, (PyObject*)&CPPOverload_Type); + result = CPPOverload_Type.tp_call(pymeth, args, kwds); + Py_DECREF(pymeth); + if (result) + return result; + } + +// moderately generic error message, but should be clear enough + PyErr_Format(PyExc_TypeError, "can not resolve method template call for \'%s\'", + CPyCppyy_PyUnicode_AsString(pytmpl->fPyName)); + return nullptr; +} + +//---------------------------------------------------------------------------- +static TemplateProxy* tpp_descrget(TemplateProxy* pytmpl, PyObject* pyobj, PyObject*) +{ +// create and use a new template proxy (language requirement) + TemplateProxy* newPyTmpl = (TemplateProxy*)TemplateProxy_Type.tp_alloc(&TemplateProxy_Type, 0); + +// new method is to be bound to current object (may be nullptr) + Py_XINCREF(pyobj); + newPyTmpl->fSelf = pyobj; + +// copy name and class pointers + Py_INCREF(pytmpl->fCppName); + newPyTmpl->fCppName = pytmpl->fCppName; + + Py_INCREF(pytmpl->fPyName); + newPyTmpl->fPyName = pytmpl->fPyName; + + Py_XINCREF(pytmpl->fTemplateArgs); + newPyTmpl->fTemplateArgs = pytmpl->fTemplateArgs; + + Py_XINCREF(pytmpl->fPyClass); + newPyTmpl->fPyClass = pytmpl->fPyClass; + +// copy non-templated method proxy pointer + Py_INCREF(pytmpl->fNonTemplated); + newPyTmpl->fNonTemplated = pytmpl->fNonTemplated; + +// copy templated method proxy pointer + Py_INCREF(pytmpl->fTemplated); + newPyTmpl->fTemplated = pytmpl->fTemplated; + + return newPyTmpl; +} + +//---------------------------------------------------------------------------- +static PyObject* tpp_subscript(TemplateProxy* pytmpl, PyObject* args) +{ +// Explicit template member lookup/instantiation. + PyObject* newArgs; + if (!PyTuple_Check(args)) { + newArgs = PyTuple_New(1); + Py_INCREF(args); + PyTuple_SET_ITEM(newArgs, 0, args); + } else { + Py_INCREF(args); + newArgs = args; + } + + PyObject* pymeth = nullptr; + +// construct full, explicit name of function + PyObject* pyfullname = CPyCppyy_PyUnicode_FromString(CPyCppyy_PyUnicode_AsString(pytmpl->fCppName)); + PyObject* tmpl_args = CPyCppyy_PyUnicode_FromString(Utility::ConstructTemplateArgs(nullptr, newArgs, 0).c_str()); + Py_DECREF(newArgs); + CPyCppyy_PyUnicode_Append(&pyfullname, tmpl_args); + +// find template cached in dictionary, if any + PyObject* dct = PyObject_GetAttr(pytmpl->fPyClass, PyStrings::gDict); + bool hasTmpl = dct ? false : (bool)PyDict_GetItem(dct, pyfullname); + Py_XDECREF(dct); + if (hasTmpl) // overloads stop here, as there is an explicit match + pymeth = PyObject_GetAttr(pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, pyfullname); + Py_DECREF(pyfullname); + +// if found, return the overload, otherwise return fresh + if (pymeth) { + Py_DECREF(tmpl_args); + return pymeth; + } + +// nothing found, return fresh template trampoline with constructed types + TemplateProxy* typeBoundMethod = tpp_descrget(pytmpl, pytmpl->fSelf, nullptr); + Py_XDECREF(typeBoundMethod->fTemplateArgs); + typeBoundMethod->fTemplateArgs = tmpl_args; + return (PyObject*)typeBoundMethod; +} + +//---------------------------------------------------------------------------- +static PyMappingMethods tpp_as_mapping = { + nullptr, (binaryfunc)tpp_subscript, nullptr +}; + +static PyGetSetDef tpp_getset[] = { + {(char*)"__doc__", (getter)tpp_doc, nullptr, nullptr, nullptr}, + {(char*)nullptr, nullptr, nullptr, nullptr, nullptr} +}; + + +//= CPyCppyy template proxy type ============================================= +PyTypeObject TemplateProxy_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + (char*)"cppyy.TemplateProxy", // tp_name + sizeof(TemplateProxy), // tp_basicsize + 0, // tp_itemsize + (destructor)tpp_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + &tpp_as_mapping, // tp_as_mapping + 0, // tp_hash + (ternaryfunc)tpp_call, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags + (char*)"cppyy template proxy (internal)", // tp_doc + (traverseproc)tpp_traverse,// tp_traverse + (inquiry)tpp_clear, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + tpp_getset, // tp_getset + 0, // tp_base + 0, // tp_dict + (descrgetfunc)tpp_descrget,// tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + (newfunc)tpp_new, // tp_new + 0, // tp_free + 0, // tp_is_gc + 0, // tp_bases + 0, // tp_mro + 0, // tp_cache + 0, // tp_subclasses + 0 // tp_weaklist +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +} // namespace CPyCppyy diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TemplateProxy.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TemplateProxy.h new file mode 100644 index 0000000000000..7d266cbb45bff --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TemplateProxy.h @@ -0,0 +1,79 @@ +#ifndef CPYCPPYY_TEMPLATEPROXY_H +#define CPYCPPYY_TEMPLATEPROXY_H + +// Bindings +#include "CPPScope.h" + +// Standard +#include + + +namespace CPyCppyy { + +class PyCallable; +class CPPOverload; + +/** Template proxy object to return functions and methods + @author WLAV + @date 01/15/2008 + @version 1.0 + */ + +class TemplateProxy { +private: + friend TemplateProxy* TemplateProxy_New( + const std::string& cppname, const std::string& pyname, PyObject* pyclass); + void Set(const std::string& cppname, const std::string& pyname, PyObject* pyclass); + +public: // public, as the python C-API works with C structs + PyObject_HEAD + PyObject* fSelf; // must be first (same layout as CPPOverload) + PyObject* fCppName; + PyObject* fPyName; + PyObject* fTemplateArgs; + PyObject* fPyClass; + CPPOverload* fNonTemplated; // holder for non-template overloads + CPPOverload* fTemplated; // holder for templated overloads + +public: + void AddOverload(CPPOverload* mp); + void AddOverload(PyCallable* pc); + void AddTemplate(PyCallable* pc); + PyCallable* Instantiate(const std::string& fullname, PyObject* tmplArgs); + +private: // private, as the python C-API will handle creation + TemplateProxy() = delete; +}; + + +//- template proxy type and type verification -------------------------------- +extern PyTypeObject TemplateProxy_Type; + +template +inline bool TemplateProxy_Check(T* object) +{ + return object && PyObject_TypeCheck(object, &TemplateProxy_Type); +} + +template +inline bool TemplateProxy_CheckExact(T* object) +{ + return object && Py_TYPE(object) == &TemplateProxy_Type; +} + +//- creation ----------------------------------------------------------------- +inline TemplateProxy* TemplateProxy_New( + const std::string& cppname, const std::string& pyname, PyObject* pyclass) +{ +// Create and initialize a new template method proxy for the class. + if (!CPPScope_Check(pyclass)) return nullptr; + + TemplateProxy* pytmpl = + (TemplateProxy*)TemplateProxy_Type.tp_new(&TemplateProxy_Type, nullptr, nullptr); + pytmpl->Set(cppname, pyname, pyclass); + return pytmpl; +} + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_TEMPLATEPROXY_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TupleOfInstances.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TupleOfInstances.cxx new file mode 100644 index 0000000000000..cdfb48aaaa2f9 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TupleOfInstances.cxx @@ -0,0 +1,96 @@ +// Bindings +#include "CPyCppyy.h" +#include "TupleOfInstances.h" +#include "CPPInstance.h" +#include "ProxyWrappers.h" + + +namespace CPyCppyy { + +//= support for C-style arrays of objects ==================================== +PyObject* TupleOfInstances_New( + Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Py_ssize_t nelems) +{ +// TODO: the extra copy is inefficient, but it appears that the only way to +// initialize a subclass of a tuple is through a sequence + PyObject* tup = PyTuple_New(nelems); + for (int i = 0; i < nelems; ++i) { + // TODO: there's an assumption here that there is no padding, which is bound + // to be incorrect in certain cases + PyTuple_SetItem(tup, i, + BindCppObject((char*)address + i*Cppyy::SizeOf(klass), klass, CPPInstance::kIsReference)); + // Note: objects are bound as pointers, yet since the pointer value stays in + // place, updates propagate just as if they were bound by-reference + } + + PyObject* args = PyTuple_New(1); + Py_INCREF(tup); PyTuple_SET_ITEM(args, 0, tup); + PyObject* arr = PyTuple_Type.tp_new(&TupleOfInstances_Type, args, nullptr); + if (PyErr_Occurred()) PyErr_Print(); + + Py_DECREF(args); + // tup ref eaten by SET_ITEM on args + + return arr; +} + +//= CPyCppyy custom tuple-like array type ==================================== +PyTypeObject TupleOfInstances_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + (char*)"cppyy.InstancesArray", // tp_name + 0, // tp_basicsize + 0, // tp_itemsize + 0, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, // tp_flags + (char*)"array of C++ instances", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyTuple_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + 0, // tp_new + 0, // tp_free + 0, // tp_is_gc + 0, // tp_bases + 0, // tp_mro + 0, // tp_cache + 0, // tp_subclasses + 0 // tp_weaklist +#if PY_VERSION_HEX >= 0x02030000 + , 0 // tp_del +#endif +#if PY_VERSION_HEX >= 0x02060000 + , 0 // tp_version_tag +#endif +#if PY_VERSION_HEX >= 0x03040000 + , 0 // tp_finalize +#endif +}; + +} // namespace CPyCppyy diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TupleOfInstances.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TupleOfInstances.h new file mode 100644 index 0000000000000..ee3c43bdd388a --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TupleOfInstances.h @@ -0,0 +1,32 @@ +#ifndef CPYCPPYY_TUPLEOFINSTANCES_H +#define CPYCPPYY_TUPLEOFINSTANCES_H + +namespace CPyCppyy { + +/** Representation of C-style array of instances + @author WLAV + @date 02/10/2014 + @version 1.0 + */ + +//- custom tuple type that can pass through C-style arrays ------------------- +extern PyTypeObject TupleOfInstances_Type; + +template +inline bool TupleOfInstances_Check(T* object) +{ + return object && PyObject_TypeCheck(object, &TupleOfInstances_Type); +} + +template +inline bool TupleOfInstances_CheckExact(T* object) +{ + return object && Py_TYPE(object) == &TupleOfInstances_Type; +} + +PyObject* TupleOfInstances_New( + Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Py_ssize_t nelems); + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_TUPLEOFINSTANCES_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TypeManip.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TypeManip.cxx new file mode 100644 index 0000000000000..8370bda9ef90e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TypeManip.cxx @@ -0,0 +1,105 @@ +// Bindings +#include "CPyCppyy.h" +#include "TypeManip.h" + +// Standard +#include + + +//- helpers ------------------------------------------------------------------ +static inline +std::string::size_type find_qualifier_index(const std::string& name) +{ +// Find the first location that is not part of the class name proper. + std::string::size_type i = name.size() - 1; + for ( ; 0 < i; --i) { + std::string::value_type c = name[i]; + if (isalnum((int)c) || c == '>') + break; + } + + return i+1; +} + +static inline void erase_const(std::string& name) +{ +// Find and remove all occurrence of 'const'. + std::string::size_type spos = std::string::npos; + while ((spos = name.find("const") ) != std::string::npos) { + std::string::size_type i = 5; + while (name[spos+i] == ' ') ++i; + name.swap(name.erase(spos, i)); + } +} + +static inline void rstrip(std::string& name) +{ +// Remove space from the right side of name. + std::string::size_type i = name.size(); + for ( ; 0 < i; --i) { + if (!isspace(name[i])) + break; + } + + if (i != name.size()) + name = name.substr(0, i); +} + + +//---------------------------------------------------------------------------- +std::string CPyCppyy::TypeManip::remove_const(const std::string& cppname) +{ +// Remove 'const' qualifiers from the given C++ name. + std::string::size_type tmplt_start = cppname.find('<'); + std::string::size_type tmplt_stop = cppname.rfind('>'); + if (tmplt_start != std::string::npos && tmplt_stop != std::string::npos) { + // only replace const qualifying cppname, not in template parameters + std::string pre = cppname.substr(0, tmplt_start); + erase_const(pre); + std::string post = cppname.substr(tmplt_stop+1, std::string::npos); + erase_const(post); + + return pre + cppname.substr(tmplt_start, tmplt_stop+1) + post; + } + + std::string clean_name = cppname; + erase_const(clean_name); + return clean_name; +} + + +//---------------------------------------------------------------------------- +std::string CPyCppyy::TypeManip::clean_type( + const std::string& cppname, bool template_strip, bool const_strip) +{ +// Strip C++ name from all qualifiers and compounds. + std::string::size_type i = find_qualifier_index(cppname); + std::string name = cppname.substr(0, i); + rstrip(name); + + if (name.back() == ']') { // array type? + // TODO: this fails templates instantiated on arrays (not common) + name = name.substr(0, name.find('[')); + } else if (template_strip && name.back() == '>') { + name = name.substr(0, name.find('<')); + } + + if (const_strip) { + if (template_strip) + erase_const(name); + else + name = remove_const(name); + } + return name; +} + +//---------------------------------------------------------------------------- +void CPyCppyy::TypeManip::cppscope_to_pyscope(std::string& cppscope) +{ +// Change '::' in C++ scope into '.' as in a Python scope. + std::string::size_type pos = 0; + while ((pos = cppscope.find("::", pos)) != std::string::npos) { + cppscope.replace(pos, 2, "."); + pos += 1; + } +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TypeManip.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TypeManip.h new file mode 100644 index 0000000000000..2c0fea71c243c --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/TypeManip.h @@ -0,0 +1,21 @@ +#ifndef CPYCPPYY_TYPEMANIP_H +#define CPYCPPYY_TYPEMANIP_H + +#include + + +namespace CPyCppyy { + +namespace TypeManip { + + std::string remove_const(const std::string& cppname); + std::string clean_type(const std::string& cppname, + bool template_strip = true, bool const_strip = true); + + void cppscope_to_pyscope(std::string& cppscope); + +} // namespace TypeManip + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_TYPEMANIP_H diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Utility.cxx b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Utility.cxx new file mode 100644 index 0000000000000..04e588c9b7f4f --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Utility.cxx @@ -0,0 +1,775 @@ +// Bindings +#include "CPyCppyy.h" +#include "Utility.h" +#include "CPPFunction.h" +#include "CPPInstance.h" +#include "CPPOverload.h" +#include "ProxyWrappers.h" +#include "PyCallable.h" +#include "PyStrings.h" +#include "CustomPyTypes.h" +#include "TemplateProxy.h" + +// Standard +#include +#include +#include +#include +#include +#include + + +//- data _____________________________________________________________________ +dict_lookup_func CPyCppyy::gDictLookupOrg = 0; +bool CPyCppyy::gDictLookupActive = false; + +typedef std::map TC2POperatorMapping_t; +static TC2POperatorMapping_t gC2POperatorMapping; + +namespace { + + using namespace CPyCppyy::Utility; + + struct InitOperatorMapping_t { + public: + InitOperatorMapping_t() { + // Initialize the global map of operator names C++ -> python. + + // gC2POperatorMapping["[]"] = "__setitem__"; // depends on return type + // gC2POperatorMapping["+"] = "__add__"; // depends on # of args (see __pos__) + // gC2POperatorMapping["-"] = "__sub__"; // id. (eq. __neg__) + // gC2POperatorMapping["*"] = "__mul__"; // double meaning in C++ + + gC2POperatorMapping["[]"] = "__getitem__"; + gC2POperatorMapping["()"] = "__call__"; + gC2POperatorMapping["/"] = CPPYY__div__; + gC2POperatorMapping["%"] = "__mod__"; + gC2POperatorMapping["**"] = "__pow__"; + gC2POperatorMapping["<<"] = "__lshift__"; + gC2POperatorMapping[">>"] = "__rshift__"; + gC2POperatorMapping["&"] = "__and__"; + gC2POperatorMapping["|"] = "__or__"; + gC2POperatorMapping["^"] = "__xor__"; + gC2POperatorMapping["~"] = "__inv__"; + gC2POperatorMapping["+="] = "__iadd__"; + gC2POperatorMapping["-="] = "__isub__"; + gC2POperatorMapping["*="] = "__imul__"; + gC2POperatorMapping["/="] = CPPYY__idiv__; + gC2POperatorMapping["%="] = "__imod__"; + gC2POperatorMapping["**="] = "__ipow__"; + gC2POperatorMapping["<<="] = "__ilshift__"; + gC2POperatorMapping[">>="] = "__irshift__"; + gC2POperatorMapping["&="] = "__iand__"; + gC2POperatorMapping["|="] = "__ior__"; + gC2POperatorMapping["^="] = "__ixor__"; + gC2POperatorMapping["=="] = "__eq__"; + gC2POperatorMapping["!="] = "__ne__"; + gC2POperatorMapping[">"] = "__gt__"; + gC2POperatorMapping["<"] = "__lt__"; + gC2POperatorMapping[">="] = "__ge__"; + gC2POperatorMapping["<="] = "__le__"; + + // the following type mappings are "exact" + gC2POperatorMapping["const char*"] = "__str__"; + gC2POperatorMapping["char*"] = "__str__"; + gC2POperatorMapping["const char *"] = gC2POperatorMapping[ "const char*" ]; + gC2POperatorMapping["char *"] = gC2POperatorMapping[ "char*" ]; + gC2POperatorMapping["int"] = "__int__"; + gC2POperatorMapping["long"] = CPPYY__long__; + gC2POperatorMapping["double"] = "__float__"; + + // the following type mappings are "okay"; the assumption is that they + // are not mixed up with the ones above or between themselves (and if + // they are, that it is done consistently) + gC2POperatorMapping["short"] = "__int__"; + gC2POperatorMapping["unsigned short"] = "__int__"; + gC2POperatorMapping["unsigned int"] = CPPYY__long__; + gC2POperatorMapping["unsigned long"] = CPPYY__long__; + gC2POperatorMapping["long long"] = CPPYY__long__; + gC2POperatorMapping["unsigned long long"] = CPPYY__long__; + gC2POperatorMapping["float"] = "__float__"; + + gC2POperatorMapping["->"] = "__follow__"; // not an actual python operator + gC2POperatorMapping["="] = "__assign__"; // id. + +#if PY_VERSION_HEX < 0x03000000 + gC2POperatorMapping["bool"] = "__nonzero__"; +#else + gC2POperatorMapping["bool"] = "__bool__"; +#endif + } + } initOperatorMapping_; + + std::once_flag sOperatorTemplateFlag; + void InitOperatorTemplate() { + /* TODO: move to Cppyy.cxx + gROOT->ProcessLine( + "namespace _pycppyy_internal { template" + " bool is_equal(const C1& c1, const C2& c2){ return (bool)(c1 == c2); } }"); + gROOT->ProcessLine( + "namespace _cpycppyy_internal { template" + " bool is_not_equal(const C1& c1, const C2& c2){ return (bool)(c1 != c2); } }"); + */ + } + +// TODO: this should live with Helpers + inline void RemoveConst(std::string& cleanName) { + std::string::size_type spos = std::string::npos; + while ((spos = cleanName.find("const")) != std::string::npos) { + cleanName.swap(cleanName.erase(spos, 5)); + } + } + +} // unnamed namespace + + +//- public functions --------------------------------------------------------- +unsigned long CPyCppyy::PyLongOrInt_AsULong(PyObject* pyobject) +{ +// Convert to C++ unsigned long, with bounds checking, allow int -> ulong. + unsigned long ul = PyLong_AsUnsignedLong(pyobject); + if (PyErr_Occurred() && PyInt_Check(pyobject)) { + PyErr_Clear(); + long i = PyInt_AS_LONG(pyobject); + if (0 <= i) { + ul = (unsigned long)i; + } else { + PyErr_SetString(PyExc_ValueError, + "can\'t convert negative value to unsigned long"); + } + } + + return ul; +} + +//---------------------------------------------------------------------------- +ULong64_t CPyCppyy::PyLongOrInt_AsULong64(PyObject* pyobject) +{ +// Convert to C++ unsigned long long, with bounds checking. + ULong64_t ull = PyLong_AsUnsignedLongLong(pyobject); + if (PyErr_Occurred() && PyInt_Check(pyobject)) { + PyErr_Clear(); + long i = PyInt_AS_LONG(pyobject); + if (0 <= i) { + ull = (ULong64_t)i; + } else { + PyErr_SetString(PyExc_ValueError, + "can\'t convert negative value to unsigned long long"); + } + } + + return ull; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::Utility::AddToClass( + PyObject* pyclass, const char* label, PyCFunction cfunc, int flags) +{ +// Add the given function to the class under name 'label'. + +// use list for clean-up (.so's are unloaded only at interpreter shutdown) + static std::list s_pymeths; + + s_pymeths.push_back(PyMethodDef()); + PyMethodDef* pdef = &s_pymeths.back(); + pdef->ml_name = const_cast(label); + pdef->ml_meth = cfunc; + pdef->ml_flags = flags; + pdef->ml_doc = nullptr; + + PyObject* func = PyCFunction_New(pdef, nullptr); + PyObject* method = CustomInstanceMethod_New(func, nullptr, pyclass); + bool isOk = PyObject_SetAttrString(pyclass, pdef->ml_name, method) == 0; + Py_DECREF(method); + Py_DECREF(func); + + if (PyErr_Occurred()) + return false; + + if (!isOk) { + PyErr_Format(PyExc_TypeError, "could not add method %s", label); + return false; + } + + return true; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::Utility::AddToClass(PyObject* pyclass, const char* label, const char* func) +{ +// Add the given function to the class under name 'label'. + PyObject* pyfunc = PyObject_GetAttrString(pyclass, const_cast(func)); + if (!pyfunc) + return false; + + bool isOk = PyObject_SetAttrString(pyclass, const_cast(label), pyfunc) == 0; + + Py_DECREF(pyfunc); + return isOk; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::Utility::AddToClass(PyObject* pyclass, const char* label, PyCallable* pyfunc) +{ +// Add the given function to the class under name 'label'. + CPPOverload* method = + (CPPOverload*)PyObject_GetAttrString(pyclass, const_cast(label)); + + if (!method || !CPPOverload_Check(method)) { + // not adding to existing CPPOverload; add callable directly to the class + if (PyErr_Occurred()) + PyErr_Clear(); + Py_XDECREF((PyObject*)method); + method = CPPOverload_New(label, pyfunc); + bool isOk = PyObject_SetAttrString( + pyclass, const_cast(label), (PyObject*)method) == 0; + Py_DECREF(method); + return isOk; + } + + method->AddMethod(pyfunc); + + Py_DECREF(method); + return true; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::Utility::AddUsingToClass(PyObject* pyclass, const char* method) +{ +// Helper to add base class methods to the derived class one (this covers the +// 'using' cases, which the dictionary does not provide). + CPPOverload* derivedMethod = + (CPPOverload*)PyObject_GetAttrString(pyclass, const_cast(method)); + if (!CPPOverload_Check(derivedMethod)) { + Py_XDECREF(derivedMethod); + return false; + } + + PyObject* mro = PyObject_GetAttr(pyclass, PyStrings::gMRO); + if (!mro || ! PyTuple_Check(mro)) { + Py_XDECREF(mro); + Py_DECREF(derivedMethod); + return false; + } + + CPPOverload* baseMethod = 0; + for (int i = 1; i < PyTuple_GET_SIZE(mro); ++i) { + baseMethod = (CPPOverload*)PyObject_GetAttrString( + PyTuple_GET_ITEM(mro, i), const_cast(method)); + + if (!baseMethod) { + PyErr_Clear(); + continue; + } + + if (CPPOverload_Check(baseMethod)) + break; + + Py_DECREF(baseMethod); + baseMethod = 0; + } + + Py_DECREF(mro); + + if (!CPPOverload_Check(baseMethod)) { + Py_XDECREF(baseMethod); + Py_DECREF(derivedMethod); + return false; + } + + derivedMethod->AddMethod(baseMethod); + + Py_DECREF(baseMethod); + Py_DECREF(derivedMethod); + + return true; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::Utility::AddBinaryOperator( + PyObject* left, PyObject* right, const char* op, const char* label, const char* alt) +{ +// Install the named operator (op) into the left object's class if such a function +// exists as a global overload; a label must be given if the operator is not in +// gC2POperatorMapping (i.e. if it is ambiguous at the member level). + +// this should be a given, nevertheless ... + if (!CPPInstance_Check(left)) + return false; + +// retrieve the class names to match the signature of any found global functions + std::string rcname = ClassName(right); + std::string lcname = ClassName(left); + PyObject* pyclass = PyObject_GetAttr(left, PyStrings::gClass); + + bool result = AddBinaryOperator(pyclass, lcname, rcname, op, label, alt); + + Py_DECREF(pyclass); + return result; +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::Utility::AddBinaryOperator( + PyObject* pyclass, const char* op, const char* label, const char* alt) +{ +// Install binary operator op in pyclass, working on two instances of pyclass. + std::string cname; + if (CPPScope_Check(pyclass)) + cname = Cppyy::GetScopedFinalName(((CPPScope*)pyclass)->fCppType); + else { + PyObject* pyname = PyObject_GetAttr(pyclass, PyStrings::gName); + cname = Cppyy::ResolveName(CPyCppyy_PyUnicode_AsString(pyname)); + Py_DECREF(pyname); + } + + return AddBinaryOperator(pyclass, cname, cname, op, label, alt); +} + +//---------------------------------------------------------------------------- +static inline +Cppyy::TCppMethod_t FindAndAddOperator(const std::string& lcname, const std::string& rcname, + const char* op, Cppyy::TCppScope_t scope = Cppyy::gGlobalScope) { +// Helper to find a function with matching signature in 'funcs'. + std::string opname = "operator"; + opname += op; + + Cppyy::TCppIndex_t idx = Cppyy::GetGlobalOperator( + scope, Cppyy::GetScope(lcname), Cppyy::GetScope(rcname), opname); + if (idx == (Cppyy::TCppIndex_t)-1) + return (Cppyy::TCppMethod_t)0; + + return Cppyy::GetMethod(scope, idx); +} + +bool CPyCppyy::Utility::AddBinaryOperator(PyObject* pyclass, const std::string& lcname, + const std::string& rcname, const char* op, const char* label, const char* alt) +{ +// Find a global function with a matching signature and install the result on pyclass; +// in addition, __gnu_cxx, std::__1, and _cpycppyy_internal are searched pro-actively (as +// there's AFAICS no way to unearth using information). + +// For GNU on clang, search the internal __gnu_cxx namespace for binary operators (is +// typically the case for STL iterators operator==/!=. +// TODO: only look in __gnu_cxx for iterators (and more generally: do lookups in the +// namespace where the class is defined + static Cppyy::TCppScope_t gnucxx = Cppyy::GetScope("__gnu_cxx"); + +// Same for clang on Mac. TODO: find proper pre-processor magic to only use those specific +// namespaces that are actually around; although to be sure, this isn't expensive. + static Cppyy::TCppScope_t std__1 = Cppyy::GetScope("std::__1"); + +// One more, mostly for Mac, but again not sure whether this is not a general issue. Some +// operators are declared as friends only in classes, so then they're not found in the +// global namespace. That's why there's this little helper. + std::call_once(sOperatorTemplateFlag, InitOperatorTemplate); +// static Cppyy::TCppScope_t _pr_int = Cppyy::GetScope("_cpycppyy_internal"); + + PyCallable* pyfunc = 0; + if (gnucxx) { + Cppyy::TCppMethod_t func = FindAndAddOperator(lcname, rcname, op, gnucxx); + if (func) pyfunc = new CPPFunction(gnucxx, func); + } + + if (!pyfunc && std__1) { + Cppyy::TCppMethod_t func = FindAndAddOperator(lcname, rcname, op, std__1); + if (func) pyfunc = new CPPFunction(std__1, func); + } + + if (!pyfunc) { + std::string::size_type pos = lcname.substr(0, lcname.find('<')).rfind("::"); + if (pos != std::string::npos) { + Cppyy::TCppScope_t lcscope = Cppyy::GetScope(lcname.substr(0, pos).c_str()); + if (lcscope) { + Cppyy::TCppMethod_t func = FindAndAddOperator(lcname, rcname, op, lcscope); + if (func) pyfunc = new CPPFunction(lcscope, func); + } + } + } + + if (!pyfunc) { + Cppyy::TCppMethod_t func = FindAndAddOperator(lcname, rcname, op); + if (func) pyfunc = new CPPFunction(Cppyy::gGlobalScope, func); + } + +#if 0 + // TODO: figure out what this was for ... + if (!pyfunc && _pr_int.GetClass() && + lcname.find("iterator") != std::string::npos && + rcname.find("iterator") != std::string::npos) { + // TODO: gets called too often; make sure it's purely lazy calls only; also try to + // find a better notion for which classes (other than iterators) this is supposed to + // work; right now it fails for cases where None is passed + std::stringstream fname; + if (strncmp(op, "==", 2) == 0) { fname << "is_equal<"; } + else if (strncmp(op, "!=", 2) == 0) { fname << "is_not_equal<"; } + else { fname << "not_implemented<"; } + fname << lcname << ", " << rcname << ">"; + Cppyy::TCppMethod_t func = (Cppyy::TCppMethod_t)Cppyy_pr_int->GetMethodAny(fname.str().c_str()); + if (func) pyfunc = new CPpFunction(Cppyy::GetScope("_cpycppyy_internal"), func); + } + +// last chance: there could be a non-instantiated templated method + TClass* lc = TClass::GetClass(lcname.c_str()); + if (lc && strcmp(op, "==") != 0 && strcmp(op, "!=") != 0) { + std::string opname = "operator"; opname += op; + gInterpreter->LoadFunctionTemplates(lc); + gInterpreter->GetFunctionTemplate(lc->GetClassInfo(), opname.c_str()); + TFunctionTemplate* f = lc->GetFunctionTemplate(opname.c_str()); + Cppyy::TCppMethod_t func = + (Cppyy::TCppMethod_t)lc->GetMethodWithPrototype(opname.c_str(), rcname.c_str()); + if (func && f) pyfunc = new CPPMethod(Cppyy::GetScope(lcname), func); + } +#endif + + if (pyfunc) { // found a matching overload; add to class + bool ok = AddToClass(pyclass, label, pyfunc); + if (ok && alt) + return AddToClass(pyclass, alt, label); + } + + return false; +} + +//---------------------------------------------------------------------------- +std::string CPyCppyy::Utility::ConstructTemplateArgs(PyObject* pyname, PyObject* args, int argoff) +{ +// Helper to construct the "" part of a templated name (either +// for a class or method lookup + std::stringstream tmpl_name; + if (pyname) + tmpl_name << CPyCppyy_PyUnicode_AsString(pyname); + tmpl_name << '<'; + + Py_ssize_t nArgs = PyTuple_GET_SIZE(args); + for (int i = argoff; i < nArgs; ++i) { + // add type as string to name + PyObject* tn = PyTuple_GET_ITEM(args, i); + if (CPyCppyy_PyUnicode_Check(tn)) { + tmpl_name << CPyCppyy_PyUnicode_AsString(tn); + } else if (CPPScope_Check(tn)) { + tmpl_name << Cppyy::GetScopedFinalName(((CPPClass*)tn)->fCppType); + } else if (PyObject_HasAttr(tn, PyStrings::gName)) { + PyObject* tpName = PyObject_GetAttr(tn, PyStrings::gName); + + // special case for strings + if (strcmp(CPyCppyy_PyUnicode_AsString(tpName), "str") == 0) + tmpl_name << "std::string"; + else + tmpl_name << CPyCppyy_PyUnicode_AsString(tpName); + Py_DECREF(tpName); + } else if (PyInt_Check(tn) || PyLong_Check(tn) || PyFloat_Check(tn)) { + // last ditch attempt, works for things like int values; since this is a + // source of errors otherwise, it is limited to specific types and not + // generally used (str(obj) can print anything ...) + PyObject* pystr = PyObject_Str(tn); + tmpl_name << CPyCppyy_PyUnicode_AsString(pystr); + Py_DECREF(pystr); + } else { + PyErr_SetString(PyExc_SyntaxError, + "could not construct C++ name from provided template argument."); + return ""; + } + + // add a comma, as needed + if (i != nArgs-1) + tmpl_name << ", "; + } + +// close template name + tmpl_name << '>'; + + return tmpl_name.str(); +} + +//---------------------------------------------------------------------------- +bool CPyCppyy::Utility::InitProxy(PyObject* module, PyTypeObject* pytype, const char* name) +{ +// Initialize a proxy class for use by python, and add it to the module. + +// finalize proxy type + if (PyType_Ready(pytype) < 0) + return false; + +// add proxy type to the given module + Py_INCREF(pytype); // PyModule_AddObject steals reference + if (PyModule_AddObject(module, (char*)name, (PyObject*)pytype) < 0) { + Py_DECREF(pytype); + return false; + } + +// declare success + return true; +} + +//---------------------------------------------------------------------------- +int CPyCppyy::Utility::GetBuffer(PyObject* pyobject, char tc, int size, void*& buf, bool check) +{ +// Retrieve a linear buffer pointer from the given pyobject. + +// special case: don't handle character strings here (yes, they're buffers, but not quite) + if (PyBytes_Check(pyobject)) + return 0; + +// new-style buffer interface + if (PyObject_CheckBuffer(pyobject)) { + Py_buffer bufinfo; + memset(&bufinfo, 0, sizeof(Py_buffer)); + if (PyObject_GetBuffer(pyobject, &bufinfo, PyBUF_FORMAT) == 0) { + if (tc == '*' || strchr(bufinfo.format, tc)) { + buf = bufinfo.buf; + if (buf && bufinfo.ndim == 0) { + return 1; + } else if (buf && bufinfo.ndim == 1 && bufinfo.shape) { + int size1d = (int)bufinfo.shape[0]; + PyBuffer_Release(&bufinfo); + return size1d; + } + } else { + // have buf, but format mismatch: bail out now, otherwise the old + // code will return based on itemsize match + return 0; + } + } + PyErr_Clear(); + } + +// attempt to retrieve pointer through old-style buffer interface + PyBufferProcs* bufprocs = Py_TYPE(pyobject)->tp_as_buffer; + + PySequenceMethods* seqmeths = Py_TYPE(pyobject)->tp_as_sequence; + if (seqmeths != 0 && bufprocs != 0 +#if PY_VERSION_HEX < 0x03000000 + && bufprocs->bf_getwritebuffer != 0 + && (*(bufprocs->bf_getsegcount))(pyobject, 0) == 1 +#else + && bufprocs->bf_getbuffer != 0 +#endif + ) { + + // get the buffer +#if PY_VERSION_HEX < 0x03000000 + Py_ssize_t buflen = (*(bufprocs->bf_getwritebuffer))(pyobject, 0, &buf); +#else + Py_buffer bufinfo; + (*(bufprocs->bf_getbuffer))(pyobject, &bufinfo, PyBUF_WRITABLE); + buf = (char*)bufinfo.buf; + Py_ssize_t buflen = bufinfo.len; +#if PY_VERSION_HEX < 0x03010000 + PyBuffer_Release(pyobject, &bufinfo); +#else + PyBuffer_Release(&bufinfo); +#endif +#endif + + if (buf && check == true) { + // determine buffer compatibility (use "buf" as a status flag) + PyObject* pytc = PyObject_GetAttr(pyobject, PyStrings::gTypeCode); + if (pytc != 0) { // for array objects + if (CPyCppyy_PyUnicode_AsString(pytc)[0] != tc) + buf = 0; // no match + Py_DECREF(pytc); + } else if (seqmeths->sq_length && + (int)(buflen/(*(seqmeths->sq_length))(pyobject)) == size) { + // this is a gamble ... may or may not be ok, but that's for the user + PyErr_Clear(); + } else if (buflen == size) { + // also a gamble, but at least 1 item will fit into the buffer, so very likely ok ... + PyErr_Clear(); + } else { + buf = 0; // not compatible + + // clarify error message + PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0; + PyErr_Fetch(&pytype, &pyvalue, &pytrace); + PyObject* pyvalue2 = CPyCppyy_PyUnicode_FromFormat( + (char*)"%s and given element size (%ld) do not match needed (%d)", + CPyCppyy_PyUnicode_AsString(pyvalue), + seqmeths->sq_length ? (Long_t)(buflen/(*(seqmeths->sq_length))(pyobject)) : (Long_t)buflen, + size); + Py_DECREF(pyvalue); + PyErr_Restore(pytype, pyvalue2, pytrace); + } + } + + return buflen; + } + + return 0; +} + +//---------------------------------------------------------------------------- +std::string CPyCppyy::Utility::MapOperatorName(const std::string& name, bool bTakesParams) +{ +// Map the given C++ operator name on the python equivalent. + if (8 < name.size() && name.substr(0, 8) == "operator") { + std::string op = name.substr(8, std::string::npos); + + // stripping ... + std::string::size_type start = 0, end = op.size(); + while (start < end && isspace(op[start])) ++start; + while (start < end && isspace(op[end-1])) --end; + // TODO: resolve name only if mapping failed + op = Cppyy::ResolveName(op.substr(start, end - start)); + + // map C++ operator to python equivalent, or made up name if no equivalent exists + TC2POperatorMapping_t::iterator pop = gC2POperatorMapping.find(op); + if (pop != gC2POperatorMapping.end()) { + return pop->second; + + } else if (op == "*") { + // dereference v.s. multiplication of two instances + return bTakesParams ? "__mul__" : "__deref__"; + + } else if (op == "+") { + // unary positive v.s. addition of two instances + return bTakesParams ? "__add__" : "__pos__"; + + } else if (op == "-") { + // unary negative v.s. subtraction of two instances + return bTakesParams ? "__sub__" : "__neg__"; + + } else if (op == "++") { + // prefix v.s. postfix increment + return bTakesParams ? "__postinc__" : "__preinc__"; + + } else if (op == "--") { + // prefix v.s. postfix decrement + return bTakesParams ? "__postdec__" : "__predec__"; + } + + } + +// might get here, as not all operator methods are handled (new, delete, etc.) + return name; +} + +//---------------------------------------------------------------------------- +const std::string CPyCppyy::Utility::Compound(const std::string& name) +{ +// TODO: consolidate with other string manipulations in Helpers.cxx +// Break down the compound of a fully qualified type name. + std::string cleanName = name; + RemoveConst(cleanName); + + std::string compound = ""; + for (int ipos = (int)cleanName.size()-1; 0 <= ipos; --ipos) { + char c = cleanName[ipos]; + if (isspace(c)) continue; + if (isalnum(c) || c == '_' || c == '>' || c == ')') break; + + compound = c + compound; + } + +// for arrays (TODO: deal with the actual size) + if (compound == "]") + return "[]"; + + return compound; +} + +//---------------------------------------------------------------------------- +Py_ssize_t CPyCppyy::Utility::ArraySize(const std::string& name) +{ +// TODO: consolidate with other string manipulations in Helpers.cxx +// Extract size from an array type, if available. + std::string cleanName = name; + RemoveConst(cleanName); + + if (cleanName[cleanName.size()-1] == ']') { + std::string::size_type idx = cleanName.rfind('['); + if (idx != std::string::npos) { + const std::string asize = cleanName.substr(idx+1, cleanName.size()-2); + return strtoul(asize.c_str(), nullptr, 0); + } + } + + return -1; +} + +//---------------------------------------------------------------------------- +std::string CPyCppyy::Utility::ClassName(PyObject* pyobj) +{ +// Retrieve the class name from the given Python instance. + if (CPPInstance_Check(pyobj)) + return Cppyy::GetScopedFinalName(((CPPInstance*)pyobj)->ObjectIsA()); + +// generic Python object ... + std::string clname = ""; + PyObject* pyclass = PyObject_GetAttr(pyobj, PyStrings::gClass); + if (pyclass) { + PyObject* pyname = PyObject_GetAttr(pyclass, PyStrings::gName); + if (pyname) { + clname = CPyCppyy_PyUnicode_AsString(pyname); + Py_DECREF(pyname); + } else { + PyErr_Clear(); + } + Py_DECREF(pyclass); + } else { + PyErr_Clear(); + } + + return clname; +} + + +//---------------------------------------------------------------------------- +PyObject* CPyCppyy::Utility::PyErr_Occurred_WithGIL() +{ +// Re-acquire the GIL before calling PyErr_Occurred() in case it has been +// released; note that the p2.2 code assumes that there are no callbacks in +// C++ to python (or at least none returning errors). +#if PY_VERSION_HEX >= 0x02030000 + PyGILState_STATE gstate = PyGILState_Ensure(); + PyObject* e = PyErr_Occurred(); + PyGILState_Release(gstate); +#else + if (PyThreadState_GET()) + return PyErr_Occurred(); + PyObject* e = 0; +#endif + + return e; +} + + +//---------------------------------------------------------------------------- +size_t CPyCppyy::Utility::FetchError(std::vector& errors) +{ +// Fetch the current python error, if any, and store it for future use. + if (PyErr_Occurred()) { + PyError_t e; + PyErr_Fetch(&e.fType, &e.fValue, &e.fTrace); + errors.push_back(e); + } + return errors.size(); +} + +//---------------------------------------------------------------------------- +void CPyCppyy::Utility::SetDetailedException(std::vector& errors, PyObject* topmsg, PyObject* defexc) +{ +// Use the collected exceptions to build up a detailed error log. + if (errors.empty()) { + // should not happen ... + Py_DECREF(topmsg); + return; + } + +// add the details to the topmsg + PyObject* separator = CPyCppyy_PyUnicode_FromString("\n "); + + PyObject* exc_type = nullptr; + for (auto& e : errors) { + if (!exc_type) exc_type = e.fType; + else if (exc_type != e.fType) exc_type = defexc; + CPyCppyy_PyUnicode_Append(&topmsg, separator); + CPyCppyy_PyUnicode_Append(&topmsg, e.fValue); + } + + Py_DECREF(separator); + std::for_each(errors.begin(), errors.end(), PyError_t::Clear); + +// set the python exception + PyErr_SetObject(exc_type, topmsg); + Py_DECREF(topmsg); +} diff --git a/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Utility.h b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Utility.h new file mode 100644 index 0000000000000..54a34c895ea07 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/CPyCppyy/src/Utility.h @@ -0,0 +1,83 @@ +#ifndef CPYCPPYY_UTILITY_H +#define CPYCPPYY_UTILITY_H + +// Standard +#include +#include +#include + + +namespace CPyCppyy { + +class PyCallable; + +extern dict_lookup_func gDictLookupOrg; +extern bool gDictLookupActive; + +// additional converter functions +unsigned long PyLongOrInt_AsULong(PyObject* pyobject); +ULong64_t PyLongOrInt_AsULong64(PyObject* pyobject); + +namespace Utility { + +// convenience functions for adding methods to classes +bool AddToClass(PyObject* pyclass, const char* label, PyCFunction cfunc, + int flags = METH_VARARGS); +bool AddToClass(PyObject* pyclass, const char* label, const char* func); +bool AddToClass(PyObject* pyclass, const char* label, PyCallable* pyfunc); + +bool AddUsingToClass(PyObject* pyclass, const char* method); + +// helpers for dynamically constructing binary operators +bool AddBinaryOperator(PyObject* left, PyObject* right, + const char* op, const char* label, const char* alt_label = nullptr); +bool AddBinaryOperator(PyObject* pyclass, + const char* op, const char* label, const char* alt_label = nullptr); +bool AddBinaryOperator(PyObject* pyclass, const std::string& lcname, const std::string& rcname, + const char* op, const char* label, const char* alt_label = nullptr); + +// helper for template classes and methods +std::string ConstructTemplateArgs(PyObject* pyname, PyObject* args, int argoff); + +// initialize proxy type objects +bool InitProxy(PyObject* module, PyTypeObject* pytype, const char* name); + +// retrieve the memory buffer from pyobject, return buflength, tc (optional) is python +// array.array type code, size is type size, buf will point to buffer, and if check is +// true, some heuristics will be applied to check buffer compatibility with the type +int GetBuffer(PyObject* pyobject, char tc, int size, void*& buf, bool check = true); + +// data/operator mappings +std::string MapOperatorName(const std::string& name, bool bTakesParames); + +// meta information +const std::string Compound(const std::string& name); +Py_ssize_t ArraySize(const std::string& name); +std::string ClassName(PyObject* pyobj); + +// for threading: save call to PyErr_Occurred() +PyObject* PyErr_Occurred_WithGIL(); + +// helpers for collecting/maintaining python exception data +struct PyError_t { + PyError_t() { fType = fValue = fTrace = 0; } + + static void Clear(PyError_t& e) + { + // Remove exception information. + Py_XDECREF(e.fType); Py_XDECREF(e.fValue); Py_XDECREF(e.fTrace); + e.fType = e.fValue = e.fTrace = 0; + } + + PyObject *fType, *fValue, *fTrace; +}; + +size_t FetchError(std::vector&); +void SetDetailedException( + std::vector& errors /* clears */, PyObject* topmsg /* steals ref */, PyObject* defexc); + +} // namespace Utility + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_UTILITY_H diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/.gitignore b/bindings/pyroot_experimental/cppyy/cppyy-backend/.gitignore new file mode 100644 index 0000000000000..99c41e704969a --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/.gitignore @@ -0,0 +1,106 @@ +releases/ +root-*/ +cling/src/ +builddir/ + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/CMakeLists.txt b/bindings/pyroot_experimental/cppyy/cppyy-backend/CMakeLists.txt new file mode 100644 index 0000000000000..c13c90b947fb7 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/CMakeLists.txt @@ -0,0 +1,23 @@ +set(py_sources + cppyy_backend/__init__.py + cppyy_backend/loader.py +) + +set(d $ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/${runtimedir}) +foreach(py_source ${py_sources}) + file(COPY clingwrapper/python/${py_source} DESTINATION ${localruntimedir}/cppyy_backend) + install(FILES clingwrapper/python/${py_source} DESTINATION ${runtimedir}/cppyy_backend) + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile ${d}/${py_source})") + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile ${d}/${py_source})") +endforeach() + +add_library(cppyy_backend SHARED clingwrapper/src/clingwrapper.cxx) +target_include_directories(cppyy_backend PRIVATE clingwrapper/src) +target_link_libraries(cppyy_backend Core ${CMAKE_DL_LIBS}) + +# cppyy uses ROOT headers from binary directory +add_dependencies(cppyy_backend move_headers) +target_include_directories(cppyy_backend PRIVATE ${CMAKE_BINARY_DIR}/include) + +set_property(GLOBAL APPEND PROPERTY ROOT_EXPORTED_TARGETS cppyy_backend) +install(TARGETS cppyy_backend EXPORT ROOTExports DESTINATION ${runtimedir}) diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/README.rst b/bindings/pyroot_experimental/cppyy/cppyy-backend/README.rst new file mode 100644 index 0000000000000..3cf75ab989f2a --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/README.rst @@ -0,0 +1,15 @@ +cppyy-backend +============= + +A repackaging of Cling, the interactive C++ interpreter, including a version +of LLVM patched for interactive use, and C/C++ wrappers that expose no further +external headers or types. + + +Cling documentation is here: + https://root.cern.ch/cling + +---- + +Find the cppyy documentation here: + http://cppyy.readthedocs.io/ diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/.travis.yml b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/.travis.yml new file mode 100644 index 0000000000000..de46ee9a711f6 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/.travis.yml @@ -0,0 +1,8 @@ +sudo: false +language: python + +script: + - python setup.py egg_info + - python create_src_directory.py + - python setup.py sdist + - ls dist diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/INSTALL.txt b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/INSTALL.txt new file mode 100644 index 0000000000000..91380ac2645d8 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/INSTALL.txt @@ -0,0 +1,17 @@ +Download ROOT sources, strip and patch them: + + $ python setup.py egg_info + $ python create_src_directory.py + +Build wheel (optional: use --keep-temp during development): + + $ MAKE_NPROCS=32 python setup.py bdist_wheel + +Build source distribution: + + $ python setup.py sdist + +Sign: + + $ gpg --detach-sign -a dist/*cppyy*.tar.gz + diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/LICENSE.txt b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/LICENSE.txt new file mode 100644 index 0000000000000..e3de5ec754ab9 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/LICENSE.txt @@ -0,0 +1,68 @@ +Copyright (c) 2003, The Regents of the University of California, +through Lawrence Berkeley National Laboratory (subject to receipt of +any required approvals from the U.S. Dept. of Energy). All rights +reserved. Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following +conditions are met: + +(1) Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +(2) Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +(3) Neither the name of the University of California, Lawrence Berkeley +National Laboratory, U.S. Dept. of Energy nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +You are under no obligation whatsoever to provide any bug fixes, +patches, or upgrades to the features, functionality or performance of +the source code ("Enhancements") to anyone; however, if you choose to +make your Enhancements available either publicly, or directly to +Lawrence Berkeley National Laboratory, without imposing a separate +written license agreement for such Enhancements, then you hereby grant +the following license: a non-exclusive, royalty-free perpetual license +to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such Enhancements +or derivative works thereof, in binary and source code form. + + + +Additional copyright holders +---------------------------- + +Except when otherwise stated (look for LICENSE files or information in +source files), this package contains files copyrighted by one or more of +the following people and organizations: + + CERN + Robert Bradshaw + Antonio Cuni + Aditi Dutta + Shaheed Haque + + +External code +------------- + +The create_src_directory.py script will pull in ROOT and LLVM sources, which +are licensed differently: + + LLVM: distributed under University of Illinois/NCSA Open Source License + https://opensource.org/licenses/UoI-NCSA.php + ROOT: distributed under LGPL 2.1 + https://root.cern.ch/license + +The ROOT code is modified before building, the LLVM code is not. diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/MANIFEST.in b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/MANIFEST.in new file mode 100644 index 0000000000000..6db55ce0e102b --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/MANIFEST.in @@ -0,0 +1,5 @@ +# Include the license file +include LICENSE.txt + +# Include the data files +recursive-include src * diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/README.rst b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/README.rst new file mode 100644 index 0000000000000..34449fd13d1ff --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/README.rst @@ -0,0 +1,26 @@ +cppyy-cling +=========== + +A repackaging of Cling, the interactive C++ interpreter, including a version +of LLVM that is patched for interactive use. + +Compilation of LLVM may take a long time, so when building from source, it is +recommended to set MAKE_NPROCS to the number of cores on your machine and to +use the verbose flag to see progress: + + $ MAKE_NPROCS=32 pip install --verbose cppyy-cling + +Alternatively, there are binary wheels (Mac 10.12, Linux/Gentoo) +available here: + https://cern.ch/wlav/wheels + +Use '--extra-index https://cern.ch/wlav/wheels' as an argument to pip to +pick them up. + +Cling documentation is here: + https://root.cern.ch/cling + +---- + +Find the cppyy documentation here: + http://cppyy.readthedocs.io/ diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/create_src_directory.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/create_src_directory.py new file mode 100755 index 0000000000000..0bd69c0610365 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/create_src_directory.py @@ -0,0 +1,366 @@ +#!/usr/bin/env python +from __future__ import print_function + +import os, sys, subprocess +import shutil, tarfile +try: + import urllib2 +except ModuleNotFoundError: + import urllib.request as urllib2 # p3 + + +DEBUG_TESTBUILD = False + +TARBALL_CACHE_DIR = 'releases' + +ROOT_KEEP = ['build', 'cmake', 'config', 'core', 'etc', 'interpreter', + 'io', 'LICENSE', 'Makefile', 'CMakeLists.txt', 'math', + 'main'] # main only needed in more recent root b/c of rootcling +ROOT_CORE_KEEP = ['CMakeLists.txt', 'base', 'clib', 'clingutils', 'cont', + 'dictgen', 'foundation', 'lz4', 'lzma', 'macosx', 'meta', + 'metacling', 'metautils', 'rootcling_stage1', 'textinput', + 'thread', 'unix', 'utils', 'winnt', 'zip', 'pcre'] +ROOT_IO_KEEP = ['CMakeLists.txt', 'io', 'rootpcm'] +ROOT_MATH_KEEP = ['CMakeLists.txt', 'mathcore'] +ROOT_ETC_KEEP = ['Makefile.arch', 'class.rules', 'cmake', 'dictpch', + 'gdb-backtrace.sh', 'gitinfo.txt', 'helgrind-root.supp', + 'hostcert.conf', 'plugins', 'system.plugins-ios', + 'valgrind-root-python.supp', 'valgrind-root.supp', 'vmc'] +ROOT_PLUGINS_KEEP = ['TVirtualStreamerInfo'] + +ROOT_EXPLICIT_REMOVE = ['core/base/v7', 'math/mathcore/v7', 'io/io/v7'] + + +ERR_RELEASE_NOT_FOUND = 2 + + +def get_root_version(try_recover=True): + import pkg_resources + path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'python') + dists = pkg_resources.find_distributions(path) + try: + cppyy_cling = [d for d in dists if d.key == 'cppyy-cling'][0] + version = cppyy_cling.version + except IndexError: + if try_recover and os.path.exists('setup.py'): + print('No egg_info ... running "python setup.py egg_info"') + if subprocess.call(['python', 'setup.py', 'egg_info']) != 0: + print('ERROR: creation of egg_info failed ... giving up') + sys.exit(2) + return get_root_version(False) + else: + print('ERROR: cannot determine version. Please run "python setup.py egg_info" first.') + sys.exit(1) + # + parts = version.split('.', 3) + major, minor, patch = map(int, parts[:3]) + root_version = '%d.%02d.%02d' % (major, minor, patch) + return root_version + + +ROOT_VERSION = get_root_version() + +# +## ROOT source pull and cleansing +# +def clean_directory(directory, keeplist, trim_cmake=True): + removed_entries = [] + for entry in os.listdir(directory): + if entry[0] == '.' or entry in keeplist: + continue + removed_entries.append(entry) + entry = os.path.join(directory, entry) + print('now removing', entry) + if os.path.isdir(entry): + shutil.rmtree(entry) + else: + os.remove(entry) + + if not trim_cmake: + return + + # now take the removed entries out of the CMakeLists.txt + if removed_entries: + inp = os.path.join(directory, 'CMakeLists.txt') + print('trimming', inp) + outp = inp+'.new' + new_cml = open(outp, 'w') + for line in open(inp).readlines(): + if ('add_subdirectory' in line) or\ + ('COMMAND' in line and 'copy' in line) or\ + ('ROOT_ADD_TEST_SUBDIRECTORY' in line) or\ + ('install(DIRECTORY' in line): + for sub in removed_entries: + if sub in line: + line = '#'+line + break + new_cml.write(line) + new_cml.close() + os.rename(outp, inp) + else: + print('reusing existing %s/CMakeLists.txt' % (directory,)) + + +if not os.path.exists(TARBALL_CACHE_DIR): + os.mkdir(TARBALL_CACHE_DIR) + +fn = 'root_v%s.source.tar.gz' % ROOT_VERSION +addr = 'https://root.cern.ch/download/'+fn +if not os.path.exists(os.path.join(TARBALL_CACHE_DIR, fn)): + try: + print('retrieving', fn) + if sys.hexversion < 0x3000000: + output_fn = fn + else: + output_fn = bytes(fn, 'utf-8') + resp = urllib2.urlopen(addr, output_fn) + out = open(os.path.join(TARBALL_CACHE_DIR, fn), 'wb') + out.write(resp.read()) + out.close() + except urllib2.HTTPError: + print('release %s not found' % ROOT_VERSION) + sys.exit(ERR_RELEASE_NOT_FOUND) +else: + print('reusing', fn, 'from local directory') + + +fn = os.path.join(TARBALL_CACHE_DIR, fn) +pkgdir = os.path.join('root-' + ROOT_VERSION) +if not os.path.exists(pkgdir): + print('now extracting', ROOT_VERSION) + tf = tarfile.TarFile.gzopen(fn) + tf.extractall() + tf.close() +else: + print('reusing existing directory', pkgdir) + +# remove everything except for the listed set of libraries +try: + shutil.rmtree('src') +except OSError: + pass +os.chdir(pkgdir) +clean_directory(os.path.curdir, ROOT_KEEP) +clean_directory('core', ROOT_CORE_KEEP) +clean_directory('etc', ROOT_ETC_KEEP, trim_cmake=False) +clean_directory('etc/plugins', ROOT_PLUGINS_KEEP, trim_cmake=False) +clean_directory('io', ROOT_IO_KEEP) +clean_directory('math', ROOT_MATH_KEEP) + + +# trim main (only need rootcling) +print('trimming main') +for entry in os.listdir('main/src'): + if entry != 'rootcling.cxx': + os.remove('main/src/'+entry) +inp = 'main/CMakeLists.txt' +outp = inp+'.new' +new_cml = open(outp, 'w') +for line in open(inp).readlines(): + if ('ROOT_EXECUTABLE' in line or\ + 'SET_TARGET_PROPERTIES' in line) and\ + not 'rootcling' in line: + line = '#'+line + new_cml.write(line) +new_cml.close() +os.rename(outp, inp) + +# trim core (gGLManager crashes on call) +print('trimming main') +os.remove("core/base/src/TVirtualGL.cxx") +os.remove("core/base/inc/TVirtualGL.h") + +# remove afterimage and ftgl explicitly +print('trimming externals') +for cmf in ['AfterImage', 'FTGL']: + fname = 'cmake/modules/Find%s.cmake' % (cmf,) + if os.path.exists(fname): + os.remove(fname) +inp = 'cmake/modules/SearchInstalledSoftware.cmake' +outp = inp+'.new' +now_stripping = False +new_cml = open(outp, 'w') +for line in open(inp).readlines(): + if '#---Check for ftgl if needed' == line[0:28] or\ + '#---Check for AfterImage' == line[0:24]: + now_stripping = True + elif '#---Check' == line[0:9]: + now_stripping = False + if now_stripping: + line = '#'+line + new_cml.write(line) +new_cml.close() +os.rename(outp, inp) + +inp = 'cmake/modules/RootBuildOptions.cmake' +outp = inp+'.new' +new_cml = open(outp, 'w') +for line in open(inp).readlines(): + if 'ROOT_BUILD_OPTION(builtin_ftgl' in line or\ + 'ROOT_BUILD_OPTION(builtin_afterimage' in line: + line = '#'+line + new_cml.write(line) +new_cml.close() +os.rename(outp, inp) + +# strip freetype +inp = 'cmake/modules/SearchInstalledSoftware.cmake' +outp = inp+'.new' +new_cml = open(outp, 'w') +for line in open(inp).readlines(): + if '#---Check for Freetype' == line[0:22]: + now_stripping = True + elif '#---Check for PCRE' == line[0:18]: + now_stripping = False + if now_stripping or 'builtin_freetype' in line: + line = '#'+line + new_cml.write(line) +new_cml.close() +os.rename(outp, inp) + +# remove testing and examples +print('trimming testing') +inp = 'CMakeLists.txt' +outp = inp+'.new' +now_stripping = False +new_cml = open(outp, 'w') +for line in open(inp).readlines(): + if '#---Configure Testing using CTest' == line[0:33] or\ + '#---hsimple.root' == line[0:16]: + now_stripping = True + elif '#---Packaging' == line[0:13] or\ + '#---version' == line[0:11]: + now_stripping = False + if now_stripping: + line = '#'+line + new_cml.write(line) +new_cml.close() +os.rename(outp, inp) + +print('trimming RootCPack') +inp = 'cmake/modules/RootCPack.cmake' +outp = inp+'.new' +new_cml = open(outp, 'w') +for line in open(inp): + if 'README.txt' in line: + line = '#'+line + new_cml.write(line) +new_cml.close() +os.rename(outp, inp) + + +# some more explicit removes: +for dir_to_remove in ROOT_EXPLICIT_REMOVE: + try: + shutil.rmtree(dir_to_remove) + except OSError: + pass + + +# special fixes +inp = 'core/base/src/TVirtualPad.cxx' +outp = inp+'.new' +new_cml = open(outp, 'w') +for line in open(inp): + if '#include "X3DBuffer.h"' == line[0:22]: + line = """//#include "X3DBuffer.h" +typedef struct _x3d_sizeof_ { + int numPoints; + int numSegs; + int numPolys; +} Size3D; +""" + new_cml.write(line) +new_cml.close() +os.rename(outp, inp) + +inp = 'core/unix/src/TUnixSystem.cxx' +outp = inp+'.new' +new_cml = open(outp, 'w') +for line in open(inp): + if '#include "TSocket.h"' == line[0:20]: + line = """//#include "TSocket.h" +enum ESockOptions { + kSendBuffer, // size of send buffer + kRecvBuffer, // size of receive buffer + kOobInline, // OOB message inline + kKeepAlive, // keep socket alive + kReuseAddr, // allow reuse of local portion of address 5-tuple + kNoDelay, // send without delay + kNoBlock, // non-blocking I/O + kProcessGroup, // socket process group (used for SIGURG and SIGIO) + kAtMark, // are we at out-of-band mark (read only) + kBytesToRead // get number of bytes to read, FIONREAD (read only) +}; + +enum ESendRecvOptions { + kDefault, // default option (= 0) + kOob, // send or receive out-of-band data + kPeek, // peek at incoming message (receive only) + kDontBlock // send/recv as much data as possible without blocking +}; +""" + new_cml.write(line) +new_cml.close() +os.rename(outp, inp) + +inp = 'math/mathcore/src/Fitter.cxx' +if os.path.exists(inp): + outp = inp+'.new' + new_cml = open(outp, 'w') + for line in open(inp): + if '#include "TF1.h"' in line: + continue + new_cml.write(line) + new_cml.close() + os.rename(outp, inp) + +# done +os.chdir(os.path.pardir) + +# debugging: run a test build +if DEBUG_TESTBUILD: + print('running a debug test build') + tb = "test_builddir" + if os.path.exists(tb): + shutil.rmtree(tb) + os.mkdir(tb) + os.chdir(tb) + os.system('cmake ../%s -DCMAKE_INSTALL_PREFIX=../install -Dminimal=ON -Dasimage=OFF' % pkgdir) + os.system('make -j 32') + + +# +## package creation +# +countdown = 0 + +print('adding src ... ') +if not os.path.exists('src'): + os.mkdir('src') +for entry in os.listdir(pkgdir): + fullp = os.path.join(pkgdir, entry) + if entry[0] == '.': + continue + dest = os.path.join('src', entry) + if os.path.isdir(fullp): + if not os.path.exists(dest): + shutil.copytree(fullp, dest) + else: + if not os.path.exists(dest): + shutil.copy2(fullp, dest) + +# +## apply patches +# +os.system('patch -p1 < patches/metacling.diff') +os.system('patch -p1 < patches/scanner.diff') +os.system('patch -p1 < patches/scanner_2.diff') +os.system('patch -p1 < patches/faux_typedef.diff') +os.system('patch -p1 < patches/template_fwd.diff') +os.system('patch -p1 < patches/dep_template.diff') +os.system('patch -p1 < patches/no_long64_t.diff') +os.system('patch -p1 < patches/using_decls.diff') +os.system('patch -p1 < patches/sfinae.diff') + +# done! diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/__init__.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/__init__.py new file mode 100644 index 0000000000000..848c37a25e63e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/__init__.py @@ -0,0 +1 @@ +from . import loader diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_cling_config.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_cling_config.py new file mode 100644 index 0000000000000..d0c642c226b5c --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_cling_config.py @@ -0,0 +1,28 @@ +from __future__ import print_function +import os, sys, subprocess + +MYHOME = os.path.dirname(__file__) + +def main(): + if len(sys.argv) == 2: + options = sys.argv[1] + + if options == '--cmake': + print(os.path.join(MYHOME, "cmake")) + return 0 + + if options == '--cppflags': + options = '--cflags' + + if options != '--help': + try: + cli_arg = subprocess.check_output( + [os.path.join(MYHOME, 'bin', 'root-config'), options], + stderr=subprocess.STDOUT) + print(cli_arg.decode("utf-8").strip()) + return 0 + except subprocess.CalledProcessError: + pass + + print('Usage: cling-config [--cflags] [--cppflags] [--cmake]') + return 1 diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_cppyy_generator.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_cppyy_generator.py new file mode 100644 index 0000000000000..b90cd78116e74 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_cppyy_generator.py @@ -0,0 +1,703 @@ +#!/usr/bin/env python + +"""Cppyy binding description generator.""" +from __future__ import print_function +import argparse +import gettext +import inspect +import json +import logging +import os +import re +import sys +import traceback + +from clang.cindex import AccessSpecifier, Config, CursorKind, Diagnostic, Index, SourceRange, TokenKind, TypeKind + + +class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter): + pass + + +logger = logging.getLogger(__name__) +gettext.install(__name__) + +# Keep PyCharm happy. +_ = _ + +EXPR_KINDS = [ + CursorKind.UNEXPOSED_EXPR, + CursorKind.CONDITIONAL_OPERATOR, CursorKind.UNARY_OPERATOR, CursorKind.BINARY_OPERATOR, + CursorKind.INTEGER_LITERAL, CursorKind.FLOATING_LITERAL, CursorKind.STRING_LITERAL, + CursorKind.CXX_BOOL_LITERAL_EXPR, CursorKind.CXX_STATIC_CAST_EXPR, CursorKind.DECL_REF_EXPR +] +TEMPLATE_KINDS = [ + CursorKind.TYPE_REF, CursorKind.TEMPLATE_REF, CursorKind.NAMESPACE_REF + ] + EXPR_KINDS +VARIABLE_KINDS = [CursorKind.VAR_DECL, CursorKind.FIELD_DECL] +FN_KINDS = [CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, CursorKind.FUNCTION_TEMPLATE, + CursorKind.CONSTRUCTOR, CursorKind.DESTRUCTOR, CursorKind.CONVERSION_FUNCTION] +# +# All Qt-specific logic is driven from these identifiers. Setting them to +# nonsense values would effectively disable all Qt-specific logic. +# +Q_SIGNALS = "Q_SIGNALS" + + +class SourceProcessor(object): + """ + Centralise all processing of the source. + Ideally, we'd use Clang for everything, but on occasion, we'll need access + to the source, without pre-processing. + """ + def __init__(self, compile_flags, verbose): + super(SourceProcessor, self).__init__() + self.compile_flags = compile_flags + ["-x", "c++"] + self.verbose = verbose + self.unpreprocessed_source = [] + self.source = None + + def compile(self, source): + """ + Use Clang to parse the source and return its AST. + :param source: The source file. + """ + if source != self.source: + self.unpreprocessed_source = [] + self.source = source + if self.verbose: + logger.info(" ".join(self.compile_flags + [self.source])) + tu = Index.create().parse(self.source, self.compile_flags) + # + # Stash ourselves on the tu for later use. + # + tu.source_processor = self + return tu + + def unpreprocessed(self, extent, nl=" "): + """ + Read the given range from the raw source. + + :param extent: The range of text required. + :param nl: What \n should be replaced by. + """ + assert self.source, "Must call compile() first!" + if not self.unpreprocessed_source: + self.unpreprocessed_source = self._read(self.source) + text = self._extract(self.unpreprocessed_source, extent) + if nl != "\n": + text = text.replace("\n", nl) + return text + + def _read(self, source): + lines = [] + with open(source, "rU") as f: + for line in f: + lines.append(line) + return lines + + def _extract(self, lines, extent): + extract = lines[extent.start.line - 1:extent.end.line] + if extent.start.line == extent.end.line: + extract[0] = extract[0][extent.start.column - 1:extent.end.column - 1] + else: + extract[0] = extract[0][extent.start.column - 1:] + extract[-1] = extract[-1][:extent.end.column - 1] + # + # Return a single buffer of text. + # + return "".join(extract) + + +class Info(dict): + def __init__(self, kind, cursor): + super(Info, self).__init__() + logger.debug(_("Processing object {}").format(item_describe(cursor))) + self["kind"] = kind + self["name"] = cursor.spelling + location = cursor.extent.start + self["row:col"] = "{}:{}".format(location.line, location.column) + if cursor.brief_comment: + self["brief_comment"] = cursor.brief_comment + if cursor.raw_comment: + self["raw_comment"] = cursor.raw_comment + + +def cursor_parents(cursor): + """ + A helper function which returns the parents of a cursor in the forms: + - A::B::C::...N for non-top level entities. + - filename.h for top level entities. + - "" in exceptional cases of having no parents. + """ + parents = "" + parent = cursor.semantic_parent + while parent and parent.kind != CursorKind.TRANSLATION_UNIT: + parents = parent.spelling + "::" + parents + parent = parent.semantic_parent + if parent and not parents: + return os.path.basename(parent.spelling) + return parents[:-2] + + +def item_describe(item, alternate_spelling=None): + """ + A helper function providing a standardised description for an item, + which may be a cursor. + """ + if isinstance(item, str): + return item + if alternate_spelling is None: + text = item.spelling + else: + text = alternate_spelling + return "{} on line {} '{}::{}'".format(item.kind.name, item.extent.start.line, cursor_parents(item), text) + + +def parameters_fixup(level, sip, key): + """ + Clang seems to replace template parameter N of the form "T" with + "type-parameter--N"...so we need to put "T" back. + + :param level: Template nesting level. + :param sip: The sip. + :param key: The key in the sip which may need + fixing up. + :return: + """ + for parent in reversed(level): + if parent.kind in [CursorKind.CLASS_TEMPLATE, CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION]: + for clang_parameter, real_parameter in enumerate(parent.template_params): + clang_parameter = "type-parameter-{}-{}".format(parent.template_level, clang_parameter) + real_parameter = real_parameter["name"] + # + # Depending on the type of the SIP entry, replace the Clang + # version of the value with the actual version. + # + value = sip[key] + if isinstance(value, str): + sip[key] = value.replace(clang_parameter, real_parameter) + elif isinstance(value, list): + for j, item in enumerate(value): + sip[key][j] = item.replace(clang_parameter, real_parameter) + elif isinstance(value, dict): + for j, item in value.items(): + sip[key][j] = item.replace(clang_parameter, real_parameter) + + +class CppyyGenerator(object): + def __init__(self, compile_flags, dump_modules=False, dump_items=False, dump_includes=False, + dump_privates=False, verbose=False): + """ + Constructor. + + :param compile_flags: The compile flags for the file. + :param dump_modules: Turn on tracing for modules. + :param dump_items: Turn on tracing for container members. + :param dump_includes: Turn on diagnostics for include files. + :param dump_privates: Turn on diagnostics for omitted private items. + :param verbose: Turn on diagnostics for command lines. + """ + self.dump_modules = dump_modules + self.dump_items = dump_items + self.dump_includes = dump_includes + self.dump_privates = dump_privates + self.verbose = verbose + self.diagnostics = set() + self.tu = None + self.source_processor = SourceProcessor(compile_flags, verbose) + + def create_mapping(self, h_files): + info = [] + for h_file in h_files: + logger.debug(_("Processing {}").format(h_file)) + file_info = self.create_file_mapping(h_file) + info.append(file_info) + return info + + def create_file_mapping(self, h_file): + """ + Generate a dict describing the given source header file. This is the + main entry point for this class. + + :param h_file: The source header file of interest. + :returns: A dict corresponding to the h_file. + """ + # + # Use Clang to parse the source and return its AST. + # + self.tu = self.source_processor.compile(h_file) + m = (logging.ERROR - logging.WARNING)/(Diagnostic.Error - Diagnostic.Warning) + c = logging.ERROR - (Diagnostic.Error * m) + for diag in self.tu.diagnostics: + # + # We expect to be run over hundreds of files. Any parsing issues are likely to be very repetitive. + # So, to avoid bothering the user, we suppress duplicates. + # + loc = diag.location + msg = "{}:{}[{}] {}".format(loc.file, loc.line, loc.column, diag.spelling) + if diag.spelling == "#pragma once in main file": + continue + if msg in self.diagnostics: + continue + self.diagnostics.add(msg) + logger.log(m * diag.severity + c, "While parsing: {}".format(msg)) + if self.dump_includes: + logger.info(_("File {}").format(h_file)) + for include in sorted(set(self.tu.get_includes())): + logger.info(_(" #includes {}").format(include.include.name)) + # + # Run through the top level children in the translation unit. + # + info = self._container_get(self.tu.cursor, [], h_file) + return info + + def _container_get(self, container, level, h_file): + """ + Generate the (recursive) translation for a class or namespace. + + :param container: A class or namespace. + :param level: Recursion level controls indentation. + :param h_file: The source header file of interest. + :return: Info(). + """ + def mark_forward_kinds(kind, definition): + has_body = False + # + # Could this be a forward declaration? + # + for token in definition.get_tokens(): + if token.kind == TokenKind.PUNCTUATION and token.spelling == "{": + has_body = True + if not has_body: + kind = "forward " + kind + return kind + + if container.kind == CursorKind.CLASS_DECL: + kind = mark_forward_kinds("class", container) + elif container.kind in [CursorKind.CLASS_TEMPLATE, CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION]: + kind = mark_forward_kinds("template class", container) + # + # What level of template parameter is on this container? + # + container.template_level = 0 + for parent in reversed(level): + if parent.kind in [CursorKind.CLASS_TEMPLATE, CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION]: + container.template_level = parent.template_level + 1 + break + container.template_params = [] + elif container.kind == CursorKind.STRUCT_DECL: + kind = mark_forward_kinds("struct", container) + elif container.kind == CursorKind.UNION_DECL: + kind = mark_forward_kinds("union", container) + elif container.kind == CursorKind.NAMESPACE: + kind = "namespace" + elif container.kind == CursorKind.TRANSLATION_UNIT: + kind = "file" + else: + logger.error(_("Unknown container kind {}").format(container.kind)) + kind = container.kind + info = Info(kind, container) + children = [] + info["children"] = children + template_count_stack = [] + template_info_stack = [] + template_stack_index = -1 + is_signal = False + for child in container.get_children(): + # + # Only emit items in the translation unit. + # + if child.location.file.name != self.tu.spelling: + continue + if child.access_specifier == AccessSpecifier.PRIVATE: + continue + if child.kind in FN_KINDS: + child_info = self._fn_get(container, child, level + [container], is_signal) + children.append(child_info) + elif child.kind == CursorKind.ENUM_DECL: + child_info = self._enum_get(container, child, level.append(container)) + children.append(child_info) + elif child.kind == CursorKind.CXX_ACCESS_SPEC_DECL: + is_signal = self._get_access_specifier(child) + elif child.kind == CursorKind.TYPEDEF_DECL: + child_info = self.typedef_decl(container, child, level + [container], h_file) + # + # Structs and unions are emitted twice: + # + # - first as just the bare fields + # - then as children of the typedef + # + if "type" in child_info and child_info["type"]["kind"] in ("struct", "union"): + assert children[-1] == child_info["type"] + children.pop() + children.append(child_info) + elif child.kind in [CursorKind.NAMESPACE, CursorKind.CLASS_DECL, CursorKind.CLASS_TEMPLATE, + CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, CursorKind.STRUCT_DECL, + CursorKind.UNION_DECL]: + child_info = self._container_get(child, level + [container], h_file) + children.append(child_info) + elif child.kind in [CursorKind.FIELD_DECL]: + child_info = self._var_get("field", child, level + [container]) + children.append(child_info) + elif child.kind in [CursorKind.VAR_DECL]: + child_info = self._var_get("variable", child, level + [container]) + children.append(child_info) + elif child.kind in [CursorKind.TEMPLATE_TYPE_PARAMETER, CursorKind.TEMPLATE_NON_TYPE_PARAMETER, + CursorKind.TEMPLATE_TEMPLATE_PARAMETER]: + info["parameters"] = container.template_params + param_info = Info("parameter", child) + container.template_params.append(param_info) + elif child.kind == CursorKind.TEMPLATE_REF: + # + # Create an entry to collect information for this level of template arguments. + # + tmp = Config().lib.clang_Type_getNumTemplateArguments(container.type) + template_count_stack.append(tmp) + template_info = Info("template", child) + template_info["parameters"] = [] + if template_stack_index == -1: + template_info_stack.append(template_info) + info["type"] = template_info + else: + # + # Non-first template_infos are just parameters. + # + template_info_stack[template_stack_index]["parameters"].append(template_info) + template_stack_index += 1 + elif child.kind == CursorKind.TYPE_REF: + if template_stack_index > -1: + # + # This is a template parameter. + # + template_parameters = template_info_stack[0]["parameters"] + for i in range(template_stack_index): + template_parameters = template_parameters[-1]["parameters"] + template_parameters.append(child.spelling) + template_count_stack[template_stack_index] -= 1 + if template_count_stack[template_stack_index] == 0: + template_stack_index -= 1 + else: + # + # Not a template. + # + child_info = Info("type", child) + info["type"] = child_info + else: + CppyyGenerator._report_ignoring(child, "unusable") + if self.dump_items: + logger.info(_("Processing {}").format(item_describe(child))) + return info + + def _get_access_specifier(self, member): + """ + In principle, we just want member.access_specifier.name.lower(), except that we need to handle: + + Q_SIGNALS:|signals: + + which are converted by the preprocessor...so read the original text. + + :param member: The access_specifier. + :return: + """ + access_specifier_text = self.source_processor.unpreprocessed(member.extent) + if access_specifier_text in (Q_SIGNALS + ":", "signals:"): + return True + return False + + def _enum_get(self, container, enum, level): + info = Info("enum", enum) + enumerations = [] + info["enumerations"] = enumerations + for enumeration in enum.get_children(): + # + # Skip visibility attributes and the like. + # + child_info = {} + if enumeration.kind == CursorKind.ENUM_CONSTANT_DECL: + child_info["name"] = enumeration.spelling + child_info["value"] = enumeration.enum_value + enumerations.append(child_info) + else: + CppyyGenerator._report_ignoring(enumeration, "unusable") + return info + + def _fn_get(self, container, fn, level, is_signal): + """ + Generate the translation for a function. + + :param container: A class or namespace. + :param fn: The function object. + :param level: Recursion level controls indentation. + :param is_signal: Is this a Qt signal? + :return: A string. + """ + info = Info("function", fn) + parameters_fixup(level, info, "name") + if fn.kind not in [CursorKind.CONSTRUCTOR, CursorKind.DESTRUCTOR]: + info["type"] = fn.result_type.spelling + parameters_fixup(level, info, "type") + parameters = [] + info["parameters"] = parameters + for child in fn.get_children(): + if child.kind == CursorKind.PARM_DECL: + # + # So far so good, but we need any default value. + # + child_info = self._fn_get_parameter(fn, child) + parameters_fixup(level, child_info, "type") + parameters.append(child_info) + elif child.kind in [CursorKind.COMPOUND_STMT, CursorKind.CXX_OVERRIDE_ATTR, + CursorKind.MEMBER_REF, CursorKind.DECL_REF_EXPR, CursorKind.CALL_EXPR, + CursorKind.UNEXPOSED_ATTR, CursorKind.VISIBILITY_ATTR] + TEMPLATE_KINDS: + # + # Ignore: + # + # CursorKind.COMPOUND_STMT: Function body. + # CursorKind.CXX_OVERRIDE_ATTR: The "override" keyword. + # CursorKind.MEMBER_REF, CursorKind.DECL_REF_EXPR, CursorKind.CALL_EXPR: Constructor initialisers. + # TEMPLATE_KINDS: The result type. + # + pass + else: + CppyyGenerator._report_ignoring(child, "unusable") + return info + + QUALIFIED_ID = re.compile("(?:[a-z_][a-z_0-9]*::)*([a-z_][a-z_0-9]*)", re.I) + + def _fn_get_parameter(self, fn, parameter): + """ + The parser does not seem to provide access to the complete text of a parameter. + This makes it hard to find any default values, so we: + + 1. Run the lexer from "here" to the end of the file, bailing out when we see the "," + or a ")" marking the end. + 2. Watch for the assignment. + """ + info = Info("parameter", parameter) + info["type"] = parameter.type.spelling + for member in parameter.get_children(): + if member.kind.is_expression(): + # + # Get the text after the "=". Macro expansion can make relying on tokens fraught...and + # member.get_tokens() simply does not always return anything. + # + possible_extent = SourceRange.from_locations(parameter.extent.start, fn.extent.end) + text = "" + bracket_level = 0 + found_start = False + found_end = False + was_punctuated = True + for token in self.tu.get_tokens(extent=possible_extent): + # + # Now count balanced anything-which-can-contain-a-comma till we get to the end. + # + if bracket_level == 0 and token.spelling == "=" and not found_start: + found_start = True + elif bracket_level == 0 and token.spelling in ",)": + found_end = True + text = text[1:] + break + elif token.spelling in "<(": + bracket_level += 1 + elif token.spelling in ")>": + bracket_level -= 1 + if found_start: + if (token.kind != TokenKind.PUNCTUATION and not was_punctuated) or (token.spelling in "*&"): + text += " " + text += token.spelling + was_punctuated = token.kind == TokenKind.PUNCTUATION + if not found_end and text: + raise RuntimeError(_("No end found for {}::{}, '{}'").format(fn.spelling, parameter.spelling, + text)) + info["default"] = text + return info + + def typedef_decl(self, container, typedef, level, h_file): + """ + Generate the translation for a typedef. + + :param container: A class or namespace. + :param typedef: The typedef object. + :param level: Recursion level controls indentation. + :param h_file: The source header file of interest. + :return: Info(). + """ + info = Info("typedef", typedef) + template_count_stack = [] + template_info_stack = [] + template_stack_index = -1 + parameters = None + for child in typedef.get_children(): + if child.kind in [CursorKind.STRUCT_DECL, CursorKind.UNION_DECL]: + child_info = self._container_get(child, level, h_file) + info["type"] = child_info + elif child.kind == CursorKind.TEMPLATE_REF: + # + # Create an entry to collect information for this level of template arguments. + # + tmp = Config().lib.clang_Type_getNumTemplateArguments(typedef.type) + if tmp == -1: + logger.error(_("Unexpected template_arg_count={}").format(tmp)) + # + # Just a WAG... + # + tmp = 1 + template_count_stack.append(tmp) + template_info = Info("template", child) + template_info["parameters"] = [] + if template_stack_index == -1: + template_info_stack.append(template_info) + info["type"] = template_info + else: + # + # Non-first template_infos are just parameters. + # + template_info_stack[template_stack_index]["parameters"].append(template_info) + template_stack_index += 1 + elif child.kind == CursorKind.TYPE_REF: + if template_stack_index > -1: + # + # This is a template parameter. + # + template_parameters = template_info_stack[0]["parameters"] + for i in range(template_stack_index): + template_parameters = template_parameters[-1]["parameters"] + template_parameters.append(child.spelling) + template_count_stack[template_stack_index] -= 1 + if template_count_stack[template_stack_index] == 0: + template_stack_index -= 1 + else: + # + # Not a template. + # + child_info = Info("type", child) + info["type"] = child_info + elif child.kind == CursorKind.PARM_DECL: + # + # This must be a function type. TODO: what if there are no PARM_DECLs? + # + if parameters is None: + child_info = Info("function", typedef) + info["type"] = child_info + # + # TODO: this is actually the signature: + # + # "int (Object::*)(QMetaObject::Call, int, void **)" + # + child_info["type"] = typedef.underlying_typedef_type.spelling + parameters = [] + child_info["parameters"] = parameters + child_info = self._fn_get_parameter(typedef, child) + parameters.append(child_info) + else: + CppyyGenerator._report_ignoring(child, "unusable") + if "type" not in info: + info["type"] = typedef.underlying_typedef_type.spelling + parameters_fixup(level, info, "type") + return info + + def _var_get(self, tag, parent, level): + """ + Generate the translation for a type. + + :param tag: "typedef", "variable" etc. + :param parent: The typed object. + :param level: Recursion level controls indentation. + :return: Info(). + """ + info = Info(tag, parent) + for child in parent.get_children(): + if child.kind == CursorKind.TYPE_REF: + info["type"] = child.spelling + parameters_fixup(level, info, "type") + else: + CppyyGenerator._report_ignoring(child, "unusable") + if "type" not in info: + info["type"] = parent.type.spelling + parameters_fixup(level, info, "type") + return info + + @staticmethod + def _report_ignoring(child, reason): + logger.debug(_("Ignoring {} {}").format(reason, item_describe(child))) + + +def main(argv=None): + """ + Takes a set of C++ header files and generate a JSON output file describing + the objects found in them. This output is intended to support more + convenient access to a set of cppyy-supported bindings. + + Examples: + + INC=/usr/include + QT5=$INC/x86_64-linux-gnu/qt5 + KF5=$INC/KF5 + INCDIRS="\\\\-I$KF5/KConfigCore;\\\\-I$QT5/QtXml;\\\\-I$QT5/QtCore" + STDDIRS="\\\\-I$Qt5/mkspecs/linux-g++-64\\\\;-I$KF5;\\\\-I$QT5" + FLAGS="\\\\-fvisibility=hidden;\\\-D__PIC__;\\\\-Wno-macro-redefined;\\\\-std=c++14" + + cppyy-generator --flags "$FLAGS;$INCDIRS;$STDDIRS" KF5/Config/Config.map $INC/KF5/KConfigCore/* + """ + if argv is None: + argv = sys.argv + parser = argparse.ArgumentParser(epilog=inspect.getdoc(main), + formatter_class=HelpFormatter) + parser.add_argument("-v", "--verbose", action="store_true", default=False, help=_("Enable verbose output")) + parser.add_argument("--flags", default="", + help=_("Semicolon-separated C++ compile flags to use, escape leading - or -- with \\")) + parser.add_argument("--libclang", help=_("libclang library to use for parsing")) + parser.add_argument("output", help=_("Output filename to write")) + parser.add_argument("sources", nargs="+", help=_("C++ headers to process")) + try: + args = parser.parse_args(argv[1:]) + if args.verbose: + logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)s %(levelname)s: %(message)s') + else: + logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') + flags = [] + for f in args.flags.lstrip().split(";"): + if f.startswith("\\-\\-"): + flags.append("--" + f[4:]) + elif f.startswith("\\-"): + flags.append("-" + f[2:]) + elif f: + flags.append(f) + # + # Load the given libclang. + # + if args.libclang: + Config.set_library_file(args.libclang) + lib = Config().lib + import ctypes + from clang.cindex import Type + items = [ + ("clang_Type_getNumTemplateArguments", [Type], ctypes.c_size_t), + ] + for item in items: + func = getattr(lib, item[0]) + if len(item) >= 2: + func.argtypes = item[1] + + if len(item) >= 3: + func.restype = item[2] + + if len(item) == 4: + func.errcheck = item[3] + # + # Generate! + # + g = CppyyGenerator(flags, verbose=args.verbose) + mapping = g.create_mapping(args.sources) + with open(args.output, "w") as f: + json.dump(mapping, f, indent=1, sort_keys=True) + return 0 + except Exception as e: + tbk = traceback.format_exc() + print(tbk) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_genreflex.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_genreflex.py new file mode 100644 index 0000000000000..5df32a2752f38 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_genreflex.py @@ -0,0 +1,15 @@ +from __future__ import print_function +import os, sys, subprocess + +MYHOME = os.path.dirname(__file__) + +def main(): + if len(sys.argv) == 2 and \ + (sys.argv[1] == '--cflags' or sys.argv[1] == '--cppflags'): + print('-I%s/include' % (MYHOME,)) + return 0 + os.environ['LD_LIBRARY_PATH'] = os.path.join(MYHOME, 'lib') + genreflex = os.path.join(MYHOME, 'bin', 'genreflex') + if not os.path.exists(genreflex): + raise RuntimeError("genreflex not installed in standard location") + return subprocess.call([genreflex] + sys.argv[1:]) diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_rootcling.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_rootcling.py new file mode 100644 index 0000000000000..84ce2cada1af9 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/_rootcling.py @@ -0,0 +1,10 @@ +import os, sys, subprocess + +MYHOME = os.path.dirname(__file__) + +def main(): + os.environ['LD_LIBRARY_PATH'] = os.path.join(MYHOME, 'lib') + rootcling = os.path.join(MYHOME, 'bin', 'rootcling') + if not os.path.exists(rootcling): + raise RuntimeError("rootcling not installed in standard location") + return subprocess.call([rootcling] + sys.argv[1:]) diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/bindings_utils.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/bindings_utils.py new file mode 100644 index 0000000000000..3f924280f5650 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/bindings_utils.py @@ -0,0 +1,339 @@ +""" +Support utilities for bindings. +""" +import glob +import json +from distutils.command.clean import clean +from distutils.util import get_platform +from setuptools.command.build_py import build_py +from wheel.bdist_wheel import bdist_wheel +import gettext +import inspect +import os +import re +import setuptools +import subprocess +import sys +try: + # + # Python2. + # + from imp import load_source +except ImportError: + # + # Python3. + # + import importlib.util + + def load_source(module_name, file_path): + spec = importlib.util.spec_from_file_location(module_name, file_path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + # Optional; only necessary if you want to be able to import the module + # by name later. + sys.modules[module_name] = module + return module + +import cppyy + + +gettext.install(__name__) + +# Keep PyCharm happy. +_ = _ + + +PRIMITIVE_TYPES = re.compile(r"\b(bool|char|short|int|unsigned|long|float|double)\b") + + +def initialise(pkg, __init__py, cmake_shared_library_prefix, cmake_shared_library_suffix): + """ + Initialise the bindings module. + + :param pkg: The bindings package. + :param __init__py: Base __init__.py file of the bindings. + :param cmake_shared_library_prefix: + ${cmake_shared_library_prefix} + :param cmake_shared_library_suffix: + ${cmake_shared_library_suffix} + """ + def add_to_pkg(file, keyword, simplenames, children): + def map_operator_name(name): + """ + Map the given C++ operator name on the python equivalent. + """ + CPPYY__idiv__ = "__idiv__" + CPPYY__div__ = "__div__" + gC2POperatorMapping = { + "[]": "__getitem__", + "()": "__call__", + "/": CPPYY__div__, + "%": "__mod__", + "**": "__pow__", + "<<": "__lshift__", + ">>": "__rshift__", + "&": "__and__", + "|": "__or__", + "^": "__xor__", + "~": "__inv__", + "+=": "__iadd__", + "-=": "__isub__", + "*=": "__imul__", + "/=": CPPYY__idiv__, + "%=": "__imod__", + "**=": "__ipow__", + "<<=": "__ilshift__", + ">>=": "__irshift__", + "&=": "__iand__", + "|=": "__ior__", + "^=": "__ixor__", + "==": "__eq__", + "!=": "__ne__", + ">": "__gt__", + "<": "__lt__", + ">=": "__ge__", + "<=": "__le__", + } + + op = name[8:] + result = gC2POperatorMapping.get(op, None) + if result: + return result + print(children) + + bTakesParams = 1 + if op == "*": + # dereference v.s. multiplication of two instances + return "__mul__" if bTakesParams else "__deref__" + elif op == "+": + # unary positive v.s. addition of two instances + return "__add__" if bTakesParams else "__pos__" + elif op == "-": + # unary negative v.s. subtraction of two instances + return "__sub__" if bTakesParams else "__neg__" + elif op == "++": + # prefix v.s. postfix increment + return "__postinc__" if bTakesParams else "__preinc__" + elif op == "--": + # prefix v.s. postfix decrement + return "__postdec__" if bTakesParams else "__predec__" + # might get here, as not all operator methods are handled (new, delete, etc.) + return name + + # + # Add level 1 objects to the pkg namespace. + # + if len(simplenames) > 1: + return + # + # Ignore some names based on heuristics. + # + simplename = simplenames[0] + if simplename in ('void', 'sizeof', 'const'): + return + if simplename[0] in '0123456789': + # + # Don't attempt to look up numbers (i.e. non-type template parameters). + # + return + if PRIMITIVE_TYPES.search(simplename): + return + if simplename.startswith("operator"): + simplename = map_operator_name(simplename) + # + # Classes, variables etc. + # + try: + entity = getattr(cppyy.gbl, simplename) + except AttributeError as e: + print(_("Unable to lookup {}:{} cppyy.gbl.{} ({})").format(file, keyword, simplename, children)) + #raise + else: + if getattr(entity, "__module__", None) == "cppyy.gbl": + setattr(entity, "__module__", pkg) + setattr(pkg_module, simplename, entity) + + pkg_dir = os.path.dirname(__init__py) + if "." in pkg: + pkg_namespace, pkg_simplename = pkg.rsplit(".", 1) + else: + pkg_namespace, pkg_simplename = "", pkg + pkg_module = sys.modules[pkg] + lib_name = pkg_namespace + pkg_simplename + "Cppyy" + lib_file = cmake_shared_library_prefix + lib_name + cmake_shared_library_suffix + map_file = os.path.join(pkg_dir, pkg_simplename + ".map") + # + # Load the library. + # + cppyy.load_reflection_info(os.path.join(pkg_dir, lib_file)) + # + # Parse the map file. + # + with open(map_file, 'rU') as map_file: + files = json.load(map_file) + # + # Iterate over all the items at the top level of each file, and add them + # to the pkg. + # + for file in files: + for child in file["children"]: + if not child["kind"] in ('class', 'var', 'namespace', 'typedef'): + continue + simplenames = child["name"].split('::') + add_to_pkg(file["name"], child["kind"], simplenames, child) + # + # Load any customisations. + # + extra_pythons = glob.glob(os.path.join(pkg_dir, "extra_*.py")) + for extra_python in extra_pythons: + extra_module = os.path.basename(extra_python) + extra_module = pkg + "." + os.path.splitext(extra_module)[0] + # + # Deleting the modules after use runs the risk of GC running on + # stuff we are using, such as ctypes.c_int. + # + extra = load_source(extra_module, extra_python) + # + # Valid customisations are routines named "c13n_". + # + fns = inspect.getmembers(extra, predicate=inspect.isroutine) + fns = {fn[0]: fn[1] for fn in fns if fn[0].startswith("c13n_")} + for fn in sorted(fns): + fns[fn](pkg_module) + + +def setup(pkg, setup_py, cmake_shared_library_prefix, cmake_shared_library_suffix, extra_pythons, + pkg_version, author, author_email, url, license): + """ + Wrap setuptools.setup for some bindings. + + :param pkg: Name of the bindings. + :param setup_py: Base __init__.py file of the bindings. + :param cmake_shared_library_prefix: + ${cmake_shared_library_prefix} + :param cmake_shared_library_suffix: + ${cmake_shared_library_suffix} + :param extra_pythons: Semicolon-separated list of customisation code. + :param pkg_version: The version of the bindings. + :param author: The name of the library author. + :param author_email: The email address of the library author. + :param url: The home page for the library. + :param license: The license. + """ + pkg_dir = os.path.dirname(setup_py) + if "." in pkg: + pkg_namespace, pkg_simplename = pkg.rsplit(".", 1) + else: + pkg_namespace, pkg_simplename = "", pkg + lib_name = pkg_namespace + pkg_simplename + "Cppyy" + lib_file = cmake_shared_library_prefix + lib_name + cmake_shared_library_suffix + long_description = """Bindings for {}. +These bindings are based on https://cppyy.readthedocs.io/en/latest/, and can be +used as per the documentation provided via the cppyy.cgl namespace. The environment +variable LD_LIBRARY_PATH must contain the path of the {}.rootmap file. Use +"import cppyy; from cppyy.gbl import ". + +Alternatively, use "import {}". This convenience wrapper supports "discovery" of the +available C++ entities using, for example Python 3's command line completion support. +""".replace("{}", pkg) + + class my_build_py(build_py): + def run(self): + # + # Base build. + # + build_py.run(self) + # + # Custom build. + # + # + # Move CMake output to self.build_lib. + # + pkg_subdir = pkg.replace(".", os.path.sep) + if pkg_namespace: + # + # Implement a pkgutil-style namespace package as per the guidance on + # https://packaging.python.org/guides/packaging-namespace-packages. + # + namespace_init = os.path.join(pkg_namespace, "__init__.py") + with open(namespace_init, "w") as f: + f.write("__path__ = __import__('pkgutil').extend_path(__path__, __name__)\n") + self.copy_file(namespace_init, os.path.join(self.build_lib, namespace_init)) + for f in self.package_data[pkg]: + self.copy_file(os.path.join(pkg_dir, pkg_subdir, f), os.path.join(self.build_lib, pkg_subdir, f)) + + class my_clean(clean): + def run(self): + # + # Custom clean. + # TODO: There is no way to reliably clean the "dist" directory. + # + # + # Base clean. + # + clean.run(self) + + class my_bdist_wheel(bdist_wheel): + def finalize_options(self): + # + # This is a universal (Python2/Python3), but platform-specific (has + # compiled parts) package; a combination that wheel does not recognize, + # thus simply fool it. + # + self.plat_name = get_platform() + bdist_wheel.finalize_options(self) + self.root_is_pure = True + + package_data = [lib_file, pkg_simplename + '.rootmap', pkg_simplename + '_rdict.pcm', pkg_simplename + ".map"] + package_data += [ep for ep in extra_pythons.split(";") if ep] + setuptools.setup( + name=pkg, + version=pkg_version, + author=author, + author_email=author_email, + url=url, + license=license, + description='Bindings for ' + pkg, + long_description=long_description, + platforms=['any'], + package_data={pkg: package_data}, + packages=[pkg], + zip_safe=False, + cmdclass={ + 'build_py': my_build_py, + 'clean': my_clean, + 'bdist_wheel': my_bdist_wheel, + }, + ) + + +def find_pips(): + """ + What pip versions do we have? + + :return: [pip_program] + """ + possible_pips = ['pip', 'pip2', 'pip3'] + pips = {} + for pip in possible_pips: + try: + # + # The command 'pip -V' returns a string of the form: + # + # pip 9.0.1 from /usr/lib/python2.7/dist-packages (python 2.7) + # + version = subprocess.check_output([pip, '-V']) + except subprocess.CalledProcessError: + pass + else: + version = version.rsplit('(', 1)[-1] + version = version.split()[-1] + # + # All pip variants that map onto a given Python version are de-duped. + # + pips[version] = pip + # + # We want the pip names. + # + assert len(pips), 'No viable pip versions found' + return pips.values() diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindCppyy.cmake b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindCppyy.cmake new file mode 100644 index 0000000000000..7238431ff6418 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindCppyy.cmake @@ -0,0 +1,488 @@ +#.rst: +# FindCppyy +# ------- +# +# Find Cppyy +# +# This module finds an installed Cppyy. It sets the following variables: +# +# :: +# +# Cppyy_FOUND - set to true if Cppyy is found +# Cppyy_DIR - the directory where Cppyy is installed +# Cppyy_EXECUTABLE - the path to the Cppyy executable +# Cppyy_INCLUDE_DIRS - Where to find the ROOT header files. +# Cppyy_VERSION - the version number of the Cppyy backend. +# +# +# The module also defines the following functions: +# +# cppyy_add_bindings - Generate a set of bindings from a set of header files. +# +# The minimum required version of Cppyy can be specified using the +# standard syntax, e.g. find_package(Cppyy 4.19) +# + +find_program(Cppyy_EXECUTABLE NAMES rootcling) + +if(Cppyy_EXECUTABLE) + # + # Cppyy_DIR. + # + set(Cppyy_DIR ${CMAKE_CURRENT_LIST_DIR}) + # + # Cppyy_INCLUDE_DIRS. + # + get_filename_component(Cppyy_INCLUDE_DIRS ${Cppyy_DIR} DIRECTORY) + set(Cppyy_INCLUDE_DIRS "${Cppyy_INCLUDE_DIRS}/include") + # + # Cppyy_VERSION. + # + find_package(ROOT QUIET REQUIRED PATHS ${CMAKE_CURRENT_LIST_DIR}) + if(ROOT_FOUND) + set(Cppyy_VERSION ${ROOT_VERSION}) + endif() +endif() + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( + Cppyy + REQUIRED_VARS Cppyy_EXECUTABLE Cppyy_DIR Cppyy_INCLUDE_DIRS + VERSION_VAR Cppyy_VERSION) + +mark_as_advanced(Cppyy_VERSION) + +# +# Generate a set of bindings from a set of header files. Somewhat like CMake's +# add_library(), the output is a compiler target. In addition ancilliary files +# are also generated to allow a complete set of bindings to be compiled, +# packaged and installed. +# +# cppyy_add_bindings( +# pkg +# pkg_version +# author +# author_email +# [URL url] +# [LICENSE license] +# [LANGUAGE_STANDARD std] +# [LINKDEFS linkdef...] +# [IMPORTS pcm...] +# [GENERATE_OPTIONS option...] +# [COMPILE_OPTIONS option...] +# [INCLUDE_DIRS dir...] +# [LINK_LIBRARIES library...] +# [H_DIRS H_DIRSectory] +# H_FILES h_file...) +# +# The bindings are based on https://cppyy.readthedocs.io/en/latest/, and can be +# used as per the documentation provided via the cppyy.cgl namespace. First add +# the directory of the .rootmap file to the LD_LIBRARY_PATH environment +# variable, then "import cppyy; from cppyy.gbl import ". +# +# Alternatively, use "import ". This convenience wrapper supports +# "discovery" of the available C++ entities using, for example Python 3's command +# line completion support. +# +# The bindings are complete with a setup.py, supporting Wheel-based +# packaging, and a test.py supporting pytest/nosetest sanity test of the bindings. +# +# The bindings are generated/built/packaged using 3 environments: +# +# - One compatible with the header files being bound. This is used to +# generate the generic C++ binding code (and some ancilliary files) using +# a modified C++ compiler. The needed options must be compatible with the +# normal build environment of the header files. +# +# - One to compile the generated, generic C++ binding code using a standard +# C++ compiler. The resulting library code is "universal" in that it is +# compatible with both Python2 and Python3. +# +# - One to package the library and ancilliary files into standard Python2/3 +# wheel format. The packaging is done using native Python tooling. +# +# Arguments and options: +# +# pkg The name of the package to generate. This can be either +# of the form "simplename" (e.g. "Akonadi"), or of the +# form "namespace.simplename" (e.g. "KF5.Akonadi"). +# +# pkg_version The version of the package. +# +# author The name of the library author. +# +# author_email The email address of the library author. +# +# URL url The home page for the library. Default is +# "https://pypi.python.org/pypi/". +# +# LICENSE license The license, default is "LGPL 2.0". +# +# LANGUAGE_STANDARD std +# The version of C++ in use, "14" by default. +# +# IMPORTS pcm Files which contain previously-generated bindings +# which pkg depends on. +# +# GENERATE_OPTIONS option +# Options which are to be passed into the rootcling +# command. For example, bindings which depend on Qt +# may need "-D__PIC__;-Wno-macro-redefined" as per +# https://sft.its.cern.ch/jira/browse/ROOT-8719. +# +# LINKDEFS def Files or lines which contain extra #pragma content +# for the linkdef.h file used by rootcling. See +# https://root.cern.ch/root/html/guides/users-guide/AddingaClass.html#the-linkdef.h-file. +# +# In lines, literal semi-colons must be escaped: "\;". +# +# EXTRA_CODES code Files which contain extra code needed by the bindings. +# Customisation is by routines named "c13n_"; +# each such routine is passed the module for : +# +# def c13n_doit(pkg_module): +# print(pkg_module.__dict__) +# +# The files and individual routines within files are +# processed in alphabetical order. +# +# EXTRA_HEADERS hdr Files which contain extra headers needed by the bindings. +# +# EXTRA_PYTHONS py Files which contain extra Python code needed by the bindings. +# +# COMPILE_OPTIONS option +# Options which are to be passed into the compile/link +# command. +# +# INCLUDE_DIRS dir Include directories. +# +# LINK_LIBRARIES library +# Libraries to link against. +# +# H_DIRS directory Base directories for H_FILES. +# +# H_FILES h_file Header files for which to generate bindings in pkg. +# Absolute filenames, or filenames relative to H_DIRS. All +# definitions found directly in these files will contribute +# to the bindings. (NOTE: This means that if "forwarding +# headers" are present, the real "legacy" headers must be +# specified as H_FILES). +# +# All header files which contribute to a given C++ namespace +# should be grouped into a single pkg to ensure a 1-to-1 +# mapping with the implementing Python class. +# +# Returns via PARENT_SCOPE variables: +# +# target The CMake target used to build. +# +# setup_py The setup.py script used to build or install pkg. +# +# Examples: +# +# find_package(Qt5Core NO_MODULE) +# find_package(KF5KDcraw NO_MODULE) +# get_target_property(_H_DIRS KF5::KDcraw INTERFACE_INCLUDE_DIRECTORIES) +# get_target_property(_LINK_LIBRARIES KF5::KDcraw INTERFACE_LINK_LIBRARIES) +# set(_LINK_LIBRARIES KF5::KDcraw ${_LINK_LIBRARIES}) +# include(${KF5KDcraw_DIR}/KF5KDcrawConfigVersion.cmake) +# +# cppyy_add_bindings( +# "KDCRAW" "${PACKAGE_VERSION}" "Shaheed" "srhaque@theiet.org" +# LANGUAGE_STANDARD "14" +# LINKDEFS "../linkdef_overrides.h" +# GENERATE_OPTIONS "-D__PIC__;-Wno-macro-redefined" +# INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} +# LINK_LIBRARIES ${_LINK_LIBRARIES} +# H_DIRS ${_H_DIRS} +# H_FILES "dcrawinfocontainer.h;kdcraw.h;rawdecodingsettings.h;rawfiles.h") +# +function(cppyy_add_bindings pkg pkg_version author author_email) + set(simple_args URL LICENSE LANGUAGE_STANDARD) + set(list_args IMPORTS GENERATE_OPTIONS COMPILE_OPTIONS INCLUDE_DIRS LINK_LIBRARIES H_DIRS H_FILES + LINKDEFS EXTRA_CODES EXTRA_HEADERS EXTRA_PYTHONS) + cmake_parse_arguments( + ARG + "" + "${simple_args}" + "${list_args}" + ${ARGN}) + if(NOT "${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") + message(SEND_ERROR "Unexpected arguments specified '${ARG_UNPARSED_ARGUMENTS}'") + endif() + string(REGEX MATCH "[^\.]+$" pkg_simplename ${pkg}) + string(REGEX REPLACE "\.?${pkg_simplename}" "" pkg_namespace ${pkg}) + set(pkg_dir ${CMAKE_CURRENT_BINARY_DIR}) + string(REPLACE "." "/" tmp ${pkg}) + set(pkg_dir "${pkg_dir}/${tmp}") + set(lib_name "${pkg_namespace}${pkg_simplename}Cppyy") + set(lib_file ${CMAKE_SHARED_LIBRARY_PREFIX}${lib_name}${CMAKE_SHARED_LIBRARY_SUFFIX}) + set(cpp_file ${CMAKE_CURRENT_BINARY_DIR}/${pkg_simplename}.cpp) + set(pcm_file ${pkg_dir}/${pkg_simplename}_rdict.pcm) + set(rootmap_file ${pkg_dir}/${pkg_simplename}.rootmap) + set(extra_map_file ${pkg_dir}/${pkg_simplename}.map) + # + # Package metadata. + # + if("${ARG_URL}" STREQUAL "") + string(REPLACE "." "-" tmp ${pkg}) + set(ARG_URL "https://pypi.python.org/pypi/${tmp}") + endif() + if("${ARG_LICENSE}" STREQUAL "") + set(ARG_LICENSE "LGPL2.1") + endif() + # + # Language standard. + # + if("${ARG_LANGUAGE_STANDARD}" STREQUAL "") + set(ARG_LANGUAGE_STANDARD "14") + endif() + # + # Make H_FILES with absolute paths. + # + if("${ARG_H_FILES}" STREQUAL "") + message(SEND_ERROR "No H_FILES specified") + endif() + if("${ARG_H_DIRS}" STREQUAL "") + set(ARG_H_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + set(tmp) + foreach(h_file IN LISTS ARG_H_FILES) + if(NOT IS_ABSOLUTE ${h_file}) + foreach(h_dir IN LISTS ARG_H_DIRS) + if(EXISTS ${h_dir}/${h_file}) + set(h_file ${h_dir}/${h_file}) + break() + endif() + endforeach(h_dir) + endif() + if(NOT EXISTS ${h_file}) + message(WARNING "H_FILES ${h_file} does not exist") + endif() + list(APPEND tmp ${h_file}) + endforeach(h_file) + set(ARG_H_FILES ${tmp}) + # + # Create the linkdef.h file with a line for each h_file. + # + set(out_linkdef ${CMAKE_CURRENT_BINARY_DIR}/linkdef.h) + file(WRITE ${out_linkdef} "/* Per H_FILES entries: */\n") + foreach(h_file IN LISTS ARG_H_FILES) + # + # Doubled-up path separators "//" causes errors in rootcling. + # + string(REGEX REPLACE "/+" "/" h_file ${h_file}) + file(APPEND ${out_linkdef} "#pragma link C++ defined_in ${h_file};\n") + endforeach(h_file) + foreach(h_file IN LISTS ARG_EXTRA_HEADERS) + # + # Doubled-up path separators "//" causes errors in rootcling. + # + string(REGEX REPLACE "/+" "/" h_file ${h_file}) + file(APPEND ${out_linkdef} "#pragma extra_include \"${h_file}\";\n") + endforeach(h_file) + # + # Append any manually-provided linkdef.h content. + # + set(LINKDEF_EXTRACTS) + string(REPLACE "\\" "\\\\" ARG_LINKDEFS "${ARG_LINKDEFS}") + foreach(in_linkdef IN LISTS ARG_LINKDEFS) + if("${in_linkdef}" STREQUAL "") + continue() + endif() + if(NOT IS_ABSOLUTE "${in_linkdef}" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${in_linkdef}") + set(in_linkdef "${CMAKE_CURRENT_SOURCE_DIR}/${in_linkdef}") + endif() + if(EXISTS "${in_linkdef}") + file(APPEND ${out_linkdef} "/* Copied from ${in_linkdef}: */\n") + file(STRINGS ${in_linkdef} in_linkdef NEWLINE_CONSUME) + else() + file(APPEND ${out_linkdef} "/* Inlined: */\n") + endif() + string(REPLACE "\n" ";" in_linkdef "${in_linkdef}") + foreach(line ${in_linkdef}) + file(APPEND ${out_linkdef} "${line}\n") + endforeach() + list(GET in_linkdef 0 in_linkdef) + list(APPEND LINKDEFS_EXTRACTS ${in_linkdef}) + endforeach(in_linkdef) + # + # Record diagnostics. + # + file(APPEND ${out_linkdef} "//\n// Diagnostics.\n//\n") + foreach(arg IN LISTS simple_args list_args) + if(arg STREQUAL "LINKDEFS") + file(APPEND ${out_linkdef} "// ${arg}=\n") + foreach(in_linkdef IN LISTS LINKDEFS_EXTRACTS) + file(APPEND ${out_linkdef} "// ${in_linkdef}...\n") + endforeach(in_linkdef) + else() + file(APPEND ${out_linkdef} "// ${arg}=${ARG_${arg}}\n") + endif() + endforeach(arg) + # + # Set up args. + # + list(APPEND ARG_GENERATE_OPTIONS "-std=c++${ARG_LANGUAGE_STANDARD}") + foreach(dir ${ARG_H_DIRS} ${ARG_INCLUDE_DIRS}) + list(APPEND ARG_GENERATE_OPTIONS "-I${dir}") + endforeach(dir) + # + # Run generator. First check dependencies. TODO: temporary hack: rather + # than an external dependency, enable libclang in the local build. + # + find_package(LibClang REQUIRED) + get_filename_component(Cppyygen_EXECUTABLE ${Cppyy_EXECUTABLE} DIRECTORY) + set(Cppyygen_EXECUTABLE ${Cppyygen_EXECUTABLE}/cppyy-generator) + # + # Set up arguments for cppyy-generator. + # + set(generator_args) + foreach(arg IN LISTS ARG_GENERATE_OPTIONS) + string(REGEX REPLACE "^-" "\\\\-" arg ${arg}) + list(APPEND generator_args ${arg}) + endforeach() + # + # Set up arguments for rootcling. + # + set(cling_args) + list(APPEND cling_args "-f" ${cpp_file}) + list(APPEND cling_args "-s" ${pkg_simplename}) + list(APPEND cling_args "-rmf" ${rootmap_file} "-rml" ${lib_file}) + foreach(in_pcm IN LISTS ARG_IMPORTS) + # + # Create -m options for any imported .pcm files. + # + list(APPEND cling_args "-m" "${in_pcm}") + endforeach(in_pcm) + list(APPEND cling_args "${ARG_GENERATE_OPTIONS}") + # + # Run rootcling, specifying the generated output. + # + file(MAKE_DIRECTORY ${pkg_dir}) + add_custom_command(OUTPUT ${extra_map_file} + COMMAND ${LibClang_PYTHON_EXECUTABLE} ${Cppyygen_EXECUTABLE} --flags "\"${generator_args}\"" + ${extra_map_file} ${ARG_H_FILES} WORKING_DIRECTORY ${pkg_dir}) + add_custom_command(OUTPUT ${cpp_file} ${pcm_file} ${rootmap_file} + COMMAND ${Cppyy_EXECUTABLE} ${cling_args} ${ARG_H_FILES} ${out_linkdef} WORKING_DIRECTORY ${pkg_dir}) + # + # Compile/link. + # + add_library(${lib_name} SHARED ${cpp_file} ${pcm_file} ${rootmap_file} ${extra_map_file} ${ARG_EXTRA_CODES}) + set_property(TARGET ${lib_name} PROPERTY VERSION ${version}) + set_property(TARGET ${lib_name} PROPERTY CXX_STANDARD ${ARG_LANGUAGE_STANDARD}) + set_property(TARGET ${lib_name} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${pkg_dir}) + target_include_directories(${lib_name} PRIVATE ${Cppyy_INCLUDE_DIRS} ${ARG_H_DIRS} ${ARG_INCLUDE_DIRS}) + target_compile_options(${lib_name} PRIVATE ${ARG_COMPILE_OPTIONS}) + target_link_libraries(${lib_name} ${ARG_LINK_LIBRARIES}) + # + # Install. NOTE: The generated files contain as few binding-specific strings + # as possible. + # + file( + GENERATE OUTPUT "${pkg_dir}/__init__.py" + CONTENT "from cppyy_backend import bindings_utils + +bindings_utils.initialise('${pkg}', __file__, '${CMAKE_SHARED_LIBRARY_PREFIX}', '${CMAKE_SHARED_LIBRARY_SUFFIX}') +del bindings_utils +") + set(setup_py ${CMAKE_CURRENT_BINARY_DIR}/setup.py) + file( + GENERATE OUTPUT ${setup_py} + CONTENT "from cppyy_backend import bindings_utils + + +bindings_utils.setup('${pkg}', __file__, '${CMAKE_SHARED_LIBRARY_PREFIX}', '${CMAKE_SHARED_LIBRARY_SUFFIX}', + '${ARG_EXTRA_PYTHONS}', + '${pkg_version}', '${author}', '${author_email}', '${ARG_URL}', '${ARG_LICENSE}') +") + set(setup_cfg ${CMAKE_CURRENT_BINARY_DIR}/setup.cfg) + file(WRITE ${setup_cfg} "[bdist_wheel] +universal=1 +") + # + # Generate a pytest/nosetest sanity test script. + # + file( + GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test.py + CONTENT "# pytest/nosetest sanity test script. +import logging +import os +import pydoc +import subprocess +import sys + +from cppyy_backend import bindings_utils + + +SCRIPT_DIR = os.path.dirname(__file__) +pkg = '${pkg}' +PIPS = None + + +class Test(object): + @classmethod + def setup_class(klass): + # + # Make an attempt to check the verbosity setting (ignore quiet!). + # + verbose = [a for a in sys.argv[1:] if a.startswith(('-v', '--verbos'))] + if verbose: + logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)s %(levelname)s: %(message)s') + else: + logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') + global PIPS + PIPS = bindings_utils.find_pips() + + @classmethod + def teardown_class(klass): + pass + + def setUp(self): + '''This method is run once before _each_ test method is executed''' + + def teardown(self): + '''This method is run once after _each_ test method is executed''' + + def test_install(self): + for pip in PIPS: + subprocess.check_call([pip, 'install', '--force-reinstall', '--pre', '.'], cwd=SCRIPT_DIR) + + def test_import(self): + __import__(pkg) + + def test_help(self): + pydoc.render_doc(pkg) + + def test_uninstall(self): + for pip in PIPS: + subprocess.check_call([pip, 'uninstall', '--yes', pkg], cwd=SCRIPT_DIR) +") + # + # Stage extra Python code. + # + foreach(extra_python IN LISTS ARG_EXTRA_PYTHONS) + file(GENERATE OUTPUT ${pkg_dir}/${extra_python} INPUT ${CMAKE_CURRENT_SOURCE_DIR}/${extra_python}) + endforeach() + # + # Return results. + # + set(target ${lib_name} PARENT_SCOPE) + set(setup_py ${setup_py} PARENT_SCOPE) +endfunction(cppyy_add_bindings) + +# +# Return a list of available pip programs. +# +function(cppyy_find_pips) + execute_process( + COMMAND python -c "from cppyy_backend import bindings_utils; print(\";\".join(bindings_utils.find_pips()))" + OUTPUT_VARIABLE _stdout + ERROR_VARIABLE _stderr + RESULT_VARIABLE _rc + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT "${_rc}" STREQUAL "0") + message(FATAL_ERROR "Error finding pips: (${_rc}) ${_stderr}") + endif() + set(PIP_EXECUTABLES ${_stdout} PARENT_SCOPE) +endfunction(cppyy_find_pips) diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindLibClang.cmake b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindLibClang.cmake new file mode 100644 index 0000000000000..768cfb57d09a6 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindLibClang.cmake @@ -0,0 +1,56 @@ +#.rst: +# FindLibClang +# ------------ +# +# Find LibClang +# +# Find LibClang headers and library +# +# :: +# +# LibClang_FOUND - True if libclang is found. +# LibClang_LIBRARY - Clang library to link against. +# LibClang_VERSION - Version number as a string (e.g. "3.9"). +# LibClang_PYTHON_EXECUTABLE - Compatible python version. + +# +# Python support for clang might not be available for Python3. We need to +# find what we have. +# +function(_find_libclang_filename python_executable filename) + # + # Prefer python3 explicitly or implicitly over python2. + # + foreach(exe IN ITEMS python3 python python2) + execute_process( + COMMAND ${exe} -c "from clang.cindex import Config; Config().lib; print(Config().get_filename())" + OUTPUT_VARIABLE lib + ERROR_VARIABLE _stderr + RESULT_VARIABLE _rc + OUTPUT_STRIP_TRAILING_WHITESPACE) + if("${_rc}" STREQUAL "0") + set(pyexe ${exe}) + break() + endif() + endforeach() + set(${python_executable} "${pyexe}" PARENT_SCOPE) + set(${filename} "${lib}" PARENT_SCOPE) +endfunction(_find_libclang_filename) + + +_find_libclang_filename(LibClang_PYTHON_EXECUTABLE _filename) +find_library(LibClang_LIBRARY ${_filename}) + +if(LibClang_LIBRARY) + set(LibClang_LIBRARY ${LibClang_LIBRARY}) + string(REGEX REPLACE ".*clang-\([0-9]+.[0-9]+\).*" "\\1" LibClang_VERSION_TMP "${LibClang_LIBRARY}") + set(LibClang_VERSION ${LibClang_VERSION_TMP} CACHE STRING "LibClang version" FORCE) +endif() + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibClang REQUIRED_VARS LibClang_LIBRARY LibClang_PYTHON_EXECUTABLE + VERSION_VAR LibClang_VERSION) + +mark_as_advanced(LibClang_VERSION) +unset(_filename) +unset(_find_libclang_filename) diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/loader.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/loader.py new file mode 100644 index 0000000000000..e82124a917ce2 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/python/cppyy_backend/loader.py @@ -0,0 +1,17 @@ +""" cppyy_backend loader +""" + +import os, ctypes + +def load_cpp_backend(): + try: + # normal load, allowing for user overrides of LD_LIBRARY_PATH + c = ctypes.CDLL("libcppyy_backend.so", ctypes.RTLD_GLOBAL) + except OSError: + # failed ... load dependencies explicitly + libpath = os.path.join(os.path.dirname(__file__), 'lib') + for dep in ['libCore.so', 'libThread.so', 'libRIO.so', 'libCling.so']: + ctypes.CDLL(os.path.join(libpath, dep), ctypes.RTLD_GLOBAL) + c = ctypes.CDLL(os.path.join(libpath, 'libcppyy_backend.so'), ctypes.RTLD_GLOBAL) + + return c diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/setup.cfg b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/setup.cfg new file mode 100644 index 0000000000000..82bf11f7840c7 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +universal=1 + +[metadata] +license_file = LICENSE.txt diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/setup.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/setup.py new file mode 100644 index 0000000000000..736244702c29a --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/setup.py @@ -0,0 +1,230 @@ +import os, sys, subprocess +import multiprocessing +from setuptools import setup, find_packages +from distutils import log +from distutils.command.build import build as _build +from distutils.command.clean import clean as _clean +from distutils.dir_util import remove_tree +from setuptools.command.install import install as _install +from wheel.bdist_wheel import bdist_wheel as _bdist_wheel +from distutils.errors import DistutilsSetupError +from codecs import open + +here = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + +builddir = None +def get_builddir(): + """cppyy_backend build.""" + global builddir + if builddir is None: + topdir = os.getcwd() + builddir = os.path.join(topdir, 'builddir') + return builddir + +srcdir = None +def get_srcdir(): + """cppyy_backend source.""" + global srcdir + if srcdir is None: + topdir = os.getcwd() + srcdir = os.path.join(topdir, 'src') + return srcdir + +prefix = None +def get_prefix(): + """cppyy_backend installation.""" + global prefix + if prefix is None: + prefix = os.path.join(get_builddir(), 'install', 'cppyy_backend') + return prefix + + +class my_cmake_build(_build): + def run(self): + # base run + _build.run(self) + + # custom run + log.info('Now building cppyy_backend') + builddir = get_builddir() + prefix = get_prefix() + srcdir = get_srcdir() + if not os.path.exists(srcdir): + log.info('No src directory ... creating with "python create_src_directory.py"') + if subprocess.call(['python', 'create_src_directory.py']) != 0: + log.error('ERROR: the source directory "%s" does not exist' % srcdir) + log.error('Please run "python create_src_directory.py" first.') + sys.exit(1) + + if not os.path.exists(builddir): + log.info('Creating build directory %s ...' % builddir) + os.makedirs(builddir) + + # get C++ standard to use, if set + try: + stdcxx = os.environ['STDCXX'] + except KeyError: + stdcxx = '14' + + if not stdcxx in ['11', '14', '17']: + log.fatal('FATAL: envar STDCXX should be one of 11, 14, or 17') + sys.exit(1) + + stdcxx='-Dcxx'+stdcxx+'=ON' + + log.info('Running cmake for cppyy_backend') + if subprocess.call([ + 'cmake', srcdir, stdcxx, + '-Dminimal=ON', '-Dasimage=OFF', '-Droot7=OFF', '-Dhttp=OFF', '-Dbuiltin_freetype=OFF', + '-DCMAKE_BUILD_TYPE=RelWithDebInfo', + '-DCMAKE_INSTALL_PREFIX='+prefix], cwd=builddir) != 0: + raise DistutilsSetupError('Failed to configure cppyy_backend') + + # default to using all available cores (x2 if hyperthreading enabled) + nprocs = os.getenv("MAKE_NPROCS") or '0' + try: + nprocs = int(nprocs) + except ValueError: + log.warn("Integer expected for MAKE_NPROCS, but got %s (ignored)", nprocs) + nprocs = 0 + if nprocs < 1: + nprocs = multiprocessing.cpu_count() + build_args = ['--build', '.', '--config', 'RelWithDebInfo', '--'] + if 'win32' in sys.platform: + build_args.append('/maxcpucount:' + str(nprocs)) + else: + build_args.append('-j' + str(nprocs)) + log.info('Now building cppyy_backend and dependencies ...') + if subprocess.call(['cmake'] + build_args, cwd=builddir) != 0: + raise DistutilsSetupError('Failed to build cppyy_backend') + + log.info('Build finished') + +class my_clean(_clean): + def run(self): + # Custom clean. Clean everything except that which the base clean + # (see below) or create_src_directory.py is responsible for. + topdir = os.getcwd() + if self.all: + # remove build directories + for directory in (get_builddir(), + os.path.join(topdir, "python", "cppyy_cling.egg-info")): + if os.path.exists(directory): + remove_tree(directory, dry_run=self.dry_run) + else: + log.warn("'%s' does not exist -- can't clean it", + directory) + # Base clean. + _clean.run(self) + +class my_install(_install): + def _get_install_path(self): + # depending on goal, copy over pre-installed tree + if hasattr(self, 'bdist_dir') and self.bdist_dir: + install_path = self.bdist_dir + else: + install_path = self.install_lib + return install_path + + def run(self): + # base install + _install.run(self) + + # custom install of backend + log.info('Now installing cppyy_backend') + builddir = get_builddir() + if not os.path.exists(builddir): + raise DistutilsSetupError('Failed to find build dir!') + + prefix = get_prefix() + log.info('Now creating installation under %s ...', prefix) + install_args = ['--build', '.', '--config', 'RelWithDebInfo', '--target', 'install'] + if subprocess.call(['cmake'] + install_args, cwd=builddir) != 0: + raise DistutilsSetupError('Failed to install cppyy_backend') + + prefix_base = os.path.join(get_prefix(), os.path.pardir) + install_path = self._get_install_path() + log.info('Copying installation to: %s ...', install_path) + self.copy_tree(prefix_base, install_path) + + log.info('Install finished') + + def get_outputs(self): + outputs = _install.get_outputs(self) + outputs.append(os.path.join(self._get_install_path(), 'cppyy_backend')) + return outputs + +class my_bdist_wheel(_bdist_wheel): + def finalize_options(self): + # this is a universal, but platform-specific package; a combination + # that wheel does not recognize, thus simply fool it + from distutils.util import get_platform + self.plat_name = get_platform() + _bdist_wheel.finalize_options(self) + self.root_is_pure = True + + +setup( + name='cppyy-cling', + description='Re-packaged Cling, as backend for cppyy', + long_description=long_description, + url='https://root.cern.ch/cling', + + # Author details + author='ROOT Developers', + author_email='rootdev@cern.ch', + + version='6.12.6.2', + + license='LLVM: UoI-NCSA; ROOT: LGPL 2.1', + + classifiers=[ + 'Development Status :: 6 - Mature', + + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + + 'Topic :: Software Development', + 'Topic :: Software Development :: Interpreters', + + 'License :: OSI Approved :: University of Illinois/NCSA Open Source License', + 'License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)', + + 'Operating System :: POSIX', + 'Operating System :: POSIX :: Linux', + 'Operating System :: MacOS :: MacOS X', + + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: C', + 'Programming Language :: C++', + + 'Natural Language :: English' + ], + + keywords='interpreter development', + + include_package_data=True, + package_data={'': ['cmake/*.cmake']}, + + package_dir={'': 'python'}, + packages=find_packages('python', include=['cppyy_backend']), + + cmdclass = { + 'build': my_cmake_build, + 'clean': my_clean, + 'install': my_install, + 'bdist_wheel': my_bdist_wheel, + }, + + entry_points={ + "console_scripts": [ + "cling-config = cppyy_backend._cling_config:main", + "genreflex = cppyy_backend._genreflex:main", + "rootcling = cppyy_backend._rootcling:main", + "cppyy-generator = cppyy_backend._cppyy_generator:main", + ], + }, +) diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/tests/test_cppyy_backend.h b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/tests/test_cppyy_backend.h new file mode 100644 index 0000000000000..ff9510d76eaf3 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/tests/test_cppyy_backend.h @@ -0,0 +1,49 @@ + +namespace Outer +{ + class Inner + { + public: + Inner(); + void fn1(int arg); + }; + + template + class Template + { + public: + Template(); + }; + + /** + * Simple specialisation. + */ + template<> + class Template + { + public: + Template(); + }; + + /** + * Complex specialisation. + */ + template<> + class Template, 1> + { + public: + Template(); + }; + + /** + * Simply templated function. + */ + template + void doit(Template arg); + + /** + * Less-simply templated function. + */ + template + void doit(Template,U> arg); +}; \ No newline at end of file diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/tests/test_cppyy_backend.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/tests/test_cppyy_backend.py new file mode 100644 index 0000000000000..034b5d1d898c8 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/cling/tests/test_cppyy_backend.py @@ -0,0 +1,52 @@ +""" +Pytest/nosetest tests. +""" +import json +import logging +import os +import tempfile + +from cppyy_backend import _cppyy_generator + + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class TestCppyyGenerator(object): + """ + Test cppyy_generator. + """ + @classmethod + def setup_class(klass): + pass + + @classmethod + def teardown_class(klass): + pass + + def setUp(self): + '''This method is run once before _each_ test method is executed''' + + def teardown(self): + '''This method is run once after _each_ test method is executed''' + + def test_generator(self): + cpp_h = os.path.join(SCRIPT_DIR, "test_cppyy_backend.h") + mapfile = tempfile.NamedTemporaryFile().name + # + # Create mapping. + # + logging.info("mapfile is {}".format(mapfile)) + result = _cppyy_generator.main([ + "", + "-v", + "--flags=\\-fvisibility=hidden;\\-D__PIC__;\\-Wno-macro-redefined;\\-std=c++14", + mapfile, cpp_h + ]) + assert result == 0 + # + # Read mapping. + # + with open(mapfile, "rU") as mapfile: + mapping = json.load(mapfile) + assert mapping[0]["children"][0]["name"] == "Outer" diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/LICENSE.txt b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/LICENSE.txt new file mode 100644 index 0000000000000..f9a0f50ea780f --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/LICENSE.txt @@ -0,0 +1,52 @@ +Copyright (c) 2017, The Regents of the University of California, +through Lawrence Berkeley National Laboratory (subject to receipt of +any required approvals from the U.S. Dept. of Energy). All rights +reserved. Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following +conditions are met: + +(1) Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +(2) Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +(3) Neither the name of the University of California, Lawrence Berkeley +National Laboratory, U.S. Dept. of Energy nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +You are under no obligation whatsoever to provide any bug fixes, +patches, or upgrades to the features, functionality or performance of +the source code ("Enhancements") to anyone; however, if you choose to +make your Enhancements available either publicly, or directly to +Lawrence Berkeley National Laboratory, without imposing a separate +written license agreement for such Enhancements, then you hereby grant +the following license: a non-exclusive, royalty-free perpetual license +to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such Enhancements +or derivative works thereof, in binary and source code form. + + +Additional copyright holders +---------------------------- + +Except when otherwise stated (look for LICENSE files or information in +source files), this package contains files copyrighted by one or more of +the following people and organizations: + + CERN + Antonio Cuni + Aditi Dutta + Shaheed Haque diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/MANIFEST.in b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/MANIFEST.in new file mode 100644 index 0000000000000..6db55ce0e102b --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/MANIFEST.in @@ -0,0 +1,5 @@ +# Include the license file +include LICENSE.txt + +# Include the data files +recursive-include src * diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/README.rst b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/README.rst new file mode 100644 index 0000000000000..0b751f618beea --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/README.rst @@ -0,0 +1,28 @@ +cppyy-backend +============= + +C/C++ wrapper around Cling for use by cppyy. + +This package will pull in cppyy-cling, which contains a version of LLVM +that is patched for interactive use. + +Compilation of LLVM may take a long time, so when building from source, it is +recommended to set MAKE_NPROCS to the number of cores on your machine and to +use the verbose flag to see progress: + + $ MAKE_NPROCS=32 pip install --verbose cppyy-backend + +Alternatively, there are binary wheels (Mac 10.12, Linux/Gentoo) +available here: + https://cern.ch/wlav/wheels + +Use '--extra-index https://cern.ch/wlav/wheels' as an argument to pip to +pick them up. + +Cling documentation is here: + https://root.cern.ch/cling + +---- + +Find the cppyy documentation here: + http://cppyy.readthedocs.io diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/python/cppyy_backend/__init__.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/python/cppyy_backend/__init__.py new file mode 100644 index 0000000000000..848c37a25e63e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/python/cppyy_backend/__init__.py @@ -0,0 +1 @@ +from . import loader diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/python/cppyy_backend/loader.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/python/cppyy_backend/loader.py new file mode 100644 index 0000000000000..e82124a917ce2 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/python/cppyy_backend/loader.py @@ -0,0 +1,17 @@ +""" cppyy_backend loader +""" + +import os, ctypes + +def load_cpp_backend(): + try: + # normal load, allowing for user overrides of LD_LIBRARY_PATH + c = ctypes.CDLL("libcppyy_backend.so", ctypes.RTLD_GLOBAL) + except OSError: + # failed ... load dependencies explicitly + libpath = os.path.join(os.path.dirname(__file__), 'lib') + for dep in ['libCore.so', 'libThread.so', 'libRIO.so', 'libCling.so']: + ctypes.CDLL(os.path.join(libpath, dep), ctypes.RTLD_GLOBAL) + c = ctypes.CDLL(os.path.join(libpath, 'libcppyy_backend.so'), ctypes.RTLD_GLOBAL) + + return c diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/setup.cfg b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/setup.cfg new file mode 100644 index 0000000000000..82bf11f7840c7 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +universal=1 + +[metadata] +license_file = LICENSE.txt diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/setup.py b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/setup.py new file mode 100644 index 0000000000000..9ddc691fac743 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/setup.py @@ -0,0 +1,181 @@ +import os, glob, subprocess +from setuptools import setup, find_packages, Extension +from distutils import log +from distutils.command.build_ext import build_ext as _build_ext +from distutils.command.clean import clean as _clean +from distutils.dir_util import remove_tree +from setuptools.command.install import install as _install +from wheel.bdist_wheel import bdist_wheel as _bdist_wheel +from distutils.errors import DistutilsSetupError +from codecs import open + + +here = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + +try: + root_install = os.environ["ROOTSYS"] + requirements = [] + add_pkg = ['cppyy_backend'] +except KeyError: + root_install = None + requirements = ['cppyy-cling'] + add_pkg = [] + +def get_include_path(): + config_exec = 'cling-config' + if root_install: + config_exec = 'root-config' + cli_arg = subprocess.check_output([config_exec, '--incdir']) + return cli_arg.decode("utf-8").strip() + +def get_cflags(): + config_exec = 'cling-config' + if root_install: + config_exec = 'root-config' + cli_arg = subprocess.check_output([config_exec, '--auxcflags']) + return cli_arg.decode("utf-8").strip() + +class my_build_cpplib(_build_ext): + def build_extension(self, ext): + include_dirs = ext.include_dirs + [get_include_path()] + log.info('checking for %s', self.build_temp) + if not os.path.exists(self.build_temp): + log.info('creating %s', self.build_temp) + os.makedirs(self.build_temp) + objects = self.compiler.compile( + ext.sources, + output_dir=self.build_temp, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=['-O2']+get_cflags().split()) + + ext_path = self.get_ext_fullpath(ext.name) + output_dir = os.path.dirname(ext_path) + full_libname = 'libcppyy_backend.so' # forced, b/c hard-wired in pypy-c/cppyy + + log.info("now building %s", full_libname) + self.compiler.link_shared_object( + objects, full_libname, + build_temp=self.build_temp, + output_dir=output_dir, + debug=self.debug, + target_lang='c++') + +class my_clean(_clean): + def run(self): + # Custom clean. Clean everything except that which the base clean + # (see below) or create_src_directory.py is responsible for. + topdir = os.getcwd() + if self.all: + # remove build directories + for directory in (os.path.join(topdir, "dist"), + os.path.join(topdir, "python", "cppyy_backend.egg-info")): + if os.path.exists(directory): + remove_tree(directory, dry_run=self.dry_run) + else: + log.warn("'%s' does not exist -- can't clean it", + directory) + # Base clean. + _clean.run(self) + +class my_install(_install): + def _get_install_path(self): + # depending on goal, copy over pre-installed tree + if hasattr(self, 'bdist_dir') and self.bdist_dir: + install_path = self.bdist_dir + else: + install_path = self.install_lib + return install_path + + def run(self): + # base install + _install.run(self) + + # custom install of backend + log.info('Now installing cppyy_backend') + builddir = self.build_lib + if not os.path.exists(builddir): + raise DistutilsSetupError('Failed to find build dir!') + + install_path = self._get_install_path() + log.info('Copying installation to: %s ...', install_path) + self.copy_tree(builddir, install_path) + + log.info('Install finished') + + def get_outputs(self): + outputs = _install.get_outputs(self) + #outputs.append(os.path.join(self._get_install_path(), 'cppyy_backend')) + return outputs + +class my_bdist_wheel(_bdist_wheel): + def run(self, *args): + # wheels do not respect dependencies; make this a no-op so that it fails (mostly) silently + pass + + def finalize_options(self): + # this is a universal, but platform-specific package; a combination + # that wheel does not recognize, thus simply fool it + from distutils.util import get_platform + self.plat_name = get_platform() + self.universal = True + _bdist_wheel.finalize_options(self) + self.root_is_pure = True + + +setup( + name='cppyy-backend', + description='C/C++ wrapper for Cling', + long_description=long_description, + url='http://pypy.org', + + # Author details + author='PyPy Developers', + author_email='pypy-dev@python.org', + + version='1.0.0', + + license='LBNL BSD', + + classifiers=[ + 'Development Status :: 5 - Production/Stable', + + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + + 'Topic :: Software Development', + 'Topic :: Software Development :: Interpreters', + + 'License :: OSI Approved :: BSD License', + + 'Operating System :: POSIX', + 'Operating System :: POSIX :: Linux', + 'Operating System :: MacOS :: MacOS X', + + 'Programming Language :: C', + 'Programming Language :: C++', + + 'Natural Language :: English' + ], + + keywords='C++ bindings data science', + + setup_requires=requirements, + install_requires=requirements, + + package_dir={'': 'python'}, + packages=find_packages('python', include=add_pkg), + + ext_modules=[Extension('cppyy_backend/lib/libcppyy_backend', + sources=glob.glob('src/clingwrapper.cxx'))], + zip_safe=False, + + cmdclass = { + 'build_ext': my_build_cpplib, + 'clean': my_clean, + 'install': my_install, + 'bdist_wheel': my_bdist_wheel + } +) diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/callcontext.h b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/callcontext.h new file mode 100644 index 0000000000000..dbbf88084a492 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/callcontext.h @@ -0,0 +1,38 @@ +#ifndef CPYCPPYY_CALLCONTEXT_H +#define CPYCPPYY_CALLCONTEXT_H + +// Standard +#include + +//Bindings +#include "cpp_cppyy.h" + +//ROOT +#include "Rtypes.h" + +namespace CPyCppyy { + +// general place holder for function parameters + struct Parameter { + union Value { + bool fBool; + short fShort; + unsigned short fUShort; + int fInt; + unsigned int fUInt; + long fLong; + unsigned long fULong; + Long64_t fLongLong; + ULong64_t fULongLong; + float fFloat; + double fDouble; + LongDouble_t fLongDouble; + void* fVoidp; + } fValue; + void* fRef; + char fTypeCode; + }; + +} // namespace CPyCppyy + +#endif // !CPYCPPYY_CALLCONTEXT_H diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/capi.h b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/capi.h new file mode 100644 index 0000000000000..fd62ae7dcf7e4 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/capi.h @@ -0,0 +1,228 @@ +#ifndef CPPYY_CAPI +#define CPPYY_CAPI + +#include +#include "precommondefs.h" + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + + typedef ptrdiff_t cppyy_scope_t; + typedef cppyy_scope_t cppyy_type_t; + typedef void* cppyy_object_t; + typedef ptrdiff_t cppyy_method_t; + + typedef long cppyy_index_t; + typedef void* cppyy_funcaddr_t; + + typedef unsigned long cppyy_exctype_t; + + /* name to opaque C++ scope representation -------------------------------- */ + RPY_EXTERN + char* cppyy_resolve_name(const char* cppitem_name); + RPY_EXTERN + char* cppyy_resolve_enum(const char* enum_type); + RPY_EXTERN + cppyy_scope_t cppyy_get_scope(const char* scope_name); + RPY_EXTERN + cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj); + RPY_EXTERN + size_t cppyy_size_of_klass(cppyy_type_t klass); + RPY_EXTERN + size_t cppyy_size_of_type(const char* type_name); + + /* memory management ------------------------------------------------------ */ + RPY_EXTERN + cppyy_object_t cppyy_allocate(cppyy_type_t type); + RPY_EXTERN + void cppyy_deallocate(cppyy_type_t type, cppyy_object_t self); + RPY_EXTERN + cppyy_object_t cppyy_construct(cppyy_type_t type); + RPY_EXTERN + void cppyy_destruct(cppyy_type_t type, cppyy_object_t self); + + /* method/function dispatching -------------------------------------------- */ + RPY_EXTERN + void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN + unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN + char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN + short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN + int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN + long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN + long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN + float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN + double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN + long double cppyy_call_ld(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + + RPY_EXTERN + void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN + char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, size_t* length); + RPY_EXTERN + cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t klass, int nargs, void* args); + RPY_EXTERN + void cppyy_destructor(cppyy_type_t type, cppyy_object_t self); + RPY_EXTERN + cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type); + + RPY_EXTERN + cppyy_funcaddr_t cppyy_function_address_from_index(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN + cppyy_funcaddr_t cppyy_function_address_from_method(cppyy_method_t method); + + /* handling of function argument buffer ----------------------------------- */ + RPY_EXTERN + void* cppyy_allocate_function_args(int nargs); + RPY_EXTERN + void cppyy_deallocate_function_args(void* args); + RPY_EXTERN + size_t cppyy_function_arg_sizeof(); + RPY_EXTERN + size_t cppyy_function_arg_typeoffset(); + + /* scope reflection information ------------------------------------------- */ + RPY_EXTERN + int cppyy_is_namespace(cppyy_scope_t scope); + RPY_EXTERN + int cppyy_is_template(const char* template_name); + RPY_EXTERN + int cppyy_is_abstract(cppyy_type_t type); + RPY_EXTERN + int cppyy_is_enum(const char* type_name); + + RPY_EXTERN + const char** cppyy_get_all_cpp_names(cppyy_scope_t scope, size_t* count); + + /* class reflection information ------------------------------------------- */ + RPY_EXTERN + char* cppyy_final_name(cppyy_type_t type); + RPY_EXTERN + char* cppyy_scoped_final_name(cppyy_type_t type); + RPY_EXTERN + int cppyy_has_complex_hierarchy(cppyy_type_t type); + RPY_EXTERN + int cppyy_num_bases(cppyy_type_t type); + RPY_EXTERN + char* cppyy_base_name(cppyy_type_t type, int base_index); + RPY_EXTERN + int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base); + RPY_EXTERN + int cppyy_smartptr_info(const char* name, cppyy_type_t* raw, cppyy_method_t* deref); + RPY_EXTERN + void cppyy_add_smartptr_type(const char* type_name); + + /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */ + RPY_EXTERN + ptrdiff_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction); + + /* method/function reflection information --------------------------------- */ + RPY_EXTERN + int cppyy_num_methods(cppyy_scope_t scope); + RPY_EXTERN + cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name); + + RPY_EXTERN + char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN + char* cppyy_method_mangled_name(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN + char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN + int cppyy_method_num_args(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN + int cppyy_method_req_args(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN + char* cppyy_method_arg_type(cppyy_scope_t scope, cppyy_index_t idx, int arg_index); + RPY_EXTERN + char* cppyy_method_arg_default(cppyy_scope_t scope, cppyy_index_t idx, int arg_index); + RPY_EXTERN + char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx, int show_formalargs); + RPY_EXTERN + char* cppyy_method_prototype(cppyy_scope_t scope, cppyy_index_t idx, int show_formalargs); + RPY_EXTERN + int cppyy_is_const_method(cppyy_method_t); + + RPY_EXTERN + int cppyy_exists_method_template(cppyy_scope_t scope, const char* name); + RPY_EXTERN + int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN + int cppyy_method_num_template_args(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN + char* cppyy_method_template_arg_name(cppyy_scope_t scope, cppyy_index_t idx, cppyy_index_t iarg); + + RPY_EXTERN + cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN + cppyy_index_t cppyy_get_global_operator( + cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op); + + /* method properties ------------------------------------------------------ */ + RPY_EXTERN + int cppyy_is_publicmethod(cppyy_type_t type, cppyy_index_t idx); + RPY_EXTERN + int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx); + RPY_EXTERN + int cppyy_is_destructor(cppyy_type_t type, cppyy_index_t idx); + RPY_EXTERN + int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx); + + /* data member reflection information ------------------------------------- */ + RPY_EXTERN + int cppyy_num_datamembers(cppyy_scope_t scope); + RPY_EXTERN + char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index); + RPY_EXTERN + char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index); + RPY_EXTERN + ptrdiff_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index); + RPY_EXTERN + int cppyy_datamember_index(cppyy_scope_t scope, const char* name); + + /* data member properties ------------------------------------------------- */ + RPY_EXTERN + int cppyy_is_publicdata(cppyy_type_t type, cppyy_index_t datamember_index); + RPY_EXTERN + int cppyy_is_staticdata(cppyy_type_t type, cppyy_index_t datamember_index); + RPY_EXTERN + int cppyy_is_const_data(cppyy_scope_t scope, cppyy_index_t idata); + RPY_EXTERN + int cppyy_is_enum_data(cppyy_scope_t scope, cppyy_index_t idata); + RPY_EXTERN + int cppyy_get_dimension_size(cppyy_scope_t scope, cppyy_index_t idata, int dimension); + + /* misc helpers ----------------------------------------------------------- */ + RPY_EXTERN + long long cppyy_strtoll(const char* str); + RPY_EXTERN + unsigned long long cppyy_strtoull(const char* str); + RPY_EXTERN + void cppyy_free(void* ptr); + + RPY_EXTERN + cppyy_object_t cppyy_charp2stdstring(const char* str, size_t sz); + RPY_EXTERN + const char* cppyy_stdstring2charp(cppyy_object_t ptr, size_t* lsz); + RPY_EXTERN + cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr); + + RPY_EXTERN + const char* cppyy_stdvector_valuetype(const char* clname); + RPY_EXTERN + size_t cppyy_stdvector_valuesize(const char* clname); + +#ifdef __cplusplus +} +#endif // ifdef __cplusplus + +#endif // ifndef CPPYY_CAPI diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx new file mode 100644 index 0000000000000..4c92d44ce5c21 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx @@ -0,0 +1,2015 @@ +// Bindings +#include "capi.h" +#include "cpp_cppyy.h" +#include "callcontext.h" + +// ROOT +#include "TBaseClass.h" +#include "TClass.h" +#include "TClassRef.h" +#include "TClassTable.h" +#include "TClassEdit.h" +#include "TCollection.h" +#include "TDataMember.h" +#include "TDataType.h" +#include "TEnum.h" +#include "TEnv.h" +#include "TError.h" +#include "TFunction.h" +#include "TFunctionTemplate.h" +#include "TGlobal.h" +#include "TInterpreter.h" +#include "TList.h" +#include "TMethod.h" +#include "TMethodArg.h" +#include "TROOT.h" +#include "TSystem.h" + +// Standard +#include +#include // for std::count +#include +#include +#include +#include +#include +#include +#include // for getenv +#include + +// temp +#include +typedef CPyCppyy::Parameter Parameter; +// --temp + + +// small number that allows use of stack for argument passing +const int SMALL_ARGS_N = 8; + +// data for life time management --------------------------------------------- +typedef std::vector ClassRefs_t; +static ClassRefs_t g_classrefs(1); +static const ClassRefs_t::size_type GLOBAL_HANDLE = 1; +static const ClassRefs_t::size_type STD_HANDLE = GLOBAL_HANDLE + 1; + +typedef std::map Name2ClassRefIndex_t; +static Name2ClassRefIndex_t g_name2classrefidx; + +struct CallWrapper { + CallWrapper(TFunction* f) : fMetaFunction(f), fWrapper(nullptr) {} + TFunction* fMetaFunction; + CallFunc_t* fWrapper; +}; +static std::vector gWrapperHolder; +static inline CallWrapper* new_CallWrapper(TFunction* f) { + CallWrapper* wrap = new CallWrapper(f); + gWrapperHolder.push_back(wrap); + return wrap; +} + + +typedef std::vector GlobalVars_t; +static GlobalVars_t g_globalvars; + +static std::set gSTLNames; + +// data ---------------------------------------------------------------------- +Cppyy::TCppScope_t Cppyy::gGlobalScope = GLOBAL_HANDLE; + +// smart pointer types +static std::set gSmartPtrTypes = + {"auto_ptr", "shared_ptr", "weak_ptr", "unique_ptr"}; + +// configuration +static bool gEnableFastPath = true; + + +// global initialization ----------------------------------------------------- +namespace { + +class ApplicationStarter { +public: + ApplicationStarter() { + // setup dummy holders for global and std namespaces + assert(g_classrefs.size() == GLOBAL_HANDLE); + g_name2classrefidx[""] = GLOBAL_HANDLE; + g_classrefs.push_back(TClassRef("")); + + // aliases for std (setup already in pythonify) + g_name2classrefidx["std"] = STD_HANDLE; + g_name2classrefidx["::std"] = g_name2classrefidx["std"]; + g_classrefs.push_back(TClassRef("std")); + + // add a dummy global to refer to as null at index 0 + g_globalvars.push_back(nullptr); + + // disable fast path if requested + if (getenv("CPPYY_DISABLE_FASTPATH")) gEnableFastPath = false; + + // fill the set of STL names + const char* stl_names[] = {"string", "bitset", "pair", "allocator", + "auto_ptr", "shared_ptr", "unique_ptr", "weak_ptr", + "vector", "list", "forward_list", "deque", "map", "multimap", + "set", "multiset", "unordered_set", "unordered_multiset", + "unordered_map", "unordered_multimap", + "iterator", "reverse_iterator", "basic_string", + "complex", "valarray"}; + for (auto& name : stl_names) + gSTLNames.insert(name); + + // create a helper for wrapping lambdas + gInterpreter->Declare( + "namespace __cppyy_internal { template " + "struct FT : public FT {};" + "template " + "struct FT { typedef std::function F; };}" + ); + + // start off with a reasonable size placeholder for wrappers + gWrapperHolder.reserve(1024); + } + + ~ApplicationStarter() { + for (auto wrap : gWrapperHolder) { + if (wrap->fWrapper) + gInterpreter->CallFunc_Delete(wrap->fWrapper); + delete wrap; + } + } +} _applicationStarter; + +} // unnamed namespace + + +// local helpers ------------------------------------------------------------- +static inline +TClassRef& type_from_handle(Cppyy::TCppScope_t scope) +{ + assert((ClassRefs_t::size_type)scope < g_classrefs.size()); + return g_classrefs[(ClassRefs_t::size_type)scope]; +} + +// type_from_handle to go here +static inline +TFunction* type_get_method(Cppyy::TCppType_t klass, Cppyy::TCppIndex_t idx) +{ + TClassRef& cr = type_from_handle(klass); + if (cr.GetClass()) + return (TFunction*)cr->GetListOfMethods(false)->At(idx); + assert(klass == (Cppyy::TCppType_t)GLOBAL_HANDLE); + return ((CallWrapper*)idx)->fMetaFunction; +} + +static inline +TFunction* m2f(Cppyy::TCppMethod_t method) { + return ((CallWrapper*)method)->fMetaFunction; +} + +static inline +Cppyy::TCppScope_t declaring_scope(Cppyy::TCppMethod_t method) +{ + if (method) { + TMethod* m = dynamic_cast(m2f(method)); + if (m) return Cppyy::GetScope(m->GetClass()->GetName()); + } + return (Cppyy::TCppScope_t)GLOBAL_HANDLE; +} + +static inline +char* cppstring_to_cstring(const std::string& cppstr) +{ + char* cstr = (char*)malloc(cppstr.size()+1); + memcpy(cstr, cppstr.c_str(), cppstr.size()+1); + return cstr; +} + +static inline +bool match_name(const std::string& tname, const std::string fname) +{ +// either match exactly, or match the name as template + if (fname.rfind(tname, 0) == 0) { + if ((tname.size() == fname.size()) || + (tname.size() < fname.size() && fname[tname.size()] == '<')) + return true; + } + return false; +} + +static inline +bool is_stl(const std::string& name) +{ + std::string w = name; + if (w.compare(0, 5, "std::") == 0) + w = w.substr(5, std::string::npos); + std::string::size_type pos = name.find('<'); + if (pos != std::string::npos) + w = w.substr(0, pos); + return gSTLNames.find(w) != gSTLNames.end(); +} + +static inline +bool is_missclassified_stl(const std::string& name) +{ + std::string::size_type pos = name.find('<'); + if (pos != std::string::npos) + return gSTLNames.find(name.substr(0, pos)) != gSTLNames.end(); + return gSTLNames.find(name) != gSTLNames.end(); +} + + +// name to opaque C++ scope representation ----------------------------------- +std::string Cppyy::ResolveName(const std::string& cppitem_name) +{ +// Fully resolve the given name to the final type name. + std::string tclean = cppitem_name.compare(0, 2, "::") == 0 ? + cppitem_name.substr(2, std::string::npos) : cppitem_name; + +// classes (most common) + tclean = TClassEdit::CleanType(tclean.c_str()); + if (tclean.empty() /* unknown, eg. an operator */) return cppitem_name; + +// reduce [N] to [] + if (tclean[tclean.size()-1] == ']') + tclean = tclean.substr(0, tclean.rfind('[')) + "[]"; + +// data types (such as builtins) + TDataType* dt = gROOT->GetType(tclean.c_str()); + if (dt) return dt->GetFullTypeName(); + +// special case for enums + if (IsEnum(cppitem_name)) + return ResolveEnum(cppitem_name); + +// typedefs + return TClassEdit::ResolveTypedef(tclean.c_str(), true); +} + +static std::map resolved_enum_types; +std::string Cppyy::ResolveEnum(const std::string& enum_type) +{ +// The underlying type of a an enum may be any kind of integer. +// Resolve that type via a workaround (note: this function assumes +// that the enum_type name is a valid enum type name) + auto res = resolved_enum_types.find(enum_type); + if (res != resolved_enum_types.end()) + return res->second; + + if (enum_type.find("(anonymous") == std::string::npos) { + std::ostringstream decl; + for (auto& itype : {"unsigned int"}) { + decl << "std::is_same<" + << itype + << ", std::underlying_type<" + << enum_type + << ">::type>::value;"; + if (gInterpreter->ProcessLine(decl.str().c_str())) { + resolved_enum_types[enum_type] = itype; + return itype; + } + } + } + +// failed or anonymous ... signal up stream to special case this + resolved_enum_types[enum_type] = "internal_enum_type_t"; + return "internal_enum_type_t"; // should default to int +} + +Cppyy::TCppScope_t Cppyy::GetScope(const std::string& sname) +{ +// TODO: scope_name should always be final already + std::string scope_name = ResolveName(sname); + auto icr = g_name2classrefidx.find(scope_name); + if (icr != g_name2classrefidx.end()) + return (TCppType_t)icr->second; + +// use TClass directly, to enable auto-loading; class may be stubbed (eg. for +// function returns) leading to a non-null TClass that is otherwise invalid + TClassRef cr(TClass::GetClass(scope_name.c_str(), true /* load */, true /* silent */)); + if (!cr.GetClass() || !cr->Property()) + return (TCppScope_t)0; + + // no check for ClassInfo as forward declared classes are okay (fragile) + + ClassRefs_t::size_type sz = g_classrefs.size(); + g_name2classrefidx[scope_name] = sz; + g_classrefs.push_back(TClassRef(scope_name.c_str())); + return (TCppScope_t)sz; +} + +bool Cppyy::IsTemplate(const std::string& template_name) +{ + return (bool)gInterpreter->CheckClassTemplate(template_name.c_str()); +} + +Cppyy::TCppType_t Cppyy::GetActualClass(TCppType_t klass, TCppObject_t obj) +{ + TClassRef& cr = type_from_handle(klass); + TClass* clActual = cr->GetActualClass((void*)obj); + if (clActual && clActual != cr.GetClass()) { + // TODO: lookup through name should not be needed + return (TCppType_t)GetScope(clActual->GetName()); + } + return klass; +} + +size_t Cppyy::SizeOf(TCppType_t klass) +{ + TClassRef& cr = type_from_handle(klass); + if (cr.GetClass()) return (size_t)cr->Size(); + return (size_t)0; +} + +size_t Cppyy::SizeOf(const std::string& type_name) +{ + TDataType* dt = gROOT->GetType(type_name.c_str()); + if (dt) return dt->Size(); + return SizeOf(GetScope(type_name)); +} + +bool Cppyy::IsBuiltin(const std::string& type_name) +{ + TDataType* dt = gROOT->GetType(TClassEdit::CleanType(type_name.c_str(), 1).c_str()); + if (dt) return dt->GetType() != kOther_t; + return false; +} + +bool Cppyy::IsComplete(const std::string& type_name) +{ +// verify whether the dictionary of this class is fully available + bool b = false; + + int oldEIL = gErrorIgnoreLevel; + gErrorIgnoreLevel = 3000; + TClass* klass = TClass::GetClass(TClassEdit::ShortType(type_name.c_str(), 1).c_str()); + if (klass && klass->GetClassInfo()) // works for normal case w/ dict + b = gInterpreter->ClassInfo_IsLoaded(klass->GetClassInfo()); + else { // special case for forward declared classes + ClassInfo_t* ci = gInterpreter->ClassInfo_Factory(type_name.c_str()); + if (ci) { + b = gInterpreter->ClassInfo_IsLoaded(ci); + gInterpreter->ClassInfo_Delete(ci); // we own the fresh class info + } + } + gErrorIgnoreLevel = oldEIL; + return b; +} + +// memory management --------------------------------------------------------- +Cppyy::TCppObject_t Cppyy::Allocate(TCppType_t type) +{ + TClassRef& cr = type_from_handle(type); + return (TCppObject_t)malloc(cr->Size()); +} + +void Cppyy::Deallocate(TCppType_t /* type */, TCppObject_t instance) +{ + ::operator delete(instance); +} + +Cppyy::TCppObject_t Cppyy::Construct(TCppType_t type) +{ + TClassRef& cr = type_from_handle(type); + return (TCppObject_t)cr->New(); +} + +void Cppyy::Destruct(TCppType_t type, TCppObject_t instance) +{ + TClassRef& cr = type_from_handle(type); + cr->Destructor((void*)instance); +} + + +// method/function dispatching ----------------------------------------------- +static inline CallFunc_t* GetCallFunc(Cppyy::TCppMethod_t method) +{ +// TODO: method should be a callfunc, so that no mapping would be needed. + CallWrapper* wrap = (CallWrapper*)method; + if (wrap->fWrapper) return wrap->fWrapper; + + TFunction* func = wrap->fMetaFunction; + + CallFunc_t* callf = gInterpreter->CallFunc_Factory(); + MethodInfo_t* meth = gInterpreter->MethodInfo_Factory(func->GetDeclId()); + gInterpreter->CallFunc_SetFunc(callf, meth); + gInterpreter->MethodInfo_Delete(meth); + + if (!(callf && gInterpreter->CallFunc_IsValid(callf))) { + // TODO: propagate this error to caller w/o use of Python C-API + /* + PyErr_Format(PyExc_RuntimeError, "could not resolve %s::%s(%s)", + const_cast(klass).GetClassName(), + func ? func->GetName() : const_cast(klass).GetClassName(), + callString.c_str()); */ + std::cerr << "TODO: report unresolved function error to Python\n"; + if (callf) gInterpreter->CallFunc_Delete(callf); + return nullptr; + } + + wrap->fWrapper = callf; + return callf; +} + +static inline +bool copy_args(void* args_, void** vargs) +{ + bool runRelease = false; + std::vector& args = *(std::vector*)args_; + for (std::vector::size_type i = 0; i < args.size(); ++i) { + switch (args[i].fTypeCode) { + case 'b': /* bool */ + vargs[i] = (void*)&args[i].fValue.fBool; + break; + case 'h': /* short */ + vargs[i] = (void*)&args[i].fValue.fShort; + break; + case 'H': /* unsigned short */ + vargs[i] = (void*)&args[i].fValue.fUShort; + break; + case 'i': /* int */ + vargs[i] = (void*)&args[i].fValue.fInt; + break; + case 'I': /* unsigned int */ + vargs[i] = (void*)&args[i].fValue.fUInt; + break; + case 'l': /* long */ + vargs[i] = (void*)&args[i].fValue.fLong; + break; + case 'L': /* unsigned long */ + vargs[i] = (void*)&args[i].fValue.fULong; + break; + case 'q': /* long long */ + vargs[i] = (void*)&args[i].fValue.fLongLong; + break; + case 'Q': /* unsigned long long */ + vargs[i] = (void*)&args[i].fValue.fULongLong; + break; + case 'f': /* float */ + vargs[i] = (void*)&args[i].fValue.fFloat; + break; + case 'd': /* double */ + vargs[i] = (void*)&args[i].fValue.fDouble; + break; + case 'g': /* long double */ + vargs[i] = (void*)&args[i].fValue.fLongDouble; + break; + case 'a': + case 'o': + case 'p': /* void* */ + vargs[i] = (void*)&args[i].fValue.fVoidp; + break; + case 'X': /* (void*)type& with free */ + runRelease = true; + case 'V': /* (void*)type& */ + vargs[i] = args[i].fValue.fVoidp; + break; + case 'r': /* const type& */ + vargs[i] = args[i].fRef; + break; + default: + std::cerr << "unknown type code: " << args[i].fTypeCode << std::endl; + break; + } + } + return runRelease; +} + +static inline +void release_args(const std::vector& args) { + for (std::vector::size_type i = 0; i < args.size(); ++i) { + if (args[i].fTypeCode == 'X') + free(args[i].fValue.fVoidp); + } +} + +static bool FastCall(Cppyy::TCppMethod_t method, void* args_, void* self, void* result) +{ + const std::vector& args = *(std::vector*)args_; + + CallFunc_t* callf = GetCallFunc(method); + if (!callf) + return false; + + TInterpreter::CallFuncIFacePtr_t faceptr = gCling->CallFunc_IFacePtr(callf); + if (faceptr.fKind == TInterpreter::CallFuncIFacePtr_t::kGeneric) { + bool runRelease = false; + if (args.size() <= SMALL_ARGS_N) { + void* smallbuf[SMALL_ARGS_N]; + runRelease = copy_args(args_, smallbuf); + faceptr.fGeneric(self, args.size(), smallbuf, result); + } else { + std::vector buf(args.size()); + runRelease = copy_args(args_, buf.data()); + faceptr.fGeneric(self, args.size(), buf.data(), result); + } + if (runRelease) release_args(args); + return true; + } + + if (faceptr.fKind == TInterpreter::CallFuncIFacePtr_t::kCtor) { + bool runRelease = false; + if (args.size() <= SMALL_ARGS_N) { + void* smallbuf[SMALL_ARGS_N]; + runRelease = copy_args(args_, (void**)smallbuf); + faceptr.fCtor((void**)smallbuf, result, args.size()); + } else { + std::vector buf(args.size()); + runRelease = copy_args(args_, buf.data()); + faceptr.fCtor(buf.data(), result, args.size()); + } + if (runRelease) release_args(args); + return true; + } + + if (faceptr.fKind == TInterpreter::CallFuncIFacePtr_t::kDtor) { + std::cerr << " DESTRUCTOR NOT IMPLEMENTED YET! " << std::endl; + return false; + } + + return false; +} + +template< typename T > +static inline +T CallT(Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, void* args) +{ + T t{}; + if (FastCall(method, args, (void*)self, &t)) + return t; + return (T)-1; +} + +#define CPPYY_IMP_CALL(typecode, rtype) \ +rtype Cppyy::Call##typecode(TCppMethod_t method, TCppObject_t self, void* args)\ +{ \ + return CallT(method, self, args); \ +} + +void Cppyy::CallV(TCppMethod_t method, TCppObject_t self, void* args) +{ + if (!FastCall(method, args, (void*)self, nullptr)) + return /* TODO ... report error */; +} + +CPPYY_IMP_CALL(B, unsigned char) +CPPYY_IMP_CALL(C, char ) +CPPYY_IMP_CALL(H, short ) +CPPYY_IMP_CALL(I, int ) +CPPYY_IMP_CALL(L, long ) +CPPYY_IMP_CALL(LL, Long64_t ) +CPPYY_IMP_CALL(F, float ) +CPPYY_IMP_CALL(D, double ) +CPPYY_IMP_CALL(LD, LongDouble_t ) + +void* Cppyy::CallR(TCppMethod_t method, TCppObject_t self, void* args) +{ + void* r = nullptr; + if (FastCall(method, args, (void*)self, &r)) + return r; + return nullptr; +} + +char* Cppyy::CallS( + TCppMethod_t method, TCppObject_t self, void* args, size_t* length) +{ + char* cstr = nullptr; + TClassRef cr("std::string"); + std::string* cppresult = (std::string*)malloc(sizeof(std::string)); + if (FastCall(method, args, self, (void*)cppresult)) { + cstr = cppstring_to_cstring(*cppresult); + *length = cppresult->size(); + cppresult->std::string::~basic_string(); + } else + *length = 0; + free((void*)cppresult); + return cstr; +} + +Cppyy::TCppObject_t Cppyy::CallConstructor( + TCppMethod_t method, TCppType_t /* klass */, void* args) +{ + void* obj = nullptr; + if (FastCall(method, args, nullptr, &obj)) + return (TCppObject_t)obj; + return (TCppObject_t)0; +} + +void Cppyy::CallDestructor(TCppType_t type, TCppObject_t self) +{ + TClassRef& cr = type_from_handle(type); + cr->Destructor((void*)self, true); +} + +Cppyy::TCppObject_t Cppyy::CallO(TCppMethod_t method, + TCppObject_t self, void* args, TCppType_t result_type) +{ + TClassRef& cr = type_from_handle(result_type); + void* obj = ::operator new(cr->Size()); + if (FastCall(method, args, self, obj)) + return (TCppObject_t)obj; + return (TCppObject_t)0; +} + +Cppyy::TCppFuncAddr_t Cppyy::GetFunctionAddress(TCppScope_t scope, TCppIndex_t idx) +{ + if (!gEnableFastPath) return (TCppFuncAddr_t)nullptr; + TFunction* f = type_get_method(scope, idx); + return (TCppFuncAddr_t)dlsym(RTLD_DEFAULT, f->GetMangledName()); +} + +Cppyy::TCppFuncAddr_t Cppyy::GetFunctionAddress(TCppMethod_t method) +{ + if (!gEnableFastPath) return (TCppFuncAddr_t)nullptr; + TFunction* f = m2f(method); + return (TCppFuncAddr_t)dlsym(RTLD_DEFAULT, f->GetMangledName()); +} + + +// handling of function argument buffer -------------------------------------- +void* Cppyy::AllocateFunctionArgs(size_t nargs) +{ + return new Parameter[nargs]; +} + +void Cppyy::DeallocateFunctionArgs(void* args) +{ + delete [] (Parameter*)args; +} + +size_t Cppyy::GetFunctionArgSizeof() +{ + return sizeof(Parameter); +} + +size_t Cppyy::GetFunctionArgTypeoffset() +{ + return offsetof(Parameter, fTypeCode); +} + + +// scope reflection information ---------------------------------------------- +bool Cppyy::IsNamespace(TCppScope_t scope) +{ +// Test if this scope represents a namespace. + if (scope == GLOBAL_HANDLE) + return true; + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) + return cr->Property() & kIsNamespace; + return false; +} + +bool Cppyy::IsAbstract(TCppType_t klass) +{ +// Test if this type may not be instantiated. + TClassRef& cr = type_from_handle(klass); + if (cr.GetClass()) + return cr->Property() & kIsAbstract; + return false; +} + +bool Cppyy::IsEnum(const std::string& type_name) +{ + if (type_name.empty()) return false; + return gInterpreter->ClassInfo_IsEnum(type_name.c_str()); +} + +// helpers for stripping scope names +static +std::string outer_with_template(const std::string& name) +{ +// Cut down to the outer-most scope from , taking proper care of templates. + int tpl_open = 0; + for (std::string::size_type pos = 0; pos < name.size(); ++pos) { + std::string::value_type c = name[pos]; + + // count '<' and '>' to be able to skip template contents + if (c == '<') + ++tpl_open; + else if (c == '>') + --tpl_open; + + // collect name up to "::" + else if (tpl_open == 0 && \ + c == ':' && pos+1 < name.size() && name[pos+1] == ':') { + // found the extend of the scope ... done + return name.substr(0, pos-1); + } + } + +// whole name is apparently a single scope + return name; +} + +static +std::string outer_no_template(const std::string& name) +{ +// Cut down to the outer-most scope from , drop templates + std::string::size_type first_scope = name.find(':'); + if (first_scope == std::string::npos) + return name.substr(0, name.find('<')); + std::string::size_type first_templ = name.find('<'); + if (first_templ == std::string::npos) + return name.substr(0, first_scope); + return name.substr(0, std::min(first_templ, first_scope)); +} + +#define FILL_COLL(type, filter) { \ + TIter itr{coll}; \ + type* obj = nullptr; \ + while ((obj = (type*)itr.Next())) { \ + const char* nm = obj->GetName(); \ + if (nm && nm[0] != '_' && !(obj->Property() & (filter))) \ + cppnames.insert(nm); \ + }} + +static inline +void cond_add(Cppyy::TCppScope_t scope, const std::string& ns_scope, + std::set& cppnames, const char* name) +{ + if (!name || name[0] == '_' || strstr(name, ".h") != 0 || strncmp(name, "operator", 8) == 0) + return; + + if (scope == GLOBAL_HANDLE) { + if (!is_missclassified_stl(name)) + cppnames.insert(outer_no_template(name)); + } else if (scope == STD_HANDLE) { + if (strncmp(name, "std::", 5) == 0) name += 5; + else if (!is_missclassified_stl(name)) return; + cppnames.insert(outer_no_template(name)); + } else { + if (strncmp(name, ns_scope.c_str(), ns_scope.size()) == 0) + cppnames.insert(outer_with_template(name + ns_scope.size())); + } +} + +void Cppyy::GetAllCppNames(TCppScope_t scope, std::set& cppnames) +{ +// Collect all known names of C++ entities under scope. This is useful for IDEs +// employing tab-completion, for example. Note that functions names need not be +// unique as they can be overloaded. + + TClassRef& cr = type_from_handle(scope); + if (scope != GLOBAL_HANDLE && !(cr.GetClass() && cr->Property())) + return; + + std::string ns_scope = GetFinalName(scope); + if (scope != GLOBAL_HANDLE) ns_scope += "::"; + +// add existing values from read rootmap files if within this scope + TCollection* coll = gInterpreter->GetMapfile()->GetTable(); + { + TIter itr{coll}; + TEnvRec* ev = nullptr; + while ((ev = (TEnvRec*)itr.Next())) + cond_add(scope, ns_scope, cppnames, ev->GetName()); + } + +// do we care about the class table or are the rootmap and list of types enough? +/* + gClassTable->Init(); + const int N = gClassTable->Classes(); + for (int i = 0; i < N; ++i) + cond_add(scope, ns_scope, cppnames, gClassTable->Next()); +*/ + +// any other types (e.g. that may have come from parsing headers) + coll = gROOT->GetListOfTypes(); + { + TIter itr{coll}; + TDataType* dt = nullptr; + while ((dt = (TDataType*)itr.Next())) { + if (!(dt->Property() & kIsFundamental)) + cond_add(scope, ns_scope, cppnames, dt->GetName()); + } + } + +// add functions + coll = (scope == GLOBAL_HANDLE) ? + gROOT->GetListOfGlobalFunctions() : cr->GetListOfMethods(); + { + TIter itr{coll}; + TFunction* obj = nullptr; + while ((obj = (TFunction*)itr.Next())) { + const char* nm = obj->GetName(); + // skip templated functions, adding only the un-instantiated ones + if (nm && nm[0] != '_' && strstr(nm, "<") == 0 && strncmp(nm, "operator", 8) != 0) + cppnames.insert(nm); + } + } + +// add uninstantiated templates + coll = (scope == GLOBAL_HANDLE) ? + gROOT->GetListOfFunctionTemplates() : cr->GetListOfFunctionTemplates(); + FILL_COLL(TFunctionTemplate, kIsPrivate | kIsProtected) + +// add (global) data members + if (scope == GLOBAL_HANDLE) { + coll = gROOT->GetListOfGlobals(); + FILL_COLL(TGlobal, kIsEnum | kIsPrivate | kIsProtected) + } else { + coll = cr->GetListOfDataMembers(); + FILL_COLL(TDataMember, kIsEnum | kIsPrivate | kIsProtected) + } + +// add enums values only for user classes/namespaces + if (scope != GLOBAL_HANDLE && scope != STD_HANDLE) { + coll = cr->GetListOfEnums(); + FILL_COLL(TEnum, kIsPrivate | kIsProtected) + } +} + + +// class reflection information ---------------------------------------------- +std::string Cppyy::GetFinalName(TCppType_t klass) +{ + if (klass == GLOBAL_HANDLE) + return ""; + TClassRef& cr = type_from_handle(klass); + std::string clName = cr->GetName(); +// TODO: why is this template splitting needed? + std::string::size_type pos = clName.substr(0, clName.find('<')).rfind("::"); + if (pos != std::string::npos) + return clName.substr(pos+2, std::string::npos); + return clName; +} + +std::string Cppyy::GetScopedFinalName(TCppType_t klass) +{ + TClassRef& cr = type_from_handle(klass); + if (cr.GetClass()) { + std::string name = cr->GetName(); + if (is_missclassified_stl(name)) + return std::string("std::")+cr->GetName(); + return cr->GetName(); + } + return ""; +} + +bool Cppyy::HasComplexHierarchy(TCppType_t klass) +{ + int is_complex = 1; + size_t nbases = 0; + + TClassRef& cr = type_from_handle(klass); + if (cr.GetClass() && cr->GetListOfBases() != 0) + nbases = GetNumBases(klass); + + if (1 < nbases) + is_complex = 1; + else if (nbases == 0) + is_complex = 0; + else { // one base class only + TBaseClass* base = (TBaseClass*)cr->GetListOfBases()->At(0); + if (base->Property() & kIsVirtualBase) + is_complex = 1; // TODO: verify; can be complex, need not be. + else + is_complex = HasComplexHierarchy(GetScope(base->GetName())); + } + + return is_complex; +} + +Cppyy::TCppIndex_t Cppyy::GetNumBases(TCppType_t klass) +{ +// Get the total number of base classes that this class has. + TClassRef& cr = type_from_handle(klass); + if (cr.GetClass() && cr->GetListOfBases() != 0) + return (TCppIndex_t)cr->GetListOfBases()->GetSize(); + return (TCppIndex_t)0; +} + +std::string Cppyy::GetBaseName(TCppType_t klass, TCppIndex_t ibase) +{ + TClassRef& cr = type_from_handle(klass); + return ((TBaseClass*)cr->GetListOfBases()->At(ibase))->GetName(); +} + +bool Cppyy::IsSubtype(TCppType_t derived, TCppType_t base) +{ + if (derived == base) + return true; + TClassRef& derived_type = type_from_handle(derived); + TClassRef& base_type = type_from_handle(base); + return derived_type->GetBaseClass(base_type) != 0; +} + +bool Cppyy::GetSmartPtrInfo( + const std::string& tname, TCppType_t& raw, TCppMethod_t& deref) +{ + const std::string& rn = ResolveName(tname); + if (gSmartPtrTypes.find(rn.substr(0, rn.find("<"))) != gSmartPtrTypes.end()) { + TClassRef& cr = type_from_handle(GetScope(tname)); + if (cr.GetClass()) { + gInterpreter->UpdateListOfMethods(cr.GetClass()); + TFunction* func = nullptr; + TIter next(cr->GetListOfAllPublicMethods()); + while ((func = (TFunction*)next())) { + if (strstr(func->GetName(), "operator->")) { + deref = (TCppMethod_t)new_CallWrapper(func); + raw = GetScope(TClassEdit::ShortType( + func->GetReturnTypeNormalizedName().c_str(), 1)); + return deref && raw; + } + } + } + } + + return false; +} + +void Cppyy::AddSmartPtrType(const std::string& type_name) +{ + gSmartPtrTypes.insert(ResolveName(type_name)); +} + + +// type offsets -------------------------------------------------------------- +ptrdiff_t Cppyy::GetBaseOffset(TCppType_t derived, TCppType_t base, + TCppObject_t address, int direction, bool rerror) +{ +// calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 + if (derived == base || !(base && derived)) + return (ptrdiff_t)0; + + TClassRef& cd = type_from_handle(derived); + TClassRef& cb = type_from_handle(base); + + if (!cd.GetClass() || !cb.GetClass()) + return (ptrdiff_t)0; + + ptrdiff_t offset = -1; + if (!(cd->GetClassInfo() && cb->GetClassInfo())) { // gInterpreter requirement + // would like to warn, but can't quite determine error from intentional + // hiding by developers, so only cover the case where we really should have + // had a class info, but apparently don't: + if (cd->IsLoaded()) { + // warn to allow diagnostics + std::ostringstream msg; + msg << "failed offset calculation between " << cb->GetName() << " and " << cd->GetName(); + // TODO: propagate this warning to caller w/o use of Python C-API + // PyErr_Warn(PyExc_RuntimeWarning, const_cast(msg.str().c_str())); + std::cerr << "Warning: " << msg.str() << '\n'; + } + + // return -1 to signal caller NOT to apply offset + return rerror ? (ptrdiff_t)offset : 0; + } + + offset = gInterpreter->ClassInfo_GetBaseOffset( + cd->GetClassInfo(), cb->GetClassInfo(), (void*)address, direction > 0); + if (offset == -1) // Cling error, treat silently + return rerror ? (ptrdiff_t)offset : 0; + + return (ptrdiff_t)(direction < 0 ? -offset : offset); +} + + +// method/function reflection information ------------------------------------ +Cppyy::TCppIndex_t Cppyy::GetNumMethods(TCppScope_t scope) +{ + if (IsNamespace(scope)) + return (TCppIndex_t)0; // enforce lazy + + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass() && cr->GetListOfMethods(true)) { + Cppyy::TCppIndex_t nMethods = (TCppIndex_t)cr->GetListOfMethods(false)->GetSize(); + if (nMethods == (TCppIndex_t)0) { + std::string clName = GetScopedFinalName(scope); + if (clName.find('<') != std::string::npos) { + // chicken-and-egg problem: TClass does not know about methods until instantiation: force it + if (TClass::GetClass(("std::"+clName).c_str())) // TODO: this doesn't work for templates + clName = "std::" + clName; + std::ostringstream stmt; + stmt << "template class " << clName << ";"; + gInterpreter->Declare(stmt.str().c_str()); + + // now reload the methods + return (TCppIndex_t)cr->GetListOfMethods(true)->GetSize(); + } + } + return nMethods; + } + + return (TCppIndex_t)0; // unknown class? +} + +std::vector Cppyy::GetMethodIndicesFromName( + TCppScope_t scope, const std::string& name) +{ + std::vector indices; + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) { + gInterpreter->UpdateListOfMethods(cr.GetClass()); + int imeth = 0; + TFunction* func = nullptr; + TIter next(cr->GetListOfMethods()); + while ((func = (TFunction*)next())) { + if (match_name(name, func->GetName())) { + if (func->Property() & kIsPublic) + indices.push_back((TCppIndex_t)imeth); + } + ++imeth; + } + } else if (scope == GLOBAL_HANDLE) { + TCollection* funcs = gROOT->GetListOfGlobalFunctions(true); + + // tickle deserialization + if (!funcs->FindObject(name.c_str())) + return indices; + + TFunction* func = nullptr; + TIter ifunc(funcs); + while ((func = (TFunction*)ifunc.Next())) { + if (match_name(name, func->GetName())) + indices.push_back((TCppIndex_t)new_CallWrapper(func)); + } + } + + return indices; +} + +Cppyy::TCppMethod_t Cppyy::GetMethod(TCppScope_t scope, TCppIndex_t imeth) +{ + TFunction* func = type_get_method(scope, imeth); + if (func) + return (Cppyy::TCppMethod_t)new_CallWrapper(func); + return (Cppyy::TCppMethod_t)nullptr; +} + +std::string Cppyy::GetMethodName(TCppMethod_t method) +{ + if (method) { + std::string name = m2f(method)->GetName(); + + if (name.compare(0, 8, "operator") != 0) + // strip template instantiation part, if any + return name.substr(0, name.find('<')); + return name; + } + return ""; +} + +std::string Cppyy::GetMethodMangledName(TCppMethod_t method) +{ + if (method) + return m2f(method)->GetMangledName(); + return ""; +} + +std::string Cppyy::GetMethodResultType(TCppMethod_t method) +{ + if (method) { + TFunction* f = m2f(method); + if (f->ExtraProperty() & kIsConstructor) + return "constructor"; + return f->GetReturnTypeNormalizedName(); + } + return ""; +} + +Cppyy::TCppIndex_t Cppyy::GetMethodNumArgs(TCppMethod_t method) +{ + if (method) + return m2f(method)->GetNargs(); + return 0; +} + +Cppyy::TCppIndex_t Cppyy::GetMethodReqArgs(TCppMethod_t method) +{ + if (method) { + TFunction* f = m2f(method); + return (TCppIndex_t)(f->GetNargs() - f->GetNargsOpt()); + } + return (TCppIndex_t)0; +} + +std::string Cppyy::GetMethodArgName(TCppMethod_t method, int iarg) +{ + if (method) { + TFunction* f = m2f(method); + TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(iarg); + return arg->GetName(); + } + return ""; +} + +std::string Cppyy::GetMethodArgType(TCppMethod_t method, int iarg) +{ + if (method) { + TFunction* f = m2f(method); + TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(iarg); + return arg->GetTypeNormalizedName(); + } + return ""; +} + +std::string Cppyy::GetMethodArgDefault(TCppMethod_t method, int iarg) +{ + if (method) { + TFunction* f = m2f(method); + TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(iarg); + const char* def = arg->GetDefault(); + if (def) + return def; + } + + return ""; +} + +std::string Cppyy::GetMethodSignature(TCppScope_t scope, TCppIndex_t imeth, bool show_formalargs) +{ + TFunction* f = type_get_method(scope, imeth); + if (f) { + std::ostringstream sig; + sig << "("; + int nArgs = f->GetNargs(); + for (int iarg = 0; iarg < nArgs; ++iarg) { + TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(iarg); + sig << arg->GetFullTypeName(); + if (show_formalargs) { + const char* argname = arg->GetName(); + if (argname && argname[0] != '\0') sig << " " << argname; + const char* defvalue = arg->GetDefault(); + if (defvalue && defvalue[0] != '\0') sig << " = " << defvalue; + } + if (iarg != nArgs-1) sig << (show_formalargs ? ", " : ","); + } + sig << ")"; + return sig.str(); + } + return ""; +} + +std::string Cppyy::GetMethodPrototype(TCppScope_t scope, TCppIndex_t imeth, bool show_formalargs) +{ + std::string scName = GetScopedFinalName(scope); + TFunction* f = type_get_method(scope, imeth); + if (f) { + std::ostringstream sig; + sig << f->GetReturnTypeName() << " " + << scName << "::" << f->GetName(); + sig << GetMethodSignature(scope, imeth, show_formalargs); + return sig.str(); + } + return ""; +} + +bool Cppyy::IsConstMethod(TCppMethod_t method) +{ + if (method) { + TFunction* f = m2f(method); + return f->Property() & kIsConstMethod; + } + return false; +} + +bool Cppyy::ExistsMethodTemplate(TCppScope_t scope, const std::string& name) +{ + if (scope == (cppyy_scope_t)GLOBAL_HANDLE) + return (bool)gROOT->GetFunctionTemplate(name.c_str()); + else { + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) + return (bool)cr->GetFunctionTemplate(name.c_str()); + } + +// failure ... + return false; +} + +bool Cppyy::IsMethodTemplate(TCppScope_t scope, TCppIndex_t imeth) +{ + TFunction* f = type_get_method(scope, imeth); + if (!f) return false; + + if (scope == (Cppyy::TCppType_t)GLOBAL_HANDLE) { + // TODO: figure this one out ... + return false; + } else { + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) { + return (bool)cr->GetFunctionTemplate(f->GetName()); + } + } + return false; +} + +Cppyy::TCppIndex_t Cppyy::GetMethodNumTemplateArgs( + TCppScope_t scope, TCppIndex_t imeth) +{ +// this is dumb, but the fact that Cling can instantiate template +// methods on-the-fly means that there is some vast reworking TODO +// in interp_cppyy.py, so this is just to make the original tests +// pass that worked in the Reflex era ... + const std::string name = GetMethodName(GetMethod(scope, imeth)); + return (TCppIndex_t)(std::count(name.begin(), name.end(), ',')+1); +} + +std::string Cppyy::GetMethodTemplateArgName( + TCppScope_t scope, TCppIndex_t imeth, TCppIndex_t /* iarg */) +{ +// TODO: like above, given Cling's instantiation capability, this +// is just dumb ... + TFunction* f = type_get_method(scope, imeth); + std::string name = f->GetName(); + std::string::size_type pos = name.find('<'); +// TODO: left as-is, this should loop over arguments, but what is here +// suffices to pass the Reflex-based tests (need more tests :)) + return cppstring_to_cstring( + ResolveName(name.substr(pos+1, name.size()-pos-2))); +} + +Cppyy::TCppMethod_t Cppyy::GetMethodTemplate( + TCppScope_t scope, const std::string& name, const std::string& proto) +{ + TFunction* func = nullptr; + if (scope == (cppyy_scope_t)GLOBAL_HANDLE) { + func = gROOT->GetGlobalFunctionWithPrototype(name.c_str(), proto.c_str()); + } else { + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) + func = cr->GetMethodWithPrototype(name.c_str(), proto.c_str()); + } + + if (func) + return (TCppMethod_t)new_CallWrapper(func); + +// failure ... + return (TCppMethod_t)nullptr; +} + +Cppyy::TCppIndex_t Cppyy::GetGlobalOperator( + TCppScope_t scope, TCppType_t lc, TCppType_t rc, const std::string& opname) +{ +// Find a global operator function with a matching signature + std::string proto = GetScopedFinalName(lc) + ", " + GetScopedFinalName(rc); + if (scope == (cppyy_scope_t)GLOBAL_HANDLE) { + TFunction* func = gROOT->GetGlobalFunctionWithPrototype(opname.c_str(), proto.c_str()); + if (func) return (TCppIndex_t)new_CallWrapper(func); + } else { + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) { + TFunction* func = cr->GetMethodWithPrototype(opname.c_str(), proto.c_str()); + if (func) return (TCppIndex_t)cr->GetListOfMethods()->IndexOf(func); + } + } + +// failure ... + return (TCppIndex_t)-1; +} + +// method properties --------------------------------------------------------- +bool Cppyy::IsPublicMethod(TCppMethod_t method) +{ + if (method) { + TFunction* f = m2f(method); + return f->Property() & kIsPublic; + } + return false; +} + +bool Cppyy::IsConstructor(TCppMethod_t method) +{ + if (method) { + TFunction* f = m2f(method); + return f->ExtraProperty() & kIsConstructor; + } + return false; +} + +bool Cppyy::IsDestructor(TCppMethod_t method) +{ + if (method) { + TFunction* f = m2f(method); + return f->ExtraProperty() & kIsDestructor; + } + return false; +} + +bool Cppyy::IsStaticMethod(TCppMethod_t method) +{ + if (method) { + TFunction* f = m2f(method); + return f->Property() & kIsStatic; + } + return false; +} + +// data member reflection information ---------------------------------------- +Cppyy::TCppIndex_t Cppyy::GetNumDatamembers(TCppScope_t scope) +{ + if (IsNamespace(scope)) + return (TCppIndex_t)0; // enforce lazy + + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass() && cr->GetListOfDataMembers()) + return cr->GetListOfDataMembers()->GetSize(); + + return (TCppIndex_t)0; // unknown class? +} + +std::string Cppyy::GetDatamemberName(TCppScope_t scope, TCppIndex_t idata) +{ + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) { + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(idata); + return m->GetName(); + } + assert(scope == GLOBAL_HANDLE); + TGlobal* gbl = g_globalvars[idata]; + return gbl->GetName(); +} + +std::string Cppyy::GetDatamemberType(TCppScope_t scope, TCppIndex_t idata) +{ + if (scope == GLOBAL_HANDLE) { + TGlobal* gbl = g_globalvars[idata]; + std::string fullType = gbl->GetFullTypeName(); + if (!strcmp(gbl->GetName(), "gInterpreter")) + return fullType; + + if (fullType[fullType.size()-1] == '*' && \ + fullType.compare(0, 4, "char") != 0) + fullType.append("*"); + else if ((int)gbl->GetArrayDim() > 1) + fullType.append("*"); + else if ((int)gbl->GetArrayDim() == 1) { + std::ostringstream s; + s << '[' << gbl->GetMaxIndex(0) << ']' << std::ends; + fullType.append(s.str()); + } + return fullType; + } + + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) { + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(idata); + std::string fullType = m->GetTrueTypeName(); + if ((int)m->GetArrayDim() > 1 || (!m->IsBasic() && m->IsaPointer())) + fullType.append("*"); + else if ((int)m->GetArrayDim() == 1) { + std::ostringstream s; + s << '[' << m->GetMaxIndex(0) << ']' << std::ends; + fullType.append(s.str()); + } + return fullType; + } + + return ""; +} + +ptrdiff_t Cppyy::GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata) +{ + if (scope == GLOBAL_HANDLE) { + TGlobal* gbl = g_globalvars[idata]; + return (ptrdiff_t)gbl->GetAddress(); + } + + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) { + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(idata); + // CLING WORKAROUND: the following causes templates to be instantiated first + // in the proper scope, making the lookup succeed and preventing spurious + // duplicate instantiations later. + if ((m->Property() & kIsStatic) && strchr(cr->GetName(), '<')) + gInterpreter->ProcessLine(((std::string)cr->GetName()+"::"+m->GetName()+";").c_str()); + return (ptrdiff_t)m->GetOffsetCint(); // yes, CINT (GetOffset() is both wrong + // and caches that wrong result! + } + + return (ptrdiff_t)-1; +} + +Cppyy::TCppIndex_t Cppyy::GetDatamemberIndex(TCppScope_t scope, const std::string& name) +{ + if (scope == GLOBAL_HANDLE) { + TGlobal* gb = (TGlobal*)gROOT->GetListOfGlobals(true)->FindObject(name.c_str()); + if (gb && gb->GetAddress()) { + if (gb->GetAddress() == (void*)-1) { + // name known, but variable not in loaded by Cling yet ... force it + // TODO: figure out a less hackish way (problem is that the metaProcessor + // is hidden in TCling) + gInterpreter->ProcessLine((name+";").c_str()); + } + if (gb->GetAddress() != (void*)-1) { + if (strcmp(gb->GetFullTypeName(), "(lambda)") == 0) { + // lambdas use a compiler internal closure type, so we wrap + // them, then return the wrapper's type + // TODO: this current leaks the std::function; also, if possible, + // should instantiate through TClass rather then ProcessLine + std::ostringstream s; + s << "auto __cppyy_internal_wrap_" << name << " = " + "new __cppyy_internal::FT::F" + "{" << name << "};"; + gInterpreter->ProcessLine(s.str().c_str()); + TGlobal* wrap = (TGlobal*)gROOT->GetListOfGlobals(true)->FindObject( + ("__cppyy_internal_wrap_"+name).c_str()); + if (wrap && wrap->GetAddress()) gb = wrap; + } + + g_globalvars.push_back(gb); + return g_globalvars.size() - 1; + } + } + + } else { + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) { + TDataMember* dm = + (TDataMember*)cr->GetListOfDataMembers()->FindObject(name.c_str()); + // TODO: turning this into an index is silly ... + if (dm) return (TCppIndex_t)cr->GetListOfDataMembers()->IndexOf(dm); + } + } + + return (TCppIndex_t)-1; +} + + +// data member properties ---------------------------------------------------- +bool Cppyy::IsPublicData(TCppScope_t scope, TCppIndex_t idata) +{ + if (scope == GLOBAL_HANDLE) + return true; + TClassRef& cr = type_from_handle(scope); + if (cr->Property() & kIsNamespace) + return true; + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(idata); + return m->Property() & kIsPublic; +} + +bool Cppyy::IsStaticData(TCppScope_t scope, TCppIndex_t idata) +{ + if (scope == GLOBAL_HANDLE) + return true; + TClassRef& cr = type_from_handle(scope); + if (cr->Property() & kIsNamespace) + return true; + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(idata); + return m->Property() & kIsStatic; +} + +bool Cppyy::IsConstData(TCppScope_t scope, TCppIndex_t idata) +{ + if (scope == GLOBAL_HANDLE) { + TGlobal* gbl = g_globalvars[idata]; + return gbl->Property() & kIsConstant; + } + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) { + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(idata); + return m->Property() & kIsConstant; + } + return false; +} + +bool Cppyy::IsEnumData(TCppScope_t scope, TCppIndex_t idata) +{ + if (scope == GLOBAL_HANDLE) { + TGlobal* gbl = g_globalvars[idata]; + return gbl->Property() & kIsEnum; + } + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) { + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(idata); + return m->Property() & kIsEnum; + } + return false; +} + +int Cppyy::GetDimensionSize(TCppScope_t scope, TCppIndex_t idata, int dimension) +{ + if (scope == GLOBAL_HANDLE) { + TGlobal* gbl = g_globalvars[idata]; + return gbl->GetMaxIndex(dimension); + } + TClassRef& cr = type_from_handle(scope); + if (cr.GetClass()) { + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(idata); + return m->GetMaxIndex(dimension); + } + return -1; +} + + +//- C-linkage wrappers ------------------------------------------------------- +static inline +std::vector vsargs_to_parvec(void* args, int nargs) +{ + std::vector v; + v.reserve(nargs); + for (int i=0; i parvec = vsargs_to_parvec(args, nargs); + Cppyy::CallV(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION +} + +unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return (unsigned char)Cppyy::CallB(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION + return (unsigned char)-1; +} + +char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return (char)Cppyy::CallC(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION + return (char)-1; +} + +short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return (short)Cppyy::CallH(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION + return (short)-1; +} + +int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return (int)Cppyy::CallI(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION + return (int)-1; +} + +long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return (long)Cppyy::CallL(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION + return (long)-1; +} + +long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return (long long)Cppyy::CallLL(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION + return (long long)-1; +} + +float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return (float)Cppyy::CallF(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION + return (float)-1; +} + +double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return (double)Cppyy::CallD(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION + return (double)-1; +} + +long double cppyy_call_ld(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return (long double)Cppyy::CallLD(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION + return (long double)-1; +} + +void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return (void*)Cppyy::CallR(method, (void*)self, &parvec); + } CPPYY_HANDLE_EXCEPTION + return (void*)nullptr; +} + +char* cppyy_call_s( + cppyy_method_t method, cppyy_object_t self, int nargs, void* args, size_t* lsz) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return Cppyy::CallS(method, (void*)self, &parvec, lsz); + } CPPYY_HANDLE_EXCEPTION + return (char*)nullptr; +} + +cppyy_object_t cppyy_constructor( + cppyy_method_t method, cppyy_type_t klass, int nargs, void* args) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return cppyy_object_t(Cppyy::CallConstructor(method, klass, &parvec)); + } CPPYY_HANDLE_EXCEPTION + return (cppyy_object_t)0; +} + +void cppyy_destructor(cppyy_type_t klass, cppyy_object_t self) { + Cppyy::CallDestructor(klass, self); +} + +cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, + int nargs, void* args, cppyy_type_t result_type) { + try { + std::vector parvec = vsargs_to_parvec(args, nargs); + return cppyy_object_t(Cppyy::CallO(method, (void*)self, &parvec, result_type)); + } CPPYY_HANDLE_EXCEPTION + return (cppyy_object_t)0; +} + +cppyy_funcaddr_t cppyy_function_address_from_index(cppyy_scope_t scope, cppyy_index_t idx) { + return cppyy_funcaddr_t(Cppyy::GetFunctionAddress(scope, idx)); +} + +cppyy_funcaddr_t cppyy_function_address_from_method(cppyy_method_t method) { + return cppyy_funcaddr_t(Cppyy::GetFunctionAddress(method)); +} + + +/* handling of function argument buffer ----------------------------------- */ +void* cppyy_allocate_function_args(int nargs) { +// for calls through C interface, require extra space for reporting exceptions + return malloc(nargs*sizeof(Parameter)+sizeof(cppyy_exctype_t)+sizeof(char**)); +} + +void cppyy_deallocate_function_args(void* args) { + free(args); +} + +size_t cppyy_function_arg_sizeof() { + return (size_t)Cppyy::GetFunctionArgSizeof(); +} + +size_t cppyy_function_arg_typeoffset() { + return (size_t)Cppyy::GetFunctionArgTypeoffset(); +} + + +/* scope reflection information ------------------------------------------- */ +int cppyy_is_namespace(cppyy_scope_t scope) { + return (int)Cppyy::IsNamespace(scope); +} + +int cppyy_is_template(const char* template_name) { + return (int)Cppyy::IsTemplate(template_name); +} + +int cppyy_is_abstract(cppyy_type_t type) { + return (int)Cppyy::IsAbstract(type); +} + +int cppyy_is_enum(const char* type_name) { + return (int)Cppyy::IsEnum(type_name); +} + +const char** cppyy_get_all_cpp_names(cppyy_scope_t scope, size_t* count) { + std::set cppnames; + Cppyy::GetAllCppNames(scope, cppnames); + const char** c_cppnames = (const char**)malloc(cppnames.size()*sizeof(const char*)); + int i = 0; + for (const auto& name : cppnames) { + c_cppnames[i] = cppstring_to_cstring(name); + ++i; + } + *count = cppnames.size(); + return c_cppnames; +} + + +/* class reflection information ------------------------------------------- */ +char* cppyy_final_name(cppyy_type_t type) { + return cppstring_to_cstring(Cppyy::GetFinalName(type)); +} + +char* cppyy_scoped_final_name(cppyy_type_t type) { + return cppstring_to_cstring(Cppyy::GetScopedFinalName(type)); +} + +int cppyy_has_complex_hierarchy(cppyy_type_t type) { + return (int)Cppyy::HasComplexHierarchy(type); +} + +int cppyy_num_bases(cppyy_type_t type) { + return (int)Cppyy::GetNumBases(type); +} + +char* cppyy_base_name(cppyy_type_t type, int base_index) { + return cppstring_to_cstring(Cppyy::GetBaseName (type, base_index)); +} + +int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base) { + return (int)Cppyy::IsSubtype(derived, base); +} + +int cppyy_smartptr_info(const char* name, cppyy_type_t* raw, cppyy_method_t* deref) { + Cppyy::TCppScope_t r2 = *raw; + Cppyy::TCppMethod_t d2 = *deref; + int result = (int)Cppyy::GetSmartPtrInfo(name, r2, d2); + *raw = r2; *deref = d2; + return result; +} + +void cppyy_add_smartptr_type(const char* type_name) { + Cppyy::AddSmartPtrType(type_name); +} + + +/* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */ +ptrdiff_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction) { + return (ptrdiff_t)Cppyy::GetBaseOffset(derived, base, (void*)address, direction, 0); +} + + +/* method/function reflection information --------------------------------- */ +int cppyy_num_methods(cppyy_scope_t scope) { + return (int)Cppyy::GetNumMethods(scope); +} + +cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name) +{ + std::vector result = Cppyy::GetMethodIndicesFromName(scope, name); + + if (result.empty()) + return (cppyy_index_t*)nullptr; + + cppyy_index_t* llresult = (cppyy_index_t*)malloc(sizeof(cppyy_index_t)*(result.size()+1)); + for (int i = 0; i < (int)result.size(); ++i) llresult[i] = result[i]; + llresult[result.size()] = -1; + return llresult; +} + +char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx) { + CallWrapper wrap{type_get_method(scope, idx)}; + return cppstring_to_cstring(Cppyy::GetMethodName((Cppyy::TCppMethod_t)&wrap)); +} + +char* cppyy_method_mangled_name(cppyy_scope_t scope, cppyy_index_t idx) { + CallWrapper wrap{type_get_method(scope, idx)}; + return cppstring_to_cstring(Cppyy::GetMethodMangledName((Cppyy::TCppMethod_t)&wrap)); +} + +char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx) { + CallWrapper wrap{type_get_method(scope, idx)}; + return cppstring_to_cstring(Cppyy::GetMethodResultType((Cppyy::TCppMethod_t)&wrap)); +} + +int cppyy_method_num_args(cppyy_scope_t scope, cppyy_index_t idx) { + CallWrapper wrap{type_get_method(scope, idx)}; + return (int)Cppyy::GetMethodNumArgs((Cppyy::TCppMethod_t)&wrap); +} + +int cppyy_method_req_args(cppyy_scope_t scope, cppyy_index_t idx) { + CallWrapper wrap{type_get_method(scope, idx)}; + return (int)Cppyy::GetMethodReqArgs((Cppyy::TCppMethod_t)&wrap); +} + +char* cppyy_method_arg_type(cppyy_scope_t scope, cppyy_index_t idx, int arg_index) { + CallWrapper wrap{type_get_method(scope, idx)}; + return cppstring_to_cstring(Cppyy::GetMethodArgType((Cppyy::TCppMethod_t)&wrap, arg_index)); +} + +char* cppyy_method_arg_default(cppyy_scope_t scope, cppyy_index_t idx, int arg_index) { + CallWrapper wrap{type_get_method(scope, idx)}; + return cppstring_to_cstring(Cppyy::GetMethodArgDefault((Cppyy::TCppMethod_t)&wrap, arg_index)); +} + +char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx, int show_formalargs) { + return cppstring_to_cstring(Cppyy::GetMethodSignature(scope, idx, (bool)show_formalargs)); +} + +char* cppyy_method_prototype(cppyy_scope_t scope, cppyy_index_t idx, int show_formalargs) { + return cppstring_to_cstring(Cppyy::GetMethodPrototype(scope, idx, (bool)show_formalargs)); +} + +int cppyy_is_const_method(cppyy_method_t method) { + return (int)Cppyy::IsConstMethod(method); +} + +int cppyy_exists_method_template(cppyy_scope_t scope, const char* name) { + return (int)Cppyy::ExistsMethodTemplate(scope, name); +} + +int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx) { + return (int)Cppyy::IsMethodTemplate(scope, idx); +} + +int cppyy_method_num_template_args(cppyy_scope_t scope, cppyy_index_t idx) { + return (int)Cppyy::GetMethodNumTemplateArgs(scope, idx); +} + +char* cppyy_method_template_arg_name(cppyy_scope_t scope, cppyy_index_t idx, cppyy_index_t iarg) { + return cppstring_to_cstring(Cppyy::GetMethodTemplateArgName(scope, idx, iarg)); +} + +cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx) { + return cppyy_method_t(Cppyy::GetMethod(scope, idx)); +} + +cppyy_index_t cppyy_get_global_operator(cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op) { + return cppyy_index_t(Cppyy::GetGlobalOperator(scope, lc, rc, op)); +} + + +/* method properties ------------------------------------------------------ */ +int cppyy_is_publicmethod(cppyy_type_t type, cppyy_index_t idx) { + CallWrapper wrap{type_get_method(type, idx)}; + return (int)Cppyy::IsPublicMethod((Cppyy::TCppMethod_t)&wrap); +} + +int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx) { + CallWrapper wrap{type_get_method(type, idx)}; + return (int)Cppyy::IsConstructor((Cppyy::TCppMethod_t)&wrap); +} + +int cppyy_is_destructor(cppyy_type_t type, cppyy_index_t idx) { + CallWrapper wrap{type_get_method(type, idx)}; + return (int)Cppyy::IsDestructor((Cppyy::TCppMethod_t)&wrap); +} + +int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx) { + CallWrapper wrap{type_get_method(type, idx)}; + return (int)Cppyy::IsStaticMethod((Cppyy::TCppMethod_t)&wrap); +} + + +/* data member reflection information ------------------------------------- */ +int cppyy_num_datamembers(cppyy_scope_t scope) { + return (int)Cppyy::GetNumDatamembers(scope); +} + +char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index) { + return cppstring_to_cstring(Cppyy::GetDatamemberName(scope, datamember_index)); +} + +char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index) { + return cppstring_to_cstring(Cppyy::GetDatamemberType(scope, datamember_index)); +} + +ptrdiff_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index) { + return ptrdiff_t(Cppyy::GetDatamemberOffset(scope, datamember_index)); +} + +int cppyy_datamember_index(cppyy_scope_t scope, const char* name) { + return (int)Cppyy::GetDatamemberIndex(scope, name); +} + + + +/* data member properties ------------------------------------------------- */ +int cppyy_is_publicdata(cppyy_type_t type, cppyy_index_t datamember_index) { + return (int)Cppyy::IsPublicData(type, datamember_index); +} + +int cppyy_is_staticdata(cppyy_type_t type, cppyy_index_t datamember_index) { + return (int)Cppyy::IsStaticData(type, datamember_index); +} + +int cppyy_is_const_data(cppyy_scope_t scope, cppyy_index_t idata) { + return (int)Cppyy::IsConstData(scope, idata); +} + +int cppyy_is_enum_data(cppyy_scope_t scope, cppyy_index_t idata) { + return (int)Cppyy::IsEnumData(scope, idata); +} + +int cppyy_get_dimension_size(cppyy_scope_t scope, cppyy_index_t idata, int dimension) { + return Cppyy::GetDimensionSize(scope, idata, dimension); +} + + +/* misc helpers ----------------------------------------------------------- */ +RPY_EXTERN +void* cppyy_load_dictionary(const char* lib_name) { + int result = gSystem->Load(lib_name); + return (void*)(result == 0 /* success */ || result == 1 /* already loaded */); +} + +#if defined(_MSC_VER) +long long cppyy_strtoll(const char* str) { + return _strtoi64(str, NULL, 0); +} + +extern "C" { +unsigned long long cppyy_strtoull(const char* str) { + return _strtoui64(str, NULL, 0); +} +} +#else +long long cppyy_strtoll(const char* str) { + return strtoll(str, NULL, 0); +} + +extern "C" { +unsigned long long cppyy_strtoull(const char* str) { + return strtoull(str, NULL, 0); +} +} +#endif + +void cppyy_free(void* ptr) { + free(ptr); +} + +cppyy_object_t cppyy_charp2stdstring(const char* str, size_t sz) { + return (cppyy_object_t)new std::string(str, sz); +} + +const char* cppyy_stdstring2charp(cppyy_object_t ptr, size_t* lsz) { + *lsz = ((std::string*)ptr)->size(); + return ((std::string*)ptr)->data(); +} + +cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr) { + return (cppyy_object_t)new std::string(*(std::string*)ptr); +} + +const char* cppyy_stdvector_valuetype(const char* clname) +{ + const char* result = nullptr; + std::string name = clname; + TypedefInfo_t* ti = gInterpreter->TypedefInfo_Factory((name+"::value_type").c_str()); + if (gInterpreter->TypedefInfo_IsValid(ti)) + result = cppstring_to_cstring(gInterpreter->TypedefInfo_TrueName(ti)); + gInterpreter->TypedefInfo_Delete(ti); + return result; +} + +size_t cppyy_stdvector_valuesize(const char* clname) +{ + size_t result = 0; + std::string name = clname; + TypedefInfo_t* ti = gInterpreter->TypedefInfo_Factory((name+"::value_type").c_str()); + if (gInterpreter->TypedefInfo_IsValid(ti)) + result = (size_t)gInterpreter->TypedefInfo_Size(ti); + gInterpreter->TypedefInfo_Delete(ti); + return result; +} + +} // end C-linkage wrappers diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.h b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.h new file mode 100644 index 0000000000000..fef5824ce3333 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.h @@ -0,0 +1,37 @@ +#ifndef CPPYY_CLINGCWRAPPER +#define CPPYY_CLINGCWRAPPER + +#include "capi.h" + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + + /* misc helpers */ + void* cppyy_load_dictionary(const char* lib_name); + +#ifdef __cplusplus +} +#endif // ifdef __cplusplus + +// TODO: pick up from llvm-config --cxxflags +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +// Wrapper callback: except this to become available from Cling directly +typedef void (*CPPYY_Cling_Wrapper_t)(void*, int, void**, void*); + +#endif // ifndef CPPYY_CLINGCWRAPPER diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h new file mode 100644 index 0000000000000..a07f09f0eeec0 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h @@ -0,0 +1,224 @@ +#ifndef CPYCPPYY_CPPYY_H +#define CPYCPPYY_CPPYY_H + +// Standard +#include +#include +#include +#include + + +// ROOT types +typedef long long Long64_t; +typedef unsigned long long ULong64_t; +typedef long double LongDouble_t; + +namespace Cppyy { + typedef ptrdiff_t TCppScope_t; + typedef TCppScope_t TCppType_t; + typedef void* TCppObject_t; + typedef ptrdiff_t TCppMethod_t; + + typedef long TCppIndex_t; + typedef void* TCppFuncAddr_t; + +// name to opaque C++ scope representation ----------------------------------- + RPY_EXTERN + std::string ResolveName(const std::string& cppitem_name); + RPY_EXTERN + std::string ResolveEnum(const std::string& enum_type); + RPY_EXTERN + TCppScope_t GetScope(const std::string& scope_name); + RPY_EXTERN + TCppType_t GetActualClass(TCppType_t klass, TCppObject_t obj); + RPY_EXTERN + size_t SizeOf(TCppType_t klass); + RPY_EXTERN + size_t SizeOf(const std::string& type_name); + + RPY_EXTERN + bool IsBuiltin(const std::string& type_name); + RPY_EXTERN + bool IsComplete(const std::string& type_name); + + RPY_EXTERN + TCppScope_t gGlobalScope; // for fast access + +// memory management --------------------------------------------------------- + RPY_EXTERN + TCppObject_t Allocate(TCppType_t type); + RPY_EXTERN + void Deallocate(TCppType_t type, TCppObject_t instance); + RPY_EXTERN + TCppObject_t Construct(TCppType_t type); + RPY_EXTERN + void Destruct(TCppType_t type, TCppObject_t instance); + +// method/function dispatching ----------------------------------------------- + RPY_EXTERN + void CallV(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + unsigned char CallB(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + char CallC(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + short CallH(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + int CallI(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + long CallL(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + Long64_t CallLL(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + float CallF(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + double CallD(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + LongDouble_t CallLD(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + void* CallR(TCppMethod_t method, TCppObject_t self, void* args); + RPY_EXTERN + char* CallS(TCppMethod_t method, TCppObject_t self, void* args, size_t* length); + RPY_EXTERN + TCppObject_t CallConstructor(TCppMethod_t method, TCppType_t type, void* args); + RPY_EXTERN + void CallDestructor(TCppType_t type, TCppObject_t self); + RPY_EXTERN + TCppObject_t CallO(TCppMethod_t method, TCppObject_t self, void* args, TCppType_t result_type); + + RPY_EXTERN + TCppFuncAddr_t GetFunctionAddress(TCppScope_t scope, TCppIndex_t imeth); + RPY_EXTERN + TCppFuncAddr_t GetFunctionAddress(TCppMethod_t method); + +// handling of function argument buffer -------------------------------------- + RPY_EXTERN + void* AllocateFunctionArgs(size_t nargs); + RPY_EXTERN + void DeallocateFunctionArgs(void* args); + RPY_EXTERN + size_t GetFunctionArgSizeof(); + RPY_EXTERN + size_t GetFunctionArgTypeoffset(); + +// scope reflection information ---------------------------------------------- + RPY_EXTERN + bool IsNamespace(TCppScope_t scope); + RPY_EXTERN + bool IsTemplate(const std::string& template_name); + RPY_EXTERN + bool IsAbstract(TCppType_t type); + RPY_EXTERN + bool IsEnum(const std::string& type_name); + + RPY_EXTERN + void GetAllCppNames(TCppScope_t scope, std::set& cppnames); + +// class reflection information ---------------------------------------------- + RPY_EXTERN + std::string GetFinalName(TCppType_t type); + RPY_EXTERN + std::string GetScopedFinalName(TCppType_t type); + RPY_EXTERN + bool HasComplexHierarchy(TCppType_t type); + RPY_EXTERN + TCppIndex_t GetNumBases(TCppType_t type); + RPY_EXTERN + std::string GetBaseName(TCppType_t type, TCppIndex_t ibase); + RPY_EXTERN + bool IsSubtype(TCppType_t derived, TCppType_t base); + RPY_EXTERN + bool GetSmartPtrInfo(const std::string&, TCppType_t& raw, TCppMethod_t& deref); + RPY_EXTERN + void AddSmartPtrType(const std::string&); + +// calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 + RPY_EXTERN + ptrdiff_t GetBaseOffset( + TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror = false); + +// method/function reflection information ------------------------------------ + RPY_EXTERN + TCppIndex_t GetNumMethods(TCppScope_t scope); + RPY_EXTERN + std::vector GetMethodIndicesFromName(TCppScope_t scope, const std::string& name); + + RPY_EXTERN + TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth); + + RPY_EXTERN + std::string GetMethodName(TCppMethod_t); + RPY_EXTERN + std::string GetMethodMangledName(TCppMethod_t); + RPY_EXTERN + std::string GetMethodResultType(TCppMethod_t); + RPY_EXTERN + TCppIndex_t GetMethodNumArgs(TCppMethod_t); + RPY_EXTERN + TCppIndex_t GetMethodReqArgs(TCppMethod_t); + RPY_EXTERN + std::string GetMethodArgName(TCppMethod_t, int iarg); + RPY_EXTERN + std::string GetMethodArgType(TCppMethod_t, int iarg); + RPY_EXTERN + std::string GetMethodArgDefault(TCppMethod_t, int iarg); + RPY_EXTERN + std::string GetMethodSignature(TCppScope_t scope, TCppIndex_t imeth, bool show_formalargs); + RPY_EXTERN + std::string GetMethodPrototype(TCppScope_t scope, TCppIndex_t imeth, bool show_formalargs); + RPY_EXTERN + bool IsConstMethod(TCppMethod_t); + + RPY_EXTERN + bool ExistsMethodTemplate(TCppScope_t scope, const std::string& name); + RPY_EXTERN + bool IsMethodTemplate(TCppScope_t scope, TCppIndex_t imeth); + RPY_EXTERN + TCppIndex_t GetMethodNumTemplateArgs(TCppScope_t scope, TCppIndex_t imeth); + RPY_EXTERN + std::string GetMethodTemplateArgName(TCppScope_t scope, TCppIndex_t imeth, TCppIndex_t iarg); + + RPY_EXTERN + TCppMethod_t GetMethodTemplate( + TCppScope_t scope, const std::string& name, const std::string& proto); + RPY_EXTERN + TCppIndex_t GetGlobalOperator( + TCppType_t scope, TCppType_t lc, TCppScope_t rc, const std::string& op); + +// method properties --------------------------------------------------------- + RPY_EXTERN + bool IsPublicMethod(TCppMethod_t method); + RPY_EXTERN + bool IsConstructor(TCppMethod_t method); + RPY_EXTERN + bool IsDestructor(TCppMethod_t method); + RPY_EXTERN + bool IsStaticMethod(TCppMethod_t method); + +// data member reflection information ---------------------------------------- + RPY_EXTERN + TCppIndex_t GetNumDatamembers(TCppScope_t scope); + RPY_EXTERN + std::string GetDatamemberName(TCppScope_t scope, TCppIndex_t idata); + RPY_EXTERN + std::string GetDatamemberType(TCppScope_t scope, TCppIndex_t idata); + RPY_EXTERN + ptrdiff_t GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata); + RPY_EXTERN + TCppIndex_t GetDatamemberIndex(TCppScope_t scope, const std::string& name); + +// data member properties ---------------------------------------------------- + RPY_EXTERN + bool IsPublicData(TCppScope_t scope, TCppIndex_t idata); + RPY_EXTERN + bool IsStaticData(TCppScope_t scope, TCppIndex_t idata); + RPY_EXTERN + bool IsConstData(TCppScope_t scope, TCppIndex_t idata); + RPY_EXTERN + bool IsEnumData(TCppScope_t scope, TCppIndex_t idata); + RPY_EXTERN + int GetDimensionSize(TCppScope_t scope, TCppIndex_t idata, int dimension); + +} // namespace Cppyy + +#endif // !CPYCPPYY_CPPYY_H diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/cppyy.h b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/cppyy.h new file mode 100644 index 0000000000000..24ed18ee2536f --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/cppyy.h @@ -0,0 +1,66 @@ +#ifndef CPPYY_CPPYY +#define CPPYY_CPPYY + +#include "cpp_cppyy.h" + +#ifdef __cplusplus +struct CPPYY_G__DUMMY_FOR_CINT7 { +#else +typedef struct +#endif + void* fTypeName; + unsigned int fModifiers; +#ifdef __cplusplus +}; +#else +} CPPYY_G__DUMMY_FOR_CINT7; +#endif + +#ifdef __cplusplus +struct CPPYY_G__p2p { +#else +typedef struct { +#endif + long i; + int reftype; +#ifdef __cplusplus +}; +#else +} CPPYY_G__p2p; +#endif + + +#ifdef __cplusplus +struct CPPYY_G__value { +#else +typedef struct { +#endif + union { + double d; + long i; /* used to be int */ + struct CPPYY_G__p2p reftype; + char ch; + short sh; + int in; + float fl; + unsigned char uch; + unsigned short ush; + unsigned int uin; + unsigned long ulo; + long long ll; + unsigned long long ull; + long double ld; + } obj; + long ref; + int type; + int tagnum; + int typenum; + char isconst; + struct CPPYY_G__DUMMY_FOR_CINT7 dummyForCint7; +#ifdef __cplusplus +}; +#else +} CPPYY_G__value; +#endif + +#endif // CPPYY_CPPYY diff --git a/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/precommondefs.h b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/precommondefs.h new file mode 100644 index 0000000000000..62710b6e41b3e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy-backend/clingwrapper/src/precommondefs.h @@ -0,0 +1,77 @@ +/***** Start of precommondefs.h *****/ + +/* This is extracted from pyconfig.h from CPython. It sets the macros + that affect the features we get from system include files. + It must not #include anything. */ + +#ifndef __PYPY_PRECOMMONDEFS_H +#define __PYPY_PRECOMMONDEFS_H + + +/* Define on Darwin to activate all library features */ +#define _DARWIN_C_SOURCE 1 +/* This must be set to 64 on some systems to enable large file support. */ +#define _FILE_OFFSET_BITS 64 +/* Define on Linux to activate all library features */ +#define _GNU_SOURCE 1 +/* This must be defined on some systems to enable large file support. */ +#define _LARGEFILE_SOURCE 1 +/* Define on NetBSD to activate all library features */ +#define _NETBSD_SOURCE 1 +/* Define to activate features from IEEE Stds 1003.1-2001 */ +#ifndef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 200112L +#endif +/* Define on FreeBSD to activate all library features */ +#define __BSD_VISIBLE 1 +#define __XSI_VISIBLE 700 +/* Windows: winsock/winsock2 mess */ +#define WIN32_LEAN_AND_MEAN +#ifdef _WIN64 + typedef __int64 Signed; + typedef unsigned __int64 Unsigned; +# define SIGNED_MIN LLONG_MIN +#else + typedef long Signed; + typedef unsigned long Unsigned; +# define SIGNED_MIN LONG_MIN +#endif + +#if !defined(RPY_ASSERT) && !defined(RPY_LL_ASSERT) && !defined(NDEBUG) +# define NDEBUG +#endif + + +/* All functions and global variables declared anywhere should use + one of the following attributes: + + RPY_EXPORTED: the symbol is exported out of libpypy-c.so. + + RPY_EXTERN: the symbol is not exported out of libpypy-c.so, but + otherwise works like 'extern' by being available to + other C sources. + + static: as usual, this means the symbol is local to this C file. + + Don't use _RPY_HIDDEN directly. For tests involving building a custom + .so, translator/tool/cbuild.py overrides RPY_EXTERN so that it becomes + equal to RPY_EXPORTED. + + Any function or global variable declared with no attribute at all is + a bug; please report or fix it. +*/ +#ifdef __GNUC__ +# define RPY_EXPORTED extern __attribute__((visibility("default"))) +# define _RPY_HIDDEN __attribute__((visibility("hidden"))) +#else +# define RPY_EXPORTED extern __declspec(dllexport) +# define _RPY_HIDDEN /* nothing */ +#endif +#ifndef RPY_EXTERN +# define RPY_EXTERN extern +#endif + + +#endif /* __PYPY_PRECOMMONDEFS_H */ + +/***** End of precommondefs.h *****/ diff --git a/bindings/pyroot_experimental/cppyy/cppyy/.gitignore b/bindings/pyroot_experimental/cppyy/cppyy/.gitignore new file mode 100644 index 0000000000000..1423e4842d179 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/.gitignore @@ -0,0 +1,35 @@ +# python compiled files +*.pyc +*.pyo + +# dictionary products +*.so +*.pcm +*.rootmap +*_rflx.cpp + +.cache +.pytest_cache + +# distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# notebook products +.ipynb_checkpoints +doc/tutorial/gsl_selection.xml diff --git a/bindings/pyroot_experimental/cppyy/cppyy/CMakeLists.txt b/bindings/pyroot_experimental/cppyy/cppyy/CMakeLists.txt new file mode 100644 index 0000000000000..dc0b75abadbc2 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/CMakeLists.txt @@ -0,0 +1,14 @@ +set(py_sources + cppyy/_stdcpp_fix.py + cppyy/__init__.py + cppyy/_cpython_cppyy.py + cppyy/_pythonization.py +) + +set(d $ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/${runtimedir}) +foreach(py_source ${py_sources}) + file(COPY python/${py_source} DESTINATION ${localruntimedir}/cppyy) + install(FILES python/${py_source} DESTINATION ${runtimedir}/cppyy) + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile ${d}/${py_source})") + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile ${d}/${py_source})") +endforeach() diff --git a/bindings/pyroot_experimental/cppyy/cppyy/LICENSE.txt b/bindings/pyroot_experimental/cppyy/cppyy/LICENSE.txt new file mode 100644 index 0000000000000..d0ed7576ad457 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/LICENSE.txt @@ -0,0 +1,52 @@ +Copyright (c) 2003, The Regents of the University of California, +through Lawrence Berkeley National Laboratory (subject to receipt of +any required approvals from the U.S. Dept. of Energy). All rights +reserved. Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following +conditions are met: + +(1) Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +(2) Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +(3) Neither the name of the University of California, Lawrence Berkeley +National Laboratory, U.S. Dept. of Energy nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +You are under no obligation whatsoever to provide any bug fixes, +patches, or upgrades to the features, functionality or performance of +the source code ("Enhancements") to anyone; however, if you choose to +make your Enhancements available either publicly, or directly to +Lawrence Berkeley National Laboratory, without imposing a separate +written license agreement for such Enhancements, then you hereby grant +the following license: a non-exclusive, royalty-free perpetual license +to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such Enhancements +or derivative works thereof, in binary and source code form. + + + +Additional copyright holders +---------------------------- + +Except when otherwise stated (look for LICENSE files or information in +source files), this package contains files copyrighted by one or more of +the following people and organizations: + + Aditi Dutta + Shaheed Haque + Toby StClere-Smithe diff --git a/bindings/pyroot_experimental/cppyy/cppyy/MANIFEST.in b/bindings/pyroot_experimental/cppyy/cppyy/MANIFEST.in new file mode 100644 index 0000000000000..face07acf0693 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/MANIFEST.in @@ -0,0 +1,6 @@ +# Include the license file +include LICENSE.txt + +# Do not add the test or doc directories +prune test +prune doc diff --git a/bindings/pyroot_experimental/cppyy/cppyy/README.rst b/bindings/pyroot_experimental/cppyy/cppyy/README.rst new file mode 100644 index 0000000000000..f3aca84184951 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/README.rst @@ -0,0 +1,15 @@ +.. -*- mode: rst -*- + +cppyy: Python-C++ bindings interface based on Cling/LLVM +======================================================== + +cppyy provides dynamic Python-C++ bindings by leveraging the Cling C++ +interpreter and LLVM. +It supports both PyPy and CPython. + +Details and performance are described in +`this paper `_. + +Full documentation: `cppyy.readthedocs.io `_. + +Notebook-based tutorial: `Cppyy Tutorial `_. diff --git a/bindings/pyroot_experimental/cppyy/cppyy/bench/Makefile b/bindings/pyroot_experimental/cppyy/cppyy/bench/Makefile new file mode 100644 index 0000000000000..d2b3022931190 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/bench/Makefile @@ -0,0 +1,29 @@ +dicts = functioncallsDict.so +all : $(dicts) + +ifeq ($(ROOTSYS),) + clingconfig := cling-config +else + clingconfig := root-config +endif + +cppflags=$(shell $(clingconfig) --cflags) -O3 -fPIC + +PLATFORM := $(shell uname -s) +ifeq ($(PLATFORM),Darwin) + cppflags+=-dynamiclib -single_module -arch x86_64 -undefined dynamic_lookup +endif + +%Dict.so: %_rflx.cpp %.cxx + $(CXX) $(cppflags) -shared -o $@ $^ + +%_rflx.cpp: %.h %.xml + genreflex $< --selection=$*.xml --rootmap=$*Dict.rootmap --rootmap-lib=$*Dict.so + +.PHONY: test clean + +test: + pytest test_*.py + +clean: + -rm -f $(dicts) $(subst .so,.rootmap,$(dicts)) $(subst Dict.so,_rflx_rdict.pcm,$(dicts)) $(subst Dict.so,_rflx.cpp,$(dicts)) $(wildcard *.pyc) diff --git a/bindings/pyroot_experimental/cppyy/cppyy/bench/bench_functioncalls.py b/bindings/pyroot_experimental/cppyy/cppyy/bench/bench_functioncalls.py new file mode 100644 index 0000000000000..1aa1d4a38027b --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/bench/bench_functioncalls.py @@ -0,0 +1,39 @@ +import py, pytest, os, sys +from support import setup_make + + +setup_make("functioncallsDict.so") + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("functioncallsDict.so")) + +import cppyy +cppyy.load_reflection_info(test_dct) + + +#- group: empty -------------------------------------------------------------- +def py_empty_call(): + pass + +group = 'empty' +@pytest.mark.benchmark(group=group, warmup=True) +def test_py_empty_call(benchmark): + benchmark(py_empty_call) + +@pytest.mark.benchmark(group=group, warmup=True) +def test_empty_call(benchmark): + benchmark(cppyy.gbl.empty_call) + + +#- group: builtin-args ------------------------------------------------------- +def py_take_a_value(val): + pass + +group = 'builtin-args' +@pytest.mark.benchmark(group=group, warmup=True) +def test_py_take_a_value(benchmark): + benchmark(py_take_a_value, 1) + +@pytest.mark.benchmark(group=group, warmup=True) +def test_take_an_int(benchmark): + benchmark(cppyy.gbl.take_an_int, 1) diff --git a/bindings/pyroot_experimental/cppyy/cppyy/bench/functioncalls.cxx b/bindings/pyroot_experimental/cppyy/cppyy/bench/functioncalls.cxx new file mode 100644 index 0000000000000..d49a83df5760b --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/bench/functioncalls.cxx @@ -0,0 +1,16 @@ +#include "functioncalls.h" + + +//- group: empty ------------------------------------------------------------- +void empty_call() +{ +/* empty, to measure pure call overhead */ +} + + +//- group: builtin-args ------------------------------------------------------ +void take_an_int(int /* unused */) +{ +/* empty, to measure pure call overhead */ +} + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/bench/functioncalls.h b/bindings/pyroot_experimental/cppyy/cppyy/bench/functioncalls.h new file mode 100644 index 0000000000000..b7b46fd785035 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/bench/functioncalls.h @@ -0,0 +1,10 @@ +#ifndef CPPYY_FUNCTIONCALLS_H +#define CPPYY_FUNCTIONCALLS_H + +//- group: empty ------------------------------------------------------------- +void empty_call(); + +//- group: builtin-args ------------------------------------------------------ +void take_an_int(int); + +#endif // !CPPYY_FUNCTIONCALLS_H diff --git a/bindings/pyroot_experimental/cppyy/cppyy/bench/functioncalls.xml b/bindings/pyroot_experimental/cppyy/cppyy/bench/functioncalls.xml new file mode 100644 index 0000000000000..62726289cbf62 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/bench/functioncalls.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/bench/support.py b/bindings/pyroot_experimental/cppyy/cppyy/bench/support.py new file mode 100644 index 0000000000000..a2eeeaf289773 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/bench/support.py @@ -0,0 +1,14 @@ +from __future__ import print_function +import py, sys, subprocess + +currpath = py.path.local(__file__).dirpath() + + +def setup_make(targetname): + if sys.platform == 'win32': + raise OSError("win32 not supported yet") + popen = subprocess.Popen(["make", targetname], cwd=str(currpath), + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout, _ = popen.communicate() + if popen.returncode: + raise OSError("'make' failed:\n%s" % (stdout,)) diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/.gitignore b/bindings/pyroot_experimental/cppyy/cppyy/doc/.gitignore new file mode 100644 index 0000000000000..378eac25d3117 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/.gitignore @@ -0,0 +1 @@ +build diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/Makefile b/bindings/pyroot_experimental/cppyy/cppyy/doc/Makefile new file mode 100644 index 0000000000000..cbe159e5ce7fe --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cppyy.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cppyy.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/cppyy" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cppyy" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/make.bat b/bindings/pyroot_experimental/cppyy/cppyy/doc/make.bat new file mode 100644 index 0000000000000..a89c8bd30100c --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/make.bat @@ -0,0 +1,263 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source +set I18NSPHINXOPTS=%SPHINXOPTS% source +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 2> nul +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\cppyy.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\cppyy.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/_static/css/custom.css b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/_static/css/custom.css new file mode 100644 index 0000000000000..5402ff8e7bd6d --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/_static/css/custom.css @@ -0,0 +1,7 @@ +.rst-content .toconly { + display: none; +} + +nav .toconly { + display: unset; +} diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/basic_types.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/basic_types.rst new file mode 100644 index 0000000000000..19dd5d244e2fb --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/basic_types.rst @@ -0,0 +1,105 @@ +.. _basic_types: + +.. role:: toconly + :class: toconly + + +Basic Types +=========== + +C++ has a far richer set of builtin types than Python. +Most Python code can remain relatively agnostic to that, and ``cppyy`` +provides automatic conversions as appropriate. +On the other hand, Python builtin types such as lists and maps are far +richer than any builtin types in C++. +These are mapped to their Standard Template Library equivalents instead. + +The C++ code used for the examples below can be found +:doc:`here `, and it is assumed that that code is +loaded at the start of any session. +Download it, save it under the name ``features.h``, and load it: + + .. code-block:: python + + >>> import cppyy + >>> cppyy.include('features.h') + >>> + + +:toconly:`Basics` +""""""""""""""""" + +Most builtin data types map onto the expected equivalent Python types, with +the caveats that there may be size differences, different precision or +rounding. +For example, a C++ ``float`` is returned as a Python ``float``, which is in +fact a C++ ``double``. +If sizes allow, conversions are automatic. +For example, a C++ ``unsigned int`` becomes a Python ``long``, but +unsigned-ness is still honored: + + .. code-block:: python + + >>> type(cppyy.gbl.gUint) + + >>> cppyy.gbl.gUint = -1 + Traceback (most recent call last): + File "", line 1, in + ValueError: cannot convert negative integer to unsigned + >>> + + +:toconly:`Arrays` +""""""""""""""""" + +Builtin arrays are supported by through arrays from module ``array`` (or any +other builtin-type array that implements the Python buffer interface). +Out-of-bounds checking is limited to those cases where the size is known at +compile time. +Example: + + .. code-block:: python + + >>> from cppyy.gbl import Concrete + >>> from array import array + >>> c = Concrete() + >>> c.array_method(array('d', [1., 2., 3., 4.]), 4) + 1 2 3 4 + >>> c.m_data[4] # static size is 4, so out of bounds + Traceback (most recent call last): + File "", line 1, in + IndexError: buffer index out of range + >>> + + +:toconly:`Pointers` +""""""""""""""""""" + +When the C++ code takes a pointer or reference type to a specific builtin +type (such as an ``unsigned int`` for example), then types need to match +exactly. +``cppyy`` supports the types provided by the standard modules ``ctypes`` and +``array`` for those cases. + +For objects, a pointer to an object and an object are represented the same, +with the necessary (de)referencing applied automatically. +Pointer variables are also bound by reference, so that updates on either the +C++ or Python side are reflected on the other side as well. + + +:toconly:`Enums` +"""""""""""""""" + +Both named and anonymous enums are supported. +The type of an enum is implementation dependent and may even be different for +different enums on the same compiler. +Typically, however, the types are ``int`` or ``unsigned int``, which +translates to Python's ``int`` or ``long`` on Python2 or class ``int`` on +Python3: + + .. code-block:: python + + >>> from cppyy.gbl import kApple, kBanana, kCitrus + >>> cppyy.gbl.kApple + 78L + >>> diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/bindings_generation.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/bindings_generation.rst new file mode 100644 index 0000000000000..11361740c6997 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/bindings_generation.rst @@ -0,0 +1,306 @@ +.. _bindings_generation: + +=================== +Bindings Generation +=================== + +Binding developers have two levels of access to cling via ``cppyy``: + +* A simple command line interface. +* Automated generation of an end-user bindings package from a CMake-based + project build. + +Both are installed as part of the ``cppyy-backend`` component since they are +not needed by users of the bindings. + +Command Line Interface +====================== + +rootcling +--------- + +This provides basic access to ``cling``:: + + $ rootcling + Usage: rootcling [-v][-v0-4] [-f] [out.cxx] [opts] file1.h[+][-][!] file2.h[+][-][!] ...[LinkDef.h] + For more extensive help type: /usr/local/lib/python2.7/dist-packages/cppyy_backend/bin/rootcling -h + +The basic mode of operation is to process the header files ('fileN.h') +according to certain `#pragmas in the LinkDef.h `_ +file in order to generate bindings accessible in Python under the 'cppyy.gbl' +namespace. + +The output is + +* A .cpp file (which, when compiled to a shared library) +* A .rootmap file +* A .pcm file + +which are used at runtime by ``cling`` to expose the semantics expressed by the +header files to Python. Nominally, the compiled .cpp provides low-level Python +access to the library API defined by the header files, while ``cling`` uses the +other files to provide the rich features it supports. Thus, the shipping form +of the bindings contains: + +* A shared library (which must be compiled from the .cpp) +* A .rootmap file +* A .pcm file + +cling-config +------------ + +This is a small utility whose main purpose is to provide access to the +as-installed configuration of other components. For-example:: + + $ cling-config --help + Usage: cling-config [--cflags] [--cppflags] [--cmake] + $ cling-config --cmake + /usr/local/lib/python2.7/dist-packages/cppyy_backend/cmake + +cppyy-generator +--------------- + +This is a clang-based utility program which takes a set of C++ header files +and generate a JSON output file describing the objects found in them. This +output is intended to support more convenient access to a set of +cppyy-supported bindings:: + + $ cppyy-generator --help + usage: cppyy-generator [-h] [-v] [--flags FLAGS] [--libclang LIBCLANG] + output sources [sources ...] + ... + +See the ``Cmake interface`` for details. + +CMake interface +=============== + +The bindings generated by rootcling, are 'raw' in the sense that: + +* The .cpp file be compiled. The required compilation steps are + platform-dependent. +* The bindings are not packaged for distribution. Typically, users expect + to have a pip-compatible package. +* The binding are in the 'cppyy.gbl' namespace. This is an inconvenience at + best for users who might expect C++ code from KF5::Config to appear in + Python via "import KF5.Config". +* The bindings are loaded lazily, which limits the discoverability of the + content of the bindings. +* ``cppyy`` supports customisation of the bindings via 'Pythonization' but + there is no automated way to load them. + +These issues are addressed by the CMake support. This is a blend of Python +packaging and CMake where CMake provides: + +* Platform-independent scripting of the creation of a Python 'wheel' package + for the bindings. +* An facility for CMake-based projects to automate the entire bindings + generation process, including basic automated tests. + +Python packaging of bindings +---------------------------- + +Modern Python packaging usage is based on the 'wheel'. This is places the onus +on the creation of binary artefacts in the package on the distributor. In this +case, this includes the platform-dependent steps necessary to compile the .cpp +file. + +The generated package also takes advantage of the __init__.py load-time +mechanism to enhance the bindings: + +* The bindings are rehosted in a "native" namespace so that C++ code from + KF5::Config appears in Python via "import KF5.Config". +* (TBD) Load Pythonizations. + +Both of these need/can use the output of the cppyy-generator (included in the +package) as well as other runtime support included in ``cppyy``. + +CMake usage +----------- + +The CMake usage is via two modules: + +* FindLibClang.cmake provides some bootstrap support needed to locate clang. + This is provided mostly as a temporary measure; hopefully upstream support + will allow this to be eliminated in due course. +* FindCppyy.cmake provides the interface described further here. + +Details of the usage of these modules is within the modules themselves, but +here is a summary of the usage. ``FindLibClang.cmake`` sets the following +variables: + +:: + + LibClang_FOUND - True if libclang is found. + LibClang_LIBRARY - Clang library to link against. + LibClang_VERSION - Version number as a string (e.g. "3.9"). + LibClang_PYTHON_EXECUTABLE - Compatible python version. + + +``FindCppyy.cmake`` sets the following variables: + +:: + + Cppyy_FOUND - set to true if Cppyy is found + Cppyy_DIR - the directory where Cppyy is installed + Cppyy_EXECUTABLE - the path to the Cppyy executable + Cppyy_INCLUDE_DIRS - Where to find the ROOT header files. + Cppyy_VERSION - the version number of the Cppyy backend. + +and also defines the following functions:: + + cppyy_add_bindings - Generate a set of bindings from a set of header files. + cppyy_find_pips - Return a list of available pip programs. + +cppyy_add_bindings +^^^^^^^^^^^^^^^^^^ + +Generate a set of bindings from a set of header files. Somewhat like CMake's +add_library(), the output is a compiler target. In addition ancilliary files +are also generated to allow a complete set of bindings to be compiled, +packaged and installed:: + + cppyy_add_bindings( + pkg + pkg_version + author + author_email + [URL url] + [LICENSE license] + [LANGUAGE_STANDARD std] + [LINKDEFS linkdef...] + [IMPORTS pcm...] + [GENERATE_OPTIONS option...] + [COMPILE_OPTIONS option...] + [INCLUDE_DIRS dir...] + [LINK_LIBRARIES library...] + [H_DIRS H_DIRSectory] + H_FILES h_file...) + +The bindings are based on https://cppyy.readthedocs.io/en/latest/, and can be +used as per the documentation provided via the cppyy.cgl namespace. First add +the directory of the .rootmap file to the LD_LIBRARY_PATH environment +variable, then "import cppyy; from cppyy.gbl import ". + +Alternatively, use "import ". This convenience wrapper supports +"discovery" of the available C++ entities using, for example Python 3's command +line completion support. + +The bindings are complete with a setup.py, supporting Wheel-based +packaging, and a test.py supporting pytest/nosetest sanity test of the bindings. + +The bindings are generated/built/packaged using 3 environments: + +- One compatible with the header files being bound. This is used to + generate the generic C++ binding code (and some ancilliary files) using + a modified C++ compiler. The needed options must be compatible with the + normal build environment of the header files. +- One to compile the generated, generic C++ binding code using a standard + C++ compiler. The resulting library code is "universal" in that it is + compatible with both Python2 and Python3. +- One to package the library and ancilliary files into standard Python2/3 + wheel format. The packaging is done using native Python tooling. + ++----------------------+---------------------------------------------------------------------------------------------+ +|Arguments and options | Description | ++======================+=============================================================================================+ +|pkg | The name of the package to generate. This can be either | +| | of the form "simplename" (e.g. "Akonadi"), or of the | +| | form "namespace.simplename" (e.g. "KF5.Akonadi"). | ++----------------------+---------------------------------------------------------------------------------------------+ +|pkg_version | The version of the package. | ++----------------------+---------------------------------------------------------------------------------------------+ +|author | The name of the library author. | ++----------------------+---------------------------------------------------------------------------------------------+ +|author_email | The email address of the library author. | ++----------------------+---------------------------------------------------------------------------------------------+ +|URL url | The home page for the library. Default is | +| | "https://pypi.python.org/pypi/". | ++----------------------+---------------------------------------------------------------------------------------------+ +|LICENSE license | The license, default is "LGPL 2.0". | ++----------------------+---------------------------------------------------------------------------------------------+ +|LANGUAGE_STANDARD std | The version of C++ in use, "14" by default. | ++----------------------+---------------------------------------------------------------------------------------------+ +|IMPORTS pcm | Files which contain previously-generated bindings | +| | which pkg depends on. | ++----------------------+---------------------------------------------------------------------------------------------+ +|GENERATE_OPTIONS optio| Options which are to be passed into the rootcling | +| | command. For example, bindings which depend on Qt | +| | may need "-D__PIC__;-Wno-macro-redefined" as per | +| | https://sft.its.cern.ch/jira/browse/ROOT-8719. | ++----------------------+---------------------------------------------------------------------------------------------+ +|LINKDEFS def | Files or lines which contain extra #pragma content | +| | for the linkdef.h file used by rootcling. See | +| | https://root.cern.ch/root/html/guides/users-guide/AddingaClass.html#the-linkdef.h-file. | +| | | +| | In lines, literal semi-colons must be escaped: "\;". | ++----------------------+---------------------------------------------------------------------------------------------+ +|EXTRA_CODES code | Files which contain extra code needed by the bindings. | +| | Customisation is by routines named "c13n_"; | +| | each such routine is passed the module for : | +| | | +| | :: code-block python | +| | | +| | def c13n_doit(pkg_module): | +| | print(pkg_module.__dict__) | +| | | +| | The files and individual routines within files are | +| | processed in alphabetical order. | ++----------------------+---------------------------------------------------------------------------------------------+ +|EXTRA_HEADERS hdr | Files which contain extra headers needed by the bindings. | ++----------------------+---------------------------------------------------------------------------------------------+ +|EXTRA_PYTHONS py | Files which contain extra Python code needed by the bindings. | ++----------------------+---------------------------------------------------------------------------------------------+ +|COMPILE_OPTIONS option| Options which are to be passed into the compile/link | +| | command. | ++----------------------+---------------------------------------------------------------------------------------------+ +|INCLUDE_DIRS dir | Include directories. | ++----------------------+---------------------------------------------------------------------------------------------+ +|LINK_LIBRARIES library| Libraries to link against. | ++----------------------+---------------------------------------------------------------------------------------------+ +|H_DIRS directory | Base directories for H_FILES. | ++----------------------+---------------------------------------------------------------------------------------------+ +|H_FILES h_file | Header files for which to generate bindings in pkg. | +| | Absolute filenames, or filenames relative to H_DIRS. All | +| | definitions found directly in these files will contribute | +| | to the bindings. (NOTE: This means that if "forwarding | +| | headers" are present, the real "legacy" headers must be | +| | specified as H_FILES). | +| | All header files which contribute to a given C++ namespace | +| | should be grouped into a single pkg to ensure a 1-to-1 | +| | mapping with the implementing Python class. | ++----------------------+---------------------------------------------------------------------------------------------+ + +Returns via PARENT_SCOPE variables:: + + target The CMake target used to build. + setup_py The setup.py script used to build or install pkg. + +Examples:: + + find_package(Qt5Core NO_MODULE) + find_package(KF5KDcraw NO_MODULE) + get_target_property(_H_DIRS KF5::KDcraw INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(_LINK_LIBRARIES KF5::KDcraw INTERFACE_LINK_LIBRARIES) + set(_LINK_LIBRARIES KF5::KDcraw ${_LINK_LIBRARIES}) + include(${KF5KDcraw_DIR}/KF5KDcrawConfigVersion.cmake) + + cppyy_add_bindings( + "KDCRAW" "${PACKAGE_VERSION}" "Shaheed" "srhaque@theiet.org" + LANGUAGE_STANDARD "14" + LINKDEFS "../linkdef_overrides.h" + GENERATE_OPTIONS "-D__PIC__;-Wno-macro-redefined" + INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} + LINK_LIBRARIES ${_LINK_LIBRARIES} + H_DIRS ${_H_DIRS} + H_FILES "dcrawinfocontainer.h;kdcraw.h;rawdecodingsettings.h;rawfiles.h") + +There is a fuller example of embedding the use of cppyy_add_bindings for a +large set of bindings:: + + https://cgit.kde.org/pykde5.git/plain/KF5/CMakeLists.txt?h=include_qt_binding + +cppyy_find_pips +^^^^^^^^^^^^^^^ + +Return a list of available pip programs. diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/classes.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/classes.rst new file mode 100644 index 0000000000000..bedd21cbd4337 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/classes.rst @@ -0,0 +1,213 @@ +.. _classes: + +.. role:: toconly + :class: toconly + + +Classes +======= + +Both Python and C++ support object-oriented code through classes and thus +it is logical to expose C++ classes as Python ones, including the full +inheritance hierarchy. + +The C++ code used for the examples below can be found +:doc:`here `, and it is assumed that that code is +loaded at the start of any session. +Download it, save it under the name ``features.h``, and load it: + + .. code-block:: python + + >>> import cppyy + >>> cppyy.include('features.h') + >>> + + +:toconly:`Basics` +""""""""""""""""" + +All bound C++ code starts off from the global C++ namespace, represented in +Python by ``gbl``. +This namespace, as any other namespace, is treated as a module after it has +been loaded. +Thus, we can import C++ classes that live underneath it: + + .. code-block:: python + + >>> from cppyy.gbl import Concrete + >>> Concrete + + >>> + +Placing classes in the same structure as imposed by C++ guarantees identity, +even if multiple Python modules bind the same class. +There is, however, no necessity to expose that structure to end-users: when +developing a Python package that exposes C++ classes through ``cppyy``, +consider ``cppyy.gbl`` an "internal" module, and expose the classes in any +structure you see fit. +The C++ names will continue to follow the C++ structure, however, as is needed +for e.g. pickling: + + .. code-block:: python + + >>> from cppyy.gbl import Namespace + >>> Concrete == Namespace.Concrete + False + >>> n = Namespace.Concrete.NestedClass() + >>> type(n) + + >>> type(n).__name__ + NestedClass + >>> type(n).__module__ + cppyy.gbl.Namespace.Concrete + >>> type(n).__cppname__ + Namespace::Concrete::NestedClass + >>> + + +:toconly:`Inheritance` +"""""""""""""""""""""" + +The output of help shows the inheritance hierarchy, constructors, public +methods, and public data. +For example, ``Concrete`` inherits from ``Abstract`` and it has +a constructor that takes an ``int`` argument, with a default value of 42. +Consider: + + .. code-block:: python + + >>> from cppyy.gbl import Abstract + >>> issubclass(Concrete, Abstract) + True + >>> a = Abstract() + Traceback (most recent call last): + File "", line 1, in + TypeError: cannot instantiate abstract class 'Abstract' + >>> c = Concrete() + >>> isinstance(c, Concrete) + True + >>> isinstance(c, Abstract) + True + >>> d = Concrete(13) + >>> + +Just like in C++, interface classes that define pure virtual methods, such +as ``Abstract`` does, can not be instantiated, but their concrete +implementations can. +As the output of ``help`` showed, the ``Concrete`` constructor takes +an integer argument, that by default is 42. + + +:toconly:`Typedefs` +"""""""""""""""""""" + +Typedefs are simple python references to the actual classes to which +they refer. + + .. code-block:: python + + >>> from cppyy.gbl import Concrete_t + >>> Concrete is Concrete_t + True + >>> + + +:toconly:`Data members` +""""""""""""""""""""""" + +The ``Concrete`` instances have a public data member ``m_int`` that +is treated as a Python property, albeit a typed one: + + .. code-block:: python + + >>> c.m_int, d.m_int + (42, 13) + >>> c.m_int = 3.14 # a float does not fit in an int + Traceback (most recent call last): + File "", line 1, in + TypeError: int/long conversion expects an integer object + >>> c.m_int = int(3.14) + >>> c.m_int, d.m_int + (3, 13) + >>> + +Note that private and protected data members are not accessible and C++ +const-ness is respected: + + .. code-block:: python + + >>> c.m_const_int = 71 # declared 'const int' in class definition + Traceback (most recent call last): + File "", line 1, in + TypeError: assignment to const data not allowed + >>> + +Static C++ data members act like Python class-level data members. +They are also represented by property objects and both read and write access +behave as expected: + + .. code-block:: python + + >>> Concrete.s_int # access through class + 321 + >>> c.s_int = 123 # access through instance + >>> Concrete.s_int + 123 + + +:toconly:`Methods` +"""""""""""""""""" + +C++ methods are represented as Python ones: these are first-class objects and +can be bound to an instance. +If a method is virtual in C++, the proper concrete method is called, whether +or not the concrete class is bound. +Similarly, if all classes are bound, the normal Python rules apply: + + .. code-block:: python + + >>> c.abstract_method() + called Concrete::abstract_method + >>> c.concrete_method() + called Concrete::concrete_method + >>> m = c.abstract_method + >>> m() + called Concrete::abstract_method + >>> + + +:toconly:`Templates` +"""""""""""""""""""" + +Templated classes are instantiated using square brackets. +(For backwards compatibility reasons, parentheses work as well.) +The instantiation of a templated class yields a class, which can then +be used to create instances. + +Templated classes need not pre-exist in the bound code, just their +declaration needs to be available. +This is true for e.g. all of STL: + + .. code-block:: python + + >>> cppyy.gbl.std.vector # template metatype + + >>> cppyy.gbl.std.vector(int) # instantiates template -> class + at 0x1532190> + cppyy.gbl.std.vector[int]() # instantiates class -> object + object at 0x2341ec0> + >>> + +The template arguments may be actual types or their names as a string, +whichever is more convenient. +Thus, the following are equivalent: + + .. code-block:: python + + >>> from cppyy.gbl.std import vector + >>> type1 = vector[Concrete] + >>> type2 = vector['Concrete'] + >>> type1 == type2 + True + >>> + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/conf.py b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/conf.py new file mode 100644 index 0000000000000..99b4b6fdd6130 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/conf.py @@ -0,0 +1,358 @@ +# -*- coding: utf-8 -*- +# +# cppyy documentation build configuration file, created by +# sphinx-quickstart on Wed Jul 12 14:35:45 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'cppyy' +copyright = u'2017, Wim Lavrijsen' +author = u'Wim Lavrijsen' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +import sphinx_rtd_theme +html_theme = "sphinx_rtd_theme" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'cppyydoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'cppyy.tex', u'cppyy Documentation', + u'Wim Lavrijsen', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'cppyy', u'cppyy Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'cppyy', u'cppyy Documentation', + author, 'cppyy', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +#epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not optimized +# for small screen space, using the same theme for HTML and epub output is +# usually not wise. This defaults to 'epub', a theme designed to save visual +# space. +#epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +#epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +#epub_fix_images = False + +# Scale large images. +#epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#epub_show_urls = 'inline' + +# If false, no index is generated. +#epub_use_index = True + +def setup(app): + app.add_stylesheet('css/custom.css') diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/cppyy_features_header.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/cppyy_features_header.rst new file mode 100644 index 0000000000000..b45c18ad1883f --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/cppyy_features_header.rst @@ -0,0 +1,104 @@ +File features.h +=============== + +.. code-block:: C++ + + #include + #include + #include + + + //----- + unsigned int gUint = 0; + + //----- + class Abstract { + public: + virtual ~Abstract() {} + virtual void abstract_method() = 0; + virtual void concrete_method() = 0; + }; + + void Abstract::concrete_method() { + std::cout << "called Abstract::concrete_method" << std::endl; + } + + //----- + class Concrete : Abstract { + public: + Concrete(int n=42) : m_int(n), m_const_int(17) {} + ~Concrete() {} + + virtual void abstract_method() { + std::cout << "called Concrete::abstract_method" << std::endl; + } + + virtual void concrete_method() { + std::cout << "called Concrete::concrete_method" << std::endl; + } + + void array_method(int* ad, int size) { + for (int i=0; i < size; ++i) + std::cout << ad[i] << ' '; + std::cout << std::endl; + } + + void array_method(double* ad, int size) { + for (int i=0; i < size; ++i) + std::cout << ad[i] << ' '; + std::cout << std::endl; + } + + Abstract* show_autocast() { + return this; + } + + operator const char*() { + return "Hello operator const char*!"; + } + + public: + double m_data[4]; + int m_int; + const int m_const_int; + + static int s_int; + }; + + typedef Concrete Concrete_t; + + int Concrete::s_int = 321; + + //----- + int global_function(int) { + return 42; + } + + double global_function(double) { + return std::exp(1); + } + + //----- + namespace Namespace { + + class Concrete { + public: + class NestedClass { + public: + std::vector m_v; + }; + + }; + + int global_function(int i) { + return 2*::global_function(i); + } + + double global_function(double d) { + return 2*::global_function(d); + } + + } // namespace Namespace + + //----- + enum EFruit {kApple=78, kBanana=29, kCitrus=34}; diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/dictionaries.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/dictionaries.rst new file mode 100644 index 0000000000000..8c6e311ee9e5e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/dictionaries.rst @@ -0,0 +1,97 @@ +.. _dictionaries: + +Dictionaries +============ + +Loading code directly into Cling is fine for interactive work and small +scripts, but large scale applications should take advantage of pre-packaging +code, linking in libraries, and describing other dependencies. +The necessary tools are installed as part of the backend. + + +Dictionary generation +--------------------- + +A "reflection dictionary" makes it simple to combine the necessary headers and +libraries into a single package for use and distribution. +The relevant headers are read by a tool called `genreflex`_ which generates +C++ files that are to be compiled into a shared library. +That library can further be linked with any relevant project libraries that +contain the implementation of the functionality declared in the headers. +For example, given a file called ``project_header.h`` and an implementation +residing in ``libproject.so``, the following will generate a +``libProjectDict.so`` reflection dictionary:: + + $ genreflex project_header.h + $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared `genreflex --cppflags` project_header_rflx.cpp -o libProjectDict.so -L$PROJECTHOME/lib -lproject + +Instead of loading the header text into Cling, you can now load the +dictionary: + +.. code-block:: python + + >>> import cppyy + >>> cppyy.load_reflection_info('libProjectDict.so') + + >>> from cppyy.gbl import SomeClassFromProject + >>> + +and use the C++ entities from the header as before. + +.. _`genreflex`: https://linux.die.net/man/1/genreflex + + +Automatic class loader +---------------------- + +Explicitly loading dictionaries is fine if this is hidden under the hood of +a Python package and thus simply done on import. +Otherwise, the automatic class loader is more convenient, as it allows direct +use without having to manually find and load dictionaries. + +The class loader utilizes so-called rootmap files, which by convention should +live alongside the dictionaries in places reachable by LD_LIBRARY_PATH. +These are simple text files, which map C++ entities (such as classes) to the +dictionaries and other libraries that need to be loaded for their use. + +The ``genreflex`` tool can produce rootmap files automatically. +For example:: + + $ genreflex project_header.h --rootmap=libProjectDict.rootmap --rootmap-lib=libProjectDict.so + $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared `genreflex --cppflags` project_header_rflx.cpp -o libProjectDict.so -L$CPPYYHOME/lib -lCling -L$PROJECTHOME/lib -lproject + +where the first option (``--rootmap``) specifies the output file name, and the +second option (``--rootmap-lib``) the name of the reflection library. +It is necessary to provide that name explicitly, since it is only in the +separate linking step where these names are fixed (if the second option is not +given, the library is assumed to be libproject_header.so). + +With the rootmap file in place, the above example can be rerun without explicit +loading of the reflection info library: + +.. code-block:: python + + >>> import cppyy + >>> from cppyy.gbl import SomeClassFromProject + >>> + + +Selection files +--------------- +.. _selection-files: + +Sometimes it is necessary to restrict or expand what genreflex will pick up +from the header files. +For example, to add or remove standard classes or to hide implementation +details. +This is where `selection files`_ come in. +These are XML specifications that allow exact or pattern matching to classes, +functions, etc. +See ``genreflex --help`` for a detailed specification and add +``--selection=project_selection.xml`` to the ``genreflex`` command line. + +With the aid of a selection file, a large project can be easily managed: +simply ``#include`` all relevant headers into a single header file that is +handed to ``genreflex``. + +.. _`selection files`: https://linux.die.net/man/1/genreflex diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/features.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/features.rst new file mode 100644 index 0000000000000..e18b16ac1dbc4 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/features.rst @@ -0,0 +1,72 @@ +.. _features: + +More Features +============= + +.. toctree:: + :hidden: + + cppyy_features_header + + +The following is not meant to be an exhaustive list, but more of a show case. +Most features will be fairly obvious in their use. + +The C++ code used for the examples below can be found +:doc:`here `, and it is assumed that that code is +loaded at the start of any session. +Download it, save it under the name ``features.h``, and load it: + + .. code-block:: python + + >>> import cppyy + >>> cppyy.include('features.h') + >>> + + +* **memory**: C++ instances created by calling their constructor from python + are owned by python. + You can check/change the ownership with the __python_owns__ flag that every + bound instance carries. + Example: + + .. code-block:: python + + >>> from cppyy.gbl import Concrete + >>> c = Concrete() + >>> c.__python_owns__ # True: object created in Python + True + >>> + +* **namespaces**: Are represented as python classes. + Namespaces are more open-ended than classes, so sometimes initial access may + result in updates as data and functions are looked up and constructed + lazily. + Thus the result of ``dir()`` on a namespace shows the classes available, + even if they may not have been created yet. + It does not show classes that could potentially be loaded by the class + loader. + Once created, namespaces are registered as modules, to allow importing from + them. + Namespace currently do not work with the class loader. + Fixing these bootstrap problems is on the TODO list. + The global namespace is ``cppyy.gbl``. + +* **NULL**: Is represented as ``cppyy.gbl.nullptr``. + In C++11, the keyword ``nullptr`` is used to represent ``NULL``. + For clarity of intent, it is recommended to use this instead of ``None`` + (or the integer ``0``, which can serve in some cases), as ``None`` is better + understood as ``void`` in C++. + +* **static methods**: Are represented as python's ``staticmethod`` objects + and can be called both from the class as well as from instances. + +* **templated functions**: Automatically participate in overloading and are + used in the same way as other global functions. + +* **templated methods**: For now, require an explicit selection of the + template parameters. + This will be changed to allow them to participate in overloads as expected. + +* **unary operators**: Are supported if a python equivalent exists, and if the + operator is defined in the C++ class. diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/functions.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/functions.rst new file mode 100644 index 0000000000000..19c502e39b24a --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/functions.rst @@ -0,0 +1,81 @@ +.. _functions: + +Functions +========= + +C++ functions are first-class objects in Python and can be used wherever +Python functions can be used, including for dynamically constructing +classes. + +The C++ code used for the examples below can be found +:doc:`here `, and it is assumed that that code is +loaded at the start of any session. +Download it, save it under the name ``features.h``, and load it: + + .. code-block:: python + + >>> import cppyy + >>> cppyy.include('features.h') + >>> + + +All bound C++ code starts off from the global C++ namespace, represented in +Python by ``gbl``. +This namespace, as any other namespace, is treated as a module after it has +been loaded. +Thus, we can directly import C++ functions that live underneath it. + + .. code-block:: python + + >>> from cppyy.gbl import global_function, Namespace + >>> global_function == Namespace.global_function + False + >>> + +C++ supports overloading, whereas Python supports "duck typing", so C++ +overloads have to be selected dynamically: + + .. code-block:: python + + >>> global_function(1.) # selects 'double' overload + 2.718281828459045 + >>> global_function(1) # selects 'int' overload + 42 + >>> + +C++ does a static dispatch at compile time based on the argument types. +The dispatch is a selection among overloads (incl. templates) visible at that +point in the translation unit. +Bound C++ in Python does a dynamic dispatch: it considers all overloads +visible _globally_ at that point in the execution. +Because the dispatch is fundamentally different (albeit in line with the +expectation of the respective languages), differences can occur. +Especially if overloads live in different header files and are only an +implicit conversion apart. + +If the overload selection fails in a specific case, the ``__overload__`` +function can be called directly with a signature: + + .. code-block:: python + + >>> global_function.__overload__('double')(1) # int implicitly converted + 2.718281828459045 + >>> + +C++ default arguments work as expected, but python keywords are not yet +supported. +(It is technically possible to support keywords, but for the C++ interface, +the formal argument names have no meaning and are not considered part of the +API, hence it is not a good idea to use keywords.) +Example: + + .. code-block:: python + + >>> from cppyy.gbl import Concrete + >>> c = Concrete() # uses default argument + >>> c.m_int + 42 + >>> c = Concrete(13) # uses provided argument + >>> c.m_int + 13 + >>> diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/index.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/index.rst new file mode 100644 index 0000000000000..847c7dd9d9105 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/index.rst @@ -0,0 +1,141 @@ +.. cppyy documentation master file, created by + sphinx-quickstart on Wed Jul 12 14:35:45 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +cppyy: Automatic Python-C++ bindings +==================================== + +cppyy is an automatic Python-C++ bindings generator designed for large scale +programs in high performance computing that use modern C++. +Design and performance are described in this `PyHPC paper`_. + +cppyy is based on `Cling`_, the C++ interpreter, to match Python's dynamism +and interactivity. +Consider this session, showing dynamic, interactive, mixing of C++ and Python +features (more examples are in the `tutorial`_): + +.. code-block:: python + + >>> import cppyy + >>> cppyy.cppdef(""" + ... class MyClass { + ... public: + ... MyClass(int i) : m_data(i) {} + ... int m_data; + ... };""") + True + >>> from cppyy.gbl import MyClass + >>> m = MyClass(42) + >>> cppyy.cppdef(""" + ... void say_hello(MyClass* m) { + ... std::cout << "Hello, the number is: " << m->m_data << std::endl; + ... }""") + True + >>> MyClass.say_hello = cppyy.gbl.say_hello + >>> m.say_hello() + Hello, the number is: 42 + >>> m.m_data = 13 + >>> m.say_hello() + Hello, the number is: 13 + >>> + +With a modern C++ compiler having its back, cppyy is future-proof. +Consider the following session using ``boost::any``, a capsule-type that +allows for heterogeneous containers in C++. +The `Boost`_ library is well known for its no holds barred use of modern C++ +and heavy use of templates: + +.. code-block:: python + + >>> import cppyy + >>> cppyy.include('boost/any.hpp') + >>> from cppyy.gbl import std, boost + >>> val = boost.any() # the capsule + >>> val.__assign__(std.vector[int]()) # assign it a std::vector + + >>> val.type() == cppyy.typeid(std.vector[int]) # verify type + True + >>> extract = boost.any_cast[int](std.move(val)) # wrong cast + Traceback (most recent call last): + File "", line 1, in + Exception: int boost::any_cast(boost::any&& operand) => + boost::bad_any_cast: failed conversion using boost::any_cast (C++ exception) + >>> extract = boost.any_cast[std.vector[int]](std.move(val)) # correct + >>> type(extract) is std.vector[int] + True + >>> extract += xrange(100) + >>> len(extract) + 100 + >>> val.__assign__(std.move(extract)) # move forced + + >>> len(extract) # now empty + 0 + >>> extract = boost.any_cast[std.vector[int]](std.move(val)) + >>> list(extract) + [0, 1, 2, 3, 4, 5, 6, ..., 97, 98, 99] + >>> + +And yes, there is no reason to use Boost from Python (in fact, this example +calls out for :doc:`pythonizations `), but the example shows +that cppyy seamlessly supports many advanced C++ features. + +cppyy is available for both `CPython`_ (v2 and v3) and `PyPy`_, reaching +C++-like performance with the latter. +It makes judicious use of precompiled headers, dynamic loading, and lazy +instantiation, to support C++ programs consisting of millions of lines of +code and many thousands of classes. +cppyy minimizes dependencies to allow its use in distributed, heterogeneous, +development environments. + +.. _Cling: https://root.cern.ch/cling +.. _tutorial: https://bitbucket.org/wlav/cppyy/src/master/doc/tutorial/CppyyTutorial.ipynb?viewer=nbviewer&fileviewer=notebook-viewer%3Anbviewer +.. _`PyHPC paper`: http://wlav.web.cern.ch/wlav/Cppyy_LavrijsenDutta_PyHPC16.pdf +.. _`Boost`: http://www.boost.org/ +.. _`CPython`: http://python.org +.. _`PyPy`: http://pypy.org + + +.. only: not latex + + Contents: + +.. toctree:: + :caption: Getting Started + :maxdepth: 1 + + installation + +.. toctree:: + :caption: Features + :maxdepth: 1 + + basic_types + classes + functions + type_conversions + python + features + +.. toctree:: + :caption: Redistribution + :maxdepth: 1 + + pythonizations + dictionaries + bindings_generation + +.. toctree:: + :caption: Developers + :maxdepth: 1 + + packages + repositories + + +Comments and bugs +----------------- + +Please report bugs or requests for improvement on the `issue tracker`_. + +.. _`issue tracker`: https://bitbucket.org/wlav/cppyy/issues diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/installation.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/installation.rst new file mode 100644 index 0000000000000..8a3987e398be5 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/installation.rst @@ -0,0 +1,64 @@ +.. _installation: + +Installation +============ + +The ``cppyy`` module and its dependencies are available through `PyPI`_ for +both CPython (2 and 3) and PyPy (5.9.0 and later). +Build-time only dependencies are ``cmake`` (for general build), ``python2.7`` +(for LLVM), and a modern C++ compiler (one that supports at least C++11). +The cleanest/easiest way to install cppyy is using `virtualenv`_. + +Compilation of the backend, which contains a customized version of +Clang/LLVM, can take a long time, so by default the setup script will use all +cores (x2 if hyperthreading is enabled). +To change that behavior, set the MAKE_NPROCS environment variable to the +desired number of processes to use. +To see progress while waiting, use ``--verbose``:: + + $ MAKE_NPROCS=32 pip install --verbose cppyy + +The bdist_wheel of the backend is reused by pip for all versions of CPython +and PyPy, thus the long compilation is needed only once. +Prepared wheels of cppyy-cling (which contains LLVM) for Mac 10.12 and +Linux/Gentoo `are available`_. +To use them, tell ``pip``:: + + $ pip install --extra-index https://cern.ch/wlav/wheels cppyy + +If you use the ``--user`` option to pip, make sure that the PATH envar points +to the bin directory that will contain the installed entry points during the +installation, as the build process needs them. +You may also need to install wheel first. +Example:: + + $ pip install wheel --user + $ PATH=$HOME/.local/bin:$PATH pip install cppyy --user + +PyPy 5.7 and 5.8 have a built-in module ``cppyy``. +You can still install the ``cppyy`` package, but the built-in module takes +precedence. +To use ``cppyy``, first import a compatibility module:: + + $ pypy + [PyPy 5.8.0 with GCC 5.4.0] on linux2 + >>>> import cppyy_compat, cppyy + >>>> + +You will have to set ``LD_LIBRARY_PATH`` appropriately if you get an +``EnvironmentError`` (it will indicate the needed directory). + +Note that your python interpreter (whether CPython or ``pypy-c``) may not have +been linked by the C++ compiler. +This can lead to problems during loading of C++ libraries and program shutdown. +In that case, re-linking is highly recommended. + +Older versions of PyPy (5.6.0 and earlier) have a built-in ``cppyy`` based on +`Reflex`_, which is less feature-rich and no longer supported. +However, both the :doc:`distribution tools ` and user-facing +Python codes are very backwards compatible. + +.. _`PyPI`: https://pypi.python.org/pypi/cppyy/ +.. _`virtualenv`: https://pypi.python.org/pypi/virtualenv +.. _`are available`: https://cern.ch/wlav/wheels/ +.. _`Reflex`: https://root.cern.ch/how/how-use-reflex diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/packages.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/packages.rst new file mode 100644 index 0000000000000..9c8981313cbc4 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/packages.rst @@ -0,0 +1,73 @@ +.. _packages: + +Packages +======== + +Cppyy +----- + +The ``cppyy`` module is a frontend (see :ref:`Package Structure +`), and most of the code is elsewhere. However, it does +contain the docs for all of the modules, which are built using +Sphinx: http://www.sphinx-doc.org/en/stable/ and published to +http://cppyy.readthedocs.io/en/latest/index.html using a webhook. To create +the docs:: + + $ pip install sphinx_rtd_theme + Collecting sphinx_rtd_theme + ... + Successfully installed sphinx-rtd-theme-0.2.4 + $ cd docs + $ make html + +The Python code in this module supports: + +* Interfacing to the correct backend for CPython or PyPy. +* Pythonizations (TBD) + +Cppyy-backend +------------- + +The ``cppyy-backend`` module contains two areas: + +* A patched copy of cling +* Wrapper code + + +Package structure +----------------- +.. _package-structure: + +There are four PyPA packages involved in a full installation, with the +following structure:: + + (A) _cppyy (PyPy) + / \ + (1) cppyy (3) cling-backend -- (4) cppyy-cling + \ / + (2) CPyCppyy (CPython) + +The user-facing package is always ``cppyy`` (1). +It is used to select the other (versioned) required packages, based on the +python interpreter for which it is being installed. + +Below (1) follows a bifurcation based on interpreter. +This is needed for functionality and performance: for CPython, there is the +CPyCppyy package (2). +It is written in C++, makes use of the Python C-API, and installs as a Python +extension module. +For PyPy, there is the builtin module ``_cppyy`` (A). +This is not a PyPA package. +It is written in RPython as it needs access to low-level pointers, JIT hints, +and the ``_cffi_backend`` backend module (itself builtin). + +Shared again across interpreters is the backend, which is split in a small +wrapper (3) and a large package that contains Cling/LLVM (4). +The former is still under development and expected to be updated frequently. +It is small enough to download and build very quickly. +The latter, however, takes a long time to build, but since it is very stable, +splitting it off allows the creation of binary wheels that need updating +only infrequently (expected about twice a year). + +All code is publicly available; see the +:doc:`section on repositories `. diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/python.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/python.rst new file mode 100644 index 0000000000000..9e3d7ab9d97fe --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/python.rst @@ -0,0 +1,74 @@ +.. _python: + +.. role:: toconly + :class: toconly + + +Python +====== + +The C++ code used for the examples below can be found +:doc:`here `, and it is assumed that that code is +loaded at the start of any session. +Download it, save it under the name ``features.h``, and load it: + + .. code-block:: python + + >>> import cppyy + >>> cppyy.include('features.h') + >>> + + +:toconly:`PyObject` +""""""""""""""""""" + +Arguments and return types of ``PyObject*`` can be used, and passed on to +CPython API calls (or through ``cpyext`` in PyPy). + + +:toconly:`Doc Strings` +"""""""""""""""""""""" + +The documentation string of a method or function contains the C++ +arguments and return types of all overloads of that name, as applicable. +Example: + + .. code-block:: python + + >>> from cppyy.gbl import Concrete + >>> print Concrete.array_method.__doc__ + void Concrete::array_method(int* ad, int size) + void Concrete::array_method(double* ad, int size) + >>> + + +:toconly:`Help` +""""""""""""""" + +Bound C++ class is first-class Python and can thus be inspected like any +Python objects can. +For example, we can ask for ``help()``: + + .. code-block:: python + + >>> help(Concrete) + Help on class Concrete in module gbl: + + class Concrete(Abstract) + | Method resolution order: + | Concrete + | Abstract + | CPPInstance + | __builtin__.object + | + | Methods defined here: + | + | __assign__(self, const Concrete&) + | Concrete& Concrete::operator=(const Concrete&) + | + | __init__(self, *args) + | Concrete::Concrete(int n = 42) + | Concrete::Concrete(const Concrete&) + | + etc. .... + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/pythonizations.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/pythonizations.rst new file mode 100644 index 0000000000000..0e0b8dd7c517c --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/pythonizations.rst @@ -0,0 +1,50 @@ +.. _pythonizations: + +Pythonizations +============== + +Automatic bindings generation mostly gets the job done, but unless a C++ +library was designed with expressiveness and interactivity in mind, using it +will feel stilted. +Thus, if you are not the end-user of a set of bindings, it is beneficial to +implement *pythonizations*. +Some of these are already provided by default, e.g. for STL containers. +Consider the following code, iterating over an STL map, using naked bindings +(i.e. "the C++ way"): + +.. code-block:: python + + >>> from cppyy.gbl import std + >>> m = std.map[int, int]() + >>> for i in range(10): + ... m[i] = i*2 + ... + >>> b = m.begin() + >>> while b != m.end(): + ... print(b.__deref__().second, end=' ') + ... b.__preinc__() + ... + 0 2 4 6 8 10 12 14 16 18 + >>> + +Yes, that is perfectly functional, but it is also very clunky. +Contrast this to the (automatic) pythonization: + +.. code-block:: python + + >>> for key, value in m: + ... print(value, end=' ') + ... + 0 2 4 6 8 10 12 14 16 18 + >>> + +Such a pythonization can be written completely in python using the bound C++ +methods, with no intermediate language necessary. +Since it is written on abstract features, there is also only one such +pythonization that works for all STL map instantiations. + + +Installing callbacks +-------------------- + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/repositories.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/repositories.rst new file mode 100644 index 0000000000000..fe03909f7202e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/repositories.rst @@ -0,0 +1,16 @@ +.. _repositories: + +Repositories +============ + +The ``cppyy`` module is a frontend that requires an intermediate (Python +interpreter dependent) layer, and a backend (see +:ref:`Package Structure `). +Because of this layering and because it leverages several existing packages +through reuse, the relevant codes are contained across a number of +repositories. + +* Frontend, cppyy: https://bitbucket.org/wlav/cppyy +* CPython (v2/v3) intermediate: https://bitbucket.org/wlav/cpycppyy +* PyPy intermediate (module _cppyy): https://bitbucket.org/pypy/pypy/ +* Backend, cppyy: https://bitbucket.org/wlav/cppyy-backend diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/source/type_conversions.rst b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/type_conversions.rst new file mode 100644 index 0000000000000..774c7480752fe --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/source/type_conversions.rst @@ -0,0 +1,90 @@ +.. _type_conversions: + +.. role:: toconly + :class: toconly + + +Type Conversions +================ + +Most type conversions are done implicitly, e.g. between Python ``str`` and +C++ ``std::string`` and ``const char*``, but low-level APIs exist to perform +explicit conversions. + +The C++ code used for the examples below can be found +:doc:`here `, and it is assumed that that code is +loaded at the start of any session. +Download it, save it under the name ``features.h``, and load it: + + .. code-block:: python + + >>> import cppyy + >>> cppyy.include('features.h') + >>> + + +:toconly:`Casting` +"""""""""""""""""" + +Object pointer returns from functions provide the most derived class known +(i.e. exposed in header files) in the hierarchy of the object being returned. +This is important to preserve object identity as well as to make casting, +a pure C++ feature after all, superfluous. +Example: + + .. code-block:: python + + >>> from cppyy.gbl import Abstract, Concrete + >>> c = Concrete() + >>> Concrete.show_autocast.__doc__ + 'Abstract* Concrete::show_autocast()' + >>> d = c.show_autocast() + >>> type(d) + + >>> + +As a consequence, if your C++ classes should only be used through their +interfaces, then no bindings should be provided to the concrete classes +(e.g. by excluding them using a :ref:`selection file `). +Otherwise, more functionality will be available in Python than in C++. + +Sometimes, however, full control over a cast is needed. +For example, if the instance is bound by another tool or even a 3rd party, +hand-written, extension library. +Assuming the object supports the ``PyCapsule`` or ``CObject`` abstraction, +then a C++-style reinterpret_cast (i.e. without implicitly taking offsets +into account), can be done by taking and rebinding the address of an +object: + + .. code-block:: python + + >>> from cppyy import addressof, bind_object + >>> e = bind_object(addressof(d), Abstract) + >>> type(e) + + >>> + + +:toconly:`Operators` +"""""""""""""""""""" + +If conversion operators are defined in the C++ class and a Python equivalent +exists (i.e. all builtin integer and floating point types, as well as +``bool``), then these will map onto those Python conversions. +Note that ``char*`` is mapped onto ``__str__``. +Example: + + .. code-block:: python + + >>> from cppyy.gbl import Concrete + >>> print(Concrete()) + Hello operator const char*! + >>> + +C++ code can overload conversion operators by providing methods in a class or +global functions. +Special care needs to be taken for the latter: first, make sure that they are +actually available in some header file. +Second, make sure that headers are loaded in the desired order. +I.e. that these global overloads are available before use. + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/tutorial/CppyyTutorial.ipynb b/bindings/pyroot_experimental/cppyy/cppyy/doc/tutorial/CppyyTutorial.ipynb new file mode 100644 index 0000000000000..b5387dee9b140 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/tutorial/CppyyTutorial.ipynb @@ -0,0 +1,496 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import print_function" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cppyy Tutorial\n", + "\n", + "_(Modified from Enrico Guiraud's cppyy tutorial.)_\n", + "\n", + "This tutorial introduces the basic concepts for using cppyy, the automatic Python-C++ generator. To install cppyy on your system, simply run (this may take a while as it will pull in and compile a custom version of LLVM):\n", + "\n", + "```\n", + "$ pip install cppyy\n", + "```\n", + "\n", + "For further details on the installation, as well as the location of binary wheels, see:\n", + " http://cppyy.readthedocs.io/en/latest/installation.html\n", + "\n", + "To start, import module cppyy. All functionality, including using bound classes, always starts at this top-level." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import cppyy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are three layers to cppyy: at the top there are the module 'gbl' (the _global_ namespace), a range of helper functions, and a set of sub-modules (such as `py`) that serve specific purposes. Let's start with defining a little helper class in C++ using the helper function `cppdef`, to make the example more interesting:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "cppyy.cppdef(\"\"\"\n", + "class Integer1 {\n", + "public:\n", + " Integer1(int i) : m_data(i) {}\n", + " int m_data;\n", + "};\"\"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now have a class 'Integer1'. Note that this class exists on the C++ side and has to follow C++ rules. For example, whereas in Python we can simply redefine a class, we can't do that in C++. Therefore, we will number the `Integer` classes as we go along, to be able to extend the example as we see fit.\n", + "\n", + "Python classes are constructed dynamically. It doesn't matter where or how they are defined, whether in a Python script, \"compiled\" into a C extension module, or otherwise. Cppyy takes advantage of this fact to generate bindings on-the-fly. This leads to performance advantages for large libraries with thousands of C++ classes; general distribution advantages since, other than the module cppyy itself, no code depends on any specific version of Python; and it enablers, through the Cling backend, interactive access to C++.\n", + "\n", + "To access our first class, find it in gbl, the global namespace:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "print(cppyy.gbl.Integer1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Namespaces have simularities to modules, so we could have imported the class as well.\n", + "\n", + "Bound C++ classes are first-class Python object. We can instantiate them, use normal Python introspection tools, call `help()`, they raise Python exceptions on failure, manage memory through Python's ref-counting and garbage collection, etc., etc. Furthermore, we can use them in conjunction with other C++ classes." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Variable has an 'm_data' data member? Yes!\n", + "Variable is an instance of int? No!\n", + "Variable is an instance of Integer1? Yes!\n" + ] + } + ], + "source": [ + "# for convenience, bring Integer1 into __main__\n", + "from cppyy.gbl import Integer1\n", + "\n", + "# create a C++ Integer1 object\n", + "i = Integer1(42)\n", + "\n", + "# use Python inspection\n", + "print(\"Variable has an 'm_data' data member?\", hasattr(i, 'm_data') and 'Yes!' or 'No!')\n", + "print(\"Variable is an instance of int?\", isinstance(i, int) and 'Yes!' or 'No!')\n", + "print(\"Variable is an instance of Integer1?\", isinstance(i, Integer1) and 'Yes!' or 'No!')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " object at 0x336ddb0>\n" + ] + } + ], + "source": [ + "# pull in the STL vector class\n", + "from cppyy.gbl.std import vector\n", + "\n", + "# create a vector of Integer1 objects; note how [] instantiates the template and () instantiates the class\n", + "v = vector[Integer1]()\n", + "\n", + "# populate it\n", + "v += [Integer1(j) for j in range(10)]\n", + "\n", + "# display our vector\n", + "print(v)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Hum, that doesn't look very pretty. However, since Integer1 is now a Python class we can decorate it, with a custom `__repr__` function (we'll punt on the `vector` and instead convert it to a Python `list` for printing)." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" + ] + } + ], + "source": [ + "# add a custom conversion for printing\n", + "Integer1.__repr__ = lambda self: repr(self.m_data)\n", + "\n", + "# now try again (note the conversion of the vector to a Python list)\n", + "print(list(v))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pythonizations\n", + "\n", + "As we have seen so far, automatic bindings are simple and easy to use. However, even though they are first-class Python objects, they do have some rough C++ edges left. There is some _pythonization_ going on in the background: the vector, for example, played nice with `+=` and the list conversion. But for presenting your own classes to end-users, specific pythonizations are desirable. To have this work correctly with lazy binding, a callback-based API exists.\n", + "\n", + "Now, it's too late for Integer1, so let's create Integer2, which lives in a namespace and in addition has a conversion feature." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# create an Integer2 class, living in namespace Math\n", + "cppyy.cppdef(\"\"\"\n", + "namespace Math {\n", + " class Integer2 : public Integer1 {\n", + " public:\n", + " using Integer1::Integer1;\n", + " operator int() { return m_data; }\n", + " };\n", + "}\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# prepare a pythonizor\n", + "def pythonizor(klass, name):\n", + " # A pythonizor receives the freshly prepared bound C++ class, and a name stripped down to\n", + " # the namespace the pythonizor is applied. Also accessible are klass.__name__ (for the\n", + " # Python name) and klass.__cppname__ (for the C++ name)\n", + " if name == 'Integer2':\n", + " klass.__repr__ = lambda self: repr(self.m_data)\n", + "\n", + "# install the pythonizor as a callback on namespace 'Math' (default is the global namespace)\n", + "cppyy.py.add_pythonization(pythonizor, 'Math')" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", + "Converted Integer2 variable: 13\n" + ] + } + ], + "source": [ + "# when we next get the Integer2 class, it will have been decorated\n", + "Integer2 = cppyy.gbl.Math.Integer2 # first time a new namespace is used, it can not be imported from\n", + "v2 = vector[Integer2]()\n", + "v2 += [Integer2(j) for j in range(10)]\n", + "\n", + "# now test the effect of the pythonizor:\n", + "print(list(v2))\n", + "\n", + "# in addition, Integer2 has a conversion function, which is automatically recognized and pythonized\n", + "i2 = Integer2(13)\n", + "print(\"Converted Integer2 variable:\", int(i2))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "# continue the decoration on the C++ side, by adding an operator+ overload\n", + "cppyy.cppdef(\"\"\"\n", + "namespace Math {\n", + " Integer2 operator+(const Integer2& left, const Integer1& right) {\n", + " return left.m_data + right.m_data;\n", + " }\n", + "}\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "55 55\n" + ] + } + ], + "source": [ + "# now use that fresh decoration (it will be located and bound on use):\n", + "k = i2 + i\n", + "print(k, i2.m_data + i.m_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Class Hierarchies\n", + "\n", + "Both Python and C++ support multiple programming paradigms, making it relatively straightforward to map language features (e.g. class inheritance, free functions, etc.); many other features can be cleanly hidden, merely because the syntax is very similar or otherwise natural (e.g. overloading, abstract classes, static data members, etc.); and yet others map gracefully because their semantic intent is expressed clearly in the syntax (e.g. smart pointers, STL, etc.).\n", + "\n", + "The following presents a range of C++ features that map naturally, and exercises them in Python." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "# create some animals to play with\n", + "cppyy.cppdef(\"\"\"\n", + "namespace Zoo {\n", + "\n", + " enum EAnimal { eLion, eMouse };\n", + " \n", + " class Animal {\n", + " public:\n", + " virtual ~Animal() {}\n", + " virtual std::string make_sound() = 0;\n", + " };\n", + " \n", + " class Lion : public Animal {\n", + " public:\n", + " virtual std::string make_sound() { return s_lion_sound; }\n", + " static std::string s_lion_sound;\n", + " };\n", + " std::string Lion::s_lion_sound = \"growl!\";\n", + "\n", + " class Mouse : public Animal {\n", + " public:\n", + " virtual std::string make_sound() { return \"peep!\"; }\n", + " };\n", + "\n", + " Animal* release_animal(EAnimal animal) {\n", + " if (animal == eLion) return new Lion{};\n", + " if (animal == eMouse) return new Mouse{};\n", + " return nullptr;\n", + " }\n", + "\n", + " std::string identify_animal(Lion*) {\n", + " return \"the animal is a lion\";\n", + " }\n", + "\n", + " std::string identify_animal(Mouse*) {\n", + " return \"the animal is a mouse\";\n", + " }\n", + "\n", + "}\n", + "\"\"\")\n", + "\n", + "# pull in the Zoo (after which we can import from it)\n", + "Zoo = cppyy.gbl.Zoo\n", + "\n", + "# pythonize the animal release function to take ownership on return\n", + "Zoo.release_animal._creates = True" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Failed: none of the 2 overloaded methods succeeded. Full details:\n", + " cannot instantiate abstract class 'Zoo::Animal'\n", + " cannot instantiate abstract class 'Zoo::Animal' \n", + "\n", + "A Lion is an Animal? Yes! \n", + "\n", + "Type of mouse: \n", + "Type of lion: \n", + "\n", + "Does Python own the 'lion'? Yes!\n", + "Does Python own the 'mouse'? Yes! \n", + "\n", + "The mouse says: peep!\n", + "The lion says: growl! \n", + "\n", + "The lion says: mooh! \n", + "\n", + "Identification of 'mouse': the animal is a mouse\n", + "Identification of 'lion': the animal is a lion\n" + ] + } + ], + "source": [ + "# abstract base classes can not be instantiated:\n", + "try:\n", + " animal = Zoo.Animal()\n", + "except TypeError as e:\n", + " print('Failed:', e, '\\n')\n", + "\n", + "# derived classes can be inspected in the same class hierarchy on the Python side\n", + "print('A Lion is an Animal?', issubclass(Zoo.Lion, Zoo.Animal) and 'Yes!' or 'No!', '\\n')\n", + "\n", + "# returned pointer types are auto-casted to the lowest known derived type:\n", + "mouse = Zoo.release_animal(Zoo.eMouse)\n", + "print('Type of mouse:', type(mouse))\n", + "lion = Zoo.release_animal(Zoo.eLion)\n", + "print('Type of lion:', type(lion), '\\n')\n", + "\n", + "# as pythonized, the ownership of the return value from release_animal is Python's\n", + "print(\"Does Python own the 'lion'?\", lion.__python_owns__ and 'Yes!' or 'No!')\n", + "print(\"Does Python own the 'mouse'?\", mouse.__python_owns__ and 'Yes!' or 'No!', '\\n')\n", + "\n", + "# virtual functions work as expected:\n", + "print('The mouse says:', mouse.make_sound())\n", + "print('The lion says:', lion.make_sound(), '\\n')\n", + "\n", + "# now change what the lion says through its static (class) variable\n", + "Zoo.Lion.s_lion_sound = \"mooh!\"\n", + "print('The lion says:', lion.make_sound(), '\\n')\n", + "\n", + "# overloads are combined into a single function on the Python side and resolved dynamically\n", + "print(\"Identification of \\'mouse\\':\", Zoo.identify_animal(mouse))\n", + "print(\"Identification of \\'lion\\':\", Zoo.identify_animal(lion))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Modern C++\n", + "\n", + "As C++ matures, more and more semantic intent (such as object ownership) is expressed in the syntax. This not for the benefit of bindings generators, but for the poor programmer having to read the code. Still, a bindings generator benefits greatly from this increased expression." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "cppyy.cppdef(\"\"\"\n", + "namespace Zoo {\n", + " std::shared_ptr free_lion{new Lion{}};\n", + "\n", + " std::string identify_animal_smart(std::shared_ptr& smart) {\n", + " return \"the animal is a lion\";\n", + " }\n", + "}\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Type of the 'free_lion' global: Lion\n", + "Type of the 'free_lion' smart ptr: shared_ptr\n", + "Dumb passing: the animal is a lion\n", + "Smart passing: the animal is a lion\n" + ] + } + ], + "source": [ + "# shared pointers are presented transparently as the wrapped type\n", + "print(\"Type of the 'free_lion' global:\", type(Zoo.free_lion).__name__)\n", + "\n", + "# if need be, the smart pointer is accessible with a helper\n", + "smart_lion = Zoo.free_lion.__smartptr__()\n", + "print(\"Type of the 'free_lion' smart ptr:\", type(smart_lion).__name__)\n", + "\n", + "# pass through functions that expect a naked pointer or smart pointer\n", + "print(\"Dumb passing: \", Zoo.identify_animal(Zoo.free_lion))\n", + "print(\"Smart passing:\", Zoo.identify_animal_smart(Zoo.free_lion))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/bindings/pyroot_experimental/cppyy/cppyy/doc/tutorial/GSLPythonizationTutorial.ipynb b/bindings/pyroot_experimental/cppyy/cppyy/doc/tutorial/GSLPythonizationTutorial.ipynb new file mode 100644 index 0000000000000..58cf576cb186e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/doc/tutorial/GSLPythonizationTutorial.ipynb @@ -0,0 +1,202 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import print_function" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## GSL Pythonization Tutorial\n", + "\n", + "_(Hat tip to Neil Dhir for the idea.)_\n", + "\n", + "This tutorial introduces pythonizations and how they can be used to solve low-level problems.\n", + "\n", + "The setup: imagine you want to use numpy, but are given a C or C++ library that is based on the GNU Scientific Library (GSL). How do make the two of them play nice together?\n", + "\n", + "GSL is written in C, but is very structured: it has consistent naming conventions, provides allocators/deallocators for its main structs, and has clear ownership rules. Because of this structure, it is possible to write pythonizations based on reflection information that end up being very simple and therefore easy to maintain." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import cppyy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For simplicity, we will use `gsl_blas_dgemm` as a stand-in for the \"C/C++ library based on GSL.\" To make our life easier, we will wrap up the bindings to GSL and GSLBLAS into a single reflection dictionary. This is overkill for simple projects, but if we want access to all of GSL (as opposed to GSL and GSLBLAS separately, say), this approach is fine." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# first, pull in all headers from the GSL installation directory (/usr/include on my system).\n", + "import glob, os\n", + "GSL_HOME = '/usr/include'\n", + "gsl_headers = [os.path.relpath(x, GSL_HOME) for x in glob.glob(GSL_HOME+'/gsl/*.h')]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we write a selection file that picks up all interesting bits from GSL. This file can be kept simple because of the proper naming conventions (it could have been simpler still if GSL were a C++ library, living in a single namespace). We then run the genreflex command to generate the dictionary file and compile it, linking in GSL and GSLBLAS. Finally, we're ready to load the dictionary reflection file into cppyy." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting gsl_selection.xml\n" + ] + } + ], + "source": [ + "%%file gsl_selection.xml\n", + "\n", + " \n", + " \n", + " \n", + " \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "genreflex done\n" + ] + } + ], + "source": [ + "# conventional name for generated output\n", + "rfldct = 'GSLDict'\n", + "\n", + "if not os.path.exists('%s_rflx.cpp' % rfldct):\n", + " import subprocess, sys\n", + "\n", + " # generate the reflection dictionary\n", + " try:\n", + " subprocess.check_output(\n", + " ['genreflex', # utility installed by pip when installing cppyy\n", + " '-s', 'gsl_selection.xml', # selection file (see above)\n", + " '-o', '%s_rflx.cpp'%rfldct, # intermediate output file\n", + " '-I'+GSL_HOME]+ # include search path for GSL headers\n", + " gsl_headers) # headers themselves\n", + " except subprocess.CalledProcessError as e:\n", + " print(\"genreflex failed (%d):\" % e.returncode, e.output)\n", + " else:\n", + " print(\"genreflex done\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cling-config done\n", + "compilation done\n" + ] + } + ], + "source": [ + "if not os.path.exists('%s.so' % rfldct):\n", + " # get command line arguments for compiler from cling\n", + " try:\n", + " clingflags = subprocess.check_output(\n", + " ['cling-config', # utility installed by pip when installing cppyy\n", + " '--cppflags'])\n", + " except subprocess.CalledProcessError as e:\n", + " print('cling-config failed (%d):' % e.returncode, e.output)\n", + " raise\n", + " else:\n", + " print('cling-config done')\n", + "\n", + " # compile generated file\n", + " try:\n", + " subprocess.check_output(\n", + " ['g++', # C++ compiler\n", + " '-fPIC', # require position independent code\n", + " '-shared', # generate shared library\n", + " '-o', '%s.so'%rfldct, # output file\n", + " '-I'+GSL_HOME, # include search path for GSL headers\n", + " '%s_rflx.cpp'%rfldct]+ # intermediate file to compile\n", + " clingflags.split()+ # extra flags provided by cling\n", + " ['-lgsl', '-lgslcblas']) # link in GSL and GSLBLAS\n", + " except subprocess.CalledProcessError as e:\n", + " print('compilation failed (%d):' % e.returncode, e.output)\n", + " else:\n", + " print('compilation done')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# load the generated dictionary\n", + "cppyy.load_reflection_info(rfldct)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/bindings/pyroot_experimental/cppyy/cppyy/etc/valgrind-cppyy-cling.supp b/bindings/pyroot_experimental/cppyy/cppyy/etc/valgrind-cppyy-cling.supp new file mode 100644 index 0000000000000..610e8f9a726f6 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/etc/valgrind-cppyy-cling.supp @@ -0,0 +1,575 @@ +# +# Cling/LLVM code generation: since cppyy is a python module, there is no +# proper control over offload ands since functions may be used during atexit() +# calls, we'll just leak all JITed code rather than risk spurious crashes in +# hard-to-reproduce cases. +# +{ + lazily JITed callfuncs + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + fun:_ZN4llvm4UsernwEm + fun:_ZN5clang7CodeGen13CodeGenModule23GetOrCreateLLVMFunctionEN4llvm9StringRefEPNS2_4TypeENS_10GlobalDeclEbbbNS2_13AttributeListENS0_15ForDefinition_tE +} + +{ + lazily JITed template instantiations + match-leak-kinds: possible + fun:_Znwm + ... + fun:__ZN5clang24TemplateDeclInstantiator18VisitCXXMethodDeclEPNS_13CXXMethodDeclEPNS_21TemplateParameterListEb +} + +{ + lazily JITed template instantiations + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang4Sema38InstantiateClassTemplateSpecializationENS_14SourceLocationEPNS_31ClassTemplateSpecializationDeclENS_26TemplateSpecializationKindEb +} + +{ + lazily JITed global operators + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + fun:_ZN4llvm4UsernwEmj + fun:_ZN4llvm14BinaryOperator6CreateENS_11Instruction9BinaryOpsEPNS_5ValueES4_RKNS_5TwineEPS1_ +} + +{ + lazily JITed casts + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + fun:_ZN4llvm4UsernwEmj + fun:_ZN4llvm8CastInst6CreateENS_11Instruction7CastOpsEPNS_5ValueEPNS_4TypeERKNS_5TwineEPS1_ +} + +{ + lazily JITed casts + Memcheck:Leak + match-leak-kinds: definite + fun:_Znam + ... + fun:_ZN20TClingDataMemberInfo6OffsetEv +} + +{ + cling initialization + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5cling11InterpreterC1EiPKPKcS2_bb +} + +{ + clang module symbol table + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + fun:allocate + ... + fun:_ZN5clang7CodeGen13CodeGenModule7ReleaseEv + fun:_ZN5cling17IncrementalParser18codeGenTransactionEPNS_11TransactionE + fun:_ZN5cling17IncrementalParser17commitTransactionEN4llvm14PointerIntPairIPNS_11TransactionELj2ENS0_12EParseResultENS1_21PointerLikeTypeTraitsIS4_EEEE +} + +{ + CodeGen + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZL21EmitMemberInitializerRN5clang7CodeGen15CodeGenFunctionEPKNS_13CXXRecordDeclEPNS_18CXXCtorInitializerEPKNS_18CXXConstructorDeclERNS0_15FunctionArgListE +} + +{ + CodeGen cleanup + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZL11EmitCleanupRN5clang7CodeGen15CodeGenFunctionEPNS0_12EHScopeStack7CleanupENS4_5FlagsEPN4llvm5ValueE +} + +{ + CodeGen globals + Memcheck:Leak + match-leak-kinds: possible + fun:_Zn* + ... + fun:_ZN5clang7CodeGen13CodeGenModule20EmitGlobalDefinitionENS_10GlobalDeclEPN4llvm11GlobalValueE +} + +{ + CodeGen cleanup + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + fun:_ZN4llvm4UsernwEmj + ... + fun:_ZN5clang7CodeGen15CodeGenFunction15PopCleanupBlockEb +} + +{ + cling Module use + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN4llvm6ModuleC1ENS_9StringRefERNS_11LLVMContextE +} + +{ + cling Module use + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang17CodeGeneratorImpl11StartModuleERKSsRN4llvm11LLVMContextERKNS_14CodeGenOptionsE +} + +{ + cling macro + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang19PreprocessorOptions11addMacroDefEN4llvm9StringRefE +} + +{ + llvm target + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN4llvm21RegisterTargetMachineINS_16X86TargetMachineEE9AllocatorERKNS_6TargetENS_9StringRefES6_S6_RKNS_13TargetOptionsENS_5Reloc5ModelENS_9CodeModel5ModelENS_10CodeGenOpt5LevelE +} + +{ + CodeGent SetFunctionAttributes + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang7CodeGen13CodeGenModule21SetFunctionAttributesENS_10GlobalDeclEPN4llvm8FunctionEbb +} + +{ + clang using statement + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZNK5clang11DeclContext16using_directivesEv +} + +{ + clang 'make decl visible' + Memcheck:Leak + match-leak-kinds: possible + ... + fun:_ZN5clang11DeclContext28makeDeclVisibleInContextImplEPNS_9NamedDeclEb +} + +{ + clang visibility + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZL24getExplicitVisibilityAuxPKN5clang9NamedDeclENS0_22ExplicitVisibilityKindEb +} + +{ + clang result of lookup declaration name + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang11DeclContext6lookupENS_15DeclarationNameE +} + +{ + clang result of lookup declaration name + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + ... + fun:_ZN5clang11DeclContext6lookupENS_15DeclarationNameE +} + +{ + clang ASTReader + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + ... + fun:_ZN5clang9ASTReader* +} + +{ + clang ASTReader + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang9ASTReader* +} + +{ + clang ASTReader + Memcheck:Leak + match-leak-kinds: possible + fun:realloc + ... + fun:_ZN5clang9ASTReader* +} + +{ + Sema ActOnEndOfTranslation + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang4Sema25ActOnEndOfTranslationUnitEv +} + +{ + Function CodeGen + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang7CodeGen15CodeGenFunction12GenerateCodeENS_10GlobalDeclEPN4llvm8FunctionERKNS0_14CGFunctionInfoE +} + +{ + clang CodeGenFunction Emit* + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang7CodeGen15CodeGenFunction*Emit* +} + +{ + clang CodeGenFunction global state + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + fun:_ZN4llvm4UsernwEmj + ... + fun:_ZL21emitPointerArithmeticRN5clang7CodeGen15CodeGenFunctionERKN12_GLOBAL__N_19BinOpInfoEb +} + +{ + clang CodeGenModule Emit* + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang7CodeGen13CodeGenModule*Emit* +} + +{ + clang CodeGenModule Emit* + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang7CodeGen13CodeGenModule*emit* +} + +{ + CodeGen VTables + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + fun:_ZN4llvm4UsernwEmj + ... + fun:_ZN5clang7CodeGen14CodeGenVTables17* +} + +{ + clang AddIncludePath + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang19HeaderSearchOptions7AddPathEN4llvm9StringRefENS_8frontend15IncludeDirGroupEbb +} + +{ + clang FileManager + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang12HeaderSearch10LookupFileEN4llvm9StringRefENS_14SourceLocationEbPKNS_15DirectoryLookupERS6_NS1_8ArrayRefISt4pairIPKNS_9FileEntryEPKNS_14DirectoryEntryEEEEPNS1_15SmallVectorImplIcEESK_PNS_9ModuleMap11KnownHeaderEbbb +} + +{ + clang getFile + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang11FileManager7getFileEN4llvm9StringRefEbb +} + +{ + clang ScalarExprEmitter + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN12_GLOBAL__N_117ScalarExprEmitter20EmitScalarConversionEPN4llvm5ValueEN5clang8QualTypeES5_ +} + +{ + llvm pass manager + Memcheck:Leak + match-leak-kinds: possible + ... + fun:_ZN4llvm13FPPassManager13runOnFunctionERNS_8FunctionE +} + + +{ + llvm PassManager initialization + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN4llvm13FPPassManager16doInitializationERNS_6ModuleE +} + +{ + llvm SubTarget initialization + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN4llvm15MCSubtargetInfo19InitMCSubtargetInfoENS_9StringRefES1_S1_NS_8ArrayRefINS_18SubtargetFeatureKVEEES4_PKNS_15SubtargetInfoKVEPKNS_19MCWriteProcResEntryEPKNS_19MCWriteLatencyEntryEPKNS_18MCReadAdvanceEntryEPKNS_10InstrStageEPKjSL_ +} + +{ + cling dynamic library manager + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5cling21DynamicLibraryManager11loadLibraryERKSsb +} + +{ + llvm compile layer + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN4llvm18ObjectMemoryBufferC1EONS_15SmallVectorImplIcEE + fun:_ZNK4llvm14SimpleCompilerclERNS_6ModuleE + fun:_ZNSt17_Function_handlerIFN4llvm6object12OwningBinaryINS1_10ObjectFileEEERNS0_6ModuleEENS0_14SimpleCompilerEE9_M_invokeERKSt9_Any_dataS6_ + fun:_ZNKSt8functionIFN4llvm6object12OwningBinaryINS1_10ObjectFileEEERNS0_6ModuleEEEclES6_ + fun:_ZN4llvm14IRCompileLayerINS_18ObjectLinkingLayerIN5cling14IncrementalJIT19NotifyObjectLoadedTEEEE12addModuleSetISt6vectorIPNS_6ModuleESaISA_EEEESt14_List_iteratorINS_22ObjectLinkingLayerBase15LinkedObjectSetEET_St10unique_ptrINS_19RTDyldMemoryManagerESt14default_deleteISJ_EE +} + +{ + InputValidator string + Memcheck:Leak + match-leak-kinds: possible + ... + fun:_ZNSs15_M_replace_safeEmmPKcm + fun:_ZN5cling14InputValidator5resetEv +} + +{ + cling pointer checker on uninitialized memory (ROOT-8144) + Memcheck:Param + write(buf) + fun:__write_nocancel + ... + fun:cling_runtime_internal_throwIfInvalidPointer +} + + +# +# ROOT/meta wrappers to JITed Cling code, same as above: kept around so as to +# not have to deal with complicated shutdown sequences. +# +{ + typedef string + Memcheck:Leak + match-leak-kinds: definite + fun:_Znam + ... + fun:_ZN10TClassEdit14ResolveTypedefB5cxx11EPKcb +} + +{ + TEnums leak + Memcheck:Leak + fun:_Znwm + fun:_ZN8TStorage11ObjectAllocEm + fun:_ZN7TObjectnwEm + fun:_ZN5TROOT14GetListOfEnumsEv +} + +{ + list of enums + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + fun:_ZN8TStorage11ObjectAllocEm + fun:_ZN7TObjectnwEm + fun:_ZN12TListOfEnumsC1EP6TClass +} + +{ + list of enums + Memcheck:Leak + match-leak-kinds: definite + fun:_Znwm + fun:_ZN8TStorage11ObjectAllocEm + fun:operator new + fun:_ZN6TClass14GetListOfEnumsEb +} + +{ + TObject::TObject() uses uninitialized value when allocated on the stack + Memcheck:Cond + fun:_ZN7TObjectC1Ev +} + +{ + TObject::TObject() uses uninitialized value when allocated on the stack + Memcheck:Cond + fun:TObject +} + +{ + dictgen fwd decls + Memcheck:Leak + match-leak-kinds: possible + fun:_Znwm + ... + fun:_ZN5clang6Parser30ParseCXXClassMemberDeclarationENS_15AccessSpecifierEPNS_13AttributeListERKNS0_18ParsedTemplateInfoEPNS_21ParsingDeclRAIIObjectE +} + +{ + exception translation + Memcheck:Leak + match-leak-kinds: possible + fun:_Znam + ... + fun:_ZL26HandleInterpreterExceptionPN5cling13MetaProcessorEPKcRNS_11Interpreter17CompilationResultEPNS_5ValueE +} + +{ + Ignore deficient in dlopen and/or pthread and/or valgrind. See for example https://bugs.kde.org/show_bug.cgi?id=358980. + Memcheck:Leak + match-leak-kinds: definite + ... + fun:_dl_signal_error +} + + +# +# Python Arena magic checkers +# +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Value4 + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 8 (x86_64 aka amd64) + Memcheck:Value8 + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value + Memcheck:Cond + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 8 + Memcheck:Value8 + fun:PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value + Memcheck:Cond + fun:PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:PyObject_Realloc +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 8 + Memcheck:Value8 + fun:PyObject_Realloc +} + +{ + ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value + Memcheck:Cond + fun:PyObject_Realloc +} + +{ + Handle PyMalloc confusing valgrind (possibly leaked) + Memcheck:Leak + fun:malloc + ... + fun:_PyObject_GC_Resize +} + +{ + Handle PyMalloc confusing valgrind (possibly leaked) + Memcheck:Leak + fun:realloc + ... + fun:_PyObject_GC_Resize +} + +{ + Handle PyMalloc confusing valgrind (possibly leaked) + Memcheck:Leak + fun:malloc + ... + fun:_PyObject_GC_NewVar +} diff --git a/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/__init__.py b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/__init__.py new file mode 100644 index 0000000000000..f16b233e991f9 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/__init__.py @@ -0,0 +1,150 @@ +"""Dynamic C++ bindings generator. + +This module provides dynamic bindings to C++ through Cling, the LLVM-based C++ +interpreter, allowing interactive mixing of Python and C++. Example: + + >>> import cppyy + >>> cppyy.cppdef(\"\"\" + ... class MyClass { + ... public: + ... MyClass(int i) : m_data(i) {} + ... int m_data; + ... };\"\"\") + True + >>> from cppyy.gbl import MyClass + >>> m = MyClass(42) + >>> cppyy.cppdef(\"\"\" + ... void say_hello(MyClass* m) { + ... std::cout << "Hello, the number is: " << m->m_data << std::endl; + ... }\"\"\") + True + >>> MyClass.say_hello = cppyy.gbl.say_hello + >>> m.say_hello() + Hello, the number is: 42 + >>> m.m_data = 13 + >>> m.say_hello() + Hello, the number is: 13 + >>> + +For full documentation, see: + https://cppyy.readthedocs.io/ + +""" + +__author__ = 'Wim Lavrijsen ' + +__all__ = [ + 'cppdef', # declare C++ source to Cling + 'include', # load and jit a header file + 'load_library', # load a shared library + 'sizeof', # size of a C++ type + 'typeid', # typeid of a C++ type + 'add_include_path', # add a path to search for headers + 'add_autoload_map', # explicitly include an autoload map + ] + +import os, sys + +try: + import __pypy__ + del __pypy__ + ispypy = True +except ImportError: + ispypy = False + +# import separately instead of in the above try/except block for easier to +# understand tracebacks +if ispypy: + from ._pypy_cppyy import * +else: + from ._cpython_cppyy import * +del ispypy + + +#- allow importing from gbl -------------------------------------------------- +sys.modules['cppyy.gbl'] = gbl +sys.modules['cppyy.gbl.std'] = gbl.std + + +#- enable auto-loading ------------------------------------------------------- +try: gbl.gInterpreter.EnableAutoLoading() +except: pass + + +#--- pythonization factories ------------------------------------------------- +from . import _pythonization as py +py._set_backend(_backend) + + +#--- CFFI style interface ---------------------------------------------------- +def cppdef(src): + """Declare C++ source to Cling.""" + gbl.gInterpreter.Declare(src) + +def load_library(name): + if name[:3] != 'lib': + if not gbl.gSystem.FindDynamicLibrary(gbl.TString(name), True) and\ + gbl.gSystem.FindDynamicLibrary(gbl.TString('lib'+name), True): + name = 'lib'+name + sc = gbl.gSystem.Load(name) + if sc == -1: + raise RuntimeError("Unable to load library "+name) + +def include(header): + """Load (and JIT) header file
into Cling.""" + gbl.gInterpreter.ProcessLine('#include "%s"' % header) + +def c_include(header): + """Load (and JIT) header file
into Cling.""" + gbl.gInterpreter.ProcessLine("""extern "C" { +#include "%s" +}""" % header) + +def add_include_path(path): + """Add a path to the include paths available to Cling.""" + if not os.path.isdir(path): + raise OSError("no such directory: %s" % path) + gbl.gInterpreter.AddIncludePath(path) + +def add_autoload_map(fname): + """Add the entries from a autoload (.rootmap) file to Cling.""" + if not os.path.isfile(fname): + raise OSError("no such file: %s" % fname) + gbl.gInterpreter.LoadLibraryMap(fname) + +def _get_name(tt): + if type(tt) == str: + return tt + try: + ttname = tt.__cppname__ + except AttributeError: + ttname = tt.__name__ + return ttname + +_sizes = {} +def sizeof(tt): + """Returns the storage size (in chars) of C++ type .""" + if not isinstance(tt, type) and not type(tt) == str: + tt = type(tt) + try: + return _sizes[tt] + except KeyError: + sz = gbl.gInterpreter.ProcessLine("sizeof(%s);" % (_get_name(tt),)) + _sizes[tt] = sz + return sz + +_typeids = {} +def typeid(tt): + """Returns the C++ runtime type information for type .""" + if not isinstance(tt, type): + tt = type(tt) + try: + return _typeids[tt] + except KeyError: + tidname = 'typeid_'+str(len(_typeids)) + gbl.gInterpreter.ProcessLine( + "namespace _cppyy_internal { auto* %s = &typeid(%s); }" %\ + (tidname, _get_name(tt),)) + tid = getattr(gbl._cppyy_internal, tidname) + _typeids[tt] = tid + return tid diff --git a/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_cpython_cppyy.py b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_cpython_cppyy.py new file mode 100644 index 0000000000000..1e3a0eb868714 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_cpython_cppyy.py @@ -0,0 +1,123 @@ +""" CPython-specific touch-ups +""" + +from . import _stdcpp_fix +from cppyy_backend import loader + +__all__ = [ + 'gbl', + 'load_reflection_info', + 'addressof', + 'bind_object', + 'nullptr', + '_backend', + ] + +# first load the dependency libraries of the backend, then pull in the +# libcppyy extension module +c = loader.load_cpp_backend() +import libcppyy as _backend +_backend._cpp_backend = c + + +import sys +if sys.hexversion < 0x3000000: + # TODO: this reliese on CPPOverload cooking up a func_code object, which atm + # is simply not implemented for p3 :/ + + # convince inspect that PyROOT method proxies are possible drop-ins for python + # methods and classes for pydoc + import inspect + + inspect._old_isfunction = inspect.isfunction + def isfunction(object): + if type(object) == _backend.CPPOverload and not object.im_class: + return True + return inspect._old_isfunction( object ) + inspect.isfunction = isfunction + + inspect._old_ismethod = inspect.ismethod + def ismethod(object): + if type(object) == _backend.CPPOverload: + return True + return inspect._old_ismethod(object) + inspect.ismethod = ismethod + del isfunction, ismethod + + +### template support --------------------------------------------------------- +class Template(object): # expected/used by ProxyWrappers.cxx in CPyCppyy + def __init__(self, name): + self.__name__ = name + + def __repr__(self): + return "" % (self.__name__, hex(id(self))) + + def __call__(self, *args): + newargs = [self.__name__] + for arg in args: + if type(arg) == str: + arg = ','.join(map(lambda x: x.strip(), arg.split(','))) + newargs.append(arg) + result = _backend.MakeCppTemplateClass(*newargs) + + # special case pythonization (builtin_map is not available from the C-API) + if 'push_back' in result.__dict__: + def iadd(self, ll): + [self.push_back(x) for x in ll] + return self + result.__iadd__ = iadd + + return result + + def __getitem__(self, *args): + if args and type(args[0]) == tuple: + return self.__call__(*(args[0])) + return self.__call__(*args) + +_backend.Template = Template + + +#- :: and std:: namespaces --------------------------------------------------- +gbl = _backend.CreateScopeProxy('') +gbl.__class__.__repr__ = lambda cls : '' % id(cls) +gbl.std = _backend.CreateScopeProxy('std') +# for move, we want our "pythonized" one, not the C++ template +gbl.std.move = _backend.move + + +#- fake namespace for interactive lazy lookups ------------------------------- +class InteractiveLazy(object): + def __getattr__(self, attr): + if attr == '__all__': + caller = sys.modules[sys._getframe(1).f_globals['__name__']] + _backend._set_cpp_lazy_lookup(caller.__dict__) + return [] + +sys.modules['cppyy.interactive'] = InteractiveLazy() +del InteractiveLazy + + +#- add to the dynamic path as needed ----------------------------------------- +import os +def add_default_paths(): + try: + for line in open('/etc/ld.so.conf'): + f = line.strip() + if (os.path.exists(f)): + gbl.gSystem.AddDynamicPath(f) + except IOError: + pass +add_default_paths() +del add_default_paths + + +#- exports ------------------------------------------------------------------- +addressof = _backend.addressof +bind_object = _backend.bind_object +nullptr = _backend.nullptr + +def load_reflection_info(name): + sc = gbl.gSystem.Load(name) + if sc == -1: + raise RuntimeError("Unable to load reflection library "+name) diff --git a/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_pypy_cppyy.py b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_pypy_cppyy.py new file mode 100644 index 0000000000000..dc47c9e750b65 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_pypy_cppyy.py @@ -0,0 +1,51 @@ +""" PyPy-specific touch-ups +""" + +from . import _stdcpp_fix + +import os, sys +from cppyy_backend import loader + +__all__ = [ + 'gbl', + 'addressof', + 'bind_object', + 'nullptr', + ] + +# first load the dependency libraries of the backend, then +# pull in the built-in low-level cppyy +c = loader.load_cpp_backend() +os.environ['CPPYY_BACKEND_LIBRARY'] = c._name + +# some older versions can be fixed up through a compatibility +# module on the python side; load it, if available +try: + import cppyy_compat +except ImportError: + pass + +import _cppyy as _backend # built-in module +try: + _backend._post_import_startup() +except AttributeError: + pass +_backend._cpp_backend = c + + +#- exports ------------------------------------------------------------------- +import sys +_thismodule = sys.modules[__name__] +for name in __all__: + setattr(_thismodule, name, getattr(_backend, name)) +del name, sys +nullptr = _backend.nullptr + +def load_reflection_info(name): + sc = _backend.gbl.gSystem.Load(name) + if sc == -1: + raise RuntimeError("Unable to load reflection library "+name) + +# add other exports to all +__all__.append('load_reflection_info') +__all__.append('_backend') diff --git a/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_pythonization.py b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_pythonization.py new file mode 100644 index 0000000000000..a580eb47fee9e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_pythonization.py @@ -0,0 +1,341 @@ +""" Pythonization API. +""" + +__all__ = [ + 'make_interface', + ] + +def _set_backend(backend): + global _backend + _backend = backend + + +# user-provided, general pythonizations +def add_pythonization(pythonizor, scope = ''): + """ should be a callable taking two arguments: a class proxy, + and its C++ name. It is called on each time a named class from + (the global one by default, but a relevant C++ namespace is recommended) + is bound. + """ + return _backend.add_pythonization(pythonizor, scope) + +def remove_pythonization(pythonizor, scope = ''): + """Remove previously registered from . + """ + return _backend.remove_pythonization(pythonizor, scope) + + +# prevent auto-casting (e.g. for interfaces) +def pin_type(klass): + return _backend._pin_type(klass) + +# TODO: move this to something like cppyy.lowlevel +def cast(some_object, new_type): + return _backend.Cast(some_object, new_type) + + +# exception pythonizations +def add_exception_mapping(cpp_exception, py_exception): + _backend.UserExceptions[cpp_exception] = py_exception + + + +#--- Pythonization factories -------------------------------------------- + +def set_gil_policy(match_class, match_method, release_gil=True): + return set_method_property(match_class, match_method, '_threaded', int(release_gil)) + + +def set_ownership_policy(match_class, match_method, python_owns_result): + return set_method_property(match_class, match_method, + '_creates', int(python_owns_result)) + +def set_smart_ptr_policy(match_class, match_method, manage_smart_ptr=False): + return set_method_property(match_class, match_method, + '_manage_smart_ptr', bool(manage_smart_ptr)) + + +# NB: Ideally, we'd use the version commented out below, but for now, we +# make do with the hackier version here. +def rename_attribute(match_class, orig_attribute, new_attribute, keep_orig=False): + class attribute_pythonizor(object): + class getter(object): + def __init__(self, attr): + self.attr = attr + def __call__(self, obj): + return getattr(obj, self.attr) + + class setter(object): + def __init__(self, attr): + self.attr = attr + def __call__(self, obj, value): + return setattr(obj, self.attr, value) + + class deleter(object): + def __init__(self, attr): + self.attr = attr + def __call__(self, obj): + return delattr(obj, self.attr) + + def __init__(self, match_class, orig_attribute, new_attribute, keep_orig): + import re + self.match_class = re.compile(match_class) + self.match_attr = re.compile(orig_attribute) + self.new_attr = new_attribute + self.keep_orig = keep_orig + + def __call__(self, obj, name): + if not self.match_class.match(name): + return + for k in dir(obj): #.__dict__: + if self.match_attr.match(k): + tmp = property(self.getter(k), self.setter(k), self.deleter(k)) + setattr(obj, self.new_attr, tmp) + #if not self.keep_orig: delattr(obj, k) + return attribute_pythonizor(match_class, orig_attribute, new_attribute, keep_orig) + +# def rename_attribute(match_class, orig_attribute, new_attribute, keep_orig=False): +# class method_pythonizor: +# def __init__(self, match_class, orig_attribute, new_attribute, keep_orig): +# import re +# self.match_class = re.compile(match_class) +# self.match_attr = re.compile(orig_attribute) +# self.new_attr = new_attribute +# self.keep_orig = keep_orig + +# def __call__(self, obj, name): +# import sys +# if not self.match_class.match(name): +# return +# sys.stderr.write("%s %s %s %s" % ("!!!", obj, name, "\n")) +# for k in dir(obj): #obj.__dict__: +# if not self.match_attr.match(k): continue +# try: +# tmp = getattr(obj, k) +# except Exception as e: +# continue +# setattr(obj, self.new_attr, tmp) +# if not self.keep_orig: delattr(obj, k) +# return method_pythonizor(match_class, orig_attribute, new_attribute, keep_orig) + + +# Shared with PyPy: + +def add_overload(match_class, match_method, overload): + class method_pythonizor(object): + def __init__(self, match_class, match_method, overload): + import re + self.match_class = re.compile(match_class) + self.match_method = re.compile(match_method) + self.overload = overload + + def __call__(self, obj, name): + if not self.match_class.match(name): + return + for k in dir(obj): #.__dict__: + try: + tmp = getattr(obj, k) + except: + continue + if self.match_method.match(k): + try: + tmp.__add_overload__(overload) + except AttributeError: pass + return method_pythonizor(match_class, match_method, overload) + + +def compose_method(match_class, match_method, g): + class composition_pythonizor(object): + def __init__(self, match_class, match_method, g): + import re + self.match_class = re.compile(match_class) + self.match_method = re.compile(match_method) + self.g = g + + def __call__(self, obj, name): + if not self.match_class.match(name): + return + g = self.g + for k in obj.__dict__: + if not self.match_method.match(k): + continue + try: + f = getattr(obj, k) + except: + continue + def make_fun(f, g): + def h(self, *args, **kwargs): + return g(self, f(self, *args, **kwargs)) + return h + h = make_fun(f, g) + setattr(obj, k, h) + return composition_pythonizor(match_class, match_method, g) + + +def set_method_property(match_class, match_method, prop, value): + class method_pythonizor(object): + def __init__(self, match_class, match_method, prop, value): + import re + self.match_class = re.compile(match_class) + self.match_method = re.compile(match_method) + self.prop = prop + self.value = value + + def __call__(self, obj, name): + if not self.match_class.match(name): + return + for k in dir(obj): #.__dict__: + try: + tmp = getattr(obj, k) + except: + continue + if self.match_method.match(k): + setattr(tmp, self.prop, self.value) + return method_pythonizor(match_class, match_method, prop, value) + + +def make_property(match_class, match_get, match_set=None, match_del=None, prop_name=None): + class property_pythonizor(object): + def __init__(self, match_class, match_get, match_set, match_del, prop_name): + import re + self.match_class = re.compile(match_class) + + self.match_get = re.compile(match_get) + match_many_getters = self.match_get.groups == 1 + + if match_set: + self.match_set = re.compile(match_set) + match_many_setters = self.match_set.groups == 1 + if match_many_getters ^ match_many_setters: + raise ValueError('Must match getters and setters equally') + else: + self.match_set = None + + if match_del: + self.match_del = re.compile(match_del) + match_many_deleters = self.match_del.groups == 1 + if match_many_getters ^ match_many_deleters: + raise ValueError('Must match getters and deleters equally') + else: + self.match_del = None + + self.match_many = match_many_getters + if not (self.match_many or prop_name): + raise ValueError("If not matching properties by regex, need a property name with exactly one substitution field") + if self.match_many and prop_name: + if prop_name.format(').!:(') == prop_name: + raise ValueError("If matching properties by regex and providing a property name, the name needs exactly one substitution field") + + self.prop_name = prop_name + + def make_get_del_proxy(self, getter): + class proxy(object): + def __init__(self, getter): + self.getter = getter + + def __call__(self, obj): + return getattr(obj, self.getter)() + return proxy(getter) + + def make_set_proxy(self, setter): + class proxy(object): + def __init__(self, setter): + self.setter = setter + + def __call__(self, obj, arg): + return getattr(obj, self.setter)(arg) + return proxy(setter) + + def __call__(self, obj, name): + if not self.match_class.match(name): + return + + names = [] + named_getters = {} + named_setters = {} + named_deleters = {} + + if not self.match_many: + fget, fset, fdel = None, None, None + + for k in dir(obj): #.__dict__: + match = self.match_get.match(k) + try: + tmp = getattr(obj, k) + except: + continue + if match and hasattr(tmp, '__call__'): + if self.match_many: + name = match.group(1) + named_getters[name] = k + else: + fget = self.make_get_del_proxy(k) + break + + if self.match_set: + for k in dir(obj): #.__dict__: + match = self.match_set.match(k) + try: + tmp = getattr(obj, k) + except: + continue + if match and hasattr(tmp, '__call__'): + if self.match_many: + name = match.group(1) + named_setters[name] = k + else: + fset = self.make_set_proxy(k) + break + + if self.match_del: + for k in dir(obj): #.__dict__: + match = self.match_del.match(k) + try: + tmp = getattr(obj, k) + except: + continue + if match and hasattr(tmp, '__call__'): + if self.match_many: + name = match.group(1) + named_deleters[name] = k + else: + fdel = self.make_get_del_proxy(k) + break + + if not self.match_many: + new_prop = property(fget, fset, fdel) + setattr(obj, self.prop_name, new_prop) + return + + names += list(named_getters.keys()) + names += list(named_setters.keys()) + names += list(named_deleters.keys()) + names = set(names) + + properties = [] + for name in names: + if name in named_getters: + fget = self.make_get_del_proxy(named_getters[name]) + else: + fget = None + + if name in named_setters: + fset = self.make_set_proxy(named_setters[name]) + else: + fset = None + + if name in named_deleters: + fdel = self.make_get_del_proxy(named_deleters[name]) + else: + fdel = None + + new_prop = property(fget, fset, fdel) + if self.prop_name: + prop_name = self.prop_name.format(name) + else: + prop_name = name + + setattr(obj, prop_name, new_prop) + + return property_pythonizor(match_class, match_get, match_set, match_del, prop_name) + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_stdcpp_fix.py b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_stdcpp_fix.py new file mode 100644 index 0000000000000..90c3687b41696 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy/_stdcpp_fix.py @@ -0,0 +1,13 @@ +import sys + +# It may be that the interpreter (wether python or pypy-c) was not linked +# with C++; force its loading before doing anything else (note that not +# linking with C++ spells trouble anyway for any C++ libraries ...) +if 'linux' in sys.platform and 'GCC' in sys.version: + # TODO: check executable to see whether linking indeed didn't happen + import ctypes + try: + stdcpp = ctypes.CDLL('libstdc++.so', ctypes.RTLD_GLOBAL) + except Exception: + pass +# TODO: what if Linux/clang and what if Mac? diff --git a/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy_compat/__init__.py b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy_compat/__init__.py new file mode 100644 index 0000000000000..d9d360553699d --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/python/cppyy_compat/__init__.py @@ -0,0 +1,69 @@ +"""Compatibility layer for PyPy 5.7-9 +""" + +def pypy58_57_compat(): + import imp, os + + # first load and move the builtin cppyy module + if not 'cppyy' in sys.modules: + try: + olddir = os.getcwd() + from cppyy_backend import loader + c = loader.load_cpp_backend() + # move to the location of the backend, just in case '.' is + # in the dynloader's path + os.chdir(os.path.dirname(c._name)) + imp.init_builtin('cppyy') + except ImportError: + raise EnvironmentError('"%s" missing in LD_LIBRARY_PATH' %\ + os.path.dirname(c._name)) + finally: + os.chdir(olddir) + + sys.modules['_cppyy'] = sys.modules['cppyy'] + del sys.modules['cppyy'] + + # now locate and load the pip cppyy module + decdir = os.path.join(os.path.dirname(__file__), os.path.pardir) + for path in sys.path: # walk over sys.path skips builtins + try: + fp, pathname, description = imp.find_module('cppyy', [path]) + sys.modules['cppyy'] = imp.load_module('cppyy_', fp, pathname, description) + break + except ImportError: + pass + + # copy over the _cppyy functions into cppyy + old = sys.modules['_cppyy'] + new = sys.modules['cppyy'] + for name in dir(old): + if not hasattr(new, name): + setattr(new, name, getattr(old, name)) + +# for pypy5.9 we may need to move to the location of the backend, if '.' happens +# to be in LD_LIBRARY_PATH, but not the full directory +def py59_compat(): + import os, cppyy_backend + olddir = os.getcwd() + c = cppyy_backend.loader.load_cpp_backend() + os.chdir(os.path.dirname(c._name)) + try: + global __name__ + actual_name = __name__; __name__ = '' + import _cppyy as _backend + except ImportError: + raise EnvironmentError('"%s" missing in LD_LIBRARY_PATH' % os.path.dirname(c._name)) + finally: + __name__ = actual_name + os.chdir(olddir) + _backend.nullptr = _backend.gbl.nullptr + + +import sys +version = sys.pypy_version_info +if version[0] == 5: + if 6 < version[1] <= 8: + pypy58_57_compat() + elif version[1] == 9: + py59_compat() +del version, sys diff --git a/bindings/pyroot_experimental/cppyy/cppyy/setup.cfg b/bindings/pyroot_experimental/cppyy/cppyy/setup.cfg new file mode 100644 index 0000000000000..8debd01371e4f --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +universal=0 + +[metadata] +license_file = LICENSE.txt diff --git a/bindings/pyroot_experimental/cppyy/cppyy/setup.py b/bindings/pyroot_experimental/cppyy/cppyy/setup.py new file mode 100755 index 0000000000000..e121ba6ae5b6b --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/setup.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +import os, glob +from setuptools import setup, find_packages, Extension +from codecs import open + + +here = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + +add_pkg = ['cppyy'] +try: + import __pypy__, sys + version = sys.pypy_version_info + requirements = ['cppyy-backend'] + if version[0] == 5: + if version[1] <= 9: + requirements = ['cppyy-cling<6.12', 'cppyy-backend<0.3'] + add_pkg += ['cppyy_compat'] + elif version[1] <= 10: + requirements = ['cppyy-cling', 'cppyy-backend<0.4'] +except ImportError: + # CPython + requirements = ['CPyCppyy>=1.0.0'] + +setup( + name='cppyy', + version='1.0.0', + description='Cling-based Python-C++ bindings', + long_description=long_description, + + url='http://cppyy.readthedocs.org', + + # Author details + author='Wim Lavrijsen', + author_email='WLavrijsen@lbl.gov', + + license='LBNL BSD', + + classifiers=[ + 'Development Status :: 5 - Production/Stable', + + 'Intended Audience :: Developers', + + 'Topic :: Software Development', + 'Topic :: Software Development :: Interpreters', + + 'License :: OSI Approved :: BSD License', + + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: Implementation :: PyPy', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: C', + 'Programming Language :: C++', + + 'Natural Language :: English' + ], + + install_requires=requirements, + + keywords='C++ bindings data science', + + package_dir={'': 'python'}, + packages=find_packages('python', include=add_pkg), +) diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/Makefile b/bindings/pyroot_experimental/cppyy/cppyy/test/Makefile new file mode 100644 index 0000000000000..8a56b4f0f6a29 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/Makefile @@ -0,0 +1,35 @@ +dicts = advancedcppDict.so \ + advancedcpp2Dict.so \ + cpp11featuresDict.so \ + datatypesDict.so \ + example01Dict.so \ + fragileDict.so \ + operatorsDict.so \ + overloadsDict.so \ + pythonizablesDict.so \ + std_streamsDict.so \ + stltypesDict.so \ + templatesDict.so +all : $(dicts) + +genreflex_flags := $(shell genreflex --cppflags) +cppflags=$(shell cling-config --cppflags) $(genreflex_flags) -O3 -fPIC + +PLATFORM := $(shell uname -s) +ifeq ($(PLATFORM),Darwin) + cppflags+=-dynamiclib -single_module -arch x86_64 -undefined dynamic_lookup -Wno-delete-non-virtual-dtor +endif + +%Dict.so: %_rflx.cpp %.cxx + $(CXX) $(cppflags) -shared -o $@ $^ + +%_rflx.cpp: %.h %.xml + genreflex $< --selection=$*.xml --rootmap=$*Dict.rootmap --rootmap-lib=$*Dict.so + +.PHONY: test clean + +test: + pytest test_*.py + +clean: + -rm -f $(dicts) $(subst .so,.rootmap,$(dicts)) $(subst Dict.so,_rflx_rdict.pcm,$(dicts)) $(subst Dict.so,_rflx.cpp,$(dicts)) $(wildcard *.pyc) diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/__init__.py b/bindings/pyroot_experimental/cppyy/cppyy/test/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp.cxx new file mode 100644 index 0000000000000..94d237148cb06 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp.cxx @@ -0,0 +1,127 @@ +#include "advancedcpp.h" + +#include + + +// for testing of default arguments +#define IMPLEMENT_DEFAULTER_CLASS(type, tname) \ +tname##_defaulter::tname##_defaulter(type a, type b, type c) { \ + m_a = a; m_b = b; m_c = c; \ +} +IMPLEMENT_DEFAULTER_CLASS(short, short) +IMPLEMENT_DEFAULTER_CLASS(unsigned short, ushort) +IMPLEMENT_DEFAULTER_CLASS(int, int) +IMPLEMENT_DEFAULTER_CLASS(unsigned, uint) +IMPLEMENT_DEFAULTER_CLASS(long, long) +IMPLEMENT_DEFAULTER_CLASS(unsigned long, ulong) +IMPLEMENT_DEFAULTER_CLASS(long long, llong) +IMPLEMENT_DEFAULTER_CLASS(unsigned long long, ullong) +IMPLEMENT_DEFAULTER_CLASS(float, float) +IMPLEMENT_DEFAULTER_CLASS(double, double) + + +// for esoteric inheritance testing +a_class* create_c1() { return new c_class_1; } +a_class* create_c2() { return new c_class_2; } + +int get_a( a_class& a ) { return a.m_a; } +int get_b( b_class& b ) { return b.m_b; } +int get_c( c_class& c ) { return c.m_c; } +int get_d( d_class& d ) { return d.m_d; } + + +// for namespace testing +int a_ns::g_a = 11; +int a_ns::b_class::s_b = 22; +int a_ns::b_class::c_class::s_c = 33; +int a_ns::d_ns::g_d = 44; +int a_ns::d_ns::e_class::s_e = 55; +int a_ns::d_ns::e_class::f_class::s_f = 66; + +int a_ns::get_g_a() { return g_a; } +int a_ns::d_ns::get_g_d() { return g_d; } + + +// for template testing +template class T1; +template class T2 >; +template class T3; +template class T3, T2 > >; +template class a_ns::T4; +template class a_ns::T4 > >; + + +// helpers for checking pass-by-ref +void set_int_through_ref(int& i, int val) { i = val; } +int pass_int_through_const_ref(const int& i) { return i; } +void set_long_through_ref(long& l, long val) { l = val; } +long pass_long_through_const_ref(const long& l) { return l; } +void set_double_through_ref(double& d, double val) { d = val; } +double pass_double_through_const_ref(const double& d) { return d; } + + +// for math conversions testing +bool operator==(const some_comparable& c1, const some_comparable& c2 ) +{ + return &c1 != &c2; // the opposite of a pointer comparison +} + +bool operator!=( const some_comparable& c1, const some_comparable& c2 ) +{ + return &c1 == &c2; // the opposite of a pointer comparison +} + + +// a couple of globals for access testing +double my_global_double = 12.; +double my_global_array[500]; +static double sd = 1234.; +double* my_global_ptr = &sd; +const char my_global_string2[] = "zus jet teun"; + +// for life-line and identity testing +int some_class_with_data::some_data::s_num_data = 0; + + +// for testing multiple inheritance +multi1::~multi1() {} +multi2::~multi2() {} +multi::~multi() {} + + +// for testing calls to overloaded new +int new_overloader::s_instances = 0; + +void* new_overloader::operator new(std::size_t size) { + ++s_instances; + return ::operator new(size); +} + +void* new_overloader::operator new(std::size_t, void* p) throw() { + // no ++s_instances, as no memory is allocated + return p; +} + +void new_overloader::operator delete(void* p, std::size_t) { + if (p == 0) return; + --s_instances; + ::operator delete(p); +} + + +// overload order testing +int overload_one_way::gime() const { return 1; } +std::string overload_one_way::gime() { return "aap"; } + +std::string overload_the_other_way::gime() { return "aap"; } +int overload_the_other_way::gime() const { return 1; } + + +// exception handling testing +void Thrower::throw_anything() { + throw 1; +} + +void Thrower::throw_exception() { + throw std::runtime_error("C++ function failed"); +} diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp.h b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp.h new file mode 100644 index 0000000000000..d37544925ef79 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp.h @@ -0,0 +1,432 @@ +#include +#include +#include + + +//=========================================================================== +#define DECLARE_DEFAULTER_CLASS(type, tname) \ +class tname##_defaulter { \ +public: \ + tname##_defaulter(type a = 11, type b = 22, type c = 33); \ + \ +public: \ + type m_a, m_b, m_c; \ +}; +DECLARE_DEFAULTER_CLASS(short, short) // for testing of default arguments +DECLARE_DEFAULTER_CLASS(unsigned short, ushort) +DECLARE_DEFAULTER_CLASS(int, int) +DECLARE_DEFAULTER_CLASS(unsigned, uint) +DECLARE_DEFAULTER_CLASS(long, long) +DECLARE_DEFAULTER_CLASS(unsigned long, ulong) +DECLARE_DEFAULTER_CLASS(long long, llong) +DECLARE_DEFAULTER_CLASS(unsigned long long, ullong) +DECLARE_DEFAULTER_CLASS(float, float) +DECLARE_DEFAULTER_CLASS(double, double) + + +//=========================================================================== +class base_class { // for simple inheritance testing +public: + base_class() { m_b = 1; m_db = 1.1; } + virtual ~base_class() {} + virtual int get_value() { return m_b; } + double get_base_value() { return m_db; } + + virtual base_class* cycle(base_class* b) { return b; } + virtual base_class* clone() { return new base_class; } + + virtual void* mask(void* p) { return p; } + +public: + int m_b; + double m_db; +}; + +class derived_class : public base_class { +public: + derived_class() { m_d = 2; m_dd = 2.2;} + virtual int get_value() { return m_d; } + double get_derived_value() { return m_dd; } + virtual base_class* clone() { return new derived_class; } + +public: + int m_d; + double m_dd; +}; + + +//=========================================================================== +class a_class { // for esoteric inheritance testing +public: + a_class() { m_a = 1; m_da = 1.1; } + virtual ~a_class() {} + virtual int get_value() = 0; + +public: + int m_a; + double m_da; +}; + +class b_class : public virtual a_class { +public: + b_class() { m_b = 2; m_db = 2.2;} + virtual int get_value() { return m_b; } + +public: + int m_b; + double m_db; +}; + +class c_class_1 : public virtual a_class, public virtual b_class { +public: + c_class_1() { m_c = 3; } + virtual int get_value() { return m_c; } + +public: + int m_c; +}; + +class c_class_2 : public virtual b_class, public virtual a_class { +public: + c_class_2() { m_c = 3; } + virtual int get_value() { return m_c; } + +public: + int m_c; +}; + +typedef c_class_2 c_class; + +class d_class : public virtual c_class, public virtual a_class { +public: + d_class() { m_d = 4; } + virtual int get_value() { return m_d; } + +public: + int m_d; +}; + +a_class* create_c1(); +a_class* create_c2(); + +int get_a(a_class& a); +int get_b(b_class& b); +int get_c(c_class& c); +int get_d(d_class& d); + + +//=========================================================================== +namespace a_ns { // for namespace testing + extern int g_a; + int get_g_a(); + + struct b_class { + b_class() { m_b = -2; } + int m_b; + static int s_b; + + struct c_class { + c_class() { m_c = -3; } + int m_c; + static int s_c; + }; + }; + + namespace d_ns { + extern int g_d; + int get_g_d(); + + struct e_class { + e_class() { m_e = -5; } + int m_e; + static int s_e; + + struct f_class { + f_class() { m_f = -6; } + int m_f; + static int s_f; + }; + }; + + } // namespace d_ns + +} // namespace a_ns + + +//=========================================================================== +template // for template testing +class T1 { +public: + T1(T t = T(1)) : m_t1(t) {} + T get_value() { return m_t1; } + +public: + T m_t1; +}; + +template +class T2 { +public: + T2(T t = T(2)) : m_t2(t) {} + T get_value() { return m_t2; } + +public: + T m_t2; +}; + +template +class T3 { +public: + T3(T t = T(3), U u = U(33)) : m_t3(t), m_u3(u) {} + T get_value_t() { return m_t3; } + U get_value_u() { return m_u3; } + +public: + T m_t3; + U m_u3; +}; + +namespace a_ns { + + template + class T4 { + public: + T4(T t = T(4)) : m_t4(t) {} + T get_value() { return m_t4; } + + public: + T m_t4; + }; + +} // namespace a_ns + +extern template class T1; +extern template class T2 >; +extern template class T3; +extern template class T3, T2 > >; +extern template class a_ns::T4; +extern template class a_ns::T4 > >; + + +//=========================================================================== +// for checking pass-by-reference of builtin types +void set_int_through_ref(int& i, int val); +int pass_int_through_const_ref(const int& i); +void set_long_through_ref(long& l, long val); +long pass_long_through_const_ref(const long& l); +void set_double_through_ref(double& d, double val); +double pass_double_through_const_ref(const double& d); + + +//=========================================================================== +class some_abstract_class { // to test abstract class handling +public: + virtual ~some_abstract_class() {} + virtual void a_virtual_method() = 0; +}; + +class some_concrete_class : public some_abstract_class { +public: + virtual void a_virtual_method() {} +}; + + +//=========================================================================== +class ref_tester { // for assignment by-ref testing +public: + ref_tester() : m_i(-99) {} + ref_tester(int i) : m_i(i) {} + ref_tester(const ref_tester& s) : m_i(s.m_i) {} + ref_tester& operator=(const ref_tester& s) { + if (&s != this) m_i = s.m_i; + return *this; + } + ~ref_tester() {} + +public: + int m_i; +}; + + +//=========================================================================== +class some_convertible { // for math conversions testing +public: + some_convertible() : m_i(-99), m_d(-99.) {} + + operator int() { return m_i; } + operator long() { return m_i; } + operator double() { return m_d; } + +public: + int m_i; + double m_d; +}; + + +class some_comparable { +}; + +bool operator==(const some_comparable& c1, const some_comparable& c2 ); +bool operator!=( const some_comparable& c1, const some_comparable& c2 ); + + +//=========================================================================== +extern double my_global_double; // a couple of globals for access testing +extern double my_global_array[500]; +extern double* my_global_ptr; +static const char my_global_string1[] = "aap " " noot " " mies"; +extern const char my_global_string2[]; + +//=========================================================================== +class some_class_with_data { // for life-line and identity testing +public: + class some_data { + public: + some_data() { ++s_num_data; } + some_data(const some_data&) { ++s_num_data; } + ~some_data() { --s_num_data; } + + static int s_num_data; + }; + + some_class_with_data gime_copy() { + return *this; + } + + const some_data& gime_data() { /* TODO: methptrgetter const support */ + return m_data; + } + + int m_padding; + some_data m_data; +}; + +class refers_to_self { // for data member reuse testing +public: + refers_to_self* m_other = nullptr; +}; + + +//=========================================================================== +class pointer_pass { // for testing passing of void*'s +public: + long gime_address_ptr(void* obj) { + return (long)obj; + } + + long gime_address_ptr_ptr(void** obj) { + return (long)*((long**)obj); + } + + long gime_address_ptr_ref(void*& obj) { + return (long)obj; + } + + static long set_address_ptr_ptr(void** obj) { + (*(long**)obj) = (long*)0x4321; + return 42; + } + + static long set_address_ptr_ref(void*& obj) { + obj = (void*)0x1234; + return 21; + } +}; + + +//=========================================================================== +class multi1 { // for testing multiple inheritance +public: + multi1(int val) : m_int(val) {} + virtual ~multi1(); + int get_multi1_int() { return m_int; } + +private: + int m_int; +}; + +class multi2 { +public: + multi2(int val) : m_int(val) {} + virtual ~multi2(); + int get_multi2_int() { return m_int; } + +private: + int m_int; +}; + +class multi : public multi1, public multi2 { +public: + multi(int val1, int val2, int val3) : + multi1(val1), multi2(val2), m_int(val3) {} + virtual ~multi(); + int get_my_own_int() { return m_int; } + +private: + int m_int; +}; + + +//=========================================================================== +class new_overloader { // for testing calls to overloaded new +public: + static int s_instances; + +public: + void* operator new(std::size_t size); + void* operator new(std::size_t, void* p) throw(); + void operator delete(void* p, std::size_t size); +}; + + +//=========================================================================== +template // more template testing +class my_templated_class { +public: + T m_b; +}; + +template +T my_templated_function(T t) { return t; } + +template class my_templated_class >; +template char my_templated_function(char); +template double my_templated_function(double); + + +//=========================================================================== +class overload_one_way { // overload order testing +public: + int gime() const; + std::string gime(); +}; + +class overload_the_other_way { +public: + std::string gime(); + int gime() const; +}; + + +//=========================================================================== +class Thrower { // exception handling testing +public: + void throw_anything(); + void throw_exception(); +}; + + +//=========================================================================== +class UsingBase { // using declaration testing +public: + UsingBase(int n = 13) : m_int(n) {} + virtual char vcheck() { return 'A'; } + int m_int; +}; + +class UsingDerived : public UsingBase { +public: + using UsingBase::UsingBase; + virtual char vcheck() { return 'B'; } + int m_int2 = 42; +}; diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp.xml new file mode 100644 index 0000000000000..8d8d18cb91567 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp2.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp2.cxx new file mode 100644 index 0000000000000..3eb76b26eba81 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp2.cxx @@ -0,0 +1,13 @@ +#include "advancedcpp2.h" + + +// for namespace testing +int a_ns::g_g = 77; +int a_ns::g_class::s_g = 88; +int a_ns::g_class::h_class::s_h = 99; +int a_ns::d_ns::g_i = 111; +int a_ns::d_ns::i_class::s_i = 222; +int a_ns::d_ns::i_class::j_class::s_j = 333; + +int a_ns::get_g_g() { return g_g; } +int a_ns::d_ns::get_g_i() { return g_i; } diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp2.h b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp2.h new file mode 100644 index 0000000000000..86167cce99aec --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp2.h @@ -0,0 +1,36 @@ +//=========================================================================== +namespace a_ns { // for namespace testing + extern int g_g; + int get_g_g(); + + struct g_class { + g_class() { m_g = -7; } + int m_g; + static int s_g; + + struct h_class { + h_class() { m_h = -8; } + int m_h; + static int s_h; + }; + }; + + namespace d_ns { + extern int g_i; + int get_g_i(); + + struct i_class { + i_class() { m_i = -9; } + int m_i; + static int s_i; + + struct j_class { + j_class() { m_j = -10; } + int m_j; + static int s_j; + }; + }; + + } // namespace d_ns + +} // namespace a_ns diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp2.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp2.xml new file mode 100644 index 0000000000000..43925d1039ef3 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/advancedcpp2.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/conftest.py b/bindings/pyroot_experimental/cppyy/cppyy/test/conftest.py new file mode 100644 index 0000000000000..c2931cdc64be7 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/conftest.py @@ -0,0 +1 @@ +disabled = None diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/cpp11features.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/cpp11features.cxx new file mode 100644 index 0000000000000..6989cf6d3193e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/cpp11features.cxx @@ -0,0 +1,18 @@ +#if __cplusplus >= 201103L + +#include "cpp11features.h" + + +// for std::shared_ptr<> testing +int TestSharedPtr::s_counter = 0; + +std::shared_ptr create_shared_ptr_instance() { + return std::shared_ptr(new TestSharedPtr); +} + + +// for move ctors etc. +int TestMoving1::s_move_counter = 0; +int TestMoving2::s_move_counter = 0; + +#endif // c++11 and later diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/cpp11features.h b/bindings/pyroot_experimental/cppyy/cppyy/test/cpp11features.h new file mode 100644 index 0000000000000..451bdb88f24cc --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/cpp11features.h @@ -0,0 +1,52 @@ +#if __cplusplus >= 201103L + +#include + + +//=========================================================================== +class TestSharedPtr { // for std::shared_ptr<> testing +public: + static int s_counter; + +public: + TestSharedPtr() { ++s_counter; } + TestSharedPtr(const TestSharedPtr&) { ++s_counter; } + ~TestSharedPtr() { --s_counter; } +}; + +std::shared_ptr create_shared_ptr_instance(); + + +//=========================================================================== +class TestMoving1 { // for move ctors etc. +public: + static int s_move_counter; + +public: + TestMoving1() {} + TestMoving1(TestMoving1&&) { ++s_move_counter; } + TestMoving1(const TestMoving1&) {} + TestMoving1& operator=(TestMoving1&&) { ++s_move_counter; return *this; } + TestMoving1& operator=(TestMoving1&) { return *this; } +}; + +class TestMoving2 { // note opposite method order from TestMoving1 +public: + static int s_move_counter; + +public: + TestMoving2() {} + TestMoving2(const TestMoving2&) {} + TestMoving2(TestMoving2&& other) { ++s_move_counter; } + TestMoving2& operator=(TestMoving2&) { return *this; } + TestMoving2& operator=(TestMoving2&&) { ++s_move_counter; return *this; } +}; + + +//=========================================================================== +struct TestData { // for initializer list construction + TestData(int i) : m_int(i) {} + int m_int; +}; + +#endif // c++11 and later diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/cpp11features.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/cpp11features.xml new file mode 100644 index 0000000000000..5e250a30461a7 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/cpp11features.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/datatypes.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/datatypes.cxx new file mode 100644 index 0000000000000..2266727903624 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/datatypes.cxx @@ -0,0 +1,356 @@ +#include "datatypes.h" + + +//=========================================================================== +std::vector vecFruits{kCitrus, kApple}; + + +//=========================================================================== +CppyyTestData::CppyyTestData() : m_const_int(17), m_owns_arrays(false) +{ + m_bool = false; + m_char = 'a'; + m_schar = 'b'; + m_uchar = 'c'; + m_short = -11; + m_ushort = 11u; + m_int = -22; + m_uint = 22u; + m_long = -33l; + m_ulong = 33ul; + m_llong = -44ll; + m_ullong = 44ull; + m_long64 = -55ll; + m_ulong64 = 55ull; + m_float = -66.f; + m_double = -77.; + m_ldouble = -88.l; + m_enum = kNothing; + m_voidp = (void*)0; + + m_bool_array2 = new bool[N]; + m_uchar_array2 = new unsigned char[N]; + m_short_array2 = new short[N]; + m_ushort_array2 = new unsigned short[N]; + m_int_array2 = new int[N]; + m_uint_array2 = new unsigned int[N]; + m_long_array2 = new long[N]; + m_ulong_array2 = new unsigned long[N]; + + m_float_array2 = new float[N]; + m_double_array2 = new double[N]; + + for (int i = 0; i < N; ++i) { + m_bool_array[i] = bool(i%2); + m_bool_array2[i] = bool((i+1)%2); + m_uchar_array[i] = 1u*i; + m_uchar_array2[i] = 2u*i; + m_short_array[i] = -1*i; + m_short_array2[i] = -2*i; + m_ushort_array[i] = 3u*i; + m_ushort_array2[i] = 4u*i; + m_int_array[i] = -5*i; + m_int_array2[i] = -6*i; + m_uint_array[i] = 7u*i; + m_uint_array2[i] = 8u*i; + m_long_array[i] = -9l*i; + m_long_array2[i] = -10l*i; + m_ulong_array[i] = 11ul*i; + m_ulong_array2[i] = 12ul*i; + + m_float_array[i] = -13.f*i; + m_float_array2[i] = -14.f*i; + m_double_array[i] = -15.*i; + m_double_array2[i] = -16.*i; + } + + m_owns_arrays = true; + + m_pod.m_int = 888; + m_pod.m_double = 3.14; + + m_ppod = &m_pod; +}; + +CppyyTestData::~CppyyTestData() +{ + destroy_arrays(); +} + +void CppyyTestData::destroy_arrays() { + if (m_owns_arrays == true) { + delete[] m_bool_array2; + delete[] m_uchar_array2; + delete[] m_short_array2; + delete[] m_ushort_array2; + delete[] m_int_array2; + delete[] m_uint_array2; + delete[] m_long_array2; + delete[] m_ulong_array2; + + delete[] m_float_array2; + delete[] m_double_array2; + + m_owns_arrays = false; + } +} + +//- getters ----------------------------------------------------------------- +bool CppyyTestData::get_bool() { return m_bool; } +char CppyyTestData::get_char() { return m_char; } +signed char CppyyTestData::get_schar() { return m_schar; } +unsigned char CppyyTestData::get_uchar() { return m_uchar; } +short CppyyTestData::get_short() { return m_short; } +unsigned short CppyyTestData::get_ushort() { return m_ushort; } +int CppyyTestData::get_int() { return m_int; } +unsigned int CppyyTestData::get_uint() { return m_uint; } +long CppyyTestData::get_long() { return m_long; } +unsigned long CppyyTestData::get_ulong() { return m_ulong; } +long long CppyyTestData::get_llong() { return m_llong; } +unsigned long long CppyyTestData::get_ullong() { return m_ullong; } +Long64_t CppyyTestData::get_long64() { return m_long64; } +ULong64_t CppyyTestData::get_ulong64() { return m_ulong64; } +float CppyyTestData::get_float() { return m_float; } +double CppyyTestData::get_double() { return m_double; } +long double CppyyTestData::get_ldouble() { return m_ldouble; } +CppyyTestData::EWhat CppyyTestData::get_enum() { return m_enum; } +void* CppyyTestData::get_voidp() { return m_voidp; } + +bool* CppyyTestData::get_bool_array() { return m_bool_array; } +bool* CppyyTestData::get_bool_array2() { return m_bool_array2; } +unsigned char* CppyyTestData::get_uchar_array() { return m_uchar_array; } +unsigned char* CppyyTestData::get_uchar_array2() { return m_uchar_array2; } +short* CppyyTestData::get_short_array() { return m_short_array; } +short* CppyyTestData::get_short_array2() { return m_short_array2; } +unsigned short* CppyyTestData::get_ushort_array() { return m_ushort_array; } +unsigned short* CppyyTestData::get_ushort_array2() { return m_ushort_array2; } +int* CppyyTestData::get_int_array() { return m_int_array; } +int* CppyyTestData::get_int_array2() { return m_int_array2; } +unsigned int* CppyyTestData::get_uint_array() { return m_uint_array; } +unsigned int* CppyyTestData::get_uint_array2() { return m_uint_array2; } +long* CppyyTestData::get_long_array() { return m_long_array; } +long* CppyyTestData::get_long_array2() { return m_long_array2; } +unsigned long* CppyyTestData::get_ulong_array() { return m_ulong_array; } +unsigned long* CppyyTestData::get_ulong_array2() { return m_ulong_array2; } + +float* CppyyTestData::get_float_array() { return m_float_array; } +float* CppyyTestData::get_float_array2() { return m_float_array2; } +double* CppyyTestData::get_double_array() { return m_double_array; } +double* CppyyTestData::get_double_array2() { return m_double_array2; } + +CppyyTestPod CppyyTestData::get_pod_val() { return m_pod; } +CppyyTestPod* CppyyTestData::get_pod_val_ptr() { return &m_pod; } +CppyyTestPod& CppyyTestData::get_pod_val_ref() { return m_pod; } +CppyyTestPod*& CppyyTestData::get_pod_ptrref() { return m_ppod; } + +CppyyTestPod* CppyyTestData::get_pod_ptr() { return m_ppod; } + +//- getters const-ref ------------------------------------------------------- +const bool& CppyyTestData::get_bool_cr() { return m_bool; } +const char& CppyyTestData::get_char_cr() { return m_char; } +const signed char& CppyyTestData::get_schar_cr() { return m_schar; } +const unsigned char& CppyyTestData::get_uchar_cr() { return m_uchar; } +const short& CppyyTestData::get_short_cr() { return m_short; } +const unsigned short& CppyyTestData::get_ushort_cr() { return m_ushort; } +const int& CppyyTestData::get_int_cr() { return m_int; } +const unsigned int& CppyyTestData::get_uint_cr() { return m_uint; } +const long& CppyyTestData::get_long_cr() { return m_long; } +const unsigned long& CppyyTestData::get_ulong_cr() { return m_ulong; } +const long long& CppyyTestData::get_llong_cr() { return m_llong; } +const unsigned long long& CppyyTestData::get_ullong_cr() { return m_ullong; } +const Long64_t& CppyyTestData::get_long64_cr() { return m_long64; } +const ULong64_t& CppyyTestData::get_ulong64_cr() { return m_ulong64; } +const float& CppyyTestData::get_float_cr() { return m_float; } +const double& CppyyTestData::get_double_cr() { return m_double; } +const long double& CppyyTestData::get_ldouble_cr() { return m_ldouble; } +const CppyyTestData::EWhat& CppyyTestData::get_enum_cr() { return m_enum; } + +//- getters ref ------------------------------------------------------------- +bool& CppyyTestData::get_bool_r() { return m_bool; } +char& CppyyTestData::get_char_r() { return m_char; } +signed char& CppyyTestData::get_schar_r() { return m_schar; } +unsigned char& CppyyTestData::get_uchar_r() { return m_uchar; } +short& CppyyTestData::get_short_r() { return m_short; } +unsigned short& CppyyTestData::get_ushort_r() { return m_ushort; } +int& CppyyTestData::get_int_r() { return m_int; } +unsigned int& CppyyTestData::get_uint_r() { return m_uint; } +long& CppyyTestData::get_long_r() { return m_long; } +unsigned long& CppyyTestData::get_ulong_r() { return m_ulong; } +long long& CppyyTestData::get_llong_r() { return m_llong; } +unsigned long long& CppyyTestData::get_ullong_r() { return m_ullong; } +Long64_t& CppyyTestData::get_long64_r() { return m_long64; } +ULong64_t& CppyyTestData::get_ulong64_r() { return m_ulong64; } +float& CppyyTestData::get_float_r() { return m_float; } +double& CppyyTestData::get_double_r() { return m_double; } +long double& CppyyTestData::get_ldouble_r() { return m_ldouble; } +CppyyTestData::EWhat& CppyyTestData::get_enum_r() { return m_enum; } + +//- setters ----------------------------------------------------------------- +void CppyyTestData::set_bool(bool b) { m_bool = b; } +void CppyyTestData::set_char(char c) { m_char = c; } +void CppyyTestData::set_schar(signed char sc) { m_schar = sc; } +void CppyyTestData::set_uchar(unsigned char uc) { m_uchar = uc; } +void CppyyTestData::set_short(short s) { m_short = s; } +void CppyyTestData::set_ushort(unsigned short us) { m_ushort = us; } +void CppyyTestData::set_int(int i) { m_int = i; } +void CppyyTestData::set_uint(unsigned int ui) { m_uint = ui; } +void CppyyTestData::set_long(long l) { m_long = l; } +void CppyyTestData::set_ulong(unsigned long ul) { m_ulong = ul; } +void CppyyTestData::set_llong(long long ll) { m_llong = ll; } +void CppyyTestData::set_ullong(unsigned long long ull) { m_ullong = ull; } +void CppyyTestData::set_long64(Long64_t l64) { m_long64 = l64; } +void CppyyTestData::set_ulong64(ULong64_t ul64) { m_ulong64 = ul64; } +void CppyyTestData::set_float(float f) { m_float = f; } +void CppyyTestData::set_double(double d) { m_double = d; } +void CppyyTestData::set_ldouble(long double ld) { m_ldouble = ld; } +void CppyyTestData::set_enum(EWhat w) { m_enum = w; } +void CppyyTestData::set_voidp(void* p) { m_voidp = p; } + +void CppyyTestData::set_pod_val(CppyyTestPod p) { m_pod = p; } +void CppyyTestData::set_pod_ptr_in(CppyyTestPod* pp) { m_pod = *pp; } +void CppyyTestData::set_pod_ptr_out(CppyyTestPod* pp) { *pp = m_pod; } +void CppyyTestData::set_pod_ref(const CppyyTestPod& rp) { m_pod = rp; } +void CppyyTestData::set_pod_ptrptr_in(CppyyTestPod** ppp) { m_pod = **ppp; } +void CppyyTestData::set_pod_void_ptrptr_in(void** pp) { m_pod = **((CppyyTestPod**)pp); } +void CppyyTestData::set_pod_ptrptr_out(CppyyTestPod** ppp) { delete *ppp; *ppp = new CppyyTestPod(m_pod); } +void CppyyTestData::set_pod_void_ptrptr_out(void** pp) { delete *((CppyyTestPod**)pp); + *((CppyyTestPod**)pp) = new CppyyTestPod(m_pod); } + +void CppyyTestData::set_pod_ptr(CppyyTestPod* pp) { m_ppod = pp; } + +//- setters const-ref ------------------------------------------------------- +void CppyyTestData::set_bool_cr(const bool& b) { m_bool = b; } +void CppyyTestData::set_char_cr(const char& c) { m_char = c; } +void CppyyTestData::set_schar_cr(const signed char& sc) { m_schar = sc; } +void CppyyTestData::set_uchar_cr(const unsigned char& uc) { m_uchar = uc; } +void CppyyTestData::set_short_cr(const short& s) { m_short = s; } +void CppyyTestData::set_ushort_cr(const unsigned short& us) { m_ushort = us; } +void CppyyTestData::set_int_cr(const int& i) { m_int = i; } +void CppyyTestData::set_uint_cr(const unsigned int& ui) { m_uint = ui; } +void CppyyTestData::set_long_cr(const long& l) { m_long = l; } +void CppyyTestData::set_ulong_cr(const unsigned long& ul) { m_ulong = ul; } +void CppyyTestData::set_llong_cr(const long long& ll) { m_llong = ll; } +void CppyyTestData::set_ullong_cr(const unsigned long long& ull) { m_ullong = ull; } +void CppyyTestData::set_long64_cr(const Long64_t& l64) { m_long64 = l64; } +void CppyyTestData::set_ulong64_cr(const ULong64_t& ul64) { m_ulong64 = ul64; } +void CppyyTestData::set_float_cr(const float& f) { m_float = f; } +void CppyyTestData::set_double_cr(const double& d) { m_double = d; } +void CppyyTestData::set_ldouble_cr(const long double& ld) { m_ldouble = ld; } +void CppyyTestData::set_enum_cr(const EWhat& w) { m_enum = w; } + +//- passers ----------------------------------------------------------------- +unsigned char* CppyyTestData::pass_array(unsigned char* a) { return a; } +short* CppyyTestData::pass_array(short* a) { return a; } +unsigned short* CppyyTestData::pass_array(unsigned short* a) { return a; } +int* CppyyTestData::pass_array(int* a) { return a; } +unsigned int* CppyyTestData::pass_array(unsigned int* a) { return a; } +long* CppyyTestData::pass_array(long* a) { return a; } +unsigned long* CppyyTestData::pass_array(unsigned long* a) { return a; } +float* CppyyTestData::pass_array(float* a) { return a; } +double* CppyyTestData::pass_array(double* a) { return a; } + +//- static data members ----------------------------------------------------- +bool CppyyTestData::s_bool = false; +char CppyyTestData::s_char = 'c'; +signed char CppyyTestData::s_schar = 's'; +unsigned char CppyyTestData::s_uchar = 'u'; +short CppyyTestData::s_short = -101; +unsigned short CppyyTestData::s_ushort = 255u; +int CppyyTestData::s_int = -202; +unsigned int CppyyTestData::s_uint = 202u; +long CppyyTestData::s_long = -303l; +unsigned long CppyyTestData::s_ulong = 303ul; +long long CppyyTestData::s_llong = -404ll; +unsigned long long CppyyTestData::s_ullong = 404ull; +Long64_t CppyyTestData::s_long64 = -505ll; +ULong64_t CppyyTestData::s_ulong64 = 505ull; +float CppyyTestData::s_float = -606.f; +double CppyyTestData::s_double = -707.; +long double CppyyTestData::s_ldouble = -808.l; +CppyyTestData::EWhat CppyyTestData::s_enum = CppyyTestData::kNothing; +void* CppyyTestData::s_voidp = (void*)0; + +//- strings ----------------------------------------------------------------- +const char* CppyyTestData::get_valid_string(const char* in) { return in; } +const char* CppyyTestData::get_invalid_string() { return (const char*)0; } + + +//= global functions ======================================================== +long get_pod_address(CppyyTestData& c) +{ + return (long)&c.m_pod; +} + +long get_int_address(CppyyTestData& c) +{ + return (long)&c.m_pod.m_int; +} + +long get_double_address(CppyyTestData& c) +{ + return (long)&c.m_pod.m_double; +} + + +//= global variables/pointers =============================================== +bool g_bool = false; +char g_char = 'w'; +signed char g_schar = 'v'; +unsigned char g_uchar = 'u'; +short g_short = -88; +unsigned short g_ushort = 88u; +int g_int = -188; +unsigned int g_uint = 188u; +long g_long = -288; +unsigned long g_ulong = 288ul; +long long g_llong = -388ll; +unsigned long long g_ullong = 388ull; +Long64_t g_long64 = -488ll; +ULong64_t g_ulong64 = 488ull; +float g_float = -588.f; +double g_double = -688.; +long double g_ldouble = -788.l; +EFruit g_enum = kBanana; +void* g_voidp = nullptr; + + +//= global accessors ======================================================== +void set_global_int(int i) { + g_int = i; +} + +int get_global_int() { + return g_int; +} + +CppyyTestPod* g_pod = (CppyyTestPod*)0; + +bool is_global_pod(CppyyTestPod* t) { + return t == g_pod; +} + +void set_global_pod(CppyyTestPod* t) { + g_pod = t; +} + +CppyyTestPod* get_global_pod() { + return g_pod; +} + +CppyyTestPod* get_null_pod() { + return (CppyyTestPod*)0; +} + + +//= function pointer passing ================================================ +int sum_of_int(int i1, int i2) { + return i1+i2; +} + +double sum_of_double(double d1, double d2) { + return d1+d2; +} + +double call_double_double(double (*d)(double, double), double d1, double d2) { + return d(d1, d2); +} diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/datatypes.h b/bindings/pyroot_experimental/cppyy/cppyy/test/datatypes.h new file mode 100644 index 0000000000000..0bb757d40fef9 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/datatypes.h @@ -0,0 +1,387 @@ +#ifndef CPPYY_DUMMY_BACKEND +#include "RtypesCore.h" +#else +// copied from RtypesCore.h ... +#if defined(R__WIN32) && !defined(__CINT__) +typedef __int64 Long64_t; //Portable signed long integer 8 bytes +typedef unsigned __int64 ULong64_t; //Portable unsigned long integer 8 bytes +#else +typedef long long Long64_t; //Portable signed long integer 8 bytes +typedef unsigned long long ULong64_t;//Portable unsigned long integer 8 bytes +#endif +#endif +#include + +const int N = 5; + + +//=========================================================================== +struct CppyyTestPod { + int m_int; + double m_double; +}; + + +//=========================================================================== +enum EFruit {kApple=78, kBanana=29, kCitrus=34}; +extern std::vector vecFruits; + + +//=========================================================================== +namespace EnumSpace { + enum E {E1 = 1, E2}; + class EnumClass { + public: + enum {E1 = -1}; + enum EE {E2 = -1}; + }; +} + + +//=========================================================================== +class FourVector { +public: + FourVector(double x, double y, double z, double t) : + m_cc_called(false), m_x(x), m_y(y), m_z(z), m_t(t) {} + FourVector(const FourVector& s) : + m_cc_called(true), m_x(s.m_x), m_y(s.m_y), m_z(s.m_z), m_t(s.m_t) {} + + double operator[](int i) { + if (i == 0) return m_x; + if (i == 1) return m_y; + if (i == 2) return m_z; + if (i == 3) return m_t; + return -1; + } + + bool operator==(const FourVector& o) { + return (m_x == o.m_x && m_y == o.m_y && + m_z == o.m_z && m_t == o.m_t); + } + +public: + bool m_cc_called; + +private: + double m_x, m_y, m_z, m_t; +}; + + +//=========================================================================== +class CppyyTestData { +public: + CppyyTestData(); + ~CppyyTestData(); + +// special cases + enum EWhat { kNothing=6, kSomething=111, kLots=42 }; + +// helper + void destroy_arrays(); + +// getters + bool get_bool(); + char get_char(); + signed char get_schar(); + unsigned char get_uchar(); + short get_short(); + unsigned short get_ushort(); + int get_int(); + unsigned int get_uint(); + long get_long(); + unsigned long get_ulong(); + long long get_llong(); + unsigned long long get_ullong(); + Long64_t get_long64(); + ULong64_t get_ulong64(); + float get_float(); + double get_double(); + long double get_ldouble(); + EWhat get_enum(); + void* get_voidp(); + + bool* get_bool_array(); + bool* get_bool_array2(); + unsigned char* get_uchar_array(); + unsigned char* get_uchar_array2(); + short* get_short_array(); + short* get_short_array2(); + unsigned short* get_ushort_array(); + unsigned short* get_ushort_array2(); + int* get_int_array(); + int* get_int_array2(); + unsigned int* get_uint_array(); + unsigned int* get_uint_array2(); + long* get_long_array(); + long* get_long_array2(); + unsigned long* get_ulong_array(); + unsigned long* get_ulong_array2(); + + float* get_float_array(); + float* get_float_array2(); + double* get_double_array(); + double* get_double_array2(); + + CppyyTestPod get_pod_val(); // for m_pod + CppyyTestPod* get_pod_val_ptr(); + CppyyTestPod& get_pod_val_ref(); + CppyyTestPod*& get_pod_ptrref(); + + CppyyTestPod* get_pod_ptr(); // for m_ppod + +// getters const-ref + const bool& get_bool_cr(); + const char& get_char_cr(); + const signed char& get_schar_cr(); + const unsigned char& get_uchar_cr(); + const short& get_short_cr(); + const unsigned short& get_ushort_cr(); + const int& get_int_cr(); + const unsigned int& get_uint_cr(); + const long& get_long_cr(); + const unsigned long& get_ulong_cr(); + const long long& get_llong_cr(); + const unsigned long long& get_ullong_cr(); + const Long64_t& get_long64_cr(); + const ULong64_t& get_ulong64_cr(); + const float& get_float_cr(); + const double& get_double_cr(); + const long double& get_ldouble_cr(); + const EWhat& get_enum_cr(); + +// getters ref + bool& get_bool_r(); + char& get_char_r(); + signed char& get_schar_r(); + unsigned char& get_uchar_r(); + short& get_short_r(); + unsigned short& get_ushort_r(); + int& get_int_r(); + unsigned int& get_uint_r(); + long& get_long_r(); + unsigned long& get_ulong_r(); + long long& get_llong_r(); + unsigned long long& get_ullong_r(); + Long64_t& get_long64_r(); + ULong64_t& get_ulong64_r(); + float& get_float_r(); + double& get_double_r(); + long double& get_ldouble_r(); + EWhat& get_enum_r(); + +// setters + void set_bool(bool); + void set_char(char); + void set_schar(signed char); + void set_uchar(unsigned char); + void set_short(short); + void set_ushort(unsigned short); + void set_int(int); + void set_uint(unsigned int); + void set_long(long); + void set_ulong(unsigned long); + void set_llong(long long); + void set_ullong(unsigned long long); + void set_long64(Long64_t); + void set_ulong64(ULong64_t); + void set_float(float); + void set_double(double); + void set_ldouble(long double); + void set_enum(EWhat); + void set_voidp(void*); + + void set_pod_val(CppyyTestPod); // for m_pod + void set_pod_ptr_in(CppyyTestPod*); + void set_pod_ptr_out(CppyyTestPod*); + void set_pod_ref(const CppyyTestPod&); + void set_pod_ptrptr_in(CppyyTestPod**); + void set_pod_void_ptrptr_in(void**); + void set_pod_ptrptr_out(CppyyTestPod**); + void set_pod_void_ptrptr_out(void**); + + void set_pod_ptr(CppyyTestPod*); // for m_ppod + +// setters const-ref + void set_bool_cr(const bool&); + void set_char_cr(const char&); + void set_schar_cr(const signed char&); + void set_uchar_cr(const unsigned char&); + void set_short_cr(const short&); + void set_ushort_cr(const unsigned short&); + void set_int_cr(const int&); + void set_uint_cr(const unsigned int&); + void set_long_cr(const long&); + void set_ulong_cr(const unsigned long&); + void set_llong_cr(const long long&); + void set_ullong_cr(const unsigned long long&); + void set_long64_cr(const Long64_t&); + void set_ulong64_cr(const ULong64_t&); + void set_float_cr(const float&); + void set_double_cr(const double&); + void set_ldouble_cr(const long double&); + void set_enum_cr(const EWhat&); + +// passers + unsigned char* pass_array(unsigned char*); + short* pass_array(short*); + unsigned short* pass_array(unsigned short*); + int* pass_array(int*); + unsigned int* pass_array(unsigned int*); + long* pass_array(long*); + unsigned long* pass_array(unsigned long*); + float* pass_array(float*); + double* pass_array(double*); + + unsigned char* pass_void_array_B(void* a) { return pass_array((unsigned char*)a); } + short* pass_void_array_h(void* a) { return pass_array((short*)a); } + unsigned short* pass_void_array_H(void* a) { return pass_array((unsigned short*)a); } + int* pass_void_array_i(void* a) { return pass_array((int*)a); } + unsigned int* pass_void_array_I(void* a) { return pass_array((unsigned int*)a); } + long* pass_void_array_l(void* a) { return pass_array((long*)a); } + unsigned long* pass_void_array_L(void* a) { return pass_array((unsigned long*)a); } + float* pass_void_array_f(void* a) { return pass_array((float*)a); } + double* pass_void_array_d(void* a) { return pass_array((double*)a); } + +// strings + const char* get_valid_string(const char* in); + const char* get_invalid_string(); + +public: +// basic types + bool m_bool; + char m_char; + signed char m_schar; + unsigned char m_uchar; + short m_short; + unsigned short m_ushort; + int m_int; + const int m_const_int; // special case: const testing + unsigned int m_uint; + long m_long; + unsigned long m_ulong; + long long m_llong; + unsigned long long m_ullong; + Long64_t m_long64; + ULong64_t m_ulong64; + float m_float; + double m_double; + long double m_ldouble; + EWhat m_enum; + void* m_voidp; + +// array types + bool m_bool_array[N]; + bool* m_bool_array2; + unsigned char m_uchar_array[N]; + unsigned char* m_uchar_array2; + short m_short_array[N]; + short* m_short_array2; + unsigned short m_ushort_array[N]; + unsigned short* m_ushort_array2; + int m_int_array[N]; + int* m_int_array2; + unsigned int m_uint_array[N]; + unsigned int* m_uint_array2; + long m_long_array[N]; + long* m_long_array2; + unsigned long m_ulong_array[N]; + unsigned long* m_ulong_array2; + + float m_float_array[N]; + float* m_float_array2; + double m_double_array[N]; + double* m_double_array2; + +// object types + CppyyTestPod m_pod; + CppyyTestPod* m_ppod; + +public: + static bool s_bool; + static char s_char; + static signed char s_schar; + static unsigned char s_uchar; + static short s_short; + static unsigned short s_ushort; + static int s_int; + static unsigned int s_uint; + static long s_long; + static unsigned long s_ulong; + static long long s_llong; + static unsigned long long s_ullong; + static Long64_t s_long64; + static ULong64_t s_ulong64; + static float s_float; + static double s_double; + static long double s_ldouble; + static EWhat s_enum; + static void* s_voidp; + +private: + bool m_owns_arrays; +}; + + +//= global functions ======================================================== +long get_pod_address(CppyyTestData& c); +long get_int_address(CppyyTestData& c); +long get_double_address(CppyyTestData& c); + + +//= global variables/pointers =============================================== +extern bool g_bool; +extern char g_char; +extern signed char g_schar; +extern unsigned char g_uchar; +extern short g_short; +extern unsigned short g_ushort; +extern int g_int; +extern unsigned int g_uint; +extern long g_long; +extern unsigned long g_ulong; +extern long long g_llong; +extern unsigned long long g_ullong; +extern Long64_t g_long64; +extern ULong64_t g_ulong64; +extern float g_float; +extern double g_double; +extern long double g_ldouble; +extern EFruit g_enum; +extern void* g_voidp; + +static const bool g_c_bool = true; +static const char g_c_char = 'z'; +static const signed char g_c_schar = 'y'; +static const unsigned char g_c_uchar = 'x'; +static const short g_c_short = -99; +static const unsigned short g_c_ushort = 99u; +static const int g_c_int = -199; +static const unsigned int g_c_uint = 199u; +static const long g_c_long = -299; +static const unsigned long g_c_ulong = 299ul; +static const long long g_c_llong = -399ll; +static const unsigned long long g_c_ullong = 399ull; +static const Long64_t g_c_long64 = -499ll; +static const ULong64_t g_c_ulong64 = 499ull; +static const float g_c_float = -599.f; +static const double g_c_double = -699.; +static const long double g_c_ldouble = -799.l; +static const EFruit g_c_enum = kApple; +static const void* g_c_voidp = nullptr; + + +//= global accessors ======================================================== +void set_global_int(int i); +int get_global_int(); + +extern CppyyTestPod* g_pod; +bool is_global_pod(CppyyTestPod* t); +void set_global_pod(CppyyTestPod* t); +CppyyTestPod* get_global_pod(); +CppyyTestPod* get_null_pod(); + + +//= function pointer passing ================================================ +int sum_of_int(int i1, int i2); +double sum_of_double(double d1, double d2); +double call_double_double(double (*d)(double, double), double d1, double d2); diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/datatypes.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/datatypes.xml new file mode 100644 index 0000000000000..9b626cf12ab56 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/datatypes.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/example01.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/example01.cxx new file mode 100644 index 0000000000000..c70f23f47e6f6 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/example01.cxx @@ -0,0 +1,214 @@ +#include +#include +#include +#include + +#include "example01.h" + +//=========================================================================== +payload::payload(double d) : m_data(d) { + count++; +} +payload::payload(const payload& p) : m_data(p.m_data) { + count++; +} +payload& payload::operator=(const payload& p) { + if (this != &p) { + m_data = p.m_data; + } + return *this; +} +payload::~payload() { + count--; +} + +double payload::getData() { return m_data; } +void payload::setData(double d) { m_data = d; } + +// class-level data +int payload::count = 0; + + +//=========================================================================== +example01::example01() : m_somedata(-99) { + count++; +} +example01::example01(int a) : m_somedata(a) { + count++; +} +example01::example01(const example01& e) : m_somedata(e.m_somedata) { + count++; +} +example01& example01::operator=(const example01& e) { + if (this != &e) { + m_somedata = e.m_somedata; + } + return *this; +} +example01::~example01() { + count--; +} + +// class-level methods +int example01::staticAddOneToInt(int a) { + return a + 1; +} +int example01::staticAddOneToInt(int a, int b) { + return a + b + 1; +} +double example01::staticAddToDouble(double a) { + return a + 0.01; +} +int example01::staticAtoi(const char* str) { + return ::atoi(str); +} +char* example01::staticStrcpy(const char* strin) { + char* strout = (char*)malloc(::strlen(strin)+1); + ::strcpy(strout, strin); + return strout; +} +void example01::staticSetPayload(payload* p, double d) { + p->setData(d); +} + +payload* example01::staticCyclePayload(payload* p, double d) { + staticSetPayload(p, d); + return p; +} + +payload example01::staticCopyCyclePayload(payload* p, double d) { + staticSetPayload(p, d); + return *p; +} + +int example01::getCount() { + return count; +} + +void example01::setCount(int value) { + count = value; +} + +// instance methods +int example01::addDataToInt(int a) { + return m_somedata + a; +} + +int example01::addDataToIntConstRef(const int& a) { + return m_somedata + a; +} + +int example01::overloadedAddDataToInt(int a, int b) { + return m_somedata + a + b; +} + +int example01::overloadedAddDataToInt(int a) { + return m_somedata + a; +} + +int example01::overloadedAddDataToInt(int a, int b, int c) { + return m_somedata + a + b + c; +} + +double example01::addDataToDouble(double a) { + return m_somedata + a; +} + +int example01::addDataToAtoi(const char* str) { + return ::atoi(str) + m_somedata; +} + +char* example01::addToStringValue(const char* str) { + int out = ::atoi(str) + m_somedata; + std::ostringstream ss; + ss << out << std::ends; + std::string result = ss.str(); + char* cresult = (char*)malloc(result.size()+1); + ::strcpy(cresult, result.c_str()); + return cresult; +} + +void example01::setPayload(payload* p) { + p->setData(m_somedata); +} + +payload* example01::cyclePayload(payload* p) { + setPayload(p); + return p; +} + +payload example01::copyCyclePayload(payload* p) { + setPayload(p); + return *p; +} + +// class-level data +int example01::count = 0; + + +// global +int globalAddOneToInt(int a) { + return a + 1; +} + +int ns_example01::globalAddOneToInt(int a) { + return ::globalAddOneToInt(a); +} + +int installableAddOneToInt(example01& e, int a) { + return e.staticAddOneToInt(a); +} + +int ns_example01::gMyGlobalInt = 99; + + +// argument passing +#define typeValueImp(itype, tname) \ +itype ArgPasser::tname##Value(itype arg0, int argn, itype arg1, itype arg2) \ +{ \ + switch (argn) { \ + case 0: \ + return arg0; \ + case 1: \ + return arg1; \ + case 2: \ + return arg2; \ + default: \ + break; \ + } \ + \ + return (itype)-1; \ +} + +typeValueImp(short, short) +typeValueImp(unsigned short, ushort) +typeValueImp(int, int) +typeValueImp(unsigned int, uint) +typeValueImp(long, long) +typeValueImp(unsigned long, ulong) + +typeValueImp(float, float) +typeValueImp(double, double) + +std::string ArgPasser::stringValue(std::string arg0, int argn, std::string arg1) +{ + switch (argn) { + case 0: + return arg0; + case 1: + return arg1; + default: + break; + } + + return "argn invalid"; +} + +std::string ArgPasser::stringRef(const std::string& arg0, int argn, const std::string& arg1) +{ + return stringValue(arg0, argn, arg1); +} + + +// special case naming +z_& z_::gime_z_(z_& z) { return z; } diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/example01.h b/bindings/pyroot_experimental/cppyy/cppyy/test/example01.h new file mode 100644 index 0000000000000..4ecdd6645ebf4 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/example01.h @@ -0,0 +1,115 @@ +#include + +class payload { +public: + payload(double d = 0.); + payload(const payload& p); + payload& operator=(const payload& e); + ~payload(); + + double getData(); + void setData(double d); + +public: // class-level data + static int count; + +private: + double m_data; +}; + + +class example01 { +public: + example01(); + example01(int a); + example01(const example01& e); + example01& operator=(const example01& e); + virtual ~example01(); + +public: // class-level methods + static int staticAddOneToInt(int a); + static int staticAddOneToInt(int a, int b); + static double staticAddToDouble(double a); + static int staticAtoi(const char* str); + static char* staticStrcpy(const char* strin); + static void staticSetPayload(payload* p, double d); + static payload* staticCyclePayload(payload* p, double d); + static payload staticCopyCyclePayload(payload* p, double d); + static int getCount(); + static void setCount(int); + +public: // instance methods + int addDataToInt(int a); + int addDataToIntConstRef(const int& a); + int overloadedAddDataToInt(int a, int b); + int overloadedAddDataToInt(int a); + int overloadedAddDataToInt(int a, int b, int c); + double addDataToDouble(double a); + int addDataToAtoi(const char* str); + char* addToStringValue(const char* str); + + void setPayload(payload* p); + payload* cyclePayload(payload* p); + payload copyCyclePayload(payload* p); + +public: // class-level data + static int count; + +public: // instance data + int m_somedata; +}; + + +// global functions and data +int globalAddOneToInt(int a); +namespace ns_example01 { + int globalAddOneToInt(int a); + extern int gMyGlobalInt; +} + +int installableAddOneToInt(example01&, int a); + +#define itypeValue(itype, tname) \ + itype tname##Value(itype arg0, int argn=0, itype arg1=1, itype arg2=2) + +#define ftypeValue(ftype) \ + ftype ftype##Value(ftype arg0, int argn=0, ftype arg1=1., ftype arg2=2.) + + +// argument passing +class ArgPasser { // use a class for now as methptrgetter not +public: // implemented for global functions + itypeValue(short, short); + itypeValue(unsigned short, ushort); + itypeValue(int, int); + itypeValue(unsigned int, uint); + itypeValue(long, long); + itypeValue(unsigned long, ulong); + + ftypeValue(float); + ftypeValue(double); + + std::string stringValue( + std::string arg0, int argn=0, std::string arg1 = "default"); + + std::string stringRef( + const std::string& arg0, int argn=0, const std::string& arg1="default"); +}; + + +// typedefs +typedef example01 example01_t; + + +// special case naming +class z_ { +public: + z_& gime_z_(z_& z); + int myint; +}; + +// for pythonization checking +class example01a : public example01 { +public: + example01a(int a) : example01(a) {} +}; diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/example01.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/example01.xml new file mode 100644 index 0000000000000..bc1dfcf2e4165 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/example01.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/fragile.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/fragile.cxx new file mode 100644 index 0000000000000..78082576380de --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/fragile.cxx @@ -0,0 +1,39 @@ +#include "fragile.h" + +fragile::H::HH* fragile::H::HH::copy() { + return (HH*)0; +} + +fragile::I fragile::gI; + +void fragile::fglobal(int, double, char) { + /* empty; only used for doc-string testing */ +} + +namespace fragile { + + class Kderived : public K { + public: + virtual ~Kderived(); + }; + +} // namespace fragile + +fragile::Kderived::~Kderived() {} + +fragile::K::~K() {} + +fragile::K* fragile::K::GimeK(bool derived) { + if (!derived) return this; + else { + static Kderived kd; + return &kd; + } +}; + +fragile::K* fragile::K::GimeL() { + static L l; + return &l; +} + +fragile::L::~L() {} diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/fragile.h b/bindings/pyroot_experimental/cppyy/cppyy/test/fragile.h new file mode 100644 index 0000000000000..ff857e6c4e656 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/fragile.h @@ -0,0 +1,124 @@ +namespace fragile { + +class no_such_class; + +class A { +public: + virtual int check() { return (int)'A'; } + virtual A* gime_null() { return (A*)0; } +}; + +class B { +public: + virtual int check() { return (int)'B'; } + no_such_class* gime_no_such() { return 0; } +}; + +class C { +public: + virtual int check() { return (int)'C'; } + void use_no_such(no_such_class*) {} +}; + +class D { +public: + virtual int check() { return (int)'D'; } + virtual int check(int, int) { return (int)'D'; } + void overload() {} + void overload(no_such_class*) {} + void overload(char, int i = 0) {} // Reflex requires a named arg + void overload(int, no_such_class* p = 0) {} +}; + + +static const int dummy_location = 0xdead; + +class E { +public: + E() : m_pp_no_such((no_such_class**)&dummy_location), m_pp_a(0) {} + + virtual int check() { return (int)'E'; } + void overload(no_such_class**) {} + + no_such_class** m_pp_no_such; + A** m_pp_a; +}; + +class F { +public: + F() : m_int(0) {} + virtual int check() { return (int)'F'; } + int m_int; +}; + +class G { +public: + enum { unnamed1=24, unnamed2=96 }; + + class GG {}; +}; + +class H { +public: + class HH { + public: + HH* copy(); + }; + HH* m_h; +}; + +class I { +public: + operator bool() { return 0; } +}; + +extern I gI; + +class J { +public: + int method1(int, double) { return 0; } +}; + +void fglobal(int, double, char); + +namespace nested1 { + class A {}; + namespace nested2 { + class A {}; + namespace nested3 { + class A {}; + } // namespace nested3 + } // namespace nested2 +} // namespace nested1 + +class K { +public: + virtual ~K(); + K* GimeK(bool derived); + K* GimeL(); +}; + +class L : public K { +public: + virtual ~L(); + no_such_class* m_no_such; +}; + +class M { +public: + virtual ~M() {} + enum E1 { kOnce=42 }; + enum E2 { kTwice=12 }; +}; + +class N : public M { +public: + enum E2 { kTwice=12 }; +}; + +class O { +public: + virtual int abstract() = 0; +}; + +} // namespace fragile diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/fragile.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/fragile.xml new file mode 100644 index 0000000000000..a9a0d1fafa30c --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/fragile.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/operators.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/operators.cxx new file mode 100644 index 0000000000000..4bd502924f051 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/operators.cxx @@ -0,0 +1,16 @@ +#include "operators.h" + +// for testing the case of virtual operator== +v_opeq_base::v_opeq_base(int val) : m_val(val) {} +v_opeq_base::~v_opeq_base() {} + +bool v_opeq_base::operator==(const v_opeq_base& other) { + return m_val == other.m_val; +} + +v_opeq_derived::v_opeq_derived(int val) : v_opeq_base(val) {} +v_opeq_derived::~v_opeq_derived() {} + +bool v_opeq_derived::operator==(const v_opeq_derived& other) { + return m_val != other.m_val; +} diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/operators.h b/bindings/pyroot_experimental/cppyy/cppyy/test/operators.h new file mode 100644 index 0000000000000..43ceaf5f74d59 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/operators.h @@ -0,0 +1,115 @@ +class number { +public: + number() { m_int = 0; } + number(int i) { m_int = i; } + + number operator+(const number& n) const { return number(m_int + n.m_int); } + number operator+(int n) const { return number(m_int + n); } + number operator-(const number& n) const { return number(m_int - n.m_int); } + number operator-(int n) const { return number(m_int - n); } + number operator*(const number& n) const { return number(m_int * n.m_int); } + number operator*(int n) const { return number(m_int * n); } + number operator/(const number& n) const { return number(m_int / n.m_int); } + number operator/(int n) const { return number(m_int / n); } + number operator%(const number& n) const { return number(m_int % n.m_int); } + number operator%(int n) const { return number(m_int % n); } + + number& operator+=(const number& n) { m_int += n.m_int; return *this; } + number& operator-=(const number& n) { m_int -= n.m_int; return *this; } + number& operator*=(const number& n) { m_int *= n.m_int; return *this; } + number& operator/=(const number& n) { m_int /= n.m_int; return *this; } + number& operator%=(const number& n) { m_int %= n.m_int; return *this; } + + number operator-() { return number( -m_int ); } + + bool operator<(const number& n) const { return m_int < n.m_int; } + bool operator>(const number& n) const { return m_int > n.m_int; } + bool operator<=(const number& n) const { return m_int <= n.m_int; } + bool operator>=(const number& n) const { return m_int >= n.m_int; } + bool operator!=(const number& n) const { return m_int != n.m_int; } + bool operator==(const number& n) const { return m_int == n.m_int; } + + operator bool() { return m_int != 0; } + + number operator&(const number& n) const { return number(m_int & n.m_int); } + number operator|(const number& n) const { return number(m_int | n.m_int); } + number operator^(const number& n) const { return number(m_int ^ n.m_int); } + + number& operator&=(const number& n) { m_int &= n.m_int; return *this; } + number& operator|=(const number& n) { m_int |= n.m_int; return *this; } + number& operator^=(const number& n) { m_int ^= n.m_int; return *this; } + + number operator<<(int i) const { return number(m_int << i); } + number operator>>(int i) const { return number(m_int >> i); } + +private: + int m_int; +}; + +//---------------------------------------------------------------------------- +struct operator_char_star { // for testing user-defined implicit casts + operator_char_star() : m_str((char*)"operator_char_star") {} + operator char*() { return m_str; } + char* m_str; +}; + +struct operator_const_char_star { + operator_const_char_star() : m_str("operator_const_char_star" ) {} + operator const char*() { return m_str; } + const char* m_str; +}; + +struct operator_int { + operator int() { return m_int; } + int m_int; +}; + +struct operator_long { + operator long() { return m_long; } + long m_long; +}; + +struct operator_double { + operator double() { return m_double; } + double m_double; +}; + +struct operator_short { + operator short() { return m_short; } + unsigned short m_short; +}; + +struct operator_unsigned_int { + operator unsigned int() { return m_uint; } + unsigned int m_uint; +}; + +struct operator_unsigned_long { + operator unsigned long() { return m_ulong; } + unsigned long m_ulong; +}; + +struct operator_float { + operator float() { return m_float; } + float m_float; +}; + +//---------------------------------------------------------------------------- +class v_opeq_base { +public: + v_opeq_base(int val); + virtual ~v_opeq_base(); + + virtual bool operator==(const v_opeq_base& other); + +protected: + int m_val; +}; + +class v_opeq_derived : public v_opeq_base { +public: + v_opeq_derived(int val); + virtual ~v_opeq_derived(); + + virtual bool operator==(const v_opeq_derived& other); +}; diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/operators.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/operators.xml new file mode 100644 index 0000000000000..00ee89a3ae402 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/operators.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/overloads.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/overloads.cxx new file mode 100644 index 0000000000000..c463b941b4bc0 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/overloads.cxx @@ -0,0 +1,56 @@ +#include "overloads.h" + + +a_overload::a_overload() { i1 = 42; i2 = -1; } + +ns_a_overload::a_overload::a_overload() { i1 = 88; i2 = -34; } +int ns_a_overload::b_overload::f(const std::vector* v) { return (*v)[0]; } + +ns_b_overload::a_overload::a_overload() { i1 = -33; i2 = 89; } + +b_overload::b_overload() { i1 = -2; i2 = 13; } + +c_overload::c_overload() {} +int c_overload::get_int(a_overload* a) { return a->i1; } +int c_overload::get_int(ns_a_overload::a_overload* a) { return a->i1; } +int c_overload::get_int(ns_b_overload::a_overload* a) { return a->i1; } +int c_overload::get_int(short* p) { return *p; } +int c_overload::get_int(b_overload* b) { return b->i2; } +int c_overload::get_int(int* p) { return *p; } + +d_overload::d_overload() {} +int d_overload::get_int(int* p) { return *p; } +int d_overload::get_int(b_overload* b) { return b->i2; } +int d_overload::get_int(short* p) { return *p; } +int d_overload::get_int(ns_b_overload::a_overload* a) { return a->i1; } +int d_overload::get_int(ns_a_overload::a_overload* a) { return a->i1; } +int d_overload::get_int(a_overload* a) { return a->i1; } + + +more_overloads::more_overloads() {} +std::string more_overloads::call(const aa_ol&) { return "aa_ol"; } +std::string more_overloads::call(const bb_ol&, void* n) { n = 0; return "bb_ol"; } +std::string more_overloads::call(const cc_ol&) { return "cc_ol"; } +std::string more_overloads::call(const dd_ol&) { return "dd_ol"; } + +std::string more_overloads::call_unknown(const dd_ol&) { return "dd_ol"; } + +std::string more_overloads::call(double) { return "double"; } +std::string more_overloads::call(int) { return "int"; } +std::string more_overloads::call1(int) { return "int"; } +std::string more_overloads::call1(double) { return "double"; } + + +more_overloads2::more_overloads2() {} +std::string more_overloads2::call(const bb_ol&) { return "bb_olref"; } +std::string more_overloads2::call(const bb_ol*) { return "bb_olptr"; } + +std::string more_overloads2::call(const dd_ol*, int) { return "dd_olptr"; } +std::string more_overloads2::call(const dd_ol&, int) { return "dd_olref"; } + + +double calc_mean(long n, const float* a) { return calc_mean(n, a); } +double calc_mean(long n, const double* a) { return calc_mean(n, a); } +double calc_mean(long n, const int* a) { return calc_mean(n, a); } +double calc_mean(long n, const short* a) { return calc_mean(n, a); } +double calc_mean(long n, const long* a) { return calc_mean(n, a); } diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/overloads.h b/bindings/pyroot_experimental/cppyy/cppyy/test/overloads.h new file mode 100644 index 0000000000000..23cfddc27cb12 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/overloads.h @@ -0,0 +1,108 @@ +#include +#include + +class a_overload { +public: + a_overload(); + int i1, i2; +}; + +namespace ns_a_overload { + class a_overload { + public: + a_overload(); + int i1, i2; + }; + + class b_overload { + public: + int f(const std::vector* v); + }; +} + +namespace ns_b_overload { + class a_overload { + public: + a_overload(); + int i1, i2; + }; +} + +class b_overload { +public: + b_overload(); + int i1, i2; +}; + +class c_overload { +public: + c_overload(); + int get_int(a_overload* a); + int get_int(ns_a_overload::a_overload* a); + int get_int(ns_b_overload::a_overload* a); + int get_int(short* p); + int get_int(b_overload* b); + int get_int(int* p); +}; + +class d_overload { +public: + d_overload(); +// int get_int(void* p) { return *(int*)p; } + int get_int(int* p); + int get_int(b_overload* b); + int get_int(short* p); + int get_int(ns_b_overload::a_overload* a); + int get_int(ns_a_overload::a_overload* a); + int get_int(a_overload* a); +}; + + +class aa_ol {}; +class bb_ol; +class cc_ol {}; +class dd_ol; + +class more_overloads { +public: + more_overloads(); + std::string call(const aa_ol&); + std::string call(const bb_ol&, void* n=0); + std::string call(const cc_ol&); + std::string call(const dd_ol&); + + std::string call_unknown(const dd_ol&); + + std::string call(double); + std::string call(int); + std::string call1(int); + std::string call1(double); +}; + +class more_overloads2 { +public: + more_overloads2(); + std::string call(const bb_ol&); + std::string call(const bb_ol*); + + std::string call(const dd_ol*, int); + std::string call(const dd_ol&, int); +}; + +template +double calc_mean(long n, const T* a) { + double sum = 0., sumw = 0.; + const T* end = a+n; + while (a != end) { + sum += *a++; + sumw += 1; + } + + return sum/sumw; +} + +double calc_mean(long n, const float* a); +double calc_mean(long n, const double* a); +double calc_mean(long n, const int* a); +double calc_mean(long n, const short* a); +double calc_mean(long n, const long* a); diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/overloads.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/overloads.xml new file mode 100644 index 0000000000000..131296e72d41d --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/overloads.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/pythonizables.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/pythonizables.cxx new file mode 100644 index 0000000000000..9f18923c6fa52 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/pythonizables.cxx @@ -0,0 +1,52 @@ +#include "pythonizables.h" + + +//=========================================================================== +pyzables::NakedBuffers::NakedBuffers(int size, double valx, double valy) : m_size(size) { + m_Xbuf = new double[size]; + m_Ybuf = new double[size]; + + for (int i=0; i(new Countable); } + +pyzables::SharedCountable_t pyzables::gime_mine() { return mine; } +pyzables::SharedCountable_t* pyzables::gime_mine_ptr() { return &mine; } +pyzables::SharedCountable_t& pyzables::gime_mine_ref() { return mine; } + +unsigned int pyzables::pass_mine_sp(std::shared_ptr ptr) { return ptr->m_check; } +unsigned int pyzables::pass_mine_sp_ref(std::shared_ptr& ptr) { return ptr->m_check; } +unsigned int pyzables::pass_mine_sp_ptr(std::shared_ptr* ptr) { return (*ptr)->m_check; } + +unsigned int pyzables::pass_mine_rp(Countable c) { return c.m_check; } +unsigned int pyzables::pass_mine_rp_ref(const Countable& c) { return c.m_check; } +unsigned int pyzables::pass_mine_rp_ptr(const Countable* c) { return c->m_check; } diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/pythonizables.h b/bindings/pyroot_experimental/cppyy/cppyy/test/pythonizables.h new file mode 100644 index 0000000000000..f2472c74ba0ee --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/pythonizables.h @@ -0,0 +1,106 @@ +#include +#include + + +namespace pyzables { + +//=========================================================================== +class SomeDummy1 {}; +class SomeDummy2 {}; + + +//=========================================================================== +class NakedBuffers { +public: + NakedBuffers(int size, double valx, double valy); + NakedBuffers(const NakedBuffers&) = delete; + NakedBuffers& operator=(const NakedBuffers&) = delete; + ~NakedBuffers(); + +public: + int GetN(); + double* GetX(); + double* GetY(); + +private: + double* m_Xbuf; + double* m_Ybuf; + int m_size; +}; + +template +class NakedBuffers2 { +public: + NakedBuffers2(int size, double valx, double valy) : m_Xbuf(size), m_Ybuf(size) { + for (int i=0; i { +public: + Vector(int size) : std::vector(size) {} +}; + + +//=========================================================================== +class MyBase { +public: + virtual ~MyBase(); +}; +class MyDerived : public MyBase { +public: + virtual ~MyDerived(); +}; + +MyBase* GimeDerived(); + + +//=========================================================================== +class Countable { +public: + Countable() { ++sInstances; } + Countable(const Countable&) { ++sInstances; } + Countable& operator=(const Countable&) { return *this; } + ~Countable() { --sInstances; } + +public: + virtual const char* say_hi() { return "Hi!"; } + +public: + unsigned int m_check = 0xcdcdcdcd; + +public: + static int sInstances; +}; + +typedef std::shared_ptr SharedCountable_t; +extern SharedCountable_t mine; + +void renew_mine(); + +SharedCountable_t gime_mine(); +SharedCountable_t* gime_mine_ptr(); +SharedCountable_t& gime_mine_ref(); + +unsigned int pass_mine_sp(SharedCountable_t p); +unsigned int pass_mine_sp_ref(SharedCountable_t& p); +unsigned int pass_mine_sp_ptr(SharedCountable_t* p); + +unsigned int pass_mine_rp(Countable); +unsigned int pass_mine_rp_ref(const Countable&); +unsigned int pass_mine_rp_ptr(const Countable*); + +} // namespace pyzables diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/pythonizables.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/pythonizables.xml new file mode 100644 index 0000000000000..154869de9f10e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/pythonizables.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/std_streams.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/std_streams.cxx new file mode 100644 index 0000000000000..94e924b7b2bde --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/std_streams.cxx @@ -0,0 +1,3 @@ +#include "std_streams.h" + +template class std::basic_ios >; diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/std_streams.h b/bindings/pyroot_experimental/cppyy/cppyy/test/std_streams.h new file mode 100644 index 0000000000000..4088e4302dfa4 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/std_streams.h @@ -0,0 +1,13 @@ +#ifndef STD_STREAMS_H +#define STD_STREAMS_H 1 + +#ifndef __CINT__ +#include +#endif +#include + +#ifndef __CINT__ +extern template class std::basic_ios >; +#endif + +#endif // STD_STREAMS_H diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/std_streams.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/std_streams.xml new file mode 100644 index 0000000000000..01eb8c73b5427 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/std_streams.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/stltypes.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/stltypes.cxx new file mode 100644 index 0000000000000..df5832d4f239f --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/stltypes.cxx @@ -0,0 +1,43 @@ +#include "stltypes.h" + + +//- explicit instantiations of used comparisons +#if defined __clang__ +namespace std { +#define ns_prefix std:: +#elif defined(__GNUC__) || defined(__GNUG__) +namespace __gnu_cxx { +#define ns_prefix +#endif +template bool ns_prefix operator==(const std::vector::iterator&, + const std::vector::iterator&); +template bool ns_prefix operator!=(const std::vector::iterator&, + const std::vector::iterator&); +} + +//- class with lots of std::string handling +stringy_class::stringy_class(const char* s) : m_string(s) {} + +std::string stringy_class::get_string1() { return m_string; } +void stringy_class::get_string2(std::string& s) { s = m_string; } + +void stringy_class::set_string1(const std::string& s) { m_string = s; } +void stringy_class::set_string2(std::string s) { m_string = s; } + + +//- helpers for testing array +int ArrayTest::get_pp_px(Point** p, int idx) { + return p[idx]->px; +} + +int ArrayTest::get_pp_py(Point** p, int idx) { + return p[idx]->py; +} + +int ArrayTest::get_pa_px(Point* p[], int idx) { + return p[idx]->px; +} + +int ArrayTest::get_pa_py(Point* p[], int idx) { + return p[idx]->py; +} diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/stltypes.h b/bindings/pyroot_experimental/cppyy/cppyy/test/stltypes.h new file mode 100644 index 0000000000000..10541d3a486fa --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/stltypes.h @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include + +//- basic example class +class just_a_class { +public: + int m_i; +}; + +//- class with lots of std::string handling +class stringy_class { +public: + stringy_class(const char* s); + + std::string get_string1(); + void get_string2(std::string& s); + + void set_string1(const std::string& s); + void set_string2(std::string s); + + std::string m_string; +}; + +//- class that has an STL-like interface +class no_dict_available; + +template +class stl_like_class { +public: + no_dict_available* begin() { return 0; } + no_dict_available* end() { return 0; } + int size() { return 4; } + int operator[](int i) { return i; } + std::string operator[](double) { return "double"; } + std::string operator[](const std::string&) { return "string"; } +}; + + +//- instantiations of used STL types +namespace { + + stl_like_class stlc_1; + +} // unnamed namespace + + +// comps for int only to allow testing: normal use of vector is looping over a +// range-checked version of __getitem__ +#if defined(__clang__) && defined(__APPLE__) +namespace std { +#define ns_prefix std:: +#elif defined(__GNUC__) || defined(__GNUG__) +namespace __gnu_cxx { +#define ns_prefix +#endif +extern template bool ns_prefix operator==(const std::vector::iterator&, + const std::vector::iterator&); +extern template bool ns_prefix operator!=(const std::vector::iterator&, + const std::vector::iterator&); +} + + +//- helpers for testing array +namespace ArrayTest { + +struct Point { + int px, py; +}; + +int get_pp_px(Point** p, int idx); +int get_pp_py(Point** p, int idx); +int get_pa_px(Point* p[], int idx); +int get_pa_py(Point* p[], int idx); + +} // namespace ArrayTest diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/stltypes.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/stltypes.xml new file mode 100644 index 0000000000000..0043d8dc74540 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/stltypes.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/support.py b/bindings/pyroot_experimental/cppyy/cppyy/test/support.py new file mode 100644 index 0000000000000..569591703ca78 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/support.py @@ -0,0 +1,21 @@ +from __future__ import print_function +import py, sys, subprocess + +currpath = py.path.local(__file__).dirpath() + + +def setup_make(targetname): + if sys.platform == 'win32': + raise OSError("win32 not supported yet") + popen = subprocess.Popen(["make", targetname], cwd=str(currpath), + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout, _ = popen.communicate() + if popen.returncode: + raise OSError("'make' failed:\n%s" % (stdout,)) + +if sys.hexversion >= 0x3000000: + pylong = int + maxvalue = sys.maxsize +else: + pylong = long + maxvalue = sys.maxint diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/templates.cxx b/bindings/pyroot_experimental/cppyy/cppyy/test/templates.cxx new file mode 100644 index 0000000000000..90489166467b0 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/templates.cxx @@ -0,0 +1,12 @@ +#include "templates.h" + + +// template methods +long MyTemplatedMethodClass::get_size() { return -1; } + +long MyTemplatedMethodClass::get_char_size() { return (long)sizeof(char); } +long MyTemplatedMethodClass::get_int_size() { return (long)sizeof(int); } +long MyTemplatedMethodClass::get_long_size() { return (long)42; /* "lying" */ } +long MyTemplatedMethodClass::get_float_size() { return (long)sizeof(float); } +long MyTemplatedMethodClass::get_double_size() { return (long)sizeof(double); } +long MyTemplatedMethodClass::get_self_size() { return (long)sizeof(MyTemplatedMethodClass); } diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/templates.h b/bindings/pyroot_experimental/cppyy/cppyy/test/templates.h new file mode 100644 index 0000000000000..bb6febf38480e --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/templates.h @@ -0,0 +1,145 @@ +#include +#include + + +//=========================================================================== +class MyTemplatedMethodClass { // template methods +public: + long get_size(); // to get around bug in genreflex + template long get_size(); + + long get_char_size(); + long get_int_size(); + long get_long_size(); + long get_float_size(); + long get_double_size(); + + long get_self_size(); + +private: + double m_data[3]; +}; + +template +inline long MyTemplatedMethodClass::get_size() { + return sizeof(B); +} + +// +typedef MyTemplatedMethodClass MyTMCTypedef_t; + +// explicit instantiation +template long MyTemplatedMethodClass::get_size(); +template long MyTemplatedMethodClass::get_size(); + +// "lying" specialization +template<> +inline long MyTemplatedMethodClass::get_size() { + return 42; +} + + +//=========================================================================== +// global templated functions +template +long global_get_size() { + return sizeof(T); +} + +template +int global_some_foo(T) { + return 42; +} + +template +int global_some_bar(T) { + return 13; +} + + +//=========================================================================== +// variadic functions +inline bool isSomeInt(int) { return true; } +inline bool isSomeInt(double) { return false; } +template +inline bool isSomeInt(Args...) { return false; } + +namespace AttrTesting { + +struct Obj1 { int var1; }; +struct Obj2 { int var2; }; + +template +constexpr auto has_var1(T t) -> decltype(t.var1, true) { return true; } + +template +constexpr bool has_var1(Args...) { return false; } + +template +constexpr bool call_has_var1(T&& t) { return AttrTesting::has_var1(std::forward(t)); } + +template +struct select_template_arg {}; + +template +struct select_template_arg<0, T0, T...> { + typedef T0 type; +}; + +template +struct select_template_arg { + typedef typename select_template_arg::type argument; +}; + +} // AttrTesting + + +namespace SomeNS { + +template +int some_foo(T) { + return 42; +} + +template +int some_bar() { + return T; +} + +inline std::string tuplify(std::ostringstream& out) { + out.seekp(-2, out.cur); out << ')'; + return out.str(); +} + +template +std::string tuplify(std::ostringstream& out, T value, Args... args) +{ + out << value << ", "; + return tuplify(out, args...); +} + +} // namespace SomeNS + + +//=========================================================================== +// using of static data +// TODO: this should live here instead of in test_templates.test08 +/* +template struct BaseClassWithStatic { + static T const ref_value; +}; + +template +T const BaseClassWithStatic::ref_value = 42; + +template +struct DerivedClassUsingStatic : public BaseClassWithStatic { + using BaseClassWithStatic::ref_value; + + explicit DerivedClassUsingStatic(T x) : BaseClassWithStatic() { + m_value = x > ref_value ? ref_value : x; + } + + T m_value; +}; +*/ diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/templates.xml b/bindings/pyroot_experimental/cppyy/cppyy/test/templates.xml new file mode 100644 index 0000000000000..17c4ffa9617a1 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/templates.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_aclassloader.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_aclassloader.py new file mode 100644 index 0000000000000..f304af57b7670 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_aclassloader.py @@ -0,0 +1,24 @@ +import py, os, sys +from pytest import raises +from .support import setup_make + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("example01Dict.so")) + +def setup_module(mod): + setup_make("example01Dict.so") + + +class TestACLASSLOADER: + + def setup_class(cls): + import cppyy + + def test01_class_autoloading(self): + """Test whether a class can be found through .rootmap.""" + import cppyy + example01_class = cppyy.gbl.example01 + assert example01_class + cl2 = cppyy.gbl.example01 + assert cl2 + assert example01_class is cl2 diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_advancedcpp.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_advancedcpp.py new file mode 100644 index 0000000000000..dbf2f3540db17 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_advancedcpp.py @@ -0,0 +1,722 @@ +import py, os, sys +from pytest import raises +from .support import setup_make, pylong + +try: + import __pypy__ + is_pypy = True +except ImportError: + is_pypy = False + + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("advancedcppDict.so")) + +def setup_module(mod): + setup_make("advancedcppDict.so") + setup_make("advancedcpp2Dict.so") + + +class TestADVANCEDCPP: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.advanced = cppyy.load_reflection_info(cls.test_dct) + + def test01_default_arguments(self): + """Test usage of default arguments""" + + import cppyy + def test_defaulter(n, t): + defaulter = getattr(cppyy.gbl, '%s_defaulter' % n) + + d = defaulter() + assert d.m_a == t(11) + assert d.m_b == t(22) + assert d.m_c == t(33) + d.__destruct__() + + d = defaulter(0) + assert d.m_a == t(0) + assert d.m_b == t(22) + assert d.m_c == t(33) + d.__destruct__() + + d = defaulter(1, 2) + assert d.m_a == t(1) + assert d.m_b == t(2) + assert d.m_c == t(33) + d.__destruct__() + + d = defaulter(3, 4, 5) + assert d.m_a == t(3) + assert d.m_b == t(4) + assert d.m_c == t(5) + d.__destruct__() + test_defaulter('short', int) + test_defaulter('ushort', int) + test_defaulter('int', int) + test_defaulter('uint', int) + test_defaulter('long', pylong) + test_defaulter('ulong', pylong) + test_defaulter('llong', pylong) + test_defaulter('ullong', pylong) + test_defaulter('float', float) + test_defaulter('double', float) + + def test02_simple_inheritance(self): + """Test binding of a basic inheritance structure""" + + import cppyy + base_class = cppyy.gbl.base_class + derived_class = cppyy.gbl.derived_class + + assert issubclass(derived_class, base_class) + assert not issubclass(base_class, derived_class) + + b = base_class() + assert isinstance(b, base_class) + assert not isinstance(b, derived_class) + + assert b.m_b == 1 + assert b.get_value() == 1 + assert b.m_db == 1.1 + assert b.get_base_value() == 1.1 + + b.m_b, b.m_db = 11, 11.11 + assert b.m_b == 11 + assert b.get_value() == 11 + assert b.m_db == 11.11 + assert b.get_base_value() == 11.11 + + b.__destruct__() + + d = derived_class() + assert isinstance(d, derived_class) + assert isinstance(d, base_class) + + assert d.m_d == 2 + assert d.get_value() == 2 + assert d.m_dd == 2.2 + assert d.get_derived_value() == 2.2 + + assert d.m_b == 1 + assert d.m_db == 1.1 + assert d.get_base_value() == 1.1 + + d.m_b, d.m_db = 11, 11.11 + d.m_d, d.m_dd = 22, 22.22 + + assert d.m_d == 22 + assert d.get_value() == 22 + assert d.m_dd == 22.22 + assert d.get_derived_value() == 22.22 + + assert d.m_b == 11 + assert d.m_db == 11.11 + assert d.get_base_value() == 11.11 + + d.__destruct__() + + def test03_namespaces(self): + """Test access to namespaces and inner classes""" + + import cppyy + gbl = cppyy.gbl + + assert gbl.a_ns is gbl.a_ns + assert gbl.a_ns.d_ns is gbl.a_ns.d_ns + + assert gbl.a_ns.b_class is gbl.a_ns.b_class + assert gbl.a_ns.b_class.c_class is gbl.a_ns.b_class.c_class + assert gbl.a_ns.d_ns.e_class is gbl.a_ns.d_ns.e_class + assert gbl.a_ns.d_ns.e_class.f_class is gbl.a_ns.d_ns.e_class.f_class + + assert gbl.a_ns.g_a == 11 + assert gbl.a_ns.get_g_a() == 11 + assert gbl.a_ns.b_class.s_b == 22 + assert gbl.a_ns.b_class().m_b == -2 + assert gbl.a_ns.b_class.c_class.s_c == 33 + assert gbl.a_ns.b_class.c_class().m_c == -3 + assert gbl.a_ns.d_ns.g_d == 44 + assert gbl.a_ns.d_ns.get_g_d() == 44 + assert gbl.a_ns.d_ns.e_class.s_e == 55 + assert gbl.a_ns.d_ns.e_class().m_e == -5 + assert gbl.a_ns.d_ns.e_class.f_class.s_f == 66 + assert gbl.a_ns.d_ns.e_class.f_class().m_f == -6 + + def test03a_namespace_lookup_on_update(self): + """Test whether namespaces can be shared across dictionaries.""" + + import cppyy + gbl = cppyy.gbl + + lib2 = cppyy.load_reflection_info("advancedcpp2Dict.so") + + assert gbl.a_ns is gbl.a_ns + assert gbl.a_ns.d_ns is gbl.a_ns.d_ns + + assert gbl.a_ns.g_class is gbl.a_ns.g_class + assert gbl.a_ns.g_class.h_class is gbl.a_ns.g_class.h_class + assert gbl.a_ns.d_ns.i_class is gbl.a_ns.d_ns.i_class + assert gbl.a_ns.d_ns.i_class.j_class is gbl.a_ns.d_ns.i_class.j_class + + assert gbl.a_ns.g_g == 77 + assert gbl.a_ns.get_g_g() == 77 + assert gbl.a_ns.g_class.s_g == 88 + assert gbl.a_ns.g_class().m_g == -7 + assert gbl.a_ns.g_class.h_class.s_h == 99 + assert gbl.a_ns.g_class.h_class().m_h == -8 + assert gbl.a_ns.d_ns.g_i == 111 + assert gbl.a_ns.d_ns.get_g_i() == 111 + assert gbl.a_ns.d_ns.i_class.s_i == 222 + assert gbl.a_ns.d_ns.i_class().m_i == -9 + assert gbl.a_ns.d_ns.i_class.j_class.s_j == 333 + assert gbl.a_ns.d_ns.i_class.j_class().m_j == -10 + + def test04_template_types(self): + """Test bindings of templated types""" + + import cppyy + gbl = cppyy.gbl + + assert gbl.T1 is gbl.T1 + assert gbl.T2 is gbl.T2 + assert gbl.T3 is gbl.T3 + assert not gbl.T1 is gbl.T2 + assert not gbl.T2 is gbl.T3 + + assert gbl.T1('int') is gbl.T1('int') + assert gbl.T1(int) is gbl.T1('int') + assert gbl.T2('T1') is gbl.T2('T1') + assert gbl.T2(gbl.T1('int')) is gbl.T2('T1') + assert gbl.T2(gbl.T1(int)) is gbl.T2('T1') + assert gbl.T3('int,double') is gbl.T3('int,double') + assert gbl.T3('int', 'double') is gbl.T3('int,double') + assert gbl.T3(int, 'double') is gbl.T3('int,double') + assert gbl.T3('T1,T2 >') is gbl.T3('T1,T2 >') + assert gbl.T3('T1', gbl.T2(gbl.T1(int))) is gbl.T3('T1,T2 >') + + assert gbl.a_ns.T4(int) is gbl.a_ns.T4('int') + assert gbl.a_ns.T4('a_ns::T4 >')\ + is gbl.a_ns.T4(gbl.a_ns.T4(gbl.T3(int, 'double'))) + + #----- mix in some of the alternative syntax + assert gbl.T1['int'] is gbl.T1('int') + assert gbl.T1[int] is gbl.T1('int') + assert gbl.T2['T1'] is gbl.T2('T1') + assert gbl.T2[gbl.T1('int')] is gbl.T2('T1') + assert gbl.T2[gbl.T1(int)] is gbl.T2('T1') + assert gbl.T3['int,double'] is gbl.T3('int,double') + assert gbl.T3['int', 'double'] is gbl.T3('int,double') + assert gbl.T3[int, 'double'] is gbl.T3('int,double') + assert gbl.T3['T1,T2 >'] is gbl.T3('T1,T2 >') + assert gbl.T3['T1', gbl.T2[gbl.T1[int]]] is gbl.T3('T1,T2 >') + + assert gbl.a_ns.T4[int] is gbl.a_ns.T4('int') + assert gbl.a_ns.T4['a_ns::T4 >']\ + is gbl.a_ns.T4(gbl.a_ns.T4(gbl.T3(int, 'double'))) + + #----- + t1 = gbl.T1(int)() + assert t1.m_t1 == 1 + assert t1.get_value() == 1 + t1.__destruct__() + + #----- + t1 = gbl.T1(int)(11) + assert t1.m_t1 == 11 + assert t1.get_value() == 11 + t1.m_t1 = 111 + assert t1.get_value() == 111 + assert t1.m_t1 == 111 + t1.__destruct__() + + #----- + t2 = gbl.T2(gbl.T1(int))(gbl.T1(int)(32)) + t2.m_t2.m_t1 = 32 + assert t2.m_t2.get_value() == 32 + assert t2.m_t2.m_t1 == 32 + t2.__destruct__() + + + def test05_abstract_classes(self): + """Test non-instatiatability of abstract classes""" + + import cppyy + gbl = cppyy.gbl + + raises(TypeError, gbl.a_class) + raises(TypeError, gbl.some_abstract_class) + + assert issubclass(gbl.some_concrete_class, gbl.some_abstract_class) + + c = gbl.some_concrete_class() + assert isinstance(c, gbl.some_concrete_class) + assert isinstance(c, gbl.some_abstract_class) + + def test06_datamembers(self): + """Test data member access when using virtual inheritence""" + + import cppyy + a_class = cppyy.gbl.a_class + b_class = cppyy.gbl.b_class + c_class_1 = cppyy.gbl.c_class_1 + c_class_2 = cppyy.gbl.c_class_2 + d_class = cppyy.gbl.d_class + + assert issubclass(b_class, a_class) + assert issubclass(c_class_1, a_class) + assert issubclass(c_class_1, b_class) + assert issubclass(c_class_2, a_class) + assert issubclass(c_class_2, b_class) + assert issubclass(d_class, a_class) + assert issubclass(d_class, b_class) + assert issubclass(d_class, c_class_2) + + #----- + b = b_class() + assert b.m_a == 1 + assert b.m_da == 1.1 + assert b.m_b == 2 + assert b.m_db == 2.2 + + b.m_a = 11 + assert b.m_a == 11 + assert b.m_b == 2 + + b.m_da = 11.11 + assert b.m_da == 11.11 + assert b.m_db == 2.2 + + b.m_b = 22 + assert b.m_a == 11 + assert b.m_da == 11.11 + assert b.m_b == 22 + assert b.get_value() == 22 + + b.m_db = 22.22 + assert b.m_db == 22.22 + + b.__destruct__() + + #----- + c1 = c_class_1() + assert c1.m_a == 1 + assert c1.m_b == 2 + assert c1.m_c == 3 + + c1.m_a = 11 + assert c1.m_a == 11 + + c1.m_b = 22 + assert c1.m_a == 11 + assert c1.m_b == 22 + + c1.m_c = 33 + assert c1.m_a == 11 + assert c1.m_b == 22 + assert c1.m_c == 33 + assert c1.get_value() == 33 + + c1.__destruct__() + + #----- + d = d_class() + assert d.m_a == 1 + assert d.m_b == 2 + assert d.m_c == 3 + assert d.m_d == 4 + + d.m_a = 11 + assert d.m_a == 11 + + d.m_b = 22 + assert d.m_a == 11 + assert d.m_b == 22 + + d.m_c = 33 + assert d.m_a == 11 + assert d.m_b == 22 + assert d.m_c == 33 + + d.m_d = 44 + assert d.m_a == 11 + assert d.m_b == 22 + assert d.m_c == 33 + assert d.m_d == 44 + assert d.get_value() == 44 + + d.__destruct__() + + def test07_pass_by_reference(self): + """Test reference passing when using virtual inheritance""" + + import cppyy + gbl = cppyy.gbl + b_class = gbl.b_class + c_class = gbl.c_class_2 + d_class = gbl.d_class + + #----- + b = b_class() + b.m_a, b.m_b = 11, 22 + assert gbl.get_a(b) == 11 + assert gbl.get_b(b) == 22 + b.__destruct__() + + #----- + c = c_class() + c.m_a, c.m_b, c.m_c = 11, 22, 33 + assert gbl.get_a(c) == 11 + assert gbl.get_b(c) == 22 + assert gbl.get_c(c) == 33 + c.__destruct__() + + #----- + d = d_class() + d.m_a, d.m_b, d.m_c, d.m_d = 11, 22, 33, 44 + assert gbl.get_a(d) == 11 + assert gbl.get_b(d) == 22 + assert gbl.get_c(d) == 33 + assert gbl.get_d(d) == 44 + d.__destruct__() + + def test08_void_pointer_passing(self): + """Test passing of variants of void pointer arguments""" + + import cppyy + pointer_pass = cppyy.gbl.pointer_pass + some_concrete_class = cppyy.gbl.some_concrete_class + + pp = pointer_pass() + o = some_concrete_class() + + assert cppyy.addressof(o) == pp.gime_address_ptr(o) + assert cppyy.addressof(o) == pp.gime_address_ptr_ptr(o) + assert cppyy.addressof(o) == pp.gime_address_ptr_ref(o) + + import array + addressofo = array.array('l', [cppyy.addressof(o)]) + assert addressofo[0] == pp.gime_address_ptr_ptr(addressofo) + + assert 0 == pp.gime_address_ptr(0) + raises(TypeError, pp.gime_address_ptr, None) + + ptr = cppyy.bind_object(0, some_concrete_class) + assert cppyy.addressof(ptr) == 0 + pp.set_address_ptr_ref(ptr) + assert cppyy.addressof(ptr) == 0x1234 + pp.set_address_ptr_ptr(ptr) + assert cppyy.addressof(ptr) == 0x4321 + + assert cppyy.addressof(cppyy.nullptr) == 0 + raises(TypeError, cppyy.addressof, None) + assert cppyy.addressof(0) == 0 + + def test09_opaque_pointer_passing(self): + """Test passing around of opaque pointers""" + + import cppyy + some_concrete_class = cppyy.gbl.some_concrete_class + + o = some_concrete_class() + + # TODO: figure out the PyPy equivalent of CObject (may have to do this + # through the C-API from C++) + + #cobj = cppyy.as_cobject(o) + addr = cppyy.addressof(o) + + #assert o == cppyy.bind_object(cobj, some_concrete_class) + #assert o == cppyy.bind_object(cobj, type(o)) + #assert o == cppyy.bind_object(cobj, o.__class__) + #assert o == cppyy.bind_object(cobj, "some_concrete_class") + assert cppyy.addressof(o) == cppyy.addressof(cppyy.bind_object(addr, some_concrete_class)) + assert o == cppyy.bind_object(addr, some_concrete_class) + assert o == cppyy.bind_object(addr, type(o)) + assert o == cppyy.bind_object(addr, o.__class__) + assert o == cppyy.bind_object(addr, "some_concrete_class") + raises(TypeError, cppyy.bind_object, addr, "does_not_exist") + raises(TypeError, cppyy.bind_object, addr, 1) + + def test10_object_identity(self): + """Test object identity""" + + import cppyy + some_concrete_class = cppyy.gbl.some_concrete_class + some_class_with_data = cppyy.gbl.some_class_with_data + + o = some_concrete_class() + addr = cppyy.addressof(o) + + o2 = cppyy.bind_object(addr, some_concrete_class) + assert o is o2 + + o3 = cppyy.bind_object(addr, some_class_with_data) + assert not o is o3 + + d1 = some_class_with_data() + d2 = d1.gime_copy() + assert not d1 is d2 + + dd1a = d1.gime_data() + dd1b = d1.gime_data() + assert dd1a is dd1b + + dd2 = d2.gime_data() + assert not dd1a is dd2 + assert not dd1b is dd2 + + d2.__destruct__() + d1.__destruct__() + + RTS = cppyy.gbl.refers_to_self + + r1 = RTS() + r2 = RTS() + r1.m_other = r2 + + r3 = r1.m_other + r4 = r1.m_other + assert r3 is r4 + + assert r3 == r2 + assert r3 is r2 + + r3.extra = 42 + assert r2.extra == 42 + assert r4.extra == 42 + + def test11_multi_methods(self): + """Test calling of methods from multiple inheritance""" + + import cppyy + multi = cppyy.gbl.multi + + assert cppyy.gbl.multi1 is multi.__bases__[0] + assert cppyy.gbl.multi2 is multi.__bases__[1] + + dict_keys = list(multi.__dict__.keys()) + assert dict_keys.count('get_my_own_int') == 1 + assert dict_keys.count('get_multi1_int') == 0 + assert dict_keys.count('get_multi2_int') == 0 + + m = multi(1, 2, 3) + assert m.get_multi1_int() == 1 + assert m.get_multi2_int() == 2 + assert m.get_my_own_int() == 3 + + def test12_actual_type(self): + """Test that a pointer to base return does an auto-downcast""" + + import cppyy + base_class = cppyy.gbl.base_class + derived_class = cppyy.gbl.derived_class + + b = base_class() + d = derived_class() + + assert b == b.cycle(b) + assert id(b) == id(b.cycle(b)) + assert b == d.cycle(b) + assert id(b) == id(d.cycle(b)) + assert d == b.cycle(d) + assert id(d) == id(b.cycle(d)) + assert d == d.cycle(d) + assert id(d) == id(d.cycle(d)) + + assert isinstance(b.cycle(b), base_class) + assert isinstance(d.cycle(b), base_class) + assert isinstance(b.cycle(d), derived_class) + assert isinstance(d.cycle(d), derived_class) + + assert isinstance(b.clone(), base_class) # TODO: clone() leaks + assert isinstance(d.clone(), derived_class) # TODO: clone() leaks + + # special case when round-tripping through a void* ptr + voidp = b.mask(d) + assert not isinstance(voidp, base_class) + assert not isinstance(voidp, derived_class) + + d1 = cppyy.bind_object(voidp, base_class, cast=True) + assert isinstance(d1, derived_class) + assert d1 is d + + b1 = cppyy.bind_object(voidp, base_class) + assert isinstance(b1, base_class) + assert cppyy.addressof(b1) == cppyy.addressof(d) + assert not (b1 is d) + + def test13_actual_type_virtual_multi(self): + """Test auto-downcast in adverse inheritance situation""" + + import cppyy + + c1 = cppyy.gbl.create_c1() + assert type(c1) == cppyy.gbl.c_class_1 + assert c1.m_c == 3 + c1.__destruct__() + + c2 = cppyy.gbl.create_c2() + assert type(c2) == cppyy.gbl.c_class_2 + assert c2.m_c == 3 + c2.__destruct__() + + def test14_new_overloader(self): + """Verify that class-level overloaded new/delete are called""" + + import cppyy + + assert cppyy.gbl.new_overloader.s_instances == 0 + nl = cppyy.gbl.new_overloader() + assert cppyy.gbl.new_overloader.s_instances == 1 + nl.__destruct__() + + import gc + gc.collect() + assert cppyy.gbl.new_overloader.s_instances == 0 + + def test15_template_instantiation_with_vector_of_float(self): + """Test template instantiation with a std::vector""" + + import cppyy + + # the following will simply fail if there is a naming problem (e.g. + # std::, allocator, etc., etc.); note the parsing required ... + b = cppyy.gbl.my_templated_class(cppyy.gbl.std.vector(float))() + + for i in range(5): + b.m_b.push_back(i) + assert round(b.m_b[i], 5) == float(i) + + def test16_template_global_functions(self): + """Test template global function lookup and calls""" + + import cppyy + + f = cppyy.gbl.my_templated_function + + assert f('c') == 'c' + assert type(f('c')) == type('c') + assert f(3.) == 3. + assert type(f(4.)) == type(4.) + + def test17_assign_to_return_byref( self ): + """Test assignment to an instance returned by reference""" + + from cppyy import gbl + + a = gbl.std.vector(gbl.ref_tester)() + a.push_back(gbl.ref_tester(42)) + + assert len(a) == 1 + assert a[0].m_i == 42 + + # TODO: + # a[0] = gbl.ref_tester(33) + # assert len(a) == 1 + # assert a[0].m_i == 33 + + def test18_math_converters(self): + """Test operator int/long/double incl. typedef""" + + from cppyy import gbl + + a = gbl.some_convertible() + a.m_i = 1234 + a.m_d = 4321. + + assert int(a) == 1234 + assert int(a) == a.m_i + assert pylong(a) == a.m_i + + assert float(a) == 4321. + assert float(a) == a.m_d + + def test19_comparator(self): + """Check that the global operator!=/== is picked up""" + + from cppyy import gbl + + a, b = gbl.some_comparable(), gbl.some_comparable() + + assert a == b + assert b == a + assert a.__eq__(b) + assert b.__eq__(a) + assert a.__ne__(a) + assert b.__ne__(b) + assert a.__eq__(b) == True + assert b.__eq__(a) == True + assert a.__eq__(a) == False + assert b.__eq__(b) == False + + def test20_overload_order_with_proper_return(self): + """Test return type against proper overload w/ const and covariance""" + + import cppyy + + assert cppyy.gbl.overload_one_way().gime() == 1 + assert cppyy.gbl.overload_the_other_way().gime() == "aap" + + def test21_access_to_global_variables(self): + """Access global_variables_and_pointers""" + + import cppyy + + if is_pypy: + raise RuntimeError("test fails with crash") + + assert cppyy.gbl.my_global_double == 12. + assert len(cppyy.gbl.my_global_array) == 500 + assert cppyy.gbl.my_global_string1 == "aap noot mies" + assert cppyy.gbl.my_global_string2 == "zus jet teun" + # TODO: currently fails b/c double** not understood as &double* + #assert cppyy.gbl.my_global_ptr[0] == 1234. + + def test22_exceptions(self): + """Catching of C++ exceptions""" + + import cppyy + Thrower = cppyy.gbl.Thrower + + if is_pypy: + # TODO: clean up this interface: + Thrower.__cppdecl__.get_overload('throw_anything').__useffi__ = False + Thrower.__cppdecl__.get_overload('throw_exception').__useffi__ = False + + t = Thrower() + + assert raises(Exception, t.throw_anything) + assert raises(Exception, t.throw_exception) + + try: + t.throw_exception() + except Exception as e: + "C++ function failed" in str(e) + + def test23_using(self): + """Accessibility of using declarations""" + + import cppyy + + assert cppyy.gbl.UsingBase().vcheck() == 'A' + + B = cppyy.gbl.UsingDerived + assert not 'UsingBase' in B.__init__.__doc__ + + b1 = B() + assert b1.m_int == 13 + assert b1.m_int2 == 42 + assert b1.vcheck() == 'B' + + b2 = B(10) + assert b2.m_int == 10 + assert b2.m_int2 == 42 + assert b2.vcheck() == 'B' + + b3 = B(b2) + assert b3.m_int == 10 + assert b3.m_int2 == 42 + assert b3.vcheck() == 'B' diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_boost_any.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_boost_any.py new file mode 100644 index 0000000000000..231eb8a2ae629 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_boost_any.py @@ -0,0 +1,44 @@ +import py, os, sys +from pytest import raises +from .support import setup_make + + +class TestBOOSTANY: + def setup_class(cls): + import cppyy + cppyy.include('boost/any.hpp') + + def test01_any_class(self): + """Availability of boost::any""" + + import cppyy + assert cppyy.gbl.boost.any + + from cppyy.gbl import std + from cppyy.gbl.boost import any + + assert std.list(any) + + def test02_any_usage(self): + """boost::any assignment and casting""" + + import cppyy + assert cppyy.gbl.boost + + from cppyy.gbl import std, boost + + val = boost.any() + val.__assign__(std.vector[int]()) + assert val.type() == cppyy.typeid(std.vector[int]) + + extract = boost.any_cast[std.vector[int]](std.move(val)) + assert type(extract) is std.vector[int] + extract += range(100) + + val.__assign__(std.move(extract)) + assert len(extract) == 0 + + raises(Exception, boost.any_cast[int], std.move(val)) + + extract = boost.any_cast[std.vector[int]](std.move(val)) + assert len(extract) == 100 diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_cpp11features.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_cpp11features.py new file mode 100644 index 0000000000000..6461899fbbc9d --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_cpp11features.py @@ -0,0 +1,137 @@ +import py, os, sys +from pytest import raises +from .support import setup_make + +try: + import __pypy__ + is_pypy = True +except ImportError: + is_pypy = False + + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("cpp11featuresDict.so")) + +def setup_module(mod): + setup_make("cpp11featuresDict.so") + +class TestCPP11FEATURES: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.cpp11features = cppyy.load_reflection_info(cls.test_dct) + + def test01_shared_ptr(self): + """Usage and access of std::shared_ptr<>""" + + from cppyy.gbl import TestSharedPtr, create_shared_ptr_instance + + # proper memory accounting + assert TestSharedPtr.s_counter == 0 + + ptr1 = create_shared_ptr_instance() + assert ptr1 + assert not not ptr1 + assert TestSharedPtr.s_counter == 1 + + ptr2 = create_shared_ptr_instance() + assert ptr2 + assert not not ptr2 + assert TestSharedPtr.s_counter == 2 + + del ptr2 + import gc; gc.collect() + assert TestSharedPtr.s_counter == 1 + + del ptr1 + gc.collect() + assert TestSharedPtr.s_counter == 0 + + def test02_nullptr(self): + """Allow the programmer to pass NULL in certain cases""" + + import cppyy + + # test existence + nullptr = cppyy.nullptr + # assert not hasattr(cppyy.gbl, 'nullptr') + + # usage is tested in datatypes.py:test15_nullptr_passing + + def test03_move(self): + """Move construction, assignment, and methods""" + + import cppyy + + def moveit(T): + from cppyy.gbl import std + + # move constructor + i1 = T() + assert T.s_move_counter == 0 + + i2 = T(i1) # cctor + assert T.s_move_counter == 0 + + if is_pypy or 0x3000000 <= sys.hexversion: + i3 = T(std.move(T())) # can't check ref-count + else: + i3 = T(T()) # should call move, not memoized cctor + assert T.s_move_counter == 1 + + i3 = T(std.move(T())) # both move and ref-count + assert T.s_move_counter == 2 + + i4 = T(std.move(i1)) + assert T.s_move_counter == 3 + + # move assignment + i4.__assign__(i2) + assert T.s_move_counter == 3 + + if is_pypy or 0x3000000 <= sys.hexversion: + i4.__assign__(std.move(T())) # can't check ref-count + else: + i4.__assign__(T()) + assert T.s_move_counter == 4 + + i4.__assign__(std.move(i2)) + assert T.s_move_counter == 5 + + # order of moving and normal functions are reversed in 1, 2, for + # overload resolution testing + moveit(cppyy.gbl.TestMoving1) + moveit(cppyy.gbl.TestMoving2) + + def test04_initializer_list(self): + """Initializer list construction""" + + from cppyy.gbl import std, TestData + + v = std.vector[int]((1, 2, 3, 4)) + assert list(v) == [1, 2, 3, 4] + + v = std.vector['double']((1, 2, 3, 4)) + assert list(v) == [1., 2., 3., 4.] + + raises(TypeError, std.vector[int], [1., 2., 3., 4.]) + + l = list() + for i in range(10): + l.append(TestData(i)) + + v = std.vector[TestData](l) + assert len(v) == len(l) + for i in range(len(l)): + assert v[i].m_int == l[i].m_int + + def test05_lambda_calls(self): + """Call (global) lambdas""" + + import cppyy + + cppyy.cppdef("auto gMyLambda = [](int a) { return 40 + a; };") + + assert cppyy.gbl.gMyLambda + assert cppyy.gbl.gMyLambda(2) == 42 + assert cppyy.gbl.gMyLambda(40) == 80 diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_datatypes.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_datatypes.py new file mode 100644 index 0000000000000..040618e6f9690 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_datatypes.py @@ -0,0 +1,765 @@ +import py, os, sys +from pytest import raises +from .support import setup_make, pylong + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("datatypesDict.so")) + +def setup_module(mod): + setup_make("datatypesDict.so") + + +class TestDATATYPES: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.datatypes = cppyy.load_reflection_info(cls.test_dct) + cls.N = cppyy.gbl.N + + def test01_instance_data_read_access(self): + """Read access to instance public data and verify values""" + + import cppyy + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + assert isinstance(c, CppyyTestData) + + # reading boolean type + assert c.m_bool == False + assert not c.get_bool(); assert not c.get_bool_cr(); assert not c.get_bool_r() + + # reading char types + assert c.m_char == 'a' + assert c.m_schar == 'b' + assert c.m_uchar == 'c' + + # reading integer types + assert c.m_short == -11; assert c.get_short_cr() == -11; assert c.get_short_r() == -11 + assert c.m_ushort == 11; assert c.get_ushort_cr() == 11; assert c.get_ushort_r() == 11 + assert c.m_int == -22; assert c.get_int_cr() == -22; assert c.get_int_r() == -22 + assert c.m_uint == 22; assert c.get_uint_cr() == 22; assert c.get_uint_r() == 22 + assert c.m_long == -33; assert c.get_long_cr() == -33; assert c.get_long_r() == -33 + assert c.m_ulong == 33; assert c.get_ulong_cr() == 33; assert c.get_ulong_r() == 33 + assert c.m_llong == -44; assert c.get_llong_cr() == -44; assert c.get_llong_r() == -44 + assert c.m_ullong == 44; assert c.get_ullong_cr() == 44; assert c.get_ullong_r() == 44 + assert c.m_long64 == -55; assert c.get_long64_cr() == -55; assert c.get_long64_r() == -55 + assert c.m_ulong64 == 55; assert c.get_ulong64_cr() == 55; assert c.get_ulong64_r() == 55 + + # reading floating point types + assert round(c.m_float + 66., 5) == 0 + assert round(c.get_float_cr() + 66., 5) == 0 + assert round(c.get_float_r() + 66., 5) == 0 + assert round(c.m_double + 77., 11) == 0 + assert round(c.get_double_cr() + 77., 11) == 0 + assert round(c.get_double_r() + 77., 11) == 0 + #assert round(c.m_ldouble + 88., 24) == 0 + #assert round(c.get_ldouble_cr() + 88., 24) == 0 + #assert round(c.get_ldouble_r() + 88., 24) == 0 + assert round(c.m_double + 77., 8) == 0 + + # reading of enum types + assert c.m_enum == CppyyTestData.kNothing + assert c.m_enum == c.kNothing + + # reading of boolean array + for i in range(self.N): + assert c.m_bool_array[i] == bool(i%2) + assert c.get_bool_array()[i] == bool(i%2) + assert c.m_bool_array2[i] == bool((i+1)%2) + assert c.get_bool_array2()[i] == bool((i+1)%2) + + # reading of integer array types + names = ['uchar', 'short', 'ushort', 'int', 'uint', 'long', 'ulong'] + alpha = [ (1, 2), (-1, -2), (3, 4), (-5, -6), (7, 8), (-9, -10), (11, 12)] + for j in range(self.N): + assert getattr(c, 'm_%s_array' % names[i])[i] == alpha[i][0]*i + assert getattr(c, 'get_%s_array' % names[i])()[i] == alpha[i][0]*i + assert getattr(c, 'm_%s_array2' % names[i])[i] == alpha[i][1]*i + assert getattr(c, 'get_%s_array2' % names[i])()[i] == alpha[i][1]*i + + # reading of floating point array types + for k in range(self.N): + assert round(c.m_float_array[k] + 13.*k, 5) == 0 + assert round(c.m_float_array2[k] + 14.*k, 5) == 0 + assert round(c.m_double_array[k] + 15.*k, 8) == 0 + assert round(c.m_double_array2[k] + 16.*k, 8) == 0 + + # out-of-bounds checks + raises(IndexError, c.m_uchar_array.__getitem__, self.N) + raises(IndexError, c.m_short_array.__getitem__, self.N) + raises(IndexError, c.m_ushort_array.__getitem__, self.N) + raises(IndexError, c.m_int_array.__getitem__, self.N) + raises(IndexError, c.m_uint_array.__getitem__, self.N) + raises(IndexError, c.m_long_array.__getitem__, self.N) + raises(IndexError, c.m_ulong_array.__getitem__, self.N) + raises(IndexError, c.m_float_array.__getitem__, self.N) + raises(IndexError, c.m_double_array.__getitem__, self.N) + + # can not access an instance member on the class + raises(AttributeError, getattr, CppyyTestData, 'm_bool') + raises(AttributeError, getattr, CppyyTestData, 'm_int') + + assert not hasattr(CppyyTestData, 'm_bool') + assert not hasattr(CppyyTestData, 'm_int') + + c.__destruct__() + + def test02_instance_data_write_access(self): + """Test write access to instance public data and verify values""" + + import cppyy + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + assert isinstance(c, CppyyTestData) + + # boolean types through functions + c.set_bool(True); assert c.get_bool() == True + c.set_bool(0); assert c.get_bool() == False + + # boolean types through data members + c.m_bool = True; assert c.get_bool() == True + c.set_bool(True); assert c.m_bool == True + c.m_bool = 0; assert c.get_bool() == False + c.set_bool(0); assert c.m_bool == False + + raises(ValueError, 'c.set_bool(10)') + + # char types through functions + c.set_char('c'); assert c.get_char() == 'c' + c.set_uchar('e'); assert c.get_uchar() == 'e' + + # char types through data members + c.m_char = 'b'; assert c.get_char() == 'b' + c.m_char = 40; assert c.get_char() == chr(40) + c.set_char('c'); assert c.m_char == 'c' + c.set_char(41); assert c.m_char == chr(41) + c.m_uchar = 'd'; assert c.get_uchar() == 'd' + c.m_uchar = 42; assert c.get_uchar() == chr(42) + c.set_uchar('e'); assert c.m_uchar == 'e' + c.set_uchar(43); assert c.m_uchar == chr(43) + + raises(ValueError, 'c.set_char("string")') + raises(ValueError, 'c.set_char(500)') + raises(ValueError, 'c.set_uchar("string")') + raises(ValueError, 'c.set_uchar(-1)') + + # integer types + names = ['short', 'ushort', 'int', 'uint', 'long', 'ulong', 'llong', 'ullong'] + for i in range(len(names)): + setattr(c, 'm_'+names[i], i) + assert eval('c.get_%s()' % names[i]) == i + + for i in range(len(names)): + getattr(c, 'set_'+names[i])(2*i) + assert eval('c.m_%s' % names[i]) == 2*i + + for i in range(len(names)): + getattr(c, 'set_'+names[i]+'_cr')(3*i) + assert eval('c.m_%s' % names[i]) == 3*i + + # float types through functions + c.set_float( 0.123 ); assert round(c.get_float() - 0.123, 5) == 0 + c.set_double( 0.456 ); assert round(c.get_double() - 0.456, 8) == 0 + + # float types through data members + c.m_float = 0.123; assert round(c.get_float() - 0.123, 5) == 0 + c.set_float(0.234); assert round(c.m_float - 0.234, 5) == 0 + c.set_float_cr(0.456); assert round(c.m_float - 0.456, 5) == 0 + c.m_double = 0.678; assert round(c.get_double() - 0.678, 8) == 0 + c.set_double(0.890); assert round(c.m_double - 0.890, 8) == 0 + c.set_double_cr(0.012); assert round(c.m_double - 0.012, 8) == 0 + + # arrays; there will be pointer copies, so destroy the current ones + c.destroy_arrays() + + # integer arrays + names = ['uchar', 'short', 'ushort', 'int', 'uint', 'long', 'ulong'] + import array + a = range(self.N) + atypes = ['B', 'h', 'H', 'i', 'I', 'l', 'L' ] + for j in range(len(names)): + b = array.array(atypes[j], a) + setattr(c, 'm_'+names[j]+'_array', b) # buffer copies + for i in range(self.N): + assert eval('c.m_%s_array[i]' % names[j]) == b[i] + + setattr(c, 'm_'+names[j]+'_array2', b) # pointer copies + assert 3 < self.N + b[3] = 28 + for i in range(self.N): + assert eval('c.m_%s_array2[i]' % names[j]) == b[i] + + # can not write to constant data + assert c.m_const_int == 17 + raises(TypeError, setattr, c, 'm_const_int', 71) + + c.__destruct__() + + def test03_array_passing(self): + """Test passing of array arguments""" + + import cppyy, array, sys + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + assert isinstance(c, CppyyTestData) + + a = range(self.N) + # test arrays in mixed order, to give overload resolution a workout + for t in ['d', 'i', 'f', 'H', 'I', 'h', 'L', 'l' ]: + b = array.array(t, a) + + # typed passing + ca = c.pass_array(b) + assert type(ca[0]) == type(b[0]) + assert len(b) == self.N + for i in range(self.N): + assert ca[i] == b[i] + + # void* passing + ca = eval('c.pass_void_array_%s(b)' % t) + assert type(ca[0]) == type(b[0]) + assert len(b) == self.N + for i in range(self.N): + assert ca[i] == b[i] + + # NULL/nullptr passing (will use short*) + assert not c.pass_array(0) + raises(Exception, c.pass_array(0).__getitem__, 0) # raises SegfaultException + assert raises(TypeError, c.pass_array, None) + assert not c.pass_array(cppyy.nullptr) + raises(Exception, c.pass_array(cppyy.nullptr).__getitem__, 0) # id. id. + + c.__destruct__() + + def test04_class_read_access(self): + """Test read access to class public data and verify values""" + + import cppyy, sys + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + assert isinstance(c, CppyyTestData) + + # char types + assert CppyyTestData.s_char == 'c' + assert c.s_char == 'c' + assert c.s_uchar == 'u' + assert CppyyTestData.s_uchar == 'u' + + # integer types + assert CppyyTestData.s_short == -101 + assert c.s_short == -101 + assert c.s_ushort == 255 + assert CppyyTestData.s_ushort == 255 + assert CppyyTestData.s_int == -202 + assert c.s_int == -202 + assert c.s_uint == 202 + assert CppyyTestData.s_uint == 202 + assert CppyyTestData.s_long == -pylong(303) + assert c.s_long == -pylong(303) + assert c.s_ulong == pylong(303) + assert CppyyTestData.s_ulong == pylong(303) + assert CppyyTestData.s_llong == -pylong(404) + assert c.s_llong == -pylong(404) + assert c.s_ullong == pylong(404) + assert CppyyTestData.s_ullong == pylong(404) + + # floating point types + assert round(CppyyTestData.s_float + 606., 5) == 0 + assert round(c.s_float + 606., 5) == 0 + assert round(CppyyTestData.s_double + 707., 8) == 0 + assert round(c.s_double + 707., 8) == 0 + + c.__destruct__() + + def test05_class_data_write_access(self): + """Test write access to class public data and verify values""" + + import cppyy, sys + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + assert isinstance(c, CppyyTestData) + + # char types + CppyyTestData.s_char = 'a' + assert c.s_char == 'a' + c.s_char = 'b' + assert CppyyTestData.s_char == 'b' + CppyyTestData.s_uchar = 'c' + assert c.s_uchar == 'c' + c.s_uchar = 'd' + assert CppyyTestData.s_uchar == 'd' + raises(ValueError, setattr, CppyyTestData, 's_uchar', -1) + raises(ValueError, setattr, c, 's_uchar', -1) + + # integer types + c.s_short = -102 + assert CppyyTestData.s_short == -102 + CppyyTestData.s_short = -203 + assert c.s_short == -203 + c.s_ushort = 127 + assert CppyyTestData.s_ushort == 127 + CppyyTestData.s_ushort = 227 + assert c.s_ushort == 227 + CppyyTestData.s_int = -234 + assert c.s_int == -234 + c.s_int = -321 + assert CppyyTestData.s_int == -321 + CppyyTestData.s_uint = 1234 + assert c.s_uint == 1234 + c.s_uint = 4321 + assert CppyyTestData.s_uint == 4321 + raises(ValueError, setattr, c, 's_uint', -1) + raises(ValueError, setattr, CppyyTestData, 's_uint', -1) + CppyyTestData.s_long = -pylong(87) + assert c.s_long == -pylong(87) + c.s_long = pylong(876) + assert CppyyTestData.s_long == pylong(876) + CppyyTestData.s_ulong = pylong(876) + assert c.s_ulong == pylong(876) + c.s_ulong = pylong(678) + assert CppyyTestData.s_ulong == pylong(678) + raises(ValueError, setattr, CppyyTestData, 's_ulong', -1) + raises(ValueError, setattr, c, 's_ulong', -1) + + # floating point types + CppyyTestData.s_float = -3.1415 + assert round(c.s_float, 5) == -3.1415 + c.s_float = 3.1415 + assert round(CppyyTestData.s_float, 5) == 3.1415 + import math + c.s_double = -math.pi + assert CppyyTestData.s_double == -math.pi + CppyyTestData.s_double = math.pi + assert c.s_double == math.pi + + c.__destruct__() + + def test06_range_access(self): + """Test the ranges of integer types""" + + import cppyy, sys + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + assert isinstance(c, CppyyTestData) + + # TODO: should these be TypeErrors, or should char/bool raise + # ValueErrors? In any case, consistency is needed ... + raises(ValueError, setattr, c, 'm_uint', -1) + raises(ValueError, setattr, c, 'm_ulong', -1) + + c.__destruct__() + + def test07_type_conversions(self): + """Test conversions between builtin types""" + + import cppyy, sys + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + assert isinstance(c, CppyyTestData) + + c.m_double = -1 + assert round(c.m_double + 1.0, 8) == 0 + + raises(TypeError, c.m_double, 'c') + raises(TypeError, c.m_int, -1.) + raises(TypeError, c.m_int, 1.) + + c.__destruct__() + + def test08_global_builtin_type(self): + """Test access to a global builtin type""" + + import cppyy + gbl = cppyy.gbl + + assert gbl.g_int == gbl.get_global_int() + + gbl.set_global_int(32) + assert gbl.get_global_int() == 32 + assert gbl.g_int == 32 + + gbl.g_int = 22 + assert gbl.get_global_int() == 22 + assert gbl.g_int == 22 + + def test09_global_ptr(self): + """Test access of global objects through a pointer""" + + import cppyy + gbl = cppyy.gbl + + raises(ReferenceError, 'gbl.g_pod.m_int') + + c = gbl.CppyyTestPod() + c.m_int = 42 + c.m_double = 3.14 + + gbl.set_global_pod(c) + assert gbl.is_global_pod(c) + assert gbl.g_pod.m_int == 42 + assert gbl.g_pod.m_double == 3.14 + + d = gbl.get_global_pod() + assert gbl.is_global_pod(d) + assert c == d + assert id(c) == id(d) + + e = gbl.CppyyTestPod() + e.m_int = 43 + e.m_double = 2.14 + + gbl.g_pod = e + assert gbl.is_global_pod(e) + assert gbl.g_pod.m_int == 43 + assert gbl.g_pod.m_double == 2.14 + + def test10_enum(self): + """Test access to enums""" + + import cppyy + gbl = cppyy.gbl + + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + assert isinstance(c, CppyyTestData) + + # test that the enum is accessible as a type + assert CppyyTestData.EWhat + + assert CppyyTestData.kNothing == 6 + assert CppyyTestData.kSomething == 111 + assert CppyyTestData.kLots == 42 + + assert CppyyTestData.EWhat(CppyyTestData.kNothing) == CppyyTestData.kNothing + assert CppyyTestData.EWhat(6) == CppyyTestData.kNothing + # TODO: only allow instantiations with correct values (C++11) + + assert c.get_enum() == CppyyTestData.kNothing + assert c.m_enum == CppyyTestData.kNothing + + c.m_enum = CppyyTestData.kSomething + assert c.get_enum() == CppyyTestData.kSomething + assert c.m_enum == CppyyTestData.kSomething + + c.set_enum(CppyyTestData.kLots) + assert c.get_enum() == CppyyTestData.kLots + assert c.m_enum == CppyyTestData.kLots + + assert c.s_enum == CppyyTestData.s_enum + assert c.s_enum == CppyyTestData.kNothing + assert CppyyTestData.s_enum == CppyyTestData.kNothing + + c.s_enum = CppyyTestData.kSomething + assert c.s_enum == CppyyTestData.s_enum + assert c.s_enum == CppyyTestData.kSomething + assert CppyyTestData.s_enum == CppyyTestData.kSomething + + # global enums + assert gbl.EFruit # test type accessible + assert gbl.kApple == 78 + assert gbl.kBanana == 29 + assert gbl.kCitrus == 34 + + assert gbl.EnumSpace.E + assert gbl.EnumSpace.EnumClass.E1 == -1 # anonymous + assert gbl.EnumSpace.EnumClass.E2 == -1 # named type + + def test11_string_passing(self): + """Test passing/returning of a const char*""" + + import cppyy + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + assert c.get_valid_string('aap') == 'aap' + #assert c.get_invalid_string() == '' + + def test12_copy_contructor(self): + """Test copy constructor""" + + import cppyy + FourVector = cppyy.gbl.FourVector + + t1 = FourVector(1., 2., 3., -4.) + t2 = FourVector(0., 0., 0., 0.) + t3 = FourVector(t1) + + assert t1 == t3 + assert t1 != t2 + + for i in range(4): + assert t1[i] == t3[i] + + def test13_object_returns(self): + """Test access to and return of PODs""" + + import cppyy + + c = cppyy.gbl.CppyyTestData() + + assert c.m_pod.m_int == 888 + assert c.m_pod.m_double == 3.14 + + pod = c.get_pod_val() + assert pod.m_int == 888 + assert pod.m_double == 3.14 + + assert c.get_pod_val_ptr().m_int == 888 + assert c.get_pod_val_ptr().m_double == 3.14 + c.get_pod_val_ptr().m_int = 777 + assert c.get_pod_val_ptr().m_int == 777 + + assert c.get_pod_val_ref().m_int == 777 + assert c.get_pod_val_ref().m_double == 3.14 + c.get_pod_val_ref().m_int = 666 + assert c.get_pod_val_ref().m_int == 666 + + assert c.get_pod_ptrref().m_int == 666 + assert c.get_pod_ptrref().m_double == 3.14 + + def test14_object_arguments(self): + """Test setting and returning of a POD through arguments""" + + import cppyy + + c = cppyy.gbl.CppyyTestData() + assert c.m_pod.m_int == 888 + assert c.m_pod.m_double == 3.14 + + p = cppyy.gbl.CppyyTestPod() + p.m_int = 123 + assert p.m_int == 123 + p.m_double = 321. + assert p.m_double == 321. + + c.set_pod_val(p) + assert c.m_pod.m_int == 123 + assert c.m_pod.m_double == 321. + + c = cppyy.gbl.CppyyTestData() + c.set_pod_ptr_in(p) + assert c.m_pod.m_int == 123 + assert c.m_pod.m_double == 321. + + c = cppyy.gbl.CppyyTestData() + c.set_pod_ptr_out(p) + assert p.m_int == 888 + assert p.m_double == 3.14 + + p.m_int = 555 + p.m_double = 666. + + c = cppyy.gbl.CppyyTestData() + c.set_pod_ref(p) + assert c.m_pod.m_int == 555 + assert c.m_pod.m_double == 666. + + c = cppyy.gbl.CppyyTestData() + c.set_pod_ptrptr_in(p) + assert c.m_pod.m_int == 555 + assert c.m_pod.m_double == 666. + assert p.m_int == 555 + assert p.m_double == 666. + + c = cppyy.gbl.CppyyTestData() + c.set_pod_void_ptrptr_in(p) + assert c.m_pod.m_int == 555 + assert c.m_pod.m_double == 666. + assert p.m_int == 555 + assert p.m_double == 666. + + c = cppyy.gbl.CppyyTestData() + c.set_pod_ptrptr_out(p) + assert c.m_pod.m_int == 888 + assert c.m_pod.m_double == 3.14 + assert p.m_int == 888 + assert p.m_double == 3.14 + + p.m_int = 777 + p.m_double = 888. + + c = cppyy.gbl.CppyyTestData() + c.set_pod_void_ptrptr_out(p) + assert c.m_pod.m_int == 888 + assert c.m_pod.m_double == 3.14 + assert p.m_int == 888 + assert p.m_double == 3.14 + + def test15_nullptr_passing(self): + """Integer 0 ('NULL') and nullptr allowed to pass through instance*""" + + import cppyy + + for o in (0, cppyy.nullptr): + c = cppyy.gbl.CppyyTestData() + assert c.m_pod.m_int == 888 + assert c.m_pod.m_double == 3.14 + assert not not c.m_ppod + + c.set_pod_ptr(o) + assert not c.m_ppod + assert not c.get_pod_ptr() + + def test16_respect_privacy(self): + """Test that privacy settings are respected""" + + import cppyy + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + assert isinstance(c, CppyyTestData) + + raises(AttributeError, getattr, c, 'm_owns_arrays') + + c.__destruct__() + + def test17_object_and_pointer_comparisons(self): + """Verify object and pointer comparisons""" + + import cppyy + gbl = cppyy.gbl + + c1 = cppyy.bind_object(0, gbl.CppyyTestData) + assert c1 == None + assert None == c1 + + c2 = cppyy.bind_object(0, gbl.CppyyTestData) + assert c1 == c2 + assert c2 == c1 + + # FourVector overrides operator== + l1 = cppyy.bind_object(0, gbl.FourVector) + assert l1 == None + assert None == l1 + + assert c1 != l1 + assert l1 != c1 + + l2 = cppyy.bind_object(0, gbl.FourVector) + assert l1 == l2 + assert l2 == l1 + + l3 = gbl.FourVector(1, 2, 3, 4) + l4 = gbl.FourVector(1, 2, 3, 4) + l5 = gbl.FourVector(4, 3, 2, 1) + assert l3 == l4 + assert l4 == l3 + + assert l3 != None # like this to ensure __ne__ is called + assert None != l3 # id. + assert l3 != l5 + assert l5 != l3 + + def test18_object_validity(self): + """Test object validity checking""" + + from cppyy import gbl + + d = gbl.CppyyTestPod() + + assert d + assert not not d + + d2 = gbl.get_null_pod() + + assert not d2 + + def test19_buffer_reshaping(self): + """Test usage of buffer sizing""" + + import cppyy + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + for func in ['get_bool_array', 'get_bool_array2', + 'get_uchar_array', 'get_uchar_array2', + 'get_ushort_array', 'get_ushort_array2', + 'get_int_array', 'get_int_array2', + 'get_uint_array', 'get_uint_array2', + 'get_long_array', 'get_long_array2', + 'get_ulong_array', 'get_ulong_array2']: + arr = getattr(c, func)() + arr.reshape((self.N,)) + assert len(arr) == self.N + + raises(TypeError, arr.reshape, (1, 2)) + assert len(arr) == self.N + + raises(TypeError, arr.reshape, 2*self.N) + assert len(arr) == self.N + + l = list(arr) + for i in range(self.N): + assert arr[i] == l[i] + + def test20_voidp(self): + """Test usage of void* data""" + + import cppyy + CppyyTestData = cppyy.gbl.CppyyTestData + + c = CppyyTestData() + + assert not cppyy.nullptr + + assert c.s_voidp is cppyy.nullptr + assert CppyyTestData.s_voidp is cppyy.nullptr + + assert c.m_voidp is cppyy.nullptr + assert c.get_voidp() is cppyy.nullptr + + c2 = CppyyTestData() + assert c2.m_voidp is cppyy.nullptr + c.set_voidp(c2.m_voidp) + assert c.m_voidp is cppyy.nullptr + c.set_voidp(c2.get_voidp()) + assert c.m_voidp is cppyy.nullptr + c.set_voidp(cppyy.nullptr) + assert c.m_voidp is cppyy.nullptr + + c.set_voidp(c2) + def address_equality_test(a, b): + assert cppyy.addressof(a) == cppyy.addressof(b) + b2 = cppyy.bind_object(a, CppyyTestData) + assert b is b2 # memory regulator recycles + b3 = cppyy.bind_object(cppyy.addressof(a), CppyyTestData) + assert b is b3 # likewise + + address_equality_test(c.m_voidp, c2) + address_equality_test(c.get_voidp(), c2) + + def null_test(null): + c.m_voidp = null + assert c.m_voidp is cppyy.nullptr + map(null_test, [0, cppyy.nullptr]) + + c.m_voidp = c2 + address_equality_test(c.m_voidp, c2) + address_equality_test(c.get_voidp(), c2) + + c.s_voidp = c2 + address_equality_test(c.s_voidp, c2) + + def test21_function_pointers(self): + """Function pointer passing""" + + import cppyy + + f1 = cppyy.gbl.sum_of_int + f2 = cppyy.gbl.sum_of_double + f3 = cppyy.gbl.call_double_double + + assert 5 == f1(2, 3) + assert 5. == f2(5., 0.) + + raises(TypeError, f3, f1, 2, 3) + + assert 5. == f3(f2, 5., 0.) diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_doc_features.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_doc_features.py new file mode 100644 index 0000000000000..d189370969941 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_doc_features.py @@ -0,0 +1,280 @@ +import py, os, sys +from pytest import raises + + +class TestDOCFEATURES: + def setup_class(cls): + import cppyy + + cppyy.cppdef(""" +#include +#include +#include + + +//----- +unsigned int gUint = 0; + +//----- +class Abstract { +public: + virtual ~Abstract() {} + virtual void abstract_method() = 0; + virtual void concrete_method() = 0; +}; + +void Abstract::concrete_method() { + std::cout << "called Abstract::concrete_method" << std::endl; +} + +//----- +class Concrete : Abstract { +public: + Concrete(int n=42) : m_int(n), m_const_int(17) {} + ~Concrete() {} + + virtual void abstract_method() { + std::cout << "called Concrete::abstract_method" << std::endl; + } + + virtual void concrete_method() { + std::cout << "called Concrete::concrete_method" << std::endl; + } + + void array_method(int* ad, int size) { + for (int i=0; i < size; ++i) + std::cout << ad[i] << ' '; + std::cout << std::endl; + } + + void array_method(double* ad, int size) { + for (int i=0; i < size; ++i) + std::cout << ad[i] << ' '; + std::cout << std::endl; + } + + Abstract* show_autocast() { + return this; + } + + operator const char*() { + return "Hello operator const char*!"; + } + +public: + double m_data[4]; + int m_int; + const int m_const_int; +}; + +//----- +int global_function(int) { + return 42; +} + +double global_function(double) { + return std::exp(1); +} + +//----- +namespace Namespace { + + class Concrete { + public: + class NestedClass { + public: + std::vector m_v; + }; + + }; + + int global_function(int i) { + return 2*::global_function(i); + } + + double global_function(double d) { + return 2*::global_function(d); + } + +} // namespace Namespace + +""") + + def test_abstract_class(self): + import cppyy + from cppyy.gbl import Abstract, Concrete + + raises(TypeError, Abstract) + assert issubclass(Concrete, Abstract) + c = Concrete() + assert isinstance(c, Abstract) + + def test_array(self): + import cppyy + from cppyy.gbl import Concrete + from array import array + + c = Concrete() + c.array_method(array('d', [1., 2., 3., 4.]), 4) + raises(IndexError, c.m_data.__getitem__, 4) + + def test_builtin_data(self): + import cppyy + + assert cppyy.gbl.gUint == 0 + raises(ValueError, setattr, cppyy.gbl, 'gUint', -1) + + def test_casting(self): + import cppyy + from cppyy.gbl import Abstract, Concrete + + c = Concrete() + assert 'Abstract' in Concrete.show_autocast.__doc__ + d = c.show_autocast() + assert type(d) == cppyy.gbl.Concrete + + from cppyy import addressof, bind_object + e = bind_object(addressof(d), Abstract) + assert type(e) == cppyy.gbl.Abstract + + def test_classes_and_structs(self): + import cppyy + from cppyy.gbl import Concrete, Namespace + + assert Concrete != Namespace.Concrete + n = Namespace.Concrete.NestedClass() + assert 'Namespace.Concrete.NestedClass' in str(type(n)) + assert 'NestedClass' == type(n).__name__ + assert 'cppyy.gbl.Namespace.Concrete' == type(n).__module__ + assert 'Namespace::Concrete::NestedClass' == type(n).__cppname__ + + def test_data_members(self): + import cppyy + from cppyy.gbl import Concrete + + c = Concrete() + assert c.m_int == 42 + raises(TypeError, setattr, c, 'm_const_int', 71) + + def test_default_arguments(self): + import cppyy + from cppyy.gbl import Concrete + + c = Concrete() + assert c.m_int == 42 + c = Concrete(13) + assert c.m_int == 13 + + def test_doc_strings(self): + import cppyy + from cppyy.gbl import Concrete + assert 'void Concrete::array_method(int* ad, int size)' in Concrete.array_method.__doc__ + assert 'void Concrete::array_method(double* ad, int size)' in Concrete.array_method.__doc__ + + def test_enums(self): + import cppyy + + pass + + def test_functions(self): + import cppyy + + from cppyy.gbl import global_function, Namespace + assert not(global_function == Namespace.global_function) + + assert round(global_function(1.)-2.718281828459045, 8) == 0. + assert global_function(1) == 42 + + assert Namespace.global_function(1) == 42*2 + assert round(Namespace.global_function(1.)-2.718281828459045*2, 8) == 0. + + assert round(global_function.__overload__('double')(1)-2.718281828459045, 8) == 0. + + def test_inheritance(self): + import cppyy + + pass + + def test_memory(self): + import cppyy + from cppyy.gbl import Concrete + + c = Concrete() + assert c.__python_owns__ == True + + def test_methods(self): + import cppyy + + pass + + def test_namespaces(self): + import cppyy + + pass + + def test_null(self): + import cppyy + + assert hasattr(cppyy, 'nullptr') + assert not cppyy.nullptr + + def test_operator_conversions(self): + import cppyy + from cppyy.gbl import Concrete + + assert str(Concrete()) == 'Hello operator const char*!' + + def test_operator_overloads(self): + import cppyy + + pass + + def test_pointers(self): + import cppyy + + pass + + def test_pyobject(self): + import cppyy + + pass + + def test_static_data_members(self): + import cppyy + + def test_static_methods(self): + import cppyy + + pass + + def test_strings(self): + import cppyy + + pass + + def test_templated_classes(self): + import cppyy + + assert cppyy.gbl.std.vector + assert isinstance(cppyy.gbl.std.vector(int), type) + assert type(cppyy.gbl.std.vector(int)()) == cppyy.gbl.std.vector(int) + + def test_templated_functions(self): + import cppyy + + pass + + def test_templated_methods(self): + import cppyy + + pass + + def test_typedefs(self): + import cppyy + + pass + + def test_unary_operators(sef): + import cppyy + + pass diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_fragile.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_fragile.py new file mode 100644 index 0000000000000..81d4d3abad8da --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_fragile.py @@ -0,0 +1,325 @@ +import py, os, sys +from pytest import raises +from .support import setup_make + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("fragileDict.so")) + +def setup_module(mod): + setup_make("fragileDict.so") + + +class TestFRAGILE: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.fragile = cppyy.load_reflection_info(cls.test_dct) + + def test01_load_failure(self): + """Test failure to load dictionary""" + + import cppyy + raises(RuntimeError, cppyy.load_reflection_info, "does_not_exist.so") + + try: + cppyy.load_reflection_info("does_not_exist.so") + except RuntimeError as e: + assert "does_not_exist.so" in str(e) + + def test02_missing_classes(self): + """Test (non-)access to missing classes""" + + import cppyy + + raises(AttributeError, getattr, cppyy.gbl, "no_such_class") + + assert cppyy.gbl.fragile is cppyy.gbl.fragile + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + + raises(AttributeError, getattr, fragile, "no_such_class") + + assert fragile.C is fragile.C + assert fragile.C == fragile.C + assert fragile.C().check() == ord('C') + + assert fragile.B is fragile.B + assert fragile.B == fragile.B + assert fragile.B().check() == ord('B') + raises(AttributeError, getattr, fragile.B().gime_no_such(), "_cpp_proxy") + + assert fragile.C is fragile.C + assert fragile.C == fragile.C + assert fragile.C().check() == ord('C') + raises(TypeError, fragile.C().use_no_such, None) + + def test03_arguments(self): + """Test reporting when providing wrong arguments""" + + import cppyy + + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + + assert fragile.D == fragile.D + assert fragile.D().check() == ord('D') + + d = fragile.D() + raises(TypeError, d.overload, None) + raises(TypeError, d.overload, None, None, None) + + d.overload('a') + d.overload(1) + + def test04_unsupported_arguments(self): + """Test arguments that are yet unsupported""" + + import cppyy + + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + + assert fragile.E == fragile.E + assert fragile.E().check() == ord('E') + + e = fragile.E() + raises(TypeError, e.overload, None) + # allowing access to e.m_pp_no_such is debatable, but it provides a raw pointer + # which may be useful ... + assert e.m_pp_no_such[0] == 0xdead + + def test05_wrong_arg_addressof(self): + """Test addressof() error reporting""" + + import cppyy + + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + + assert fragile.F == fragile.F + assert fragile.F().check() == ord('F') + + f = fragile.F() + o = object() + + cppyy.addressof(f) + raises(TypeError, cppyy.addressof, o) + raises(TypeError, cppyy.addressof, 1) + # see also test08_void_pointer_passing in test_advancedcpp.py + + def test06_wrong_this(self): + """Test that using an incorrect self argument raises""" + + import cppyy + + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + + a = fragile.A() + assert fragile.A.check(a) == ord('A') + + b = fragile.B() + assert fragile.B.check(b) == ord('B') + raises(TypeError, fragile.A.check, b) + raises(TypeError, fragile.B.check, a) + + assert not a.gime_null() + + assert isinstance(a.gime_null(), fragile.A) + raises(ReferenceError, fragile.A.check, a.gime_null()) + + def test07_unnamed_enum(self): + """Test that an unnamed enum does not cause infinite recursion""" + + import cppyy + + assert cppyy.gbl.fragile is cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + assert cppyy.gbl.fragile is fragile + + g = fragile.G() + + def test08_unhandled_scoped_datamember(self): + """Test that an unhandled scoped data member does not cause infinite recursion""" + + import cppyy + + assert cppyy.gbl.fragile is cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + assert cppyy.gbl.fragile is fragile + + h = fragile.H() + + def test09_operator_bool(self): + """Access to global vars with an operator bool() returning False""" + + import cppyy + + i = cppyy.gbl.fragile.I() + assert not i + + g = cppyy.gbl.fragile.gI + assert not g + + def test10_documentation(self): + """Check contents of documentation""" + + import cppyy + + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + + d = fragile.D() + try: + d.check(None) # raises TypeError + assert 0 + except TypeError as e: + assert "fragile::D::check()" in str(e) + assert "TypeError: takes at most 0 arguments (1 given)" in str(e) + assert "TypeError: takes at least 2 arguments (1 given)" in str(e) + + try: + d.overload(None) # raises TypeError + assert 0 + except TypeError as e: + # TODO: pypy-c does not indicate which argument failed to convert, CPython does + # likewise there are still minor differences in descriptiveness of messages + assert "fragile::D::overload()" in str(e) + assert "TypeError: takes at most 0 arguments (1 given)" in str(e) + assert "fragile::D::overload(fragile::no_such_class*)" in str(e) + #assert "no converter available for 'fragile::no_such_class*'" in str(e) + assert "void fragile::D::overload(char, int i = 0)" in str(e) + #assert "char or small int type expected" in str(e) + assert "void fragile::D::overload(int, fragile::no_such_class* p = 0)" in str(e) + #assert "int/long conversion expects an integer object" in str(e) + + j = fragile.J() + assert fragile.J.method1.__doc__ == j.method1.__doc__ + assert j.method1.__doc__ == "int fragile::J::method1(int, double)" + + f = fragile.fglobal + assert f.__doc__ == "void fragile::fglobal(int, double, char)" + + try: + o = fragile.O() # raises TypeError + assert 0 + except TypeError as e: + assert "cannot instantiate abstract class 'fragile::O'" in str(e) + + def test11_dir(self): + """Test __dir__ method""" + + import cppyy + + members = dir(cppyy.gbl.fragile) + assert 'A' in members + assert 'B' in members + assert 'C' in members + assert 'D' in members # classes + + assert 'nested1' in members # namespace + + # TODO: think this through ... probably want this, but interferes with + # the (new) policy of lazy lookups + #assert 'fglobal' in members # function + #assert 'gI'in members # variable + + def test12_imports(self): + """Test ability to import from namespace (or fail with ImportError)""" + + import cppyy + + # TODO: namespaces aren't loaded (and thus not added to sys.modules) + # with just the from ... import statement; actual use is needed + from cppyy.gbl import fragile + + def fail_import(): + from cppyy.gbl import does_not_exist + raises(ImportError, fail_import) + + from cppyy.gbl.fragile import A, B, C, D + assert cppyy.gbl.fragile.A is A + assert cppyy.gbl.fragile.B is B + assert cppyy.gbl.fragile.C is C + assert cppyy.gbl.fragile.D is D + + # according to warnings, can't test "import *" ... + + from cppyy.gbl.fragile import nested1 + assert cppyy.gbl.fragile.nested1 is nested1 + assert nested1.__name__ == 'nested1' + assert nested1.__module__ == 'cppyy.gbl.fragile' + assert nested1.__cppname__ == 'fragile::nested1' + + from cppyy.gbl.fragile.nested1 import A, nested2 + assert cppyy.gbl.fragile.nested1.A is A + assert A.__name__ == 'A' + assert A.__module__ == 'cppyy.gbl.fragile.nested1' + assert A.__cppname__ == 'fragile::nested1::A' + assert cppyy.gbl.fragile.nested1.nested2 is nested2 + assert nested2.__name__ == 'nested2' + assert nested2.__module__ == 'cppyy.gbl.fragile.nested1' + assert nested2.__cppname__ == 'fragile::nested1::nested2' + + from cppyy.gbl.fragile.nested1.nested2 import A, nested3 + assert cppyy.gbl.fragile.nested1.nested2.A is A + assert A.__name__ == 'A' + assert A.__module__ == 'cppyy.gbl.fragile.nested1.nested2' + assert A.__cppname__ == 'fragile::nested1::nested2::A' + assert cppyy.gbl.fragile.nested1.nested2.nested3 is nested3 + assert nested3.__name__ == 'nested3' + assert nested3.__module__ == 'cppyy.gbl.fragile.nested1.nested2' + assert nested3.__cppname__ == 'fragile::nested1::nested2::nested3' + + from cppyy.gbl.fragile.nested1.nested2.nested3 import A + assert cppyy.gbl.fragile.nested1.nested2.nested3.A is nested3.A + assert A.__name__ == 'A' + assert A.__module__ == 'cppyy.gbl.fragile.nested1.nested2.nested3' + assert A.__cppname__ == 'fragile::nested1::nested2::nested3::A' + + # test writability of __module__ + nested3.__module__ = "peanut butter" + assert nested3.__module__ == "peanut butter" + + # classes in namespace should inherit + assert A.__module__ == 'peanut butter.nested3' + assert 'peanut butter' in repr(A) + assert 'class' in repr(A) + assert 'peanut butter' in repr(nested3) + assert 'namespace' in repr(nested3) + + # as should objects + a = A() + assert 'peanut butter' in repr(a) + assert 'object' in repr(a) + + def test13_missing_casts(self): + """Test proper handling when a hierarchy is not fully available""" + + import cppyy + + k = cppyy.gbl.fragile.K() + + assert k is k.GimeK(False) + assert k is not k.GimeK(True) + + kd = k.GimeK(True) + assert kd is k.GimeK(True) + assert kd is not k.GimeK(False) + + l = k.GimeL() + assert l is k.GimeL() + + def test14_double_enum_trouble(self): + """Test a redefinition of enum in a derived class""" + + return # don't bother; is fixed in cling-support + + import cppyy + + M = cppyy.gbl.fragile.M + N = cppyy.gbl.fragile.N + + assert M.kOnce == N.kOnce + assert M.kTwice == N.kTwice + assert M.__dict__['kTwice'] is not N.__dict__['kTwice'] diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_operators.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_operators.py new file mode 100644 index 0000000000000..bbeeeca8ec631 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_operators.py @@ -0,0 +1,173 @@ +import py, os, sys +from pytest import raises +from .support import setup_make, pylong, maxvalue + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("operatorsDict.so")) + +def setup_module(mod): + setup_make("operatorsDict.so") + + +class TestOPERATORS: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.operators = cppyy.load_reflection_info(cls.test_dct) + cls.N = cppyy.gbl.N + + def teardown_method(self, meth): + import gc + gc.collect() + + def test01_math_operators(self): + """Test overloading of math operators""" + + import cppyy + number = cppyy.gbl.number + + assert (number(20) + number(10)) == number(30) + assert (number(20) + 10 ) == number(30) + assert (number(20) - number(10)) == number(10) + assert (number(20) - 10 ) == number(10) + assert (number(20) / number(10)) == number(2) + assert (number(20) / 10 ) == number(2) + assert (number(20) * number(10)) == number(200) + assert (number(20) * 10 ) == number(200) + assert (number(20) % 10 ) == number(0) + assert (number(20) % number(10)) == number(0) + assert (number(5) & number(14)) == number(4) + assert (number(5) | number(14)) == number(15) + assert (number(5) ^ number(14)) == number(11) + assert (number(5) << 2) == number(20) + assert (number(20) >> 2) == number(5) + + def test02_unary_math_operators(self): + """Test overloading of unary math operators""" + + import cppyy + number = cppyy.gbl.number + + n = number(20) + n += number(10) + n -= number(10) + n *= number(10) + n /= number(2) + assert n == number(100) + + nn = -n; + assert nn == number(-100) + + def test03_comparison_operators(self): + """Test overloading of comparison operators""" + + import cppyy + number = cppyy.gbl.number + + assert (number(20) > number(10)) == True + assert (number(20) < number(10)) == False + assert (number(20) >= number(20)) == True + assert (number(20) <= number(10)) == False + assert (number(20) != number(10)) == True + assert (number(20) == number(10)) == False + + def test04_boolean_operator(self): + """Test implementation of operator bool""" + + import cppyy + number = cppyy.gbl.number + + n = number(20) + assert n + + n = number(0) + assert not n + + def test05_exact_types(self): + """Test converter operators of exact types""" + + import cppyy + gbl = cppyy.gbl + + o = gbl.operator_char_star() + assert o.m_str == 'operator_char_star' + assert str(o) == 'operator_char_star' + + o = gbl.operator_const_char_star() + assert o.m_str == 'operator_const_char_star' + assert str(o) == 'operator_const_char_star' + + o = gbl.operator_int(); o.m_int = -13 + assert o.m_int == -13 + assert int(o) == -13 + + o = gbl.operator_long(); o.m_long = 42 + assert o.m_long == 42 + assert pylong(o) == 42 + + o = gbl.operator_double(); o.m_double = 3.1415 + assert o.m_double == 3.1415 + assert float(o) == 3.1415 + + def test06_approximate_types(self): + """Test converter operators of approximate types""" + + import cppyy, sys + gbl = cppyy.gbl + + o = gbl.operator_short(); o.m_short = 256 + assert o.m_short == 256 + assert int(o) == 256 + + o = gbl.operator_unsigned_int(); o.m_uint = 2147483647 + 32 + assert o.m_uint == 2147483647 + 32 + assert pylong(o) == 2147483647 + 32 + + o = gbl.operator_unsigned_long(); + o.m_ulong = maxvalue + 128 + assert o.m_ulong == maxvalue + 128 + assert pylong(o) == maxvalue + 128 + + o = gbl.operator_float(); o.m_float = 3.14 + assert round(o.m_float - 3.14, 5) == 0. + assert round(float(o) - 3.14, 5) == 0. + + def test07_virtual_operator_eq(self): + """Test use of virtual bool operator==""" + + import cppyy + + b1 = cppyy.gbl.v_opeq_base(1) + b1a = cppyy.gbl.v_opeq_base(1) + b2 = cppyy.gbl.v_opeq_base(2) + b2a = cppyy.gbl.v_opeq_base(2) + + assert b1 == b1 + assert b1 == b1a + assert not b1 == b2 + assert not b1 == b2a + assert b2 == b2 + assert b2 == b2a + + d1 = cppyy.gbl.v_opeq_derived(1) + d1a = cppyy.gbl.v_opeq_derived(1) + d2 = cppyy.gbl.v_opeq_derived(2) + d2a = cppyy.gbl.v_opeq_derived(2) + + # derived operator== returns opposite + assert not d1 == d1 + assert not d1 == d1a + assert d1 == d2 + assert d1 == d2a + assert not d2 == d2 + assert not d2 == d2a + + # the following is a wee bit interesting due to python resolution + # rules on the one hand, and C++ inheritance on the other: python + # will never select the derived comparison b/c the call will fail + # to pass a base through a const derived& + assert b1 == d1 + assert d1 == b1 + assert not b1 == d2 + assert not d2 == b1 + diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_overloads.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_overloads.py new file mode 100644 index 0000000000000..82364876dc5de --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_overloads.py @@ -0,0 +1,138 @@ +import py, os, sys +from pytest import raises +from .support import setup_make + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("overloadsDict.so")) + +def setup_module(mod): + setup_make("overloadsDict.so") + + +class TestOVERLOADS: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.overloads = cppyy.load_reflection_info(cls.test_dct) + + def test01_class_based_overloads(self): + """Test functions overloaded on different C++ clases""" + + import cppyy + a_overload = cppyy.gbl.a_overload + b_overload = cppyy.gbl.b_overload + c_overload = cppyy.gbl.c_overload + d_overload = cppyy.gbl.d_overload + + ns_a_overload = cppyy.gbl.ns_a_overload + ns_b_overload = cppyy.gbl.ns_b_overload + + assert c_overload().get_int(a_overload()) == 42 + assert c_overload().get_int(b_overload()) == 13 + assert d_overload().get_int(a_overload()) == 42 + assert d_overload().get_int(b_overload()) == 13 + + assert c_overload().get_int(ns_a_overload.a_overload()) == 88 + assert c_overload().get_int(ns_b_overload.a_overload()) == -33 + + assert d_overload().get_int(ns_a_overload.a_overload()) == 88 + assert d_overload().get_int(ns_b_overload.a_overload()) == -33 + + def test02_class_based_overloads_explicit_resolution(self): + """Test explicitly resolved function overloads""" + + import cppyy + a_overload = cppyy.gbl.a_overload + b_overload = cppyy.gbl.b_overload + c_overload = cppyy.gbl.c_overload + d_overload = cppyy.gbl.d_overload + + ns_a_overload = cppyy.gbl.ns_a_overload + + c = c_overload() + raises(TypeError, c.__dispatch__, 'get_int', 12) + raises(LookupError, c.__dispatch__, 'get_int', 'does_not_exist') + assert c.__dispatch__('get_int', 'a_overload*')(a_overload()) == 42 + assert c.__dispatch__('get_int', 'b_overload*')(b_overload()) == 13 + + assert c_overload().__dispatch__('get_int', 'a_overload*')(a_overload()) == 42 + # TODO: #assert c_overload.__dispatch__('get_int', 'b_overload*')(c, b_overload()) == 13 + + d = d_overload() + assert d.__dispatch__('get_int', 'a_overload*')(a_overload()) == 42 + assert d.__dispatch__('get_int', 'b_overload*')(b_overload()) == 13 + + nb = ns_a_overload.b_overload() + raises(TypeError, nb.f, c_overload()) + + def test03_fragile_class_based_overloads(self): + """Test functions overloaded on void* and non-existing classes""" + + # TODO: make Reflex generate unknown classes ... + + import cppyy + more_overloads = cppyy.gbl.more_overloads + aa_ol = cppyy.gbl.aa_ol +# bb_ol = cppyy.gbl.bb_ol + cc_ol = cppyy.gbl.cc_ol +# dd_ol = cppyy.gbl.dd_ol + + assert more_overloads().call(aa_ol()) == "aa_ol" +# assert more_overloads().call(bb_ol()) == "dd_ol" # <- bb_ol has an unknown + void* + assert more_overloads().call(cc_ol()) == "cc_ol" +# assert more_overloads().call(dd_ol()) == "dd_ol" # <- dd_ol has an unknown + + def test04_fully_fragile_overloads(self): + """Test that unknown* is preferred over unknown&""" + + # TODO: make Reflex generate unknown classes ... + return + + import cppyy + more_overloads2 = cppyy.gbl.more_overloads2 + bb_ol = cppyy.gbl.bb_ol + dd_ol = cppyy.gbl.dd_ol + + assert more_overloads2().call(bb_ol()) == "bb_olptr" + assert more_overloads2().call(dd_ol(), 1) == "dd_olptr" + + def test05_array_overloads(self): + """Test functions overloaded on different arrays""" + + import cppyy + c_overload = cppyy.gbl.c_overload + d_overload = cppyy.gbl.d_overload + + from array import array + + ai = array('i', [525252]) + assert c_overload().get_int(ai) == 525252 + assert d_overload().get_int(ai) == 525252 + + ah = array('h', [25]) + assert c_overload().get_int(ah) == 25 + assert d_overload().get_int(ah) == 25 + + def test06_double_int_overloads(self): + """Test overloads on int/doubles""" + + import cppyy + more_overloads = cppyy.gbl.more_overloads + + assert more_overloads().call(1) == "int" + assert more_overloads().call(1.) == "double" + assert more_overloads().call1(1) == "int" + assert more_overloads().call1(1.) == "double" + + def test07_mean_overloads(self): + """Adapted test for array overloading""" + + import cppyy, array + cmean = cppyy.gbl.calc_mean + + numbers = [8, 2, 4, 2, 4, 2, 4, 4, 1, 5, 6, 3, 7] + mean, median = 4.0, 4.0 + + for l in ['f', 'd', 'i', 'h', 'l']: + a = array.array(l, numbers) + assert round(cmean(len(a), a) - mean, 8) == 0 diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_pythonify.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_pythonify.py new file mode 100644 index 0000000000000..21ba401082e6d --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_pythonify.py @@ -0,0 +1,414 @@ +import py, os, sys +from pytest import raises +from .support import setup_make, pylong + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("example01Dict.so")) + +def setup_module(mod): + setup_make("example01Dict.so") + + +class TestPYTHONIFY: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.example01 = cppyy.load_reflection_info(cls.test_dct) + + def test01_load_dictionary_cache(self): + """Test whether loading a dictionary twice results in the same object.""" + import cppyy + lib2 = cppyy.load_reflection_info(self.test_dct) + assert self.example01 is lib2 + + def test02_finding_classes(self): + """Test the lookup of a class, and its caching.""" + import cppyy + example01_class = cppyy.gbl.example01 + cl2 = cppyy.gbl.example01 + assert example01_class is cl2 + + raises(AttributeError, 'cppyy.gbl.nonexistingclass') + + def test03_calling_static_functions(self): + """Test calling of static methods.""" + import cppyy, sys, math + example01_class = cppyy.gbl.example01 + res = example01_class.staticAddOneToInt(1) + assert res == 2 + + res = example01_class.staticAddOneToInt(pylong(1)) + assert res == 2 + res = example01_class.staticAddOneToInt(1, 2) + assert res == 4 + res = example01_class.staticAddOneToInt(-1) + assert res == 0 + maxint32 = int(2 ** 31 - 1) + res = example01_class.staticAddOneToInt(maxint32-1) + assert res == maxint32 + res = example01_class.staticAddOneToInt(maxint32) + assert res == -maxint32-1 + + raises(TypeError, 'example01_class.staticAddOneToInt(1, [])') + raises(TypeError, 'example01_class.staticAddOneToInt(1.)') + raises(TypeError, 'example01_class.staticAddOneToInt(maxint32+1)') + res = example01_class.staticAddToDouble(0.09) + assert res == 0.09 + 0.01 + + res = example01_class.staticAtoi("1") + assert res == 1 + + res = example01_class.staticStrcpy("aap") # TODO: this leaks + assert res == "aap" + + res = example01_class.staticStrcpy(u"aap") # TODO: this leaks + assert res == "aap" + + raises(TypeError, 'example01_class.staticStrcpy(1.)') # TODO: this leaks + + def test04_constructing_and_calling(self): + """Test object and method calls.""" + import cppyy + example01_class = cppyy.gbl.example01 + assert example01_class.getCount() == 0 + instance = example01_class(7) + assert example01_class.getCount() == 1 + res = instance.addDataToInt(4) + assert res == 11 + res = instance.addDataToInt(-4) + assert res == 3 + instance.__destruct__() + assert example01_class.getCount() == 0 + raises(ReferenceError, 'instance.addDataToInt(4)') + + instance = example01_class(7) + instance2 = example01_class(8) + assert example01_class.getCount() == 2 + instance.__destruct__() + assert example01_class.getCount() == 1 + instance2.__destruct__() + assert example01_class.getCount() == 0 + + instance = example01_class(13) + res = instance.addDataToDouble(16) + assert round(res-29, 8) == 0. + instance.__destruct__() + instance = example01_class(-13) + res = instance.addDataToDouble(16) + assert round(res-3, 8) == 0. + instance.__destruct__() + + instance = example01_class(42) + assert example01_class.getCount() == 1 + + res = instance.addDataToAtoi("13") + assert res == 55 + + res = instance.addToStringValue("12") # TODO: this leaks + assert res == "54" + res = instance.addToStringValue("-12") # TODO: this leaks + assert res == "30" + + res = instance.staticAddOneToInt(pylong(1)) + assert res == 2 + + instance.__destruct__() + assert example01_class.getCount() == 0 + + def test05_passing_object_by_pointer(self): + import cppyy + example01_class = cppyy.gbl.example01 + payload_class = cppyy.gbl.payload + + e = example01_class(14) + pl = payload_class(3.14) + assert round(pl.getData()-3.14, 8) == 0 + + example01_class.staticSetPayload(pl, 41.) + assert pl.getData() == 41. + example01_class.staticSetPayload(pl, 43.) + assert pl.getData() == 43. + e.staticSetPayload(pl, 45.) + assert pl.getData() == 45. + + e.setPayload(pl) + assert round(pl.getData()-14., 8) == 0 + + pl.__destruct__() + e.__destruct__() + assert example01_class.getCount() == 0 + + def test06_returning_object_by_pointer(self): + import cppyy + example01_class = cppyy.gbl.example01 + payload_class = cppyy.gbl.payload + + pl = payload_class(3.14) + assert round(pl.getData()-3.14, 8) == 0 + + pl2 = example01_class.staticCyclePayload(pl, 38.) + assert pl2.getData() == 38. + + e = example01_class(14) + + pl2 = e.cyclePayload(pl) + assert round(pl2.getData()-14., 8) == 0 + + pl.__destruct__() + e.__destruct__() + assert example01_class.getCount() == 0 + + def test07_returning_object_by_value(self): + import cppyy + example01_class = cppyy.gbl.example01 + payload_class = cppyy.gbl.payload + + pl = payload_class(3.14) + assert round(pl.getData()-3.14, 8) == 0 + + pl2 = example01_class.staticCopyCyclePayload(pl, 38.) + assert pl2.getData() == 38. + pl2.__destruct__() + + e = example01_class(14) + + pl2 = e.copyCyclePayload(pl) + assert round(pl2.getData()-14., 8) == 0 + pl2.__destruct__() + + pl.__destruct__() + e.__destruct__() + assert example01_class.getCount() == 0 + + def test08_global_functions(self): + import cppyy + + assert cppyy.gbl.globalAddOneToInt(3) == 4 # creation lookup + assert cppyy.gbl.globalAddOneToInt(3) == 4 # cached lookup + + assert cppyy.gbl.ns_example01.globalAddOneToInt(4) == 5 + assert cppyy.gbl.ns_example01.globalAddOneToInt(4) == 5 + + def test09_memory(self): + """Test proper C++ destruction by the garbage collector""" + + import cppyy, gc + example01_class = cppyy.gbl.example01 + payload_class = cppyy.gbl.payload + + pl = payload_class(3.14) + assert payload_class.count == 1 + assert round(pl.getData()-3.14, 8) == 0 + + pl2 = example01_class.staticCopyCyclePayload(pl, 38.) + assert payload_class.count == 2 + assert pl2.getData() == 38. + pl2 = None + gc.collect() + assert payload_class.count == 1 + + e = example01_class(14) + + pl2 = e.copyCyclePayload(pl) + assert payload_class.count == 2 + assert round(pl2.getData()-14., 8) == 0 + pl2 = None + gc.collect() + assert payload_class.count == 1 + + pl = None + e = None + gc.collect() + assert payload_class.count == 0 + assert example01_class.getCount() == 0 + + pl = payload_class(3.14) + pl_a = example01_class.staticCyclePayload(pl, 66.) + pl_a.getData() == 66. + assert payload_class.count == 1 + pl_a = None + pl = None + gc.collect() + assert payload_class.count == 0 + + # TODO: need ReferenceError on touching pl_a + + def test10_default_arguments(self): + """Test propagation of default function arguments""" + + import cppyy + a = cppyy.gbl.ArgPasser() + + # NOTE: when called through the stub, default args are fine + f = a.stringRef + s = cppyy.gbl.std.string + assert f(s("aap"), 0, s("noot")) == "aap" + assert f(s("noot"), 1) == "default" + assert f(s("mies")) == "mies" + + for itype in ['short', 'ushort', 'int', 'uint', 'long', 'ulong']: + g = getattr(a, '%sValue' % itype) + raises(TypeError, 'g(1, 2, 3, 4, 6)') + assert g(11, 0, 12, 13) == 11 + assert g(11, 1, 12, 13) == 12 + assert g(11, 1, 12) == 12 + assert g(11, 2, 12) == 2 + assert g(11, 1) == 1 + assert g(11, 2) == 2 + assert g(11) == 11 + + for ftype in ['float', 'double']: + g = getattr(a, '%sValue' % ftype) + raises(TypeError, 'g(1., 2, 3., 4., 6.)') + assert g(11., 0, 12., 13.) == 11. + assert g(11., 1, 12., 13.) == 12. + assert g(11., 1, 12.) == 12. + assert g(11., 2, 12.) == 2. + assert g(11., 1) == 1. + assert g(11., 2) == 2. + assert g(11.) == 11. + + def test11_overload_on_arguments(self): + """Test functions overloaded on arguments""" + + import cppyy + e = cppyy.gbl.example01(1) + + assert e.addDataToInt(2) == 3 + assert e.overloadedAddDataToInt(3) == 4 + assert e.overloadedAddDataToInt(4, 5) == 10 + assert e.overloadedAddDataToInt(6, 7, 8) == 22 + + def test12_typedefs(self): + """Test access and use of typedefs""" + + import cppyy + + assert cppyy.gbl.example01 == cppyy.gbl.example01_t + + def test13_underscore_in_class_name(self): + """Test recognition of '_' as part of a valid class name""" + + import cppyy + + assert cppyy.gbl.z_ == cppyy.gbl.z_ + + z = cppyy.gbl.z_() + + assert hasattr(z, 'myint') + assert z.gime_z_(z) + + def test14_bound_unbound_calls(self): + """Test (un)bound method calls""" + + import cppyy + + raises(TypeError, cppyy.gbl.example01.addDataToInt, 1) + + meth = cppyy.gbl.example01.addDataToInt + raises(TypeError, meth) + raises(TypeError, meth, 1) + + e = cppyy.gbl.example01(2) + assert 5 == meth(e, 3) + + def test15_installable_function(self): + """Test installing and calling global C++ function as python method""" + + import cppyy + + cppyy.gbl.example01.fresh = cppyy.gbl.installableAddOneToInt + + e = cppyy.gbl.example01(0) + assert 2 == e.fresh(1) + assert 3 == e.fresh(2) + + + def test16_subclassing(self): + """A sub-class on the python side should have that class as type""" + + import cppyy, gc + gc.collect() + + example01 = cppyy.gbl.example01 + + assert example01.getCount() == 0 + + o = example01() + assert type(o) == example01 + assert example01.getCount() == 1 + o.__destruct__() + assert example01.getCount() == 0 + + class MyClass1(example01): + def myfunc(self): + return 1 + + o = MyClass1() + assert type(o) == MyClass1 + assert isinstance(o, example01) + assert example01.getCount() == 1 + assert o.myfunc() == 1 + o.__destruct__() + assert example01.getCount() == 0 + + class MyClass2(example01): + def __init__(self, what): + example01.__init__(self) + self.what = what + + o = MyClass2('hi') + assert type(o) == MyClass2 + assert example01.getCount() == 1 + assert o.what == 'hi' + o.__destruct__() + + assert example01.getCount() == 0 + + +class TestPYTHONIFY_UI: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.example01 = cppyy.load_reflection_info(cls.test_dct) + + def test01_pythonizations(self): + """Test addition of user-defined pythonizations""" + + import cppyy + + def example01a_pythonize(pyclass, pyname): + if pyname == 'example01a': + def getitem(self, idx): + return self.addDataToInt(idx) + pyclass.__getitem__ = getitem + + cppyy.py.add_pythonization(example01a_pythonize) + + e = cppyy.gbl.example01a(1) + + assert e[0] == 1 + assert e[1] == 2 + assert e[5] == 6 + + def test02_fragile_pythonizations(self): + """Test pythonizations error reporting""" + + import cppyy + + example01_pythonize = 1 + raises(TypeError, cppyy.py.add_pythonization, example01_pythonize) + + def test03_write_access_to_globals(self): + """Test overwritability of globals""" + + import cppyy + + oldval = cppyy.gbl.ns_example01.gMyGlobalInt + assert oldval == 99 + + proxy = cppyy.gbl.ns_example01.__class__.__dict__['gMyGlobalInt'] + cppyy.gbl.ns_example01.gMyGlobalInt = 3 + assert proxy.__get__(proxy, None) == 3 + + cppyy.gbl.ns_example01.gMyGlobalInt = oldval diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_pythonization.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_pythonization.py new file mode 100644 index 0000000000000..370ba3a3275f8 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_pythonization.py @@ -0,0 +1,196 @@ +import py, os, sys +from pytest import raises +from .support import setup_make, pylong + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("pythonizablesDict.so")) + +def setup_module(mod): + setup_make("pythonizablesDict.so") + + +class TestClassPYTHONIZATION: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.pyzables = cppyy.load_reflection_info(cls.test_dct) + + def test00_api(self): + """Test basic semantics of the pythonization API""" + + import cppyy + + raises(TypeError, cppyy.py.add_pythonization, 1) + + def pythonizor1(klass, name): + pass + + def pythonizor2(klass, name): + pass + + pythonizor3 = pythonizor1 + + cppyy.py.add_pythonization(pythonizor1) + assert cppyy.py.remove_pythonization(pythonizor2) == False + assert cppyy.py.remove_pythonization(pythonizor3) == True + + def pythonizor(klass, name): + if name == 'pyzables::SomeDummy1': + klass.test = 1 + + cppyy.py.add_pythonization(pythonizor) + assert cppyy.gbl.pyzables.SomeDummy1.test == 1 + + def pythonizor(klass, name): + if name == 'SomeDummy2': + klass.test = 2 + cppyy.py.add_pythonization(pythonizor, 'pyzables') + + def pythonizor(klass, name): + if name == 'pyzables::SomeDummy2': + klass.test = 3 + cppyy.py.add_pythonization(pythonizor) + + assert cppyy.gbl.pyzables.SomeDummy2.test == 2 + + def root_pythonizor(klass, name): + if name == 'TString': + klass.__len__ = klass.Length + + cppyy.py.add_pythonization(root_pythonizor) + + assert len(cppyy.gbl.TString("aap")) == 3 + + def test01_size_mapping(self): + """Use composites to map GetSize() onto buffer returns""" + + import cppyy + + def set_size(self, buf): + buf.reshape((self.GetN(),)) + return buf + + cppyy.py.add_pythonization( + cppyy.py.compose_method('NakedBuffers$', 'Get[XY]$', set_size), 'pyzables') + + bsize, xval, yval = 3, 2, 5 + m = cppyy.gbl.pyzables.NakedBuffers(bsize, xval, yval) + + x = m.GetX() + assert len(x) == bsize + assert list(x) == list(map(lambda x: x*xval, range(bsize))) + + y = m.GetY() + assert len(y) == bsize + assert list(y) == list(map(lambda x: x*yval, range(bsize))) + + def test02_size_mapping_of_templated_method(self): + """Use composites to map GetSize() onto buffer returns""" + + import cppyy + + def set_size(self, buf): + buf.reshape((self.GetN(),)) + return buf + + cppyy.py.add_pythonization( + cppyy.py.compose_method('NakedBuffers2.*Vector.*', 'Get[XY]$', set_size), 'pyzables') + + bsize, xval, yval = 3, 2, 5 + m = cppyy.gbl.pyzables.NakedBuffers2[cppyy.gbl.pyzables.Vector](bsize, xval, yval) + + x = m.GetX() + assert len(x) == bsize + assert list(x) == list(map(lambda x: x*xval, range(bsize))) + + y = m.GetY() + assert len(y) == bsize + assert list(y) == list(map(lambda x: x*yval, range(bsize))) + + def test03_type_pinning(self): + """Verify pinnability of returns""" + + import cppyy + + cppyy.gbl.pyzables.GimeDerived._creates = True + + result = cppyy.gbl.pyzables.GimeDerived() + assert type(result) == cppyy.gbl.pyzables.MyDerived + + cppyy.py.pin_type(cppyy.gbl.pyzables.MyBase) + assert type(result) == cppyy.gbl.pyzables.MyDerived + + + def test04_transparency(self): + """Transparent use of smart pointers""" + + import cppyy + + Countable = cppyy.gbl.pyzables.Countable + mine = cppyy.gbl.pyzables.mine + + assert type(mine) == Countable + assert mine.m_check == 0xcdcdcdcd + assert type(mine.__smartptr__()) == cppyy.gbl.std.shared_ptr(Countable) + assert mine.__smartptr__().get().m_check == 0xcdcdcdcd + assert mine.say_hi() == "Hi!" + + def test05_converters(self): + """Smart pointer argument passing""" + + import cppyy + + pz = cppyy.gbl.pyzables + mine = pz.mine + + assert 0xcdcdcdcd == pz.pass_mine_rp_ptr(mine) + assert 0xcdcdcdcd == pz.pass_mine_rp_ref(mine) + assert 0xcdcdcdcd == pz.pass_mine_rp(mine) + + assert 0xcdcdcdcd == pz.pass_mine_sp_ptr(mine) + assert 0xcdcdcdcd == pz.pass_mine_sp_ref(mine) + + assert 0xcdcdcdcd == pz.pass_mine_sp_ptr(mine.__smartptr__()) + assert 0xcdcdcdcd == pz.pass_mine_sp_ref(mine.__smartptr__()) + + assert 0xcdcdcdcd == pz.pass_mine_sp(mine) + assert 0xcdcdcdcd == pz.pass_mine_sp(mine.__smartptr__()) + + # TODO: + # cppyy.gbl.mine = mine + pz.renew_mine() + + def test06_executors(self): + """Smart pointer return types""" + + import cppyy + + pz = cppyy.gbl.pyzables + Countable = pz.Countable + + mine = pz.gime_mine_ptr() + assert type(mine) == Countable + assert mine.m_check == 0xcdcdcdcd + assert type(mine.__smartptr__()) == cppyy.gbl.std.shared_ptr(Countable) + assert mine.__smartptr__().get().m_check == 0xcdcdcdcd + assert mine.say_hi() == "Hi!" + + mine = pz.gime_mine_ref() + assert type(mine) == Countable + assert mine.m_check == 0xcdcdcdcd + assert type(mine.__smartptr__()) == cppyy.gbl.std.shared_ptr(Countable) + assert mine.__smartptr__().get().m_check == 0xcdcdcdcd + assert mine.say_hi() == "Hi!" + + mine = pz.gime_mine() + assert type(mine) == Countable + assert mine.m_check == 0xcdcdcdcd + assert type(mine.__smartptr__()) == cppyy.gbl.std.shared_ptr(Countable) + assert mine.__smartptr__().get().m_check == 0xcdcdcdcd + assert mine.say_hi() == "Hi!" + + +## actual test run +if __name__ == '__main__': + result = run_pytest(__file__) + sys.exit(result) diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_regression.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_regression.py new file mode 100644 index 0000000000000..5cad0ce6df10c --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_regression.py @@ -0,0 +1,93 @@ +import py, os, sys +from pytest import raises +from .support import setup_make + + +class TestREGRESSION: + helpout = [] + + def setup_class(cls): + import cppyy + + def stringpager(text, cls=cls): + cls.helpout.append(text) + + import pydoc + pydoc.pager = stringpager + + def test01_kdcraw(self): + """Doc strings for KDcrawIface (used to crash).""" + + import cppyy, pydoc + + # TODO: run a find for these paths + qtpath = "/usr/include/qt5" + kdcraw_h = "/usr/include/KF5/KDCRAW/kdcraw/kdcraw.h" + if not os.path.isdir(qtpath) or not os.path.exists(kdcraw_h): + import warnings + warnings.warn("no KDE/Qt found, skipping test01_kdcraw") + return + + # need to resolve qt_version_tag for the incremental compiler; since + # it's not otherwise used, just make something up + cppyy.cppdef("int qt_version_tag = 42;") + cppyy.add_include_path(qtpath) + cppyy.include(kdcraw_h) + + from cppyy.gbl import KDcrawIface + + self.__class__.helpout = [] + pydoc.doc(KDcrawIface.KDcraw) + helptext = ''.join(self.__class__.helpout) + assert 'KDcraw' in helptext + assert 'CPPInstance' in helptext + + def test02_dir(self): + """For the same reasons as test01_kdcraw, this used to crash.""" + + import cppyy, pydoc + + assert not '__abstractmethods__' in dir(cppyy.gbl.gInterpreter) + assert '__class__' in dir(cppyy.gbl.gInterpreter) + + self.__class__.helpout = [] + pydoc.doc(cppyy.gbl.gInterpreter) + helptext = ''.join(self.__class__.helpout) + assert 'TInterpreter' in helptext + assert 'CPPInstance' in helptext + assert 'AddIncludePath' in helptext + + cppyy.cppdef("namespace cppyy_regression_test { void iii() {}; }") + + assert not 'iii' in cppyy.gbl.cppyy_regression_test.__dict__ + assert not '__abstractmethods__' in dir(cppyy.gbl.cppyy_regression_test) + assert '__class__' in dir(cppyy.gbl.cppyy_regression_test) + assert 'iii' in dir(cppyy.gbl.cppyy_regression_test) + + assert not 'iii' in cppyy.gbl.cppyy_regression_test.__dict__ + assert cppyy.gbl.cppyy_regression_test.iii + assert 'iii' in cppyy.gbl.cppyy_regression_test.__dict__ + + self.__class__.helpout = [] + pydoc.doc(cppyy.gbl.cppyy_regression_test) + helptext = ''.join(self.__class__.helpout) + assert 'CPPInstance' in helptext + + def test03_pyfunc_doc(self): + """Help on a generated pyfunc used to crash.""" + + import cppyy, distutils, pydoc, sys + + cppyy.add_include_path(distutils.sysconfig_get_python_inc()) + if sys.hexversion < 0x3000000: + cppyy.cppdef("#undef _POSIX_C_SOURCE") + cppyy.cppdef("#undef _XOPEN_SOURCE") + else: + cppyy.cppdef("#undef slots") # potentially pulled in by Qt/xapian.h + + cppyy.cppdef("""#include "Python.h" + long py2long(PyObject* obj) { return PyLong_AsLong(obj); }""") + + pydoc.doc(cppyy.gbl.py2long) + + assert 1 == cppyy.gbl.py2long(1) diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_stltypes.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_stltypes.py new file mode 100644 index 0000000000000..ddef4f84077ee --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_stltypes.py @@ -0,0 +1,547 @@ +import py, os, sys +from pytest import raises +from .support import setup_make, maxvalue + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("stltypesDict.so")) + +def setup_module(mod): + setup_make("stltypesDict.so") + + +class TestSTLVECTOR: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.stltypes = cppyy.load_reflection_info(cls.test_dct) + cls.N = cppyy.gbl.N + + def test01_builtin_type_vector_types(self): + """Test access to std::vector/std::vector""" + + import cppyy + + assert cppyy.gbl.std is cppyy.gbl.std + assert cppyy.gbl.std.vector is cppyy.gbl.std.vector + + assert callable(cppyy.gbl.std.vector) + + type_info = ( + ("int", int), + ("float", "float"), + ("double", "double"), + ) + + for c_type, p_type in type_info: + tv1 = getattr(cppyy.gbl.std, 'vector<%s>' % c_type) + tv2 = cppyy.gbl.std.vector(p_type) + assert tv1 is tv2 + assert tv1.iterator is cppyy.gbl.std.vector(p_type).iterator + + #----- + v = tv1(); v += range(self.N) # default args from Reflex are useless :/ + if p_type == int: # only type with == and != reflected in .xml + assert v.begin().__eq__(v.begin()) + assert v.begin() == v.begin() + assert v.end() == v.end() + assert v.begin() != v.end() + assert v.end() != v.begin() + + #----- + for i in range(self.N): + v[i] = i + assert v[i] == i + assert v.at(i) == i + + assert v.size() == self.N + assert len(v) == self.N + + #----- + v = tv1() + for i in range(self.N): + v.push_back(i) + assert v.size() == i+1 + assert v.at(i) == i + assert v[i] == i + + assert v.size() == self.N + assert len(v) == self.N + + def test02_user_type_vector_type(self): + """Test access to an std::vector""" + + import cppyy + + assert cppyy.gbl.std is cppyy.gbl.std + assert cppyy.gbl.std.vector is cppyy.gbl.std.vector + + assert callable(cppyy.gbl.std.vector) + + tv1 = getattr(cppyy.gbl.std, 'vector') + tv2 = cppyy.gbl.std.vector('just_a_class') + tv3 = cppyy.gbl.std.vector(cppyy.gbl.just_a_class) + + assert tv1 is tv2 + assert tv2 is tv3 + + v = tv3() + assert hasattr(v, 'size' ) + assert hasattr(v, 'push_back' ) + assert hasattr(v, '__getitem__' ) + assert hasattr(v, 'begin' ) + assert hasattr(v, 'end' ) + + for i in range(self.N): + v.push_back(cppyy.gbl.just_a_class()) + v[i].m_i = i + assert v[i].m_i == i + + assert len(v) == self.N + v.__destruct__() + + def test03_empty_vector_type(self): + """Test behavior of empty std::vector""" + + import cppyy + + v = cppyy.gbl.std.vector(int)() + for arg in v: + pass + v.__destruct__() + + def test04_vector_iteration(self): + """Test iteration over an std::vector""" + + import cppyy + + v = cppyy.gbl.std.vector(int)() + + for i in range(self.N): + v.push_back(i) + assert v.size() == i+1 + assert v.at(i) == i + assert v[i] == i + + assert v.size() == self.N + assert len(v) == self.N + + i = 0 + for arg in v: + assert arg == i + i += 1 + + assert list(v) == [i for i in range(self.N)] + + v.__destruct__() + + def test05_push_back_iterables_with_iadd(self): + """Test usage of += of iterable on push_back-able container""" + + import cppyy + + v = cppyy.gbl.std.vector(int)() + + v += [1, 2, 3] + assert len(v) == 3 + assert v[0] == 1 + assert v[1] == 2 + assert v[2] == 3 + + v += (4, 5, 6) + assert len(v) == 6 + assert v[3] == 4 + assert v[4] == 5 + assert v[5] == 6 + + raises(TypeError, v.__iadd__, (7, '8')) # string shouldn't pass + assert len(v) == 7 # TODO: decide whether this should roll-back + + v2 = cppyy.gbl.std.vector(int)() + v2 += [8, 9] + assert len(v2) == 2 + assert v2[0] == 8 + assert v2[1] == 9 + + v += v2 + assert len(v) == 9 + assert v[6] == 7 + assert v[7] == 8 + assert v[8] == 9 + + def test06_vector_indexing(self): + """Test python-style indexing to an std::vector""" + + import cppyy + + v = cppyy.gbl.std.vector(int)() + + for i in range(self.N): + v.push_back(i) + + raises(IndexError, 'v[self.N]') + raises(IndexError, 'v[self.N+1]') + + assert v[-1] == self.N-1 + assert v[-2] == self.N-2 + + assert len(v[0:0]) == 0 + assert v[1:2][0] == v[1] + + v2 = v[2:-1] + assert len(v2) == self.N-3 # 2 off from start, 1 from end + assert v2[0] == v[2] + assert v2[-1] == v[-2] + assert v2[self.N-4] == v[-2] + + def test07_vector_bool(self): + """Usability of std::vector which can be a specialization""" + + import cppyy + + vb = cppyy.gbl.std.vector(bool)(8) + assert [x for x in vb] == [False]*8 + + vb[0] = True + assert vb[0] + vb[-1] = True + assert vb[7] + + assert [x for x in vb] == [True]+[False]*6+[True] + + assert len(vb[4:8]) == 4 + assert list(vb[4:8]) == [False]*3+[True] + +class estSTLSTRING: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.stltypes = cppyy.load_reflection_info(cls.test_dct) + + def test01_string_argument_passing(self): + """Test mapping of python strings and std::string""" + + import cppyy + std = cppyy.gbl.std + stringy_class = cppyy.gbl.stringy_class + + c, s = stringy_class(""), std.string("test1") + + # pass through const std::string& + c.set_string1(s) + assert c.get_string1() == s + + c.set_string1("test2") + assert c.get_string1() == "test2" + + # pass through std::string (by value) + s = std.string("test3") + c.set_string2(s) + assert c.get_string1() == s + + c.set_string2("test4") + assert c.get_string1() == "test4" + + # getting through std::string& + s2 = std.string() + c.get_string2(s2) + assert s2 == "test4" + + raises(TypeError, c.get_string2, "temp string") + + def test02_string_data_access(self): + """Test access to std::string object data members""" + + import cppyy + std = cppyy.gbl.std + stringy_class = cppyy.gbl.stringy_class + + c, s = stringy_class("dummy"), std.string("test string") + + c.m_string = "another test" + assert c.m_string == "another test" + assert str(c.m_string) == c.m_string + assert c.get_string1() == "another test" + + c.m_string = s + assert str(c.m_string) == s + assert c.m_string == s + assert c.get_string1() == s + + def test03_string_with_null_character(self): + """Test that strings with NULL do not get truncated""" + + return # don't bother; is fixed in cling-support + + import cppyy + std = cppyy.gbl.std + stringy_class = cppyy.gbl.stringy_class + + t0 = "aap\0noot" + assert t0 == "aap\0noot" + + c, s = stringy_class(""), std.string(t0, len(t0)) + + c.set_string1(s) + assert t0 == c.get_string1() + assert s == c.get_string1() + + +class TestSTLLIST: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.stltypes = cppyy.load_reflection_info(cls.test_dct) + cls.N = 13 + + def test01_builtin_list_type(self): + """Test access to a list""" + + import cppyy + from cppyy.gbl import std + + type_info = ( + ("int", int), + ("float", "float"), + ("double", "double"), + ) + + for c_type, p_type in type_info: + tl1 = getattr(std, 'list<%s>' % c_type) + tl2 = cppyy.gbl.std.list(p_type) + assert tl1 is tl2 + assert tl1.iterator is cppyy.gbl.std.list(p_type).iterator + + #----- + a = tl1() + for i in range(self.N): + a.push_back( i ) + + assert len(a) == self.N + assert 11 < self.N + assert 11 in a + + #----- + ll = list(a) + for i in range(self.N): + assert ll[i] == i + + for val in a: + assert ll[ll.index(val)] == val + + def test02_empty_list_type(self): + """Test behavior of empty list""" + + import cppyy + from cppyy.gbl import std + + a = std.list(int)() + for arg in a: + pass + + +class TestSTLMAP: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.stltypes = cppyy.load_reflection_info(cls.test_dct) + cls.N = 13 + + def test01_builtin_map_type(self): + """Test access to a map""" + + import cppyy + std = cppyy.gbl.std + + a = std.map(int, int)() + for i in range(self.N): + a[i] = i + assert a[i] == i + + assert len(a) == self.N + + for key, value in a: + assert key == value + assert key == self.N-1 + assert value == self.N-1 + + # add a variation, just in case + m = std.map(int, int)() + for i in range(self.N): + m[i] = i*i + assert m[i] == i*i + + for key, value in m: + assert key*key == value + assert key == self.N-1 + assert value == (self.N-1)*(self.N-1) + + def test02_keyed_maptype(self): + """Test access to a map""" + + import cppyy + std = cppyy.gbl.std + + a = std.map(std.string, int)() + for i in range(self.N): + a[str(i)] = i + assert a[str(i)] == i + + assert len(a) == self.N + + def test03_empty_maptype(self): + """Test behavior of empty map""" + + import cppyy + std = cppyy.gbl.std + + m = std.map(int, int)() + for key, value in m: + pass + + def test04_unsignedvalue_typemap_types(self): + """Test assignability of maps with unsigned value types""" + + import cppyy, math, sys + std = cppyy.gbl.std + + mui = std.map(str, 'unsigned int')() + mui['one'] = 1 + assert mui['one'] == 1 + raises(TypeError, mui.__setitem__, 'minus one', -1) + + # UInt_t is always 32b, maxvalue is sys.maxint/maxsize and follows system int + maxint32 = int(math.pow(2,31)-1) + mui['maxint'] = maxint32 + 3 + assert mui['maxint'] == maxint32 + 3 + + mul = std.map(str, 'unsigned long')() + mul['two'] = 2 + assert mul['two'] == 2 + mul['maxint'] = maxvalue + 3 + assert mul['maxint'] == maxvalue + 3 + + raises(TypeError, mul.__setitem__, 'minus two', -2) + + def test05_STL_like_class_indexing_overloads(self): + """Test overloading of operator[] in STL like class""" + + import cppyy + stl_like_class = cppyy.gbl.stl_like_class + + a = stl_like_class(int)() + assert a["some string" ] == 'string' + assert a[3.1415] == 'double' + + def test06_STL_like_class_iterators(self): + """Test the iterator protocol mapping for an STL like class""" + + return + + # TODO: reconsider this (this is a case where there is no return + # type available and the code should (?) fall back onto getitem + # iteration. (Python does, and that would break this.) + + import cppyy + stl_like_class = cppyy.gbl.stl_like_class + + a = stl_like_class(int)() + for i in a: + pass + + assert i == 3 + + +class TestSTLITERATOR: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.stltypes = cppyy.load_reflection_info(cls.test_dct) + + def test01_builtin_vector_iterators(self): + """Test iterator comparison with operator== reflected""" + + import cppyy + from cppyy.gbl import std + + v = std.vector(int)() + v.resize(1) + + b1, e1 = v.begin(), v.end() + b2, e2 = v.begin(), v.end() + + assert b1 == b2 + assert not b1 != b2 + + assert e1 == e2 + assert not e1 != e2 + + assert not b1 == e1 + assert b1 != e1 + + b1.__preinc__() + assert not b1 == b2 + assert b1 == e2 + assert b1 != b2 + assert b1 == e2 + + +class TestSTLARRAY: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.stltypes = cppyy.load_reflection_info(cls.test_dct) + + def test01_array_of_basic_types(self): + """Usage of std::array of basic types""" + + import cppyy + from cppyy.gbl import std + + a = std.array[int, 4]() + assert len(a) == 4 + for i in range(len(a)): + a[i] = i + assert a[i] == i + + def test02_array_of_pods(self): + """Usage of std::array of PODs""" + + import cppyy + from cppyy import gbl + from cppyy.gbl import std + + a = std.array[gbl.ArrayTest.Point, 4]() + assert len(a) == 4 + for i in range(len(a)): + a[i].px = i + assert a[i].px == i + a[i].py = i**2 + assert a[i].py == i**2 + + def test03_array_of_pointer_to_pods(self): + """Usage of std::array of pointer to PODs""" + + import cppyy + from cppyy import gbl + from cppyy.gbl import std + + ll = [gbl.ArrayTest.Point() for i in range(4)] + for i in range(len(ll)): + ll[i].px = 13*i + ll[i].py = 42*i + + a = std.array['ArrayTest::Point*', 4]() + assert len(a) == 4 + for i in range(len(a)): + a[i] = ll[i] + assert a[i].px == 13*i + assert a[i].py == 42*i + + raises(TypeError, a.__setitem__, 1, 42) + + for i in range(len(a)): + assert gbl.ArrayTest.get_pp_px(a.data(), i) == 13*i + assert gbl.ArrayTest.get_pp_py(a.data(), i) == 42*i + + assert gbl.ArrayTest.get_pa_px(a.data(), i) == 13*i + assert gbl.ArrayTest.get_pa_py(a.data(), i) == 42*i diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_streams.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_streams.py new file mode 100644 index 0000000000000..70d644f535285 --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_streams.py @@ -0,0 +1,33 @@ +import py, os, sys +from pytest import raises +from .support import setup_make + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("std_streamsDict.so")) + +def setup_module(mod): + setup_make("std_streamsDict.so") + + +class TestSTDStreams: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.streams = cppyy.load_reflection_info(cls.test_dct) + + def test01_std_ostream(self): + """Test availability of std::ostream""" + + import cppyy + + assert cppyy.gbl.std is cppyy.gbl.std + assert cppyy.gbl.std.ostream is cppyy.gbl.std.ostream + + assert callable(cppyy.gbl.std.ostream) + + def test02_std_cout(self): + """Test access to std::cout""" + + import cppyy + + assert not (cppyy.gbl.std.cout is None) diff --git a/bindings/pyroot_experimental/cppyy/cppyy/test/test_templates.py b/bindings/pyroot_experimental/cppyy/cppyy/test/test_templates.py new file mode 100644 index 0000000000000..a16fc25f6cb3b --- /dev/null +++ b/bindings/pyroot_experimental/cppyy/cppyy/test/test_templates.py @@ -0,0 +1,172 @@ +import py, os, sys +from pytest import raises +from .support import setup_make + +currpath = py.path.local(__file__).dirpath() +test_dct = str(currpath.join("templatesDict.so")) + +def setup_module(mod): + setup_make("templatesDict.so") + + +class TestTEMPLATES: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.templates = cppyy.load_reflection_info(cls.test_dct) + + def test01_template_member_functions(self): + """Template member functions lookup and calls""" + + import cppyy + + m = cppyy.gbl.MyTemplatedMethodClass() + + # pre-instantiated + assert m.get_size['char']() == m.get_char_size() + assert m.get_size[int]() == m.get_int_size() + + # specialized + if sys.hexversion >= 0x3000000: + targ = 'long' + else: + targ = long + assert m.get_size[targ]() == m.get_long_size() + + # auto-instantiation + assert m.get_size[float]() == m.get_float_size() + assert m.get_size['double']() == m.get_double_size() + assert m.get_size['MyTemplatedMethodClass']() == m.get_self_size() + + # auto through typedef + assert m.get_size['MyTMCTypedef_t']() == m.get_self_size() + + def test02_non_type_template_args(self): + """Use of non-types as template arguments""" + + import cppyy + + cppyy.cppdef("template int nt_templ_args() { return i; };") + + assert cppyy.gbl.nt_templ_args[1]() == 1 + assert cppyy.gbl.nt_templ_args[256]() == 256 + + def test03_templated_function(self): + """Templated global and static functions lookup and calls""" + + import cppyy + + # TODO: the following only works if something else has already + # loaded the headers associated with this template + ggs = cppyy.gbl.global_get_size + assert ggs['char']() == 1 + + gsf = cppyy.gbl.global_some_foo + + assert gsf[int](3) == 42 + assert gsf(3) == 42 + assert gsf(3.) == 42 + + gsb = cppyy.gbl.global_some_bar + + assert gsb(3) == 13 + assert gsb['double'](3.) == 13 + + # TODO: the following only works in a namespace + nsgsb = cppyy.gbl.SomeNS.some_bar + + assert nsgsb[3] + assert nsgsb[3]() == 3 + + # TODO: add some static template method + + def test04_variadic_function(self): + """Call a variadic function""" + + from cppyy import gbl + from cppyy.gbl import std + + s = std.ostringstream() + #s << '(' + #gbl.SomeNS.tuplify(s, 1, 4., "aap") + #assert s.str() == '(1, 4, aap) + + def test05_variadic_overload(self): + """Call an overloaded variadic function""" + + import cppyy + + assert cppyy.gbl.isSomeInt(3.) == False + assert cppyy.gbl.isSomeInt(1) == True + assert cppyy.gbl.isSomeInt() == False + assert cppyy.gbl.isSomeInt(1, 2, 3) == False + + def test06_variadic_sfinae(self): + """Attribute testing through SFINAE""" + + import cppyy + cppyy.gbl.AttrTesting # load + from cppyy.gbl.AttrTesting import Obj1, Obj2, has_var1, call_has_var1 + from cppyy.gbl.std import move + + assert has_var1(Obj1()) == hasattr(Obj1(), 'var1') + assert has_var1(Obj2()) == hasattr(Obj2(), 'var1') + assert has_var1(3) == hasattr(3, 'var1') + assert has_var1("aap") == hasattr("aap", 'var1') + + assert call_has_var1(move(Obj1())) == True + assert call_has_var1(move(Obj2())) == False + + def test07_type_deduction(self): + """Traits/type deduction""" + + import cppyy + cppyy.gbl.AttrTesting # load + from cppyy.gbl.AttrTesting import select_template_arg, Obj1, Obj2 + + #assert select_template_arg[0, Obj1, Obj2].argument == Obj1 + assert select_template_arg[1, Obj1, Obj2].argument == Obj2 + raises(TypeError, select_template_arg.__getitem__, 2, Obj1, Obj2) + + # TODO, this doesn't work for builtin types as the 'argument' + # typedef will not resolve to a class + #assert select_template_arg[1, int, float].argument == float + + def test08_using_of_static_data(self): + """Derived class using static data of base""" + + import cppyy + + # TODO: the following should live in templates.h, but currently fails + # in TClass::GetListOfMethods() + cppyy.cppdef(""" + template struct BaseClassWithStatic { + static T const ref_value; + }; + + template + T const BaseClassWithStatic::ref_value = 42; + + template + struct DerivedClassUsingStatic : public BaseClassWithStatic { + using BaseClassWithStatic::ref_value; + + explicit DerivedClassUsingStatic(T x) : BaseClassWithStatic() { + m_value = x > ref_value ? ref_value : x; + } + + T m_value; + };""") + + + # TODO: the ref_value property is inaccessible (offset == -1) + # assert cppyy.gbl.BaseClassWithStatic["size_t"].ref_value == 42 + + b1 = cppyy.gbl.DerivedClassUsingStatic["size_t"]( 0) + b2 = cppyy.gbl.DerivedClassUsingStatic["size_t"](100) + + # assert b1.ref_value == 42 + assert b1.m_value == 0 + + # assert b2.ref_value == 42 + assert b2.m_value == 42 diff --git a/build/win/w32pragma.h b/build/win/w32pragma.h index e2d2ebfff93b2..c21debefd499a 100644 --- a/build/win/w32pragma.h +++ b/build/win/w32pragma.h @@ -61,7 +61,7 @@ #define WIN32 1 #define _WINDOWS 1 -#define WINVER 0x0400 +#define WINVER 0x0500 #define CRTAPI1 _cdecl #define CRTAPI2 _cdecl #define _X86_ 1 diff --git a/builtins/openssl/CMakeLists.txt b/builtins/openssl/CMakeLists.txt index 6227416f3c05f..4109e83eb4271 100644 --- a/builtins/openssl/CMakeLists.txt +++ b/builtins/openssl/CMakeLists.txt @@ -1,13 +1,21 @@ include(ExternalProject) +# find_package(OpenSSL) may not have found it, +# clear parent scope variables set to NOTFOUND +foreach(suffix FOUND INCLUDE_DIR INCLUDE_DIRS CRYPTO_LIBRARY SSL_LIBRARY LIBRARY LIBRARIES VERSION) + unset(OPENSSL_${suffix} PARENT_SCOPE) +endforeach() + +set(OPENSSL_FOUND TRUE) set(OPENSSL_VERSION "1.0.2o") set(OPENSSL_URL "http://lcgpackages.web.cern.ch/lcgpackages/tarFiles/sources/openssl-${OPENSSL_VERSION}.tar.gz") set(OPENSSL_URLHASH "SHA256=ec3f5c9714ba0fd45cb4e087301eb1336c317e0d20b575a125050470e8089e4d") set(OPENSSL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/OPENSSL-prefix) foreach(lib ssl crypto) + string(TOUPPER ${lib} libupper) set(libname ${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}) - list(APPEND OPENSSL_LIBRARIES ${OPENSSL_PREFIX}/lib/${libname}) + set(OPENSSL_${libupper}_LIBRARY ${OPENSSL_PREFIX}/lib/${libname}) endforeach() if(APPLE) @@ -23,21 +31,27 @@ ExternalProject_Add(OPENSSL INSTALL_COMMAND make install_sw BUILD_IN_SOURCE 1 LOG_BUILD 1 LOG_CONFIGURE 1 LOG_DOWNLOAD 1 LOG_INSTALL 1 - BUILD_BYPRODUCTS ${OPENSSL_LIBRARIES}) + BUILD_BYPRODUCTS ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY}) set(OPENSSL_VERSION ${OPENSSL_VERSION} CACHE INTERNAL "" FORCE) set(OPENSSL_PREFIX ${OPENSSL_PREFIX} CACHE INTERNAL "" FORCE) # needed by Davix set(OPENSSL_INCLUDE_DIR ${OPENSSL_PREFIX}/include CACHE INTERNAL "" FORCE) set(OPENSSL_INCLUDE_DIRS ${OPENSSL_PREFIX}/include CACHE INTERNAL "" FORCE) -set(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} CACHE INTERNAL "" FORCE) - -add_library(rssl INTERFACE) -target_include_directories(rssl INTERFACE $) -target_link_libraries(rssl INTERFACE $) -add_dependencies(rssl OPENSSL) - -if(NOT TARGET OpenSSL::SSL) - add_library(OpenSSL::SSL ALIAS rssl) -endif() +set(OPENSSL_CRYPTO_LIBRARY ${OPENSSL_CRYPTO_LIBRARY} CACHE INTERNAL "" FORCE) +set(OPENSSL_SSL_LIBRARY ${OPENSSL_SSL_LIBRARY} CACHE INTERNAL "" FORCE) +set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} ${CMAKE_DL_LIBS} CACHE INTERNAL "" FORCE) + +add_library(builtin_crypto INTERFACE) +target_include_directories(builtin_crypto INTERFACE $) +target_link_libraries(builtin_crypto INTERFACE $) +add_dependencies(builtin_crypto OPENSSL) + +add_library(builtin_ssl INTERFACE) +target_include_directories(builtin_ssl INTERFACE $) +target_link_libraries(builtin_ssl INTERFACE $) +add_dependencies(builtin_ssl OPENSSL) + +add_library(OpenSSL::Crypto ALIAS builtin_crypto) +add_library(OpenSSL::SSL ALIAS builtin_ssl) set_property(GLOBAL APPEND PROPERTY ROOT_BUILTIN_TARGETS OPENSSL) diff --git a/cmake/modules/Findchirp.cmake b/cmake/modules/Findchirp.cmake deleted file mode 100644 index f6e6edc85f9e6..0000000000000 --- a/cmake/modules/Findchirp.cmake +++ /dev/null @@ -1,21 +0,0 @@ -# - Locate chirp (from cctools) library -# Defines: -# -# CHIRP_FOUND -# CHIRP_INCLUDE_DIR -# CHIRP_INCLUDE_DIRS (not cached) -# CHIRP_LIBRARIES - -find_path(CHIRP_INCLUDE_DIR NAMES chirp.h HINTS ${CHIRP_DIR}/include/cctools $ENV{CHIRP_DIR}/include/cctools) -find_library(CHIRP_LIBRARY NAMES chirp_client HINTS ${CHIRP_DIR}/lib $ENV{CHIRP_DIR}/lib) - -set(CHIRP_INCLUDE_DIRS ${CHIRP_INCLUDE_DIR}) -set(CHIRP_LIBRARIES ${CHIRP_LIBRARY}) - - -# handle the QUIETLY and REQUIRED arguments and set CHIRP_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(CHIRP DEFAULT_MSG CHIRP_INCLUDE_DIR CHIRP_LIBRARY) - -mark_as_advanced(CHIRP_FOUND CHIRP_INCLUDE_DIR CHIRP_LIBRARY) diff --git a/cmake/modules/RootBuildOptions.cmake b/cmake/modules/RootBuildOptions.cmake index 1ba829788bbca..c38cad6c5027a 100644 --- a/cmake/modules/RootBuildOptions.cmake +++ b/cmake/modules/RootBuildOptions.cmake @@ -56,12 +56,11 @@ endfunction() #-------------------------------------------------------------------------------------------------- -#---Full list of options with their descriptios and default values +#---Full list of options with their descriptions and default values # The default value can be changed as many times as we wish before calling ROOT_APPLY_OPTIONS() #-------------------------------------------------------------------------------------------------- ROOT_BUILD_OPTION(afdsmgrd OFF "Dataset manager for PROOF-based analysis facilities") -ROOT_BUILD_OPTION(afs OFF "AFS support, requires AFS libs and objects") ROOT_BUILD_OPTION(alien OFF "AliEn support, requires libgapiUI from ALICE") ROOT_BUILD_OPTION(asimage ON "Image processing support, requires libAfterImage") ROOT_BUILD_OPTION(arrow OFF "Apache Arrow in memory columnar storage support") @@ -91,13 +90,12 @@ ROOT_BUILD_OPTION(builtin_xrootd OFF "Build the XROOTD internally (downloading t ROOT_BUILD_OPTION(builtin_xxhash OFF "Build included xxHash library") ROOT_BUILD_OPTION(builtin_zlib OFF "Build included libz, or use system libz") ROOT_BUILD_OPTION(castor ON "CASTOR support, requires libshift from CASTOR >= 1.5.2") -if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") +if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SIZEOF_VOID_P EQUAL 4) ROOT_BUILD_OPTION(ccache ON "Enable ccache usage for speeding up builds") else() ROOT_BUILD_OPTION(ccache OFF "Enable ccache usage for speeding up builds") endif() ROOT_BUILD_OPTION(cefweb OFF "Chromium Embedded Framework web-based display") -ROOT_BUILD_OPTION(chirp OFF "Chirp support (Condor remote I/O), requires libchirp_client") ROOT_BUILD_OPTION(cling ON "Enable new CLING C++ interpreter") ROOT_BUILD_OPTION(cocoa OFF "Use native Cocoa/Quartz graphics backend (MacOS X only)") set(compression_default "lz4" CACHE STRING "ROOT compression algorithm used as a default, default option is lz4. Can be lz4, zlib, or lzma") @@ -118,7 +116,6 @@ ROOT_BUILD_OPTION(gdml ON "GDML writer and reader") ROOT_BUILD_OPTION(genvector ON "Build the new libGenVector library") ROOT_BUILD_OPTION(geocad OFF "ROOT-CAD Interface") ROOT_BUILD_OPTION(gfal ON "GFAL support, requires libgfal") -ROOT_BUILD_OPTION(glite OFF "gLite support, requires libglite-api-wrapper v.3 from GSI (https://subversion.gsi.de/trac/dgrid/wiki)") ROOT_BUILD_OPTION(globus OFF "Globus authentication support, requires Globus toolkit") ROOT_BUILD_OPTION(gnuinstall OFF "Perform installation following the GNU guidelines") ROOT_BUILD_OPTION(gsl_shared OFF "Enable linking against shared libraries for GSL (default no)") @@ -146,6 +143,7 @@ ROOT_BUILD_OPTION(pythia6 ON "Pythia6 EG support, requires libPythia6") ROOT_BUILD_OPTION(pythia6_nolink OFF "Delayed linking of Pythia6 library") ROOT_BUILD_OPTION(pythia8 ON "Pythia8 EG support, requires libPythia8") ROOT_BUILD_OPTION(python ON "Python ROOT bindings, requires python >= 2.2") +ROOT_BUILD_OPTION(pyroot_experimental OFF "Use experimental Python bindings for ROOT") ROOT_BUILD_OPTION(qt OFF "Qt4 graphics backend, requires Qt4 >= 4.8") ROOT_BUILD_OPTION(qtgsi OFF "GSI's Qt4 integration, requires Qt4 >= 4.8") ROOT_BUILD_OPTION(qt5web OFF "Qt5 web-based display, requires Qt5") @@ -154,14 +152,11 @@ ROOT_BUILD_OPTION(rfio OFF "RFIO support, requires libshift from CASTOR >= 1.5.2 ROOT_BUILD_OPTION(roofit ON "Build the libRooFit advanced fitting package") ROOT_BUILD_OPTION(root7 OFF "Build the ROOT 7 interface prototype, requires >= cxx14") ROOT_BUILD_OPTION(rpath OFF "Set run-time library load path on executables and shared libraries (at installation area)") -ROOT_BUILD_OPTION(ruby OFF "Ruby ROOT bindings, requires ruby >= 1.8") ROOT_BUILD_OPTION(runtime_cxxmodules OFF "Enable runtime support for C++ modules.") -ROOT_BUILD_OPTION(sapdb OFF "MaxDB/SapDB support, requires libsqlod and libsqlrte") ROOT_BUILD_OPTION(shadowpw OFF "Shadow password support") ROOT_BUILD_OPTION(shared ON "Use shared 3rd party libraries if possible") ROOT_BUILD_OPTION(soversion OFF "Set version number in sonames (recommended)") ROOT_BUILD_OPTION(sqlite ON "SQLite support, requires libsqlite3") -ROOT_BUILD_OPTION(srp OFF "SRP support, requires SRP source tree") ROOT_BUILD_OPTION(ssl ON "SSL encryption support, requires openssl") ROOT_BUILD_OPTION(table OFF "Build libTable contrib library") ROOT_BUILD_OPTION(tcmalloc OFF "Using the tcmalloc allocator") @@ -227,7 +222,6 @@ endif() if(all) set(arrow_defvalue ON) set(bonjour_defvalue ON) - set(chirp_defvalue ON) set(dcache_defvalue ON) set(fitsio_defvalue ON) set(glite_defvalue ON) diff --git a/cmake/modules/RootConfiguration.cmake b/cmake/modules/RootConfiguration.cmake index d026fd99ffb94..0b10fef87f5d3 100644 --- a/cmake/modules/RootConfiguration.cmake +++ b/cmake/modules/RootConfiguration.cmake @@ -263,20 +263,11 @@ set(dnssdlibdir ${BONJOUR_LIBRARY_DIR}) set(dnssdlib ${BONJOUR_LIBRARY}) set(dnsdincdir ${BONJOUR_INCLUDE_DIR}) -set(buildchirp ${value${chirp}}) -set(chirplibdir ${CHIRP_LIBRARY_DIR}) -set(chirplib ${CHIRP_LIBRARY}) -set(chirpincdir ${CHIRP_INCLUDE_DIR}) - set(buildhdfs ${value${hdfs}}) set(hdfslibdir ${HDFS_LIBRARY_DIR}) set(hdfslib ${HDFS_LIBRARY}) set(hdfsincdir ${HDFS_INCLUDE_DIR}) -set(jniincdir ${Java_INCLUDE_DIRS}) -set(jvmlib ${Java_LIBRARIES}) -set(jvmlibdir ${Java_LIBRARY_DIR}) - set(buildalien ${value${alien}}) set(alienlibdir ${ALIEN_LIBRARY_DIR}) set(alienlib ${ALIEN_LIBRARY}) @@ -330,10 +321,9 @@ set(pythonlib ${PYTHON_LIBRARY}) set(pythonincdir ${PYTHON_INCLUDE_DIR}) set(pythonlibflags) -set(buildruby ${value${ruby}}) -set(rubylibdir ${RUBY_LIBRARY_DIR}) -set(rubylib ${RUBY_LIBRARY}) -set(rubyincdir ${RUBY_INCLUDE_DIR}) +if (ruby) + message(FATAL_ERROR "Ruby bindings are discontinued; please report to root-dev@cern.ch should you still need them!") +endif() set(buildxml ${value${xml}}) set(xmllibdir ${LIBXML2_LIBRARY_DIR}) @@ -781,6 +771,7 @@ configure_file(${CMAKE_SOURCE_DIR}/config/root-config.in ${CMAKE_BINARY_DIR}/ins configure_file(${CMAKE_SOURCE_DIR}/config/memprobe.in ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/memprobe @ONLY NEWLINE_STYLE UNIX) configure_file(${CMAKE_SOURCE_DIR}/config/thisroot.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/thisroot.sh @ONLY NEWLINE_STYLE UNIX) configure_file(${CMAKE_SOURCE_DIR}/config/thisroot.csh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/thisroot.csh @ONLY NEWLINE_STYLE UNIX) +configure_file(${CMAKE_SOURCE_DIR}/config/thisroot.fish ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/thisroot.fish @ONLY NEWLINE_STYLE UNIX) configure_file(${CMAKE_SOURCE_DIR}/config/setxrd.csh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/setxrd.csh COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/config/setxrd.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/setxrd.sh COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/config/proofserv.in ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/proofserv @ONLY NEWLINE_STYLE UNIX) @@ -805,6 +796,7 @@ configure_file(${CMAKE_SOURCE_DIR}/config/root-config.in ${CMAKE_RUNTIME_OUTPUT_ install(FILES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/thisroot.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/thisroot.csh + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/thisroot.fish ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/setxrd.csh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/setxrd.sh ${thisrootbat} diff --git a/cmake/modules/SearchInstalledSoftware.cmake b/cmake/modules/SearchInstalledSoftware.cmake index 07e5f7fb5c0d6..2a3c3dc95165a 100644 --- a/cmake/modules/SearchInstalledSoftware.cmake +++ b/cmake/modules/SearchInstalledSoftware.cmake @@ -237,6 +237,9 @@ endif() #---Check for LZ4-------------------------------------------------------------------- if(NOT builtin_lz4) message(STATUS "Looking for LZ4") + foreach(suffix FOUND INCLUDE_DIR LIBRARY LIBRARY_DEBUG LIBRARY_RELEASE) + unset(LZ4_${suffix} CACHE) + endforeach() find_package(LZ4) if(NOT LZ4_FOUND) message(STATUS "LZ4 not found. Switching on builtin_lz4 option") @@ -441,18 +444,14 @@ endif() #---Check for Python installation------------------------------------------------------- if(python) - if(fail-on-missing) - find_package(PythonInterp ${python_version} REQUIRED) - find_package(PythonLibs ${python_version} REQUIRED) - if (tmva) + find_package(PythonInterp ${python_version} REQUIRED) + find_package(PythonLibs ${python_version} REQUIRED) + if (tmva) + if(fail-on-missing) find_package(NumPy REQUIRED) else() find_package(NumPy) endif() - else() - find_package(PythonInterp ${python_version}) - find_package(PythonLibs ${python_version}) - find_package(NumPy) endif() endif() @@ -1035,20 +1034,6 @@ if(builtin_ftgl) set(FTGL_LIBRARIES FTGL) endif() -#---Check for chirp-------------------------------------------------------------------- -if(chirp) - find_package(chirp) - if(NOT CHIRP_FOUND) - if(fail-on-missing) - message(FATAL_ERROR "chirp library not found and is required (chirp option enabled)") - else() - message(STATUS "chirp library not found. Set variable CHIRP_DIR to point to your chirp installation") - message(STATUS "For the time being switching OFF 'chirp' option") - set(chirp OFF CACHE BOOL "Disabled because chirp not found (${chirp_description})" FORCE) - endif() - endif() -endif() - #---Check for R/Rcpp/RInside-------------------------------------------------------------------- #added search of R packages here to remove multiples searches if(r) @@ -1472,7 +1457,8 @@ if(vdt OR builtin_vdt) DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) install(DIRECTORY ${CMAKE_BINARY_DIR}/include/vdt DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT extra-headers) - set(vdt ON CACHE BOOL "Enabled because builtin_vdt enabled (${vdt_description})" FORCE) + set(vdt ON CACHE BOOL "Enabled because builtin_vdt enabled (${vdt_description})" FORCE) + set_property(GLOBAL APPEND PROPERTY ROOT_BUILTIN_TARGETS VDT) endif() endif() @@ -1609,11 +1595,10 @@ if (testing) endif() -#---Report non implemented options--------------------------------------------------- -foreach(opt afs glite sapdb srp) +#---Report removed options--------------------------------------------------- +foreach(opt afs glite sapdb srp chirp ios) if(${opt}) - message(STATUS ">>> Option '${opt}' not implemented yet! Signal your urgency to pere.mato@cern.ch") - set(${opt} OFF CACHE BOOL "Disabled because not implemented yet (${${opt}_description})" FORCE) + message(FATAL_ERROR ">>> Option '${opt}' has been removed in ROOT v6.16.") endif() endforeach() diff --git a/cmake/modules/SetUpLinux.cmake b/cmake/modules/SetUpLinux.cmake index 71f50bfdcd3ed..e52cf7df3dd40 100644 --- a/cmake/modules/SetUpLinux.cmake +++ b/cmake/modules/SetUpLinux.cmake @@ -119,7 +119,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS}") set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined -Wl,--hash-style=\"both\"") # Select flags. set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG") diff --git a/config/Makefile.in b/config/Makefile.in index f7b427169c4da..53ad3c6f2bfa9 100644 --- a/config/Makefile.in +++ b/config/Makefile.in @@ -268,9 +268,6 @@ BUILDHDFS := @buildhdfs@ HDFSLIBDIR := @hdfslibdir@ HDFSCLILIB := @hdfslib@ HDFSINCDIR := $(filter-out /usr/include, @hdfsincdir@) -JNIINCDIR := $(filter-out /usr/include, @jniincdir@) $(filter-out /usr/include, @jniincdir@/linux) -JVMCLILIB := @jvmlib@ -JVMLIBDIR := @jvmlibdir@ BUILDALIEN := @buildalien@ ALIENLIBDIR := @alienlibdir@ diff --git a/config/root-config.in b/config/root-config.in index e7b9d0fb24b6c..cd530c8a8db58 100755 --- a/config/root-config.in +++ b/config/root-config.in @@ -69,19 +69,12 @@ fi ### ROOT libraries ### -if test "$platform" = "ios"; then - newlib= - rootglibs= - rootevelibs= - rootlibs="-lRoota" -else - newlib="-lNew" - rootglibs="-lGui" - rootevelibs="-lEve -lEG -lGeom -lGed -lRGL" - rootlibs="-lCore -lImt -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lROOTDataFrame -lROOTVecOps -lTree -lTreePlayer\ - -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lThread\ - -lMultiProc" -fi +newlib="-lNew" +rootglibs="-lGui" +rootevelibs="-lEve -lEG -lGeom -lGed -lRGL" +rootlibs="-lCore -lImt -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lROOTDataFrame -lROOTVecOps -lTree -lTreePlayer\ + -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lThread\ + -lMultiProc" if test "$platform" = "win32"; then rootulibs="-include:_G__cpp_setupG__Net \ @@ -321,11 +314,6 @@ macosx64) auxldflags="-m64" auxlibs="-lm -ldl" ;; -ios*) - auxcflags="${cxxversionflag} -m32" - auxldflags="-m32" - auxlibs="-lm -ldl" - ;; hiux) # Hitachi HIUX auxcflags= diff --git a/config/rootrc.in b/config/rootrc.in index 60a1ba6091f12..2a4abb8f01ca4 100644 --- a/config/rootrc.in +++ b/config/rootrc.in @@ -34,9 +34,12 @@ WinNT.UseNetAPI: true # Use thread library (if exists). Unix.*.Root.UseThreads: false -# Select the compression algorithm (0=old zlib, 1=new zlib) -# Note, setting this to `0' may be a security vulnerability. -Root.ZipMode: 1 +# Select the compression algorithm: 0=default, 1=zlib, 2=lzma, 4=LZ4. +# (3 is an old setting and shouldn't be used.) +# See the documentation of ECompressionAlgorithm. +# A simple "0" (the default value) uses the default compression algorithm as +# specified by the initialization of R__ZipMode. +Root.CompressionAlgorithm: 0 # Show where item is found in the specified path. Root.ShowPath: false @@ -582,6 +585,16 @@ Url.Special: file: rfio: hpss: castor: gfal: dcache: # Socket read timeout [in secs: default 10 secs] # XProof.ReadTimeout: 10 +# The following controls the verbosity of the TXNetFile XRootD client +# +# XNet.Debug - log verbosity level (default 0) +# (0 = nothing, +# 1 = Info (messages of interest to the user) +# 2 = Debug (adds messages of interest to the developers) +# 3 = Dump (adds dump of all sent/received data buffers) +# 4 = Dump+ (adds dump of data received/sent at the lower +# level) + # The following env vars are handled by TXNetFile and related classes # (module netx, libNetx.so). # @@ -619,15 +632,6 @@ Url.Special: file: rfio: hpss: castor: gfal: dcache: # slac.stanford.edu|pd.infn.it|fe.infn.it # XNet.MaxRedirectCount - maximum number of redirections from # server [16] -# XNet.Debug - log verbosity level -# (0=nothing, -# 1=messages of interest to the user, -# 2=messages of interest to the developers -# (includes also user messages), -# 3=dump of all sent/received data buffers -# (includes also user and developers -# messages). [0] -# 4=dump also the data received/sent at the lower level # XNet.ReconnectWait - sleep-time before going back to the # load balancer (or rebouncing to the same # failing host) after a read/write error @@ -688,6 +692,13 @@ XNet.ParStreamsPerPhyConn: 0 # Use the old xrootd client (libNetx) instead of the new (libNetxNG) XNet.UseOldClient: @useoldnetx@ +# The following controls the verbosity of the TXNetNGFile XRootD client +# +# NetXNG.Debug - "" use default level +# "Info" messages of interest to the user +# "Debug" adds messages of interest to the developers +# "Dump" adds details of the request and responses + # NetXNG.ConnectionWindow - A time window for the connection establishment. A # connection failure is declared if the connection # is not established within the time window. If a diff --git a/config/thisroot.fish b/config/thisroot.fish new file mode 100644 index 0000000000000..6b317b6d8fe62 --- /dev/null +++ b/config/thisroot.fish @@ -0,0 +1,55 @@ +# Source this script to set up the ROOT build that this script is part of. +# +# This script is for the fish shell. +# +# Author: Axel Naumann, 2018-06-25 + +function update_path -d "Remove argv[2]argv[3] from argv[1] if argv[2], and prepend argv[4]" + # Assert that we got enough arguments + if test (count $argv) -ne 4 + echo "update_path: needs 4 arguments but have " (count $argv) + return 1 + end + + set var $argv[1] + + set newpath $argv[4] + for el in $$var + if test "$argv[2]" = ""; or not test "$el" = "$argv[2]$argv[3]" + set newpath $newpath $el + end + end + + set -x $var $newpath +end + +if set -q ROOTSYS + set old_rootsys $ROOTSYS +end + +set SOURCE (status -f) +# normalize path +set thisroot (dirname $SOURCE) +set -x ROOTSYS (set oldpwd $PWD; cd $thisroot/.. > /dev/null;pwd;cd $oldpwd; set -e oldpwd) + +if not set -q MANPATH + # Grab the default man path before setting the path to avoid duplicates + if which manpath > /dev/null ^ /dev/null + set -x MANPATH (manpath) + else + set -x MANPATH (man -w 2> /dev/null) + end +end + +update_path PATH "$old_rootsys" "/bin" @bindir@ +update_path LD_LIBRARY_PATH "$old_rootsys" "/lib" @libdir@ +update_path DYLD_LIBRARY_PATH "$old_rootsys" "/lib" @libdir@ +update_path PYTHONPATH "$old_rootsys" "/lib" @libdir@ +update_path MANPATH "$old_rootsys" "/man" @mandir@ +update_path CMAKE_PREFIX_PATH "$old_rootsys" "" $ROOTSYS +update_path JUPYTER_PATH "$old_rootsys" "/etc/notebook" ROOTSYS/etc/notebook + +functions -e update_path +set -e old_rootsys +set -e thisroot +set -e SOURCE diff --git a/core/base/inc/ROOT/RConfig.h b/core/base/inc/ROOT/RConfig.h index 3c192e458d8d9..8c0836e3aea24 100644 --- a/core/base/inc/ROOT/RConfig.h +++ b/core/base/inc/ROOT/RConfig.h @@ -20,6 +20,7 @@ *************************************************************************/ #include "RVersion.h" +#include "RConfigure.h" /*---- new C++ features ------------------------------------------------------*/ diff --git a/core/base/inc/TVirtualMutex.h b/core/base/inc/TVirtualMutex.h index 1ae5d2200d1c9..bdc29ff4e3668 100644 --- a/core/base/inc/TVirtualMutex.h +++ b/core/base/inc/TVirtualMutex.h @@ -103,9 +103,9 @@ class TLockGuard { #define R__LOCKGUARD_NAMED(name,mutex) TLockGuard _NAME2_(R__guard,name)(mutex) #define R__LOCKGUARD_UNLOCK(name) _NAME2_(R__guard,name).UnLock() #else -#define R__LOCKGUARD(mutex) (void)mutex; { } -#define R__LOCKGUARD_NAMED(name,mutex) (void)mutex; { } -#define R__LOCKGUARD2(mutex) (void)mutex; { } +#define R__LOCKGUARD(mutex) (void)(mutex); { } +#define R__LOCKGUARD_NAMED(name,mutex) (void)(mutex); { } +#define R__LOCKGUARD2(mutex) (void)(mutex); { } #define R__LOCKGUARD_UNLOCK(name) { } #endif diff --git a/core/base/src/TAttAxis.cxx b/core/base/src/TAttAxis.cxx index 498a4d2b33693..1550ff0e3cbb0 100644 --- a/core/base/src/TAttAxis.cxx +++ b/core/base/src/TAttAxis.cxx @@ -142,7 +142,7 @@ void TAttAxis::SaveAttributes(std::ostream &out, const char *name, const char *s if (TMath::Abs(fTickLength-0.03) > 0.001) { out<<" "<SetTickLength("< 0.001) { + if (TMath::Abs(fTitleOffset) > 0.001) { out<<" "<SetTitleOffset("<GetValue("Root.ErrorHandlers", 1)) gSystem->ResetSignals(); - // by default the zipmode is 1 (see Bits.h) - Int_t zipmode = gEnv->GetValue("Root.ZipMode", 1); - if (zipmode != 1) R__SetZipMode(zipmode); + Int_t zipmode = gEnv->GetValue("Root.CompressionAlgorithm", 0); + if (zipmode != 0) R__SetZipMode(zipmode); const char *sdeb; if ((sdeb = gSystem->Getenv("ROOTDEBUG"))) @@ -2144,12 +2143,9 @@ TClass *TROOT::LoadClass(const char *requestedname, Bool_t silent) const //////////////////////////////////////////////////////////////////////////////// /// Check if class "classname" is known to the interpreter (in fact, /// this check is not needed anymore, so classname is ignored). If -/// not it will load library "libname". If the library name does -/// not start with "lib", "lib" will be prepended and a search will -/// be made in the DynamicPath (see .rootrc). If not found a search -/// will be made on libname (without "lib" prepended) and if not found -/// a direct try of libname will be made (in case it contained an -/// absolute path). +/// not it will load library "libname". If the library couldn't be found with original +/// libname and if the name was not prefixed with lib, try to prefix with "lib" and search again. +/// If DynamicPathName still couldn't find the library, return -1. /// If check is true it will only check if libname exists and is /// readable. /// Returns 0 on successful loading, -1 in case libname does not @@ -2158,46 +2154,45 @@ TClass *TROOT::LoadClass(const char *requestedname, Bool_t silent) const Int_t TROOT::LoadClass(const char * /*classname*/, const char *libname, Bool_t check) { - Int_t err = -1; + TString lib(libname); - char *path; - TString lib = libname; - if (!lib.BeginsWith("lib")) - lib = "lib" + lib; - if ((path = gSystem->DynamicPathName(lib, kTRUE))) { - if (check) - err = 0; + // Check if libname exists in path or not + if (char *path = gSystem->DynamicPathName(lib, kTRUE)) { + // If check == true, only check if it exists and if it's readable + if (check) { + delete [] path; + return 0; + } + + // If check == false, try to load the library else { - err = gSystem->Load(path, 0, kTRUE); + int err = gSystem->Load(path, 0, kTRUE); + delete [] path; + + // TSystem::Load returns 1 when the library was already loaded, return success in this case. + if (err == 1) + err = 0; + return err; } - delete [] path; } else { + // This is the branch where libname didn't exist if (check) { FileStat_t stat; - if (!gSystem->GetPathInfo(libname, stat)) { - if (R_ISREG(stat.fMode) && - !gSystem->AccessPathName(libname, kReadPermission)) - err = 0; - else - err = -1; - } else - err = -1; - } else { - err = gSystem->Load(libname, 0, kTRUE); + if (!gSystem->GetPathInfo(libname, stat) && (R_ISREG(stat.fMode) && + !gSystem->AccessPathName(libname, kReadPermission))) + return 0; } - } - if (err == -1) { - //Error("LoadClass", "library %s could not be loaded", libname); - } - - if (err == 1) { - //Error("LoadClass", "library %s already loaded, but class %s unknown", - // libname, classname); - err = 0; + // Take care of user who didn't write the whole name + if (!lib.BeginsWith("lib")) { + lib = "lib" + lib; + return LoadClass("", lib.Data(), check); + } } - return err; + // Execution reaches here when library was prefixed with lib, check is false and couldn't find + // the library name. + return -1; } //////////////////////////////////////////////////////////////////////////////// diff --git a/core/base/v7/inc/ROOT/TDrawable.hxx b/core/base/v7/inc/ROOT/RDrawable.hxx similarity index 84% rename from core/base/v7/inc/ROOT/TDrawable.hxx rename to core/base/v7/inc/ROOT/RDrawable.hxx index c5ac88cffe582..5645bf06f4d8f 100644 --- a/core/base/v7/inc/ROOT/TDrawable.hxx +++ b/core/base/v7/inc/ROOT/RDrawable.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TDrawable.h +/// \file ROOT/RDrawable.hxx /// \ingroup Base ROOT7 /// \author Axel Naumann /// \date 2015-08-07 @@ -13,8 +13,8 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TDrawable -#define ROOT7_TDrawable +#ifndef ROOT7_RDrawable +#define ROOT7_RDrawable #include #include @@ -22,45 +22,45 @@ namespace ROOT { namespace Experimental { -class TDrawingOptsBase; -class TMenuItems; -class TPadBase; +class RDrawingOptsBase; +class RMenuItems; +class RPadBase; namespace Internal { -class TPadPainter; +class RPadPainter; } -/** \class TDrawable - Base class for drawable entities: objects that can be painted on a `TPad`. +/** \class RDrawable + Base class for drawable entities: objects that can be painted on a `RPad`. */ -class TDrawable { -friend class TPadBase; +class RDrawable { +friend class RPadBase; private: - std::string fId; ///< object identifier, unique inside TCanvas + std::string fId; ///< object identifier, unique inside RCanvas public: - virtual ~TDrawable(); + virtual ~RDrawable(); - virtual void Paint(Internal::TPadPainter &onPad) = 0; + virtual void Paint(Internal::RPadPainter &onPad) = 0; /** Method can be used to provide menu items for the drawn object */ - virtual void PopulateMenu(TMenuItems &){}; + virtual void PopulateMenu(RMenuItems &){}; virtual void Execute(const std::string &); - /// Get the reference to the drawing options as TDrawingOptsBase. Used e.g. to identify the TDrawable in + /// Get the reference to the drawing options as RDrawingOptsBase. Used e.g. to identify the RDrawable in /// the list of primitives. - virtual TDrawingOptsBase& GetOptionsBase() = 0; + virtual RDrawingOptsBase& GetOptionsBase() = 0; std::string GetId() const { return fId; } }; template -class TDrawableBase: public TDrawable { +class RDrawableBase: public RDrawable { public: - TDrawingOptsBase& GetOptionsBase() override { return static_cast(this)->GetOptions(); } + RDrawingOptsBase& GetOptionsBase() override { return static_cast(this)->GetOptions(); } }; namespace Internal { diff --git a/core/base/v7/src/TDrawable.cxx b/core/base/v7/src/RDrawable.cxx similarity index 83% rename from core/base/v7/src/TDrawable.cxx rename to core/base/v7/src/RDrawable.cxx index ba78dbafe277e..9dddc854d9d15 100644 --- a/core/base/v7/src/TDrawable.cxx +++ b/core/base/v7/src/RDrawable.cxx @@ -1,4 +1,4 @@ -/// \file TDrawable.cxx +/// \file RDrawable.cxx /// \ingroup Base ROOT7 /// \author Axel Naumann /// \date 2015-07-08 @@ -13,14 +13,14 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TDrawable.hxx" +#include "ROOT/RDrawable.hxx" #include // pin vtable -ROOT::Experimental::TDrawable::~TDrawable() {} +ROOT::Experimental::RDrawable::~RDrawable() {} -void ROOT::Experimental::TDrawable::Execute(const std::string &) +void ROOT::Experimental::RDrawable::Execute(const std::string &) { assert(false && "Did not expect a menu item to be invoked!"); } diff --git a/core/clingutils/src/TClingUtils.cxx b/core/clingutils/src/TClingUtils.cxx index b4043a4f3d5bb..83990b1cc7e7f 100644 --- a/core/clingutils/src/TClingUtils.cxx +++ b/core/clingutils/src/TClingUtils.cxx @@ -3383,11 +3383,6 @@ void ROOT::TMetaUtils::GetFullyQualifiedTypeName(std::string &typenamestr, const clang::QualType &qtype, const cling::Interpreter &interpreter) { - // We need this barrior because GetFullyQualifiedTypeName is triggering deserialization - // This calling the same name function GetFullyQualifiedTypeName, but this should stay here because - // callee doesn't have an interpreter pointer - cling::Interpreter::PushTransactionRAII RAII(const_cast(&interpreter)); - GetFullyQualifiedTypeName(typenamestr, qtype, interpreter.getCI()->getASTContext()); diff --git a/core/dictgen/src/rootcling_impl.cxx b/core/dictgen/src/rootcling_impl.cxx index a049e7a1c1af6..9e6dae407a3a1 100644 --- a/core/dictgen/src/rootcling_impl.cxx +++ b/core/dictgen/src/rootcling_impl.cxx @@ -2742,15 +2742,16 @@ bool ProcessAndAppendIfNotThere(const std::string &el, { std::stringstream elStream(el); std::string tmp; + bool added = false; while (getline(elStream, tmp, '\n')) { // Add if not there if (el_set.insert(tmp).second && !tmp.empty()) { el_list.push_back(tmp); - return true; + added = true; } } - return false; + return added; } //////////////////////////////////////////////////////////////////////////////// diff --git a/core/foundation/res/ROOT/RSha256.hxx b/core/foundation/res/ROOT/RSha256.hxx new file mode 100644 index 0000000000000..081131a22dd6c --- /dev/null +++ b/core/foundation/res/ROOT/RSha256.hxx @@ -0,0 +1,330 @@ +// Author: Danilo Piparo May 2018 +// Inspired by public domain code of Igor Pavlov: https://github.com/jb55/sha256.c + +/************************************************************************* + * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_RSHA +#define ROOT_RSHA + +#include "Rtypes.h" + +#include +#include +#include + + +namespace ROOT { +namespace Internal { +namespace SHA256 { + +#ifdef _MSC_VER + +#define ROTL32(v, n) _rotl((v), (n)) +#define ROTL64(v, n) _rotl64((v), (n)) + +#define ROTR32(v, n) _rotr((v), (n)) +#define ROTR64(v, n) _rotr64((v), (n)) + +#else + +#define U8V(v) ((uint8_t)(v)&0xFFU) +#define U16V(v) ((uint16_t)(v)&0xFFFFU) +#define U32V(v) ((uint32_t)(v)&0xFFFFFFFFU) +#define U64V(v) ((uint64_t)(v)&0xFFFFFFFFFFFFFFFFU) + +#define ROTL32(v, n) (U32V((uint32_t)(v) << (n)) | ((uint32_t)(v) >> (32 - (n)))) + +// tests fail if we don't have this cast... +#define ROTL64(v, n) (U64V((uint64_t)(v) << (n)) | ((uint64_t)(v) >> (64 - (n)))) + +#define ROTR32(v, n) ROTL32(v, 32 - (n)) +#define ROTR64(v, n) ROTL64(v, 64 - (n)) + +#endif + +#define ROTL8(v, n) (U8V((uint8_t)(v) << (n)) | ((uint8_t)(v) >> (8 - (n)))) + +#define ROTL16(v, n) (U16V((uint16_t)(v) << (n)) | ((uint16_t)(v) >> (16 - (n)))) + +#define ROTR8(v, n) ROTL8(v, 8 - (n)) +#define ROTR16(v, n) ROTL16(v, 16 - (n)) + +#define SHA256_DIGEST_SIZE 32 + +typedef struct sha256_t { + uint32_t state[8]; + uint64_t count; + unsigned char buffer[64]; +} sha256_t; + +void sha256_init(sha256_t *p); +void sha256_update(sha256_t *p, const unsigned char *data, size_t size); +void sha256_final(sha256_t *p, unsigned char *digest); +void sha256_hash(unsigned char *buf, const unsigned char *data, size_t size); + +/* define it for speed optimization */ +#define _SHA256_UNROLL +#define _SHA256_UNROLL2 + +void sha256_init(sha256_t *p) +{ + p->state[0] = 0x6a09e667; + p->state[1] = 0xbb67ae85; + p->state[2] = 0x3c6ef372; + p->state[3] = 0xa54ff53a; + p->state[4] = 0x510e527f; + p->state[5] = 0x9b05688c; + p->state[6] = 0x1f83d9ab; + p->state[7] = 0x5be0cd19; + p->count = 0; +} + +#define S0(x) (ROTR32(x, 2) ^ ROTR32(x, 13) ^ ROTR32(x, 22)) +#define S1(x) (ROTR32(x, 6) ^ ROTR32(x, 11) ^ ROTR32(x, 25)) +#define s0(x) (ROTR32(x, 7) ^ ROTR32(x, 18) ^ (x >> 3)) +#define s1(x) (ROTR32(x, 17) ^ ROTR32(x, 19) ^ (x >> 10)) + +#define blk0(i) (W[i] = data[i]) +#define blk2(i) (W[i & 15] += s1(W[(i - 2) & 15]) + W[(i - 7) & 15] + s0(W[(i - 15) & 15])) + +#define Ch(x, y, z) (z ^ (x & (y ^ z))) +#define Maj(x, y, z) ((x & y) | (z & (x | y))) + +#define a(i) T[(0 - (i)) & 7] +#define b(i) T[(1 - (i)) & 7] +#define c(i) T[(2 - (i)) & 7] +#define d(i) T[(3 - (i)) & 7] +#define e(i) T[(4 - (i)) & 7] +#define f(i) T[(5 - (i)) & 7] +#define g(i) T[(6 - (i)) & 7] +#define h(i) T[(7 - (i)) & 7] + +#ifdef _SHA256_UNROLL2 + +#define R(a, b, c, d, e, f, g, h, i) \ + h += S1(e) + Ch(e, f, g) + K[i + j] + (j ? blk2(i) : blk0(i)); \ + d += h; \ + h += S0(a) + Maj(a, b, c) + +#define RX_8(i) \ + R(a, b, c, d, e, f, g, h, i); \ + R(h, a, b, c, d, e, f, g, (i + 1)); \ + R(g, h, a, b, c, d, e, f, (i + 2)); \ + R(f, g, h, a, b, c, d, e, (i + 3)); \ + R(e, f, g, h, a, b, c, d, (i + 4)); \ + R(d, e, f, g, h, a, b, c, (i + 5)); \ + R(c, d, e, f, g, h, a, b, (i + 6)); \ + R(b, c, d, e, f, g, h, a, (i + 7)) + +#else + +#define R(i) \ + h(i) += S1(e(i)) + Ch(e(i), f(i), g(i)) + K[i + j] + (j ? blk2(i) : blk0(i)); \ + d(i) += h(i); \ + h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) + +#ifdef _SHA256_UNROLL + +#define RX_8(i) \ + R(i + 0); \ + R(i + 1); \ + R(i + 2); \ + R(i + 3); \ + R(i + 4); \ + R(i + 5); \ + R(i + 6); \ + R(i + 7); + +#endif + +#endif + +static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +static void sha256_transform(uint32_t *state, const uint32_t *data) +{ + uint32_t W[16] = {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U}; + unsigned j; +#ifdef _SHA256_UNROLL2 + uint32_t a, b, c, d, e, f, g, h; + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; +#else + uint32_t T[8]; + for (j = 0; j < 8; j++) + T[j] = state[j]; +#endif + + for (j = 0; j < 64; j += 16) { +#if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2) + RX_8(0); + RX_8(8); +#else + unsigned i; + for (i = 0; i < 16; i++) { + R(i); + } +#endif + } + +#ifdef _SHA256_UNROLL2 + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; +#else + for (j = 0; j < 8; j++) + state[j] += T[j]; +#endif + + /* Wipe variables */ + /* memset(W, 0, sizeof(W)); */ + /* memset(T, 0, sizeof(T)); */ +} + +#undef S0 +#undef S1 +#undef s0 +#undef s1 + +static void sha256_write_byte_block(sha256_t *p) +{ + uint32_t data32[16]; + unsigned i; + for (i = 0; i < 16; i++) + data32[i] = ((uint32_t)(p->buffer[i * 4]) << 24) + ((uint32_t)(p->buffer[i * 4 + 1]) << 16) + + ((uint32_t)(p->buffer[i * 4 + 2]) << 8) + ((uint32_t)(p->buffer[i * 4 + 3])); + sha256_transform(p->state, data32); +} + +void sha256_update(sha256_t *p, const unsigned char *data, size_t size) +{ + uint32_t curBufferPos = (uint32_t)p->count & 0x3F; + while (size > 0) { + p->buffer[curBufferPos++] = *data++; + p->count++; + size--; + if (curBufferPos == 64) { + curBufferPos = 0; + sha256_write_byte_block(p); + } + } +} + +void sha256_final(sha256_t *p, unsigned char *digest) +{ + uint64_t lenInBits = (p->count << 3); + uint32_t curBufferPos = (uint32_t)p->count & 0x3F; + unsigned i; + p->buffer[curBufferPos++] = 0x80; + while (curBufferPos != (64 - 8)) { + curBufferPos &= 0x3F; + if (curBufferPos == 0) + sha256_write_byte_block(p); + p->buffer[curBufferPos++] = 0; + } + for (i = 0; i < 8; i++) { + p->buffer[curBufferPos++] = (unsigned char)(lenInBits >> 56); + lenInBits <<= 8; + } + sha256_write_byte_block(p); + + for (i = 0; i < 8; i++) { + *digest++ = (unsigned char)(p->state[i] >> 24); + *digest++ = (unsigned char)(p->state[i] >> 16); + *digest++ = (unsigned char)(p->state[i] >> 8); + *digest++ = (unsigned char)(p->state[i]); + } + sha256_init(p); +} + +} // End NS SHA256 + + +/// This helper class represents a sha256 hash. Operator == and std::less +/// complete its functionality. +class RSha256Hash { + friend std::ostream &operator<<(std::ostream &os, const ROOT::Internal::RSha256Hash &h) + { + auto digest = h.Get(); + os << digest[0] << "-" << digest[1] << "-" << digest[2] << "-" << digest[3]; + return os; + } +private: + void Sha256(const unsigned char *data, int len) + { + // Here the final cast is to match the interface of the C code and + // the data member. The lenght is the same! + SHA256::sha256_init(&fHash); + SHA256::sha256_update(&fHash, data, len); + SHA256::sha256_final(&fHash, reinterpret_cast(fDigest)); + } + + SHA256::sha256_t fHash; + ULong64_t fDigest[4]; + +public: + RSha256Hash(const char *data, int len) + { + // The cast here is because in the TBuffer ecosystem, the type used is char* + Sha256(reinterpret_cast(data), len); + } + ULong64_t const *Get() const { return fDigest; } +}; + +bool operator==(const RSha256Hash &lhs, const RSha256Hash &rhs) +{ + auto l = lhs.Get(); + auto r = rhs.Get(); + return l[0] == r[0] && l[1] == r[1] && l[2] == r[2] && l[3] == r[3]; +} + +} // End NS Internal +} // End NS ROOT + +namespace std { +template <> +struct less { + bool operator()(const ROOT::Internal::RSha256Hash &lhs, const ROOT::Internal::RSha256Hash &rhs) const + { + /// Check piece by piece the 4 64 bits ints which make up the hash. + auto l = lhs.Get(); + auto r = rhs.Get(); + // clang-format off + return l[0] < r[0] ? true : + l[0] > r[0] ? false : + l[1] < r[1] ? true : + l[1] > r[1] ? false : + l[2] < r[2] ? true : + l[2] > r[2] ? false : + l[3] < r[3] ? true : false; + // clang-format on + } +}; +} // End NS std + +#endif diff --git a/core/imt/inc/ROOT/TThreadExecutor.hxx b/core/imt/inc/ROOT/TThreadExecutor.hxx index 3358047c7d197..1b0a5f6c6099e 100644 --- a/core/imt/inc/ROOT/TThreadExecutor.hxx +++ b/core/imt/inc/ROOT/TThreadExecutor.hxx @@ -51,6 +51,8 @@ namespace ROOT { /// \endcond template void Foreach(F func, std::vector &args); + template + void Foreach(F func, const std::vector &args); using TExecutor::Map; template> @@ -143,6 +145,14 @@ namespace ROOT { ParallelFor(0U, nToProcess, 1, [&](unsigned int i){func(args[i]);}); } + ////////////////////////////////////////////////////////////////////////// + /// Execute func in parallel, taking an element of a std::vector as argument. + template + void TThreadExecutor::Foreach(F func, const std::vector &args) { + unsigned int nToProcess = args.size(); + ParallelFor(0U, nToProcess, 1, [&](unsigned int i){func(args[i]);}); + } + ////////////////////////////////////////////////////////////////////////// /// Execute func (with no arguments) nTimes in parallel. /// A vector containg executions' results is returned. diff --git a/core/meta/inc/TInterpreter.h b/core/meta/inc/TInterpreter.h index 0f4baa6f3b351..8bec2edbc2cff 100644 --- a/core/meta/inc/TInterpreter.h +++ b/core/meta/inc/TInterpreter.h @@ -44,7 +44,7 @@ R__EXTERN TVirtualMutex *gInterpreterMutex; #if defined (_REENTRANT) || defined (WIN32) # define R__LOCKGUARD_CLING(mutex) ::ROOT::Internal::InterpreterMutexRegistrationRAII _R__UNIQUE_(R__guard)(mutex); { } #else -# define R__LOCKGUARD_CLING(mutex) (void)mutex; { } +# define R__LOCKGUARD_CLING(mutex) (void)(mutex); { } #endif namespace ROOT { diff --git a/core/meta/inc/TStreamerElement.h b/core/meta/inc/TStreamerElement.h index 2815d2bc583b7..248e86528d055 100644 --- a/core/meta/inc/TStreamerElement.h +++ b/core/meta/inc/TStreamerElement.h @@ -80,7 +80,8 @@ class TStreamerElement : public TNamed { kRead = BIT(11), kWrite = BIT(12), kDoNotDelete = BIT(13), - kWholeObject = BIT(14) + kWholeObject = BIT(14), + kWarned = BIT(21) }; enum class EStatusBitsDupExceptions { @@ -389,10 +390,6 @@ class TStreamerString : public TStreamerElement { //________________________________________________________________________ class TStreamerSTL : public TStreamerElement { - enum EStatusBits { - kWarned = BIT(21) - }; - private: TStreamerSTL(const TStreamerSTL&); // Not implemented TStreamerSTL&operator=(const TStreamerSTL&); // Not implemented diff --git a/core/metacling/src/TCling.cxx b/core/metacling/src/TCling.cxx index 27014324c6183..b5038fd1fe18d 100644 --- a/core/metacling/src/TCling.cxx +++ b/core/metacling/src/TCling.cxx @@ -113,6 +113,9 @@ clang/LLVM technology. #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Object/SymbolicFile.h" #include #include @@ -129,6 +132,7 @@ clang/LLVM technology. #include #include #include +#include #ifndef R__WIN32 #include @@ -362,6 +366,16 @@ extern "C" void TCling__RestoreInterpreterMutex(void *delta) ((TCling*)gCling)->ApplyToInterpreterMutex(delta); } +//////////////////////////////////////////////////////////////////////////////// +/// Lookup libraries in LD_LIBRARY_PATH and DYLD_LIBRARY_PATH with mangled_name, +/// which is extracted by error messages we get from callback from cling. Return true +/// when the missing library was autoloaded. + +extern "C" bool TCling__LibraryLoadingFailed(const std::string& errmessage, const std::string& libStem, bool permanent, bool resolved) +{ + return ((TCling*)gCling)->LibraryLoadingFailed(errmessage, libStem, permanent, resolved); +} + //////////////////////////////////////////////////////////////////////////////// /// Reset the interpreter lock to the state it had before interpreter-related /// calls happened. @@ -430,10 +444,6 @@ static void TCling__UpdateClassInfo(const NamedDecl* TD) void TCling::UpdateEnumConstants(TEnum* enumObj, TClass* cl) const { const clang::Decl* D = static_cast(enumObj->GetDeclId()); if(const clang::EnumDecl* ED = dyn_cast(D)) { - - // clang::EnumDecl::enumerator_begin can triggering deserialization - cling::Interpreter::PushTransactionRAII deserRAII(fInterpreter); - // Add the constants to the enum type. for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(), EDE = ED->enumerator_end(); EDI != EDE; ++EDI) { @@ -632,27 +642,6 @@ extern "C" int TCling__AutoLoadCallback(const char* className) return ((TCling*)gCling)->AutoLoad(className); } -extern "C" int TCling__AutoLoadLibraryForModules(const char* StemName) -{ - // FIXME: We're excluding some libraries from autoloading. Adding annotations to - // pcms from LinkDef files would fix this workaround. - static constexpr std::array excludelibs = { {"RooStats", - "RooFitCore", "RooFit", "HistFactory"} }; - for (const char* exLibs : excludelibs) - if (strcmp(exLibs, StemName) == 0) - return -1; - - // Add lib prefix - TString LibName("lib" + std::string(StemName)); - // Construct the actual library name from the stem name. - // Eg. FindDynamicLibrary("libCore") returns "/path/to/libCore.so" - const char *Name = gSystem->FindDynamicLibrary(LibName, kTRUE); - - if (!Name || ((TCling*)gCling)->IsLoaded(Name)) return 1; - - return ((TCling*)gCling)->Load(Name); -} - extern "C" int TCling__AutoParseCallback(const char* className) { return ((TCling*)gCling)->AutoParse(className); @@ -1969,10 +1958,7 @@ void TCling::RegisterModule(const char* modulename, } } - // Don't do "PCM" optimization with runtime modules because we are loading libraries - // at decl deserialization time and it triggers infinite deserialization chain. - // In short, this optimization leads to infinite loop. - if (!hasCxxModule && gIgnoredPCMNames.find(modulename) == gIgnoredPCMNames.end()) { + if (gIgnoredPCMNames.find(modulename) == gIgnoredPCMNames.end()) { if (!LoadPCM(pcmFileName, headers, triggerFunc)) { ::Error("TCling::RegisterModule", "cannot find dictionary module %s", ROOT::TMetaUtils::GetModuleFileName(modulename).c_str()); @@ -3365,6 +3351,8 @@ Int_t TCling::DeleteVariable(const char* name) } unscopedName += posScope + 2; } + // Could trigger deserialization of decls. + cling::Interpreter::PushTransactionRAII RAII(fInterpreter); clang::NamedDecl* nVarDecl = cling::utils::Lookup::Named(&fInterpreter->getSema(), unscopedName, declCtx); if (!nVarDecl) { @@ -4246,6 +4234,8 @@ TInterpreter::DeclId_t TCling::GetDataMember(ClassInfo_t *opaque_cl, const char LookupResult R(SemaR, DName, SourceLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); + // Could trigger deserialization of decls. + cling::Interpreter::PushTransactionRAII RAII(fInterpreter); cling::utils::Lookup::Named(&SemaR, R); LookupResult::Filter F = R.makeFilter(); @@ -4285,6 +4275,8 @@ TInterpreter::DeclId_t TCling::GetEnum(TClass *cl, const char *name) const } if (dc) { // If it is a data member enum. + // Could trigger deserialization of decls. + cling::Interpreter::PushTransactionRAII RAII(fInterpreter); possibleEnum = cling::utils::Lookup::Named(&fInterpreter->getSema(), name, dc); } else { Error("TCling::GetEnum", "DeclContext not found for %s .\n", name); @@ -4292,6 +4284,8 @@ TInterpreter::DeclId_t TCling::GetEnum(TClass *cl, const char *name) const } } else { // If it is a global enum. + // Could trigger deserialization of decls. + cling::Interpreter::PushTransactionRAII RAII(fInterpreter); possibleEnum = cling::utils::Lookup::Named(&fInterpreter->getSema(), name); } if (possibleEnum && (possibleEnum != (clang::Decl*)-1) @@ -5891,11 +5885,182 @@ Int_t TCling::AutoParse(const char *cls) return nHheadersParsed > 0 ? 1 : 0; } +// This is a function which gets callback from cling when DynamicLibraryManager->loadLibrary failed for some reason. +// Try to solve the problem by autoloading. Return true when autoloading success, return +// false if not. +bool TCling::LibraryLoadingFailed(const std::string& errmessage, const std::string& libStem, bool permanent, bool resolved) +{ + StringRef errMsg(errmessage); + if (errMsg.contains("undefined symbol: ")) { + std::string mangled_name = std::string(errMsg.split("undefined symbol: ").second); + void* res = ((TCling*)gCling)->LazyFunctionCreatorAutoload(mangled_name); + cling::DynamicLibraryManager* DLM = fInterpreter->getDynamicLibraryManager(); + if (res && DLM && (DLM->loadLibrary(libStem, permanent, resolved) == cling::DynamicLibraryManager::kLoadLibSuccess)) + // Return success when LazyFunctionCreatorAutoload could find mangled_name + return true; + } + + return false; +} + +// This is a GNU implementation of hash used in bloom filter! +static uint32_t GNUHash(StringRef S) { + uint32_t H = 5381; + for (uint8_t C : S) + H = (H << 5) + H + C; + return H; +} + +static StringRef GetGnuHashSection(llvm::object::ObjectFile *file) { + for (auto S : file->sections()) { + StringRef name; + S.getName(name); + if (name == ".gnu.hash") { + StringRef content; + S.getContents(content); + return content; + } + } + return ""; +} + +// Bloom filter. See https://blogs.oracle.com/solaris/gnu-hash-elf-sections-v2 +// for detailed desctiption. In short, there is a .gnu.hash section in so files which contains +// bloomfilter hash value that we can compare with our mangled_name hash. This is a false positive +// probability data structure and enables us to skip libraries which doesn't contain mangled_name definition! +// PE and Mach-O files doesn't have .gnu.hash bloomfilter section, so this is a specific optimization for ELF. +// This is fine because performance critical part (data centers) are running on Linux :) +static bool LookupBloomFilter(llvm::object::ObjectFile *soFile, uint32_t hash) { + const int bits = 64; + + StringRef contents = GetGnuHashSection(soFile); + if (contents.size() < 16) + // We need to search if the library doesn't have .gnu.hash section! + return true; + const char* hashContent = contents.data(); + + // See https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/ for .gnu.hash table layout. + uint32_t maskWords = *reinterpret_cast(hashContent + 8); + uint32_t shift2 = *reinterpret_cast(hashContent + 12); + uint32_t hash2 = hash >> shift2; + uint32_t n = (hash / bits) % maskWords; + + const char *bloomfilter = hashContent + 16; + const char *hash_pos = bloomfilter + n*(bits/8); // * (Bits / 8) + uint64_t word = *reinterpret_cast(hash_pos); + uint64_t bitmask = ( (1ULL << (hash % bits)) | (1ULL << (hash2 % bits))); + return (bitmask & word) == bitmask; +} + +static void* LazyFunctionCreatorAutoloadForModule(const std::string& mangled_name, + cling::Interpreter *fInterpreter) { + using namespace llvm::object; + using namespace llvm::sys::path; + using namespace llvm::sys::fs; + + R__LOCKGUARD(gInterpreterMutex); + + static bool sFirstRun = true; + // sLibraies contains pair of sPaths[i] (eg. /home/foo/module) and library name (eg. libTMVA.so). The + // reason why we're separating sLibraries and sPaths is that we have a lot of + // dupulication in path, for example we have "/home/foo/module-release/lib/libFoo.so", "/home/../libBar.so", "/home/../lib.." + // and it's waste of memory to store the full path. + static std::vector< std::pair > sLibraries; + static std::vector sPaths; + + if (sFirstRun) { + // Store the information of path so that we don't have to iterate over the same path again and again. + std::unordered_set alreadyLookedPath; + const clang::Preprocessor &PP = fInterpreter->getCI()->getPreprocessor(); + const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); + const std::vector& ModulePaths(HSOpts.PrebuiltModulePaths); + cling::DynamicLibraryManager* dyLibManager = fInterpreter->getDynamicLibraryManager(); + + // Take path here eg. "/home/foo/module-release/lib/" + for (const std::string& Path : ModulePaths) { + // Already searched? + auto it = alreadyLookedPath.insert(Path); + if (!it.second) + continue; + StringRef DirPath(Path); + // Skip current directory, because what we want to autoload is not a random shared libraries but libraries generated + // by ROOT. In fact, some tests were failing because of this as they have their custom shared libraries (which is not supporsed + // to be autoloaded) + if (!is_directory(DirPath) || Path == ".") + continue; + + sPaths.push_back(Path); + + std::error_code EC; + for (llvm::sys::fs::directory_iterator DirIt(DirPath, EC), DirEnd; + DirIt != DirEnd && !EC; DirIt.increment(EC)) { + + std::string FileName(DirIt->path()); + if (!llvm::sys::fs::is_directory(FileName) && extension(FileName) == ".so") { + // TCling::IsLoaded is incredibly slow! + // No need to check linked libraries, as this function is only invoked + // for symbols that cannot be found (neither by dlsym nor in the JIT). + if (dyLibManager->isLibraryLoaded(FileName.c_str())) + continue; + sLibraries.push_back(std::make_pair(sPaths.size() - 1, llvm::sys::path::filename(FileName))); + } + } + } + sFirstRun = false; + } + + uint32_t hashedMangle = GNUHash(mangled_name); + // Iterate over files under this path. We want to get each ".so" files + for (std::pair &P : sLibraries) { + llvm::SmallString<400> Vec(sPaths[P.first]); + llvm::sys::path::append(Vec, StringRef(P.second)); + std::string LibName = Vec.str(); + auto SoFile = ObjectFile::createObjectFile(LibName); + if (SoFile) { + auto RealSoFile = SoFile.get().getBinary(); + + // Check Bloom filter. If false, it means that this library doesn't contain mangled_name defenition + if (!LookupBloomFilter(RealSoFile, hashedMangle)) + continue; + + auto Symbols = RealSoFile->symbols(); + for (auto S : Symbols) { + // DO NOT insert to table if symbol was weak or undefined + if (S.getFlags() == SymbolRef::SF_Weak || S.getFlags() == SymbolRef::SF_Undefined) continue; + + llvm::Expected SymNameErr = S.getName(); + if (!SymNameErr) { + Warning("LazyFunctionCreatorAutoloadForModule", "Failed to read symbol"); + continue; + } + + if (SymNameErr.get() == mangled_name) { + if (gSystem->Load(LibName.c_str(), "", false) < 0) + Error("LazyFunctionCreatorAutoloadForModule", "Failed to load library %s", LibName.c_str()); + + // We want to delete a loaded library from sLibraries cache, because sLibraries is + // a vector of candidate libraries which might be loaded in the future. + sLibraries.erase(std::remove(sLibraries.begin(), sLibraries.end(), P), sLibraries.end()); + void* addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(mangled_name.c_str()); + return addr; + } + } + } + } + return nullptr; +} //////////////////////////////////////////////////////////////////////////////// /// Autoload a library based on a missing symbol. void* TCling::LazyFunctionCreatorAutoload(const std::string& mangled_name) { + bool useCxxModules = false; +#ifdef R__USE_CXXMODULES + useCxxModules = true; +#endif + if (useCxxModules) + return LazyFunctionCreatorAutoloadForModule(mangled_name, fInterpreter); + // First see whether the symbol is in the library that we are currently // loading. It will have access to the symbols of its dependent libraries, // thus checking "back()" is sufficient. diff --git a/core/metacling/src/TCling.h b/core/metacling/src/TCling.h index 646cf53a46bf3..f10000c267b72 100644 --- a/core/metacling/src/TCling.h +++ b/core/metacling/src/TCling.h @@ -177,6 +177,7 @@ class TCling : public TInterpreter { Int_t AutoLoad(const std::type_info& typeinfo, Bool_t knowDictNotLoaded = kFALSE); Int_t AutoParse(const char* cls); void* LazyFunctionCreatorAutoload(const std::string& mangled_name); + bool LibraryLoadingFailed(const std::string&, const std::string&, bool, bool); Bool_t IsAutoLoadNamespaceCandidate(const char* name); Bool_t IsAutoLoadNamespaceCandidate(const clang::NamespaceDecl* nsDecl); void ClearFileBusy(); diff --git a/core/metacling/src/TClingBaseClassInfo.cxx b/core/metacling/src/TClingBaseClassInfo.cxx index 9991a9682e626..1bba75265638c 100644 --- a/core/metacling/src/TClingBaseClassInfo.cxx +++ b/core/metacling/src/TClingBaseClassInfo.cxx @@ -110,8 +110,6 @@ TClingBaseClassInfo::TClingBaseClassInfo(cling::Interpreter* interp, //CRD->isDerivedFrom(BaseCRD, Paths); // Check that base derives from derived. clang::CXXBasePaths Paths; - // isDerivedFrom can trigger deserialization - cling::Interpreter::PushTransactionRAII RAII(fInterp); if (!CRD->isDerivedFrom(BaseCRD, Paths)) { //Not valid fBaseInfo = 0. return; @@ -260,11 +258,6 @@ int TClingBaseClassInfo::InternalNext(int onlyDirect) (fIter == llvm::dyn_cast(fDecl)->bases_end())) { return 0; } - - // getASTRecordLayout() can trigger deserialization, and this should stay here - // instead of inside the while loop - cling::Interpreter::PushTransactionRAII RAII(fInterp); - // Advance to the next valid base. while (1) { // Advance the iterator. @@ -276,6 +269,8 @@ int TClingBaseClassInfo::InternalNext(int onlyDirect) // We previously processed a base class which itself has bases, // now we process the bases of that base class. + // At least getASTRecordLayout() might deserialize. + cling::Interpreter::PushTransactionRAII RAII(fInterp); fDescend = false; const clang::RecordType *Ty = fIter->getType()-> getAs(); @@ -509,10 +504,6 @@ long TClingBaseClassInfo::Property() const clang::CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, /*DetectVirtual=*/true); - - // isDerivedFrom can trigger deserialization - cling::Interpreter::PushTransactionRAII RAII(fInterp); - if (!CRD->isDerivedFrom(BaseCRD, Paths)) { // Error really unexpected here, because construction / iteration guarantees //inheritance; diff --git a/core/metacling/src/TClingCallbacks.cxx b/core/metacling/src/TClingCallbacks.cxx index 9b18677c242ee..cf3307e4abf37 100644 --- a/core/metacling/src/TClingCallbacks.cxx +++ b/core/metacling/src/TClingCallbacks.cxx @@ -50,13 +50,13 @@ extern "C" { Decl* TCling__GetObjectDecl(TObject *obj); int TCling__AutoLoadCallback(const char* className); int TCling__AutoParseCallback(const char* className); - void TCling__AutoLoadLibraryForModules(const char* StemName); const char* TCling__GetClassSharedLibs(const char* className); // int TCling__IsAutoLoadNamespaceCandidate(const char* name); int TCling__IsAutoLoadNamespaceCandidate(const clang::NamespaceDecl* name); int TCling__CompileMacro(const char *fileName, const char *options); void TCling__SplitAclicMode(const char* fileName, std::string &mode, std::string &args, std::string &io, std::string &fname); + bool TCling__LibraryLoadingFailed(const std::string&, const std::string&, bool, bool); void TCling__LibraryLoadedRTTI(const void* dyLibHandle, llvm::StringRef canonicalName); void TCling__LibraryUnloadedRTTI(const void* dyLibHandle, @@ -125,6 +125,12 @@ void TClingCallbacks::InclusionDirective(clang::SourceLocation sLoc/*HashLoc*/, tryAutoParseInternal(localString, RHeader, SemaR.getCurScope(), FE); } +// TCling__LibraryLoadingFailed is a function in TCling which handles errmessage +bool TClingCallbacks::LibraryLoadingFailed(const std::string& errmessage, const std::string& libStem, + bool permanent, bool resolved) { + return TCling__LibraryLoadingFailed(errmessage, libStem, permanent, resolved); +} + // Preprocessor callbacks used to handle special cases like for example: // #include "myMacro.C+" // @@ -750,29 +756,6 @@ void TClingCallbacks::TransactionCommitted(const Transaction &T) { TCling__UpdateListsOnCommitted(T, m_Interpreter); } -// Collect modules and put them into fPendingCxxModules at first run. Interpreter is not yet initialized at first run -// but we need to use interpreter services when loading libraries. -void TClingCallbacks::beforeExecuteTransaction(const Transaction &T) { - - const std::vector &modules = T.getClangModules(); - - if (fFirstRun) { - for (auto M : modules) - fPendingCxxModules.push_back(M); - return; - } - - if (!fPendingCxxModules.empty()) { - for (auto M : fPendingCxxModules) - TCling__AutoLoadLibraryForModules(M->Name.c_str()); - fPendingCxxModules.clear(); - return; - } - - for (auto M : modules) - TCling__AutoLoadLibraryForModules(M->Name.c_str()); -} - // The callback is used to update the list of globals in ROOT. // void TClingCallbacks::TransactionUnloaded(const Transaction &T) { diff --git a/core/metacling/src/TClingCallbacks.h b/core/metacling/src/TClingCallbacks.h index 55caae110e87f..b9a21bbef7525 100644 --- a/core/metacling/src/TClingCallbacks.h +++ b/core/metacling/src/TClingCallbacks.h @@ -12,7 +12,6 @@ #include "cling/Interpreter/InterpreterCallbacks.h" #include -#include namespace clang { class Decl; @@ -28,7 +27,6 @@ namespace clang { namespace cling { class Interpreter; class Transaction; - class Module; } namespace llvm { @@ -47,9 +45,6 @@ class TClingCallbacks : public cling::InterpreterCallbacks { bool fIsAutoParsingSuspended; bool fPPOldFlag; bool fPPChanged; - // This vector holds a clang cxxmodules where corresponding library should be loaded in Transaction - // afterwards. - std::vector fPendingCxxModules; public: TClingCallbacks(cling::Interpreter* interp); @@ -63,6 +58,8 @@ class TClingCallbacks : public cling::InterpreterCallbacks { void SetAutoParsingSuspended(bool val = true) { fIsAutoParsingSuspended = val; } bool IsAutoParsingSuspended() { return fIsAutoParsingSuspended; } + virtual bool LibraryLoadingFailed(const std::string&, const std::string&, bool, bool); + virtual void InclusionDirective(clang::SourceLocation /*HashLoc*/, const clang::Token &/*IncludeTok*/, llvm::StringRef FileName, @@ -88,8 +85,6 @@ class TClingCallbacks : public cling::InterpreterCallbacks { // virtual void TransactionCommitted(const cling::Transaction &T); - virtual void beforeExecuteTransaction(const cling::Transaction &T); - // The callback is used to update the list of globals in ROOT. // virtual void TransactionUnloaded(const cling::Transaction &T); diff --git a/core/metacling/src/TClingClassInfo.cxx b/core/metacling/src/TClingClassInfo.cxx index 8d8e3cbac6d22..1cb6973800a9f 100644 --- a/core/metacling/src/TClingClassInfo.cxx +++ b/core/metacling/src/TClingClassInfo.cxx @@ -606,27 +606,30 @@ long TClingClassInfo::GetOffset(const CXXMethodDecl* md) const ptrdiff_t TClingClassInfo::GetBaseOffset(TClingClassInfo* base, void* address, bool isDerivedObject) { - R__LOCKGUARD(gInterpreterMutex); - - // Check for the offset in the cache. - auto iter = fOffsetCache.find(base->GetDecl()); - if (iter != fOffsetCache.end()) { - std::pair offsetCache = (*iter).second; - if (OffsetPtrFunc_t executableFunc = offsetCache.second) { - if (address) { - return (*executableFunc)(address, isDerivedObject); + { + R__READ_LOCKGUARD(ROOT::gCoreMutex); + + // Check for the offset in the cache. + auto iter = fOffsetCache.find(base->GetDecl()); + if (iter != fOffsetCache.end()) { + std::pair offsetCache = (*iter).second; + if (OffsetPtrFunc_t executableFunc = offsetCache.second) { + if (address) { + return (*executableFunc)(address, isDerivedObject); + } + else { + Error("TClingBaseClassInfo::Offset", "The address of the object for virtual base offset calculation is not valid."); + return -1; + } } else { - Error("TClingBaseClassInfo::Offset", "The address of the object for virtual base offset calculation is not valid."); - return -1; + return offsetCache.first; } } - else { - return offsetCache.first; - } } // Compute the offset. + R__WRITE_LOCKGUARD(ROOT::gCoreMutex); TClingBaseClassInfo binfo(fInterp, this, base); return binfo.Offset(address, isDerivedObject); } @@ -1267,10 +1270,6 @@ const char *TClingClassInfo::Name() const if (const NamedDecl* ND = llvm::dyn_cast(fDecl)) { PrintingPolicy Policy(fDecl->getASTContext().getPrintingPolicy()); llvm::raw_string_ostream stream(buf); - - // getNameForDiagnostic can trigger deserialization - cling::Interpreter::PushTransactionRAII RAII(fInterp); - ND->getNameForDiagnostic(stream, Policy, /*Qualified=*/false); } return buf.c_str(); diff --git a/core/metacling/src/TClingDataMemberInfo.cxx b/core/metacling/src/TClingDataMemberInfo.cxx index 21c6a82f670b2..9c8fa9980f42f 100644 --- a/core/metacling/src/TClingDataMemberInfo.cxx +++ b/core/metacling/src/TClingDataMemberInfo.cxx @@ -308,9 +308,6 @@ long TClingDataMemberInfo::Offset() const Decl *D = GetDecl(); ASTContext& C = D->getASTContext(); if (const FieldDecl *FldD = dyn_cast(D)) { - // getASTRecordLayout can trigger deserialization - cling::Interpreter::PushTransactionRAII RAII(fInterp); - // The current member is a non-static data member. const clang::RecordDecl *RD = FldD->getParent(); const clang::ASTRecordLayout &Layout = C.getASTRecordLayout(RD); diff --git a/core/metacling/src/TClingTypeInfo.cxx b/core/metacling/src/TClingTypeInfo.cxx index f718dbd54b2e3..10e5cc58465dd 100644 --- a/core/metacling/src/TClingTypeInfo.cxx +++ b/core/metacling/src/TClingTypeInfo.cxx @@ -168,10 +168,6 @@ long TClingTypeInfo::Property() const // Note: Now we have class, struct, union only. const clang::CXXRecordDecl *CRD = llvm::dyn_cast(TD); - - // isAbstract can trigger deserialization - cling::Interpreter::PushTransactionRAII RAII(fInterp); - if (CRD->isClass()) { property |= kIsClass; } diff --git a/core/newdelete/src/NewDelete.cxx b/core/newdelete/src/NewDelete.cxx index 0ab4301370243..b997d9e3aa55d 100644 --- a/core/newdelete/src/NewDelete.cxx +++ b/core/newdelete/src/NewDelete.cxx @@ -211,13 +211,13 @@ void *operator new(size_t size, const std::nothrow_t&) noexcept #if __cplusplus >= 201700L -void *operator new(size_t size, std::align_val_t al) +void *operator new(size_t /*size*/, std::align_val_t /*al*/) { Fatal("operator new","with std::align_val_t is not implemented yet"); return nullptr; } -void *operator new(size_t size, std::align_val_t al, const std::nothrow_t&) noexcept +void *operator new(size_t /*size*/, std::align_val_t /*al*/, const std::nothrow_t&) noexcept { Fatal("operator new","with std::align_val_t is not implemented yet"); return nullptr; @@ -297,11 +297,11 @@ void operator delete(void *ptr, const std::nothrow_t&) noexcept } #if __cplusplus >= 201700L -void operator delete(void *ptr, std::align_val_t al) noexcept +void operator delete(void * /*ptr*/, std::align_val_t /*al*/) noexcept { Fatal("operator delete","with std::align_val_t is not implemented yet"); } -void operator delete(void *ptr, std::align_val_t al, const std::nothrow_t&) noexcept +void operator delete(void * /*ptr*/, std::align_val_t /*al*/, const std::nothrow_t&) noexcept { Fatal("operator delete","with std::align_val_t is not implemented yet"); } @@ -315,7 +315,7 @@ void operator delete(void* ptr, std::size_t) noexcept { operator delete(ptr); } #if __cplusplus >= 201700L -void operator delete(void *ptr, std::size_t, std::align_val_t al) noexcept +void operator delete(void * /*ptr*/, std::size_t, std::align_val_t /*al*/) noexcept { Fatal("operator delete","with std::align_val_t is not implemented yet"); } @@ -338,13 +338,13 @@ void *operator new[](size_t size, const std::nothrow_t&) noexcept #if __cplusplus >= 201700L -void *operator new[](size_t size, std::align_val_t al) +void *operator new[](size_t /*size*/, std::align_val_t /*al*/) { Fatal("operator new[]","with std::align_val_t is not implemented yet"); return nullptr; } -void *operator new[](size_t size, std::align_val_t al, const std::nothrow_t&) noexcept +void *operator new[](size_t /*size*/, std::align_val_t /*al*/, const std::nothrow_t&) noexcept { Fatal("operator new[]","with std::align_val_t is not implemented yet"); return nullptr; @@ -370,7 +370,7 @@ void operator delete[](void *ptr) noexcept } #if __cplusplus >= 201700L -void operator delete[](void *ptr, std::align_val_t al) noexcept +void operator delete[](void * /*ptr*/, std::align_val_t /*al*/) noexcept { Fatal("operator delete[]","with std::align_val_t is not implemented yet"); } diff --git a/core/textinput/src/textinput/SignalHandler.cpp b/core/textinput/src/textinput/SignalHandler.cpp index cd69b29131fae..103ba9dbb7451 100644 --- a/core/textinput/src/textinput/SignalHandler.cpp +++ b/core/textinput/src/textinput/SignalHandler.cpp @@ -22,11 +22,6 @@ namespace textinput { using std::raise; - void - SignalHandler::EmitCtrlC() { - raise(SIGINT); - } - void SignalHandler::EmitCtrlZ() { #ifndef _WIN32 diff --git a/core/textinput/src/textinput/SignalHandler.h b/core/textinput/src/textinput/SignalHandler.h index 3a1a96b3ec289..a096361629130 100644 --- a/core/textinput/src/textinput/SignalHandler.h +++ b/core/textinput/src/textinput/SignalHandler.h @@ -22,7 +22,6 @@ namespace textinput { SignalHandler() {} ~SignalHandler() {} - void EmitCtrlC(); void EmitCtrlZ(); }; } diff --git a/core/textinput/src/textinput/Text.h b/core/textinput/src/textinput/Text.h index e433114d9a06a..5a03e33f09046 100644 --- a/core/textinput/src/textinput/Text.h +++ b/core/textinput/src/textinput/Text.h @@ -71,7 +71,7 @@ namespace textinput { Text& operator+=(char C) { insert(length(), C); return *this; } Text& operator=(const std::string& S) { - // Assing string S to this, initialize with default colors. + // Assign string S to this, initialize with default colors. fColor.clear(); fColor.resize(S.length()); fString = S; diff --git a/core/textinput/src/textinput/TextInput.cpp b/core/textinput/src/textinput/TextInput.cpp index b06ed3334592b..34dcc9531f8a4 100644 --- a/core/textinput/src/textinput/TextInput.cpp +++ b/core/textinput/src/textinput/TextInput.cpp @@ -152,12 +152,19 @@ namespace textinput { && (Cmd.GetChar() == 3 || Cmd.GetChar() == 26)) { // If there are modifications in the queue, process them now. UpdateDisplay(R); - EmitSignal(Cmd.GetChar(), R); + HandleControl(Cmd.GetChar(), R); } else if (Cmd.GetKind() == Editor::kCKCommand && Cmd.GetCommandID() == Editor::kCmdWindowResize) { std::for_each(fContext->GetDisplays().begin(), fContext->GetDisplays().end(), [](Display *D) { return D->NotifyWindowChange(); }); + } else if (Cmd.GetKind() == Editor::kCKCommand + && Cmd.GetCommandID() == Editor::kCmdDel && + !fContext->GetLine().length()) { + fContext->SetLine(".q"); + Redraw(); + fLastReadResult = kRREOF; + return; } else { if (!in.IsRaw() && in.GetExtendedInput() == InputData::kEIEOF) { fLastReadResult = kRREOF; @@ -228,15 +235,18 @@ namespace textinput { } void - TextInput::EmitSignal(char C, EditorRange& R) { - - ReleaseInputOutput(); - SignalHandler* Signal = fContext->GetSignalHandler(); - - if (C == 3) - Signal->EmitCtrlC(); - else if (C == 26) + TextInput::HandleControl(char C, EditorRange& R) { + if (C == 3) { // Control+C + std::string input = fContext->GetLine().GetText(); + size_t length = input.size(); + fContext->SetLine(input + "^C"); + UpdateDisplay(EditorRange(Range(length), Range::AllText())); + TakeInput(input, true); + } else if (C == 26) { // Control+Z + ReleaseInputOutput(); + SignalHandler* Signal = fContext->GetSignalHandler(); Signal->EmitCtrlZ(); + } GrabInputOutput(); diff --git a/core/textinput/src/textinput/TextInput.h b/core/textinput/src/textinput/TextInput.h index abe6a16938717..d4749c9061e5e 100644 --- a/core/textinput/src/textinput/TextInput.h +++ b/core/textinput/src/textinput/TextInput.h @@ -89,7 +89,7 @@ namespace textinput { void AddHistoryLine(const char* line); private: - void EmitSignal(char c, EditorRange& r); + void HandleControl(char c, EditorRange& r); void ProcessNewInput(const InputData& in, EditorRange& r); void DisplayNewInput(EditorRange& r, size_t& oldCursorPos); diff --git a/core/thread/CMakeLists.txt b/core/thread/CMakeLists.txt index 2149ff5d473f8..77801c20ff3d7 100644 --- a/core/thread/CMakeLists.txt +++ b/core/thread/CMakeLists.txt @@ -2,10 +2,12 @@ # CMakeLists.txt file for building ROOT core/thread package ############################################################################ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../foundation/res) + set(headers TAtomicCount.h TCondition.h TConditionImp.h TMutex.h TMutexImp.h TRWLock.h ROOT/TRWSpinLock.hxx TSemaphore.h TThread.h TThreadFactory.h TThreadImp.h ROOT/TThreadedObject.hxx TThreadPool.h - ThreadLocalStorage.h ROOT/TSpinMutex.hxx ROOT/TReentrantRWLock.hxx) + ThreadLocalStorage.h ROOT/TSpinMutex.hxx ROOT/TReentrantRWLock.hxx ROOT/RConcurrentHashColl.hxx) if(NOT WIN32) set(headers ${headers} TPosixCondition.h TPosixMutex.h TPosixThread.h TPosixThreadFactory.h PosixThreadInc.h) @@ -18,7 +20,7 @@ endif() set(sources TCondition.cxx TConditionImp.cxx TMutex.cxx TMutexImp.cxx TRWLock.cxx TRWSpinLock.cxx TSemaphore.cxx TThread.cxx TThreadFactory.cxx - TThreadImp.cxx TRWMutexImp.cxx TReentrantRWLock.cxx) + TThreadImp.cxx TRWMutexImp.cxx TReentrantRWLock.cxx RConcurrentHashColl.cxx) if(NOT WIN32) set(sources ${sources} TPosixCondition.cxx TPosixMutex.cxx TPosixThread.cxx TPosixThreadFactory.cxx) diff --git a/core/thread/inc/ROOT/RConcurrentHashColl.hxx b/core/thread/inc/ROOT/RConcurrentHashColl.hxx new file mode 100644 index 0000000000000..4161da9f96e7a --- /dev/null +++ b/core/thread/inc/ROOT/RConcurrentHashColl.hxx @@ -0,0 +1,40 @@ +// Author: Danilo Piparo May 2018 + +/************************************************************************* + * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_RConcurrentHashColl +#define ROOT_RConcurrentHashColl + +#include + +namespace ROOT { + +class TRWSpinLock; + +namespace Internal { + +struct RHashSet; + +/// This class is a TS set of unsigned set +class RConcurrentHashColl { +private: + mutable std::unique_ptr fHashSet; + mutable std::unique_ptr fRWLock; + +public: + RConcurrentHashColl(); + ~RConcurrentHashColl(); + /// If the hash is there, return false. Otherwise, insert the hash and return true; + bool Insert(char *buf, int len) const; +}; + +} // End NS Internal +} // End NS ROOT + +#endif diff --git a/core/thread/inc/ROOT/TRWSpinLock.hxx b/core/thread/inc/ROOT/TRWSpinLock.hxx index 66f40c0dbfeae..79d9921e17c5a 100644 --- a/core/thread/inc/ROOT/TRWSpinLock.hxx +++ b/core/thread/inc/ROOT/TRWSpinLock.hxx @@ -18,27 +18,45 @@ #include #include - namespace ROOT { - class TRWSpinLock { - private: - std::atomic fReaders; /// fReaderReservation; /// fWriterReservation; /// fWriter; /// fReaders; /// fReaderReservation; /// fWriterReservation; /// fWriter; /// +#include +#include +#include +#include + +#include + +namespace ROOT { +namespace Internal { + +struct RHashSet { + std::set fSet; +}; + +RConcurrentHashColl::RConcurrentHashColl() + : fHashSet(std::make_unique()), fRWLock(std::make_unique()){}; +RConcurrentHashColl::~RConcurrentHashColl() = default; + +/// If the buffer is there, return false. Otherwise, insert the hash and return true +bool RConcurrentHashColl::Insert(char *buffer, int len) const +{ + RSha256Hash hash(buffer, len); + + { + ROOT::TRWSpinLockReadGuard rg(*fRWLock); + if (fHashSet->fSet.end() != fHashSet->fSet.find(hash)) + return false; + } + { + ROOT::TRWSpinLockWriteGuard wg(*fRWLock); + fHashSet->fSet.insert(hash); + return true; + } +} + +} // End NS Internal +} // End NS ROOT \ No newline at end of file diff --git a/core/thread/src/TRWSpinLock.cxx b/core/thread/src/TRWSpinLock.cxx index 5aea5b23af4de..37b51c5c6ed1c 100644 --- a/core/thread/src/TRWSpinLock.cxx +++ b/core/thread/src/TRWSpinLock.cxx @@ -110,3 +110,25 @@ void TRWSpinLock::WriteUnLock() fCond.notify_all(); } + +TRWSpinLockReadGuard::TRWSpinLockReadGuard(TRWSpinLock &lock) : fLock(lock) +{ + fLock.ReadLock(); +} + +TRWSpinLockReadGuard::~TRWSpinLockReadGuard() +{ + fLock.ReadUnLock(); +} + +TRWSpinLockWriteGuard::TRWSpinLockWriteGuard(TRWSpinLock &lock) : fLock(lock) +{ + fLock.WriteLock(); +} + +TRWSpinLockWriteGuard::~TRWSpinLockWriteGuard() +{ + fLock.WriteUnLock(); +} + + diff --git a/core/winnt/src/TWin32SplashThread.cxx b/core/winnt/src/TWin32SplashThread.cxx index fe88cac7d8193..e17be708024a9 100644 --- a/core/winnt/src/TWin32SplashThread.cxx +++ b/core/winnt/src/TWin32SplashThread.cxx @@ -12,7 +12,7 @@ TWin32SplashThread *gSplash = 0; -extern void CreateSplash(DWORD time, BOOL extended); +extern void CreateSplash(DWORD time, bool extended); extern void DestroySplashScreen(); //////////////////////////////////////////////////////////////////////////////// diff --git a/core/winnt/src/TWinNTSystem.cxx b/core/winnt/src/TWinNTSystem.cxx index c085a83a2899e..865e8e2b0938b 100644 --- a/core/winnt/src/TWinNTSystem.cxx +++ b/core/winnt/src/TWinNTSystem.cxx @@ -886,16 +886,17 @@ namespace { bool NeedSplash() { static bool once = true; - if (!once || gROOT->IsBatch() || !gApplication) return false; - TString arg = gSystem->BaseName(gApplication->Argv(0)); - if ((arg != "root") && (arg != "rootn") && - (arg != "root.exe") && (arg != "rootn.exe")) return false; - for(int i=1; iArgc(); i++) { - arg = gApplication->Argv(i); + TString arg; + + if (!once || gROOT->IsBatch()) return false; + TString cmdline(::GetCommandLine()); + Int_t i = 0, from = 0; + while (cmdline.Tokenize(arg, from, " ")) { arg.Strip(TString::kBoth); - if ((arg == "-l") || (arg == "-b")) { - return false; - } + if (i == 0 && ((arg != "root") && (arg != "rootn") && + (arg != "root.exe") && (arg != "rootn.exe"))) return false; + else if ((arg == "-l") || (arg == "-b")) return false; + ++i; } if (once) { once = false; diff --git a/core/winnt/src/Win32Splash.cxx b/core/winnt/src/Win32Splash.cxx index c3992a0edb062..7868d777df83b 100644 --- a/core/winnt/src/Win32Splash.cxx +++ b/core/winnt/src/Win32Splash.cxx @@ -10,13 +10,16 @@ *************************************************************************/ #ifdef WIN32 -#include "Windows4Root.h" #include "RVersion.h" #include "strlcpy.h" -#include -#include -#include -#include +#include +#include +#include +#include +#define WIN32_LEAN_AND_MEAN +#include +#pragma comment(lib, "windowscodecs.lib") +#pragma comment(lib, "msimg32.lib") #define ID_SPLASHSCREEN 25 @@ -26,502 +29,477 @@ static const char *gConception[] = { 0 }; -static const char *gLeadDevelopers[] = { +const char * gROOTCoreTeam[] = { "Rene Brun", - "Philippe Canal", "Fons Rademakers", - 0 -}; - -static const char *gRootDevelopers[] = { - "Ilka Antcheva", - "Maarten Ballintijn", - "Bertrand Bellenot", + "Philippe Canal", + "Axel Naumann", "Olivier Couet", - "Valery Fine", + "Lorenzo Moneta", + "Vassil Vassilev", "Gerardo Ganis", - "Eddy Offermann", - "Valeriy Onuchin", - 0 -}; - -//static const char *gCintDevelopers[] = { -// "Masaharu Goto", -// 0 -//}; - -static const char *gRootDocumentation[] = { + "Bertrand Bellenot", + "Danilo Piparo", + "Wouter Verkerke", + "Timur Pocheptsov", + "Matevz Tadel", + "Pere Mato", + "Wim Lavrijsen", "Ilka Antcheva", - "Suzanne Panacek", + "Paul Russo", + "Andrei Gheata", + "Anirudha Bose", + "Valeri Onuchine", 0 }; -static char **gContributors = 0; - -typedef struct tagImgInfo { - IPicture *Ipic; - SIZE sizeInHiMetric; - SIZE sizeInPix; - char *Path; -} IMG_INFO; - -static IMG_INFO gImageInfo; - /////////////////////////////////////////////////////////////////////////////// // Global Variables: -static HINSTANCE gInst; // Current instance -static HWND gSplashWnd = 0; // Splash screen -static BOOL gShow = FALSE; -static DWORD gDelayVal = 0; -static HDC gDCScreen = 0, gDCCredits = 0; -static HBITMAP gBmpScreen = 0, gBmpOldScreen = 0; -static HBITMAP gBmpCredits = 0, gBmpOldCredits = 0; -static HRGN gRgnScreen = 0; -static int gCreditsBmpWidth; -static int gCreditsBmpHeight; - -static bool gStayUp = true; +static HINSTANCE gInst = 0; // Current instance +static HWND gSplashWnd = 0; // Splash screen +static bool gShow = FALSE; +static DWORD gDelayVal = 0; static bool gAbout = false; -static RECT gCreditsRect = { 15, 155, 305, 285 }; // clip rect in logo +static RECT gCreditsRect = { 115, 0, 580, 80 }; // clip rect in logo static unsigned int gCreditsWidth = gCreditsRect.right - gCreditsRect.left; // credits pixmap size -static unsigned int gCreditsHeight = gCreditsRect.bottom - gCreditsRect.top; // credits rect height -static void ReadContributors() -{ - // Read the file $ROOTSYS/README/CREDITS for the names of the - // contributors. +/////////////////////////////////////////////////////////////////////////// +/// Create a bitmap and draw alpha blended text on it. - char buf[2048]; -#ifdef ROOTDOCDIR - sprintf(buf, "%s/CREDITS", ROOTDOCDIR); -#else - sprintf(buf, "%s/README/CREDITS", getenv("ROOTSYS")); -#endif - - gContributors = 0; - - FILE *f = fopen(buf, "r"); - if (!f) return; - - int cnt = 0; - while (fgets(buf, sizeof(buf), f)) { - if (!strncmp(buf, "N: ", 3)) { - cnt++; +HBITMAP CreateAlphaTextBitmap(LPCSTR inText, HFONT inFont, COLORREF inColour) +{ + int TextLength = (int)strlen(inText); + if (TextLength <= 0) return NULL; + + // Create DC and select font into it + HDC hTextDC = CreateCompatibleDC(NULL); + HFONT hOldFont = (HFONT)SelectObject(hTextDC, inFont); + HBITMAP hMyDIB = NULL; + + // Get text area + RECT TextArea = {0, 0, 0, 0}; + DrawText(hTextDC, inText, TextLength, &TextArea, DT_CALCRECT); + if ((TextArea.right > TextArea.left) && (TextArea.bottom > TextArea.top)) { + BITMAPINFOHEADER BMIH; + memset(&BMIH, 0x0, sizeof(BITMAPINFOHEADER)); + void *pvBits = NULL; + + // Specify DIB setup + BMIH.biSize = sizeof(BMIH); + BMIH.biWidth = TextArea.right - TextArea.left; + BMIH.biHeight = TextArea.bottom - TextArea.top; + BMIH.biPlanes = 1; + BMIH.biBitCount = 32; + BMIH.biCompression = BI_RGB; + + // Create and select DIB into DC + hMyDIB = CreateDIBSection(hTextDC, (LPBITMAPINFO)&BMIH, 0, + (LPVOID*)&pvBits, NULL, 0); + HBITMAP hOldBMP = (HBITMAP)SelectObject(hTextDC, hMyDIB); + if (hOldBMP != NULL) { + // Set up DC properties + SetTextColor(hTextDC, 0x00FFFFFF); + SetBkColor(hTextDC, 0x00000000); + SetBkMode(hTextDC, OPAQUE); + + // Draw text to buffer + DrawText(hTextDC, inText, TextLength, &TextArea, DT_NOCLIP); + BYTE* DataPtr = (BYTE*)pvBits; + BYTE FillR = GetRValue(inColour); + BYTE FillG = GetGValue(inColour); + BYTE FillB = GetBValue(inColour); + BYTE ThisA; + for (int LoopY = 0; LoopY < BMIH.biHeight; LoopY++) { + for (int LoopX = 0; LoopX < BMIH.biWidth; LoopX++) { + ThisA = *DataPtr; // Move alpha and pre-multiply with RGB + *DataPtr++ = (FillB * ThisA) >> 8; + *DataPtr++ = (FillG * ThisA) >> 8; + *DataPtr++ = (FillR * ThisA) >> 8; + *DataPtr++ = ThisA; // Set Alpha + } + } + // De-select bitmap + SelectObject(hTextDC, hOldBMP); } } - gContributors = new char*[cnt+1]; - - cnt = 0; - rewind(f); - while (fgets(buf, sizeof(buf), f)) { - if (!strncmp(buf, "N: ", 3)) { - int len = strlen(buf); - buf[len-1] = 0; // remove \n - len -= 3; // remove "N: " - gContributors[cnt] = new char[len]; - strlcpy(gContributors[cnt], buf+3, len); - cnt++; + // De-select font and destroy temp DC + SelectObject(hTextDC, hOldFont); + DeleteDC(hTextDC); + + // Return DIBSection + return hMyDIB; +} +/////////////////////////////////////////////////////////////////////////// +/// Draw alpha blended text on the splash screen. + +void DrawAlphaText(HDC inDC, HFONT inFont, COLORREF inColor, + const char *text, int inX, int inY) +{ + RECT TextArea = {0, 0, 0, 0}; + HBITMAP MyBMP = CreateAlphaTextBitmap(text, inFont, inColor); + if (MyBMP) { + // Create temporary DC and select new Bitmap into it + HDC hTempDC = CreateCompatibleDC(inDC); + HBITMAP hOldBMP = (HBITMAP)SelectObject(hTempDC, MyBMP); + if (hOldBMP) { + // Get Bitmap image size + BITMAP BMInf; + GetObject(MyBMP, sizeof(BITMAP), &BMInf); + + // Fill blend function and blend new text to window + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 0xFF; + bf.AlphaFormat = AC_SRC_ALPHA; + AlphaBlend(inDC, inX, inY, BMInf.bmWidth, BMInf.bmHeight, hTempDC, + 0, 0, BMInf.bmWidth, BMInf.bmHeight, bf); + + // Clean up + SelectObject(hTempDC, hOldBMP); + DeleteObject(MyBMP); + DeleteDC(hTempDC); } } - gContributors[cnt] = 0; - - fclose(f); } -static void DrawVersion(HDC hDC) +//////////////////////////////////////////////////////////////////////////////// +/// Draw the ROOT version on the bottom right of the splash screen. + +static void DrawVersion(HDC hDC, HFONT inFont, COLORREF inColor) { - // Draw version string. - RECT drawRect; SIZE lpSize; - char version[80]; - int Height; + char version[256]; sprintf(version, "Version %s", ROOT_RELEASE); - - Height = gImageInfo.sizeInPix.cy; - GetTextExtentPoint32(hDC, version, strlen(version), &lpSize); - - drawRect.left = 15; - drawRect.top = Height - 25; - drawRect.right = 15 + lpSize.cx; - drawRect.bottom = drawRect.top + lpSize.cy; - DrawTextEx(hDC, version, strlen(version), &drawRect, DT_LEFT, 0); + DrawAlphaText(hDC, inFont, inColor, version, 580-lpSize.cx, 400); } -static int DrawCreditItem(HDC hDC, const char *creditItem, const char **members, - int y, bool draw) -{ - // Draw credit item. +//////////////////////////////////////////////////////////////////////////////// +/// Draw credit item. +static int DrawCreditItem(HDC hDC, HFONT inFont, COLORREF inColor, + const char *creditItem, const char **members, int y) +{ char credit[1024]; SIZE lpSize1, lpSize2; - RECT drawRect; TEXTMETRIC lptm; int i; int lineSpacing; - GetTextMetrics(hDC, &lptm); - lineSpacing = lptm.tmAscent + lptm.tmDescent; - strcpy(credit, creditItem); for (i = 0; members && members[i]; i++) { if (i) strcat(credit, ", "); GetTextExtentPoint32(hDC, credit, strlen(credit), &lpSize1); GetTextExtentPoint32(hDC, members[i], strlen(members[i]), &lpSize2); if((lpSize1.cx + lpSize2.cx) > (int) gCreditsWidth) { - drawRect.left = 0; - drawRect.top = y; - drawRect.right = gCreditsRect.right; - drawRect.bottom = y + lineSpacing; - if (draw) - DrawTextEx(hDC, credit, strlen(credit), &drawRect, DT_LEFT, 0); + DrawAlphaText(hDC, inFont, inColor, credit, gCreditsRect.left, y); y += lineSpacing; strcpy(credit, " "); } strcat(credit, members[i]); } - drawRect.left = 0; - drawRect.top = y; - drawRect.right = gCreditsRect.right; - drawRect.bottom = y + lineSpacing; - if (draw) - DrawTextEx(hDC, credit, strlen(credit), &drawRect, DT_LEFT, 0); - + DrawAlphaText(hDC, inFont, inColor, credit, gCreditsRect.left, y); return y; } -static int DrawCredits(HDC hDC, bool draw, bool extended) -{ - // Draw credits. If draw is true draw credits, - // otherwise just return size of all credit text. - // If extended is true draw or returns size for extended full - // credits list. +//////////////////////////////////////////////////////////////////////////////// +/// Draw the credits on the splah window. - char user_name[256]; +void DrawCredits(HDC hDC, HFONT inFont, COLORREF inColor) +{ TEXTMETRIC lptm; - DWORD length = sizeof (user_name); int lineSpacing, y; - GetTextMetrics(hDC, &lptm); - lineSpacing = lptm.tmAscent + lptm.tmDescent; - y = 0; // 140 - y = DrawCreditItem(hDC, "Conception: ", gConception, y, draw); - y += 2 * lineSpacing - 3; - y = DrawCreditItem(hDC, "Lead Developers: ", gLeadDevelopers, y, draw); - y += 2 * lineSpacing - 3; // special layout tweak - y = DrawCreditItem(hDC, "Core Engineering: ", gRootDevelopers, y, draw); - //y += 2 * lineSpacing - 3; // to just not cut the bottom of the "p" - //y = DrawCreditItem(hDC, "CINT C/C++ Intepreter: ", gCintDevelopers, y, draw); - y += 2 * lineSpacing - 3; - y = DrawCreditItem(hDC, "Documentation: ", gRootDocumentation, y, draw); - - if (extended && gContributors) { - y += 2 * lineSpacing; - y = DrawCreditItem(hDC, "Contributors: ", (const char **)gContributors, y, draw); - - y += 2 * lineSpacing; - y = DrawCreditItem(hDC, "Our sincere thanks and apologies to anyone who deserves", 0, y, draw); - y += lineSpacing; - y = DrawCreditItem(hDC, "credit but fails to appear in this list.", 0, y, draw); - - if (GetUserName (user_name, &length)) { - char *name = new char [strlen(user_name)+1]; - strcpy(name, user_name); - char *s = strchr(name, ','); - if (s) *s = 0; - char line[1024]; - sprintf(line, "Extra special thanks go to %s,", name); - delete [] name; - y += 2 * lineSpacing; - y = DrawCreditItem(hDC, line, 0, y, draw); - y += lineSpacing; - y = DrawCreditItem(hDC, "one of our favorite users.", 0, y, draw); - } - } - return y; + y = 305; + y = DrawCreditItem(hDC, inFont, inColor, "Conception: ", gConception, y); + y += 2 * lineSpacing - 4; + y = DrawCreditItem(hDC, inFont, inColor, "Core Engineering: ", gROOTCoreTeam, y); } -void CreateCredits(HDC hDC, bool extended) -{ - HFONT hFont, hOldFont; - HBRUSH hBr; - LOGFONT lf; - RECT fillRect; - - gRgnScreen = CreateRectRgnIndirect(&gCreditsRect); - SelectClipRgn(hDC, gRgnScreen); - - gDCScreen = CreateCompatibleDC(hDC); - gBmpScreen = CreateCompatibleBitmap(hDC, (gCreditsRect.right - gCreditsRect.left), - (gCreditsRect.bottom - gCreditsRect.top) ); - gBmpOldScreen = (HBITMAP)SelectObject(gDCScreen, gBmpScreen); - - gDCCredits = CreateCompatibleDC(hDC); - - gCreditsBmpWidth = (gCreditsRect.right - gCreditsRect.left); - gCreditsBmpHeight = DrawCredits(gDCCredits, false, extended); - - gBmpCredits = CreateCompatibleBitmap(gDCCredits, gCreditsBmpWidth, gCreditsBmpHeight); - gBmpOldCredits = (HBITMAP)SelectObject(gDCCredits, gBmpCredits); - - hBr = CreateSolidBrush(RGB(255,255,255)); - fillRect.top = fillRect.left = 0; - fillRect.bottom = gCreditsBmpHeight; - fillRect.right = gCreditsBmpWidth; - FillRect(gDCCredits, &fillRect, hBr); +//////////////////////////////////////////////////////////////////////////////// +/// Get a stream from the specified file name (using Windows Imaging Component). - memset((void*)&lf, 0, sizeof(lf)); - lf.lfHeight = 14; - lf.lfWeight = 400; - lf.lfQuality = NONANTIALIASED_QUALITY; - strcpy(lf.lfFaceName, "Arial"); - hFont = CreateFontIndirect(&lf); +IStream *FromFile(LPCWSTR Filename) +{ + IWICStream *Stream = 0; + IWICImagingFactory *Factory = 0; + +#if(_WIN32_WINNT >= 0x0602) || defined(_WIN7_PLATFORM_UPDATE) + // WIC2 is available on Windows 8 and Windows 7 SP1 with KB 2670838 installed + HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory2, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&Factory)); + if (FAILED(hr)) { + hr = CoCreateInstance(CLSID_WICImagingFactory1, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&Factory)); + if (FAILED(hr)) { + return NULL; + } + } +#else + HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&Factory)); + if (FAILED(hr)) { + return NULL; + } +#endif + if (SUCCEEDED(Factory->CreateStream(&Stream))) { + Stream->InitializeFromFilename(Filename, GENERIC_READ); + } + Factory->Release(); + return Stream; +} - if(hFont) - hOldFont = (HFONT)SelectObject(gDCCredits, hFont); +//////////////////////////////////////////////////////////////////////////////// +/// Loads a PNG image from the specified stream (using Windows Imaging +/// Component). - SetBkMode(gDCCredits, TRANSPARENT); - SetTextColor(gDCCredits, 0x00000000); +IWICBitmapSource *LoadBitmapFromStream(IStream *ipImageStream) +{ + // initialize return value + IWICBitmapSource *ipBitmap = NULL; + + // load WIC's PNG decoder + IWICBitmapDecoder *ipDecoder = NULL; + +#if(_WIN32_WINNT >= 0x0602) || defined(_WIN7_PLATFORM_UPDATE) + // WIC2 is available on Windows 8 and Windows 7 SP1 with KB 2670838 installed + HRESULT hr = CoCreateInstance(CLSID_WICPngDecoder2, NULL, CLSCTX_INPROC_SERVER, __uuidof(ipDecoder), reinterpret_cast(&ipDecoder)); + if (FAILED(hr)) { + hr = CoCreateInstance(CLSID_WICPngDecoder1, NULL, CLSCTX_INPROC_SERVER, __uuidof(ipDecoder), reinterpret_cast(&ipDecoder)); + if (FAILED(hr)) { + return NULL; + } + } +#else + HRESULT hr = CoCreateInstance(CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER, __uuidof(ipDecoder), reinterpret_cast(&ipDecoder)); + if (FAILED(hr)) { + return NULL; + } +#endif + // load the PNG + if (FAILED(ipDecoder->Initialize(ipImageStream, WICDecodeMetadataCacheOnLoad))) { + ipDecoder->Release(); + return NULL; + } + // check for the presence of the first frame in the bitmap + UINT nFrameCount = 0; - DrawCredits(gDCCredits, true, extended); + if (FAILED(ipDecoder->GetFrameCount(&nFrameCount)) || nFrameCount != 1) { + ipDecoder->Release(); + return NULL; + } + // load the first frame (i.e., the image) + IWICBitmapFrameDecode *ipFrame = NULL; - SetBkColor(gDCCredits, 0x00FFFFFF); - SelectObject(gDCCredits, hOldFont); + if (FAILED(ipDecoder->GetFrame(0, &ipFrame))) { + ipDecoder->Release(); + return NULL; + } + // convert the image to 32bpp BGRA format with pre-multiplied alpha + // (it may not be stored in that format natively in the PNG resource, + // but we need this format to create the DIB to use on-screen) + WICConvertBitmapSource(GUID_WICPixelFormat32bppPBGRA, ipFrame, &ipBitmap); + ipFrame->Release(); + + ipDecoder->Release(); + return ipBitmap; } -void ScrollCredits(BOOL extended) +//////////////////////////////////////////////////////////////////////////////// +/// Create a 32-bit DIB from the specified WIC bitmap. + +HBITMAP CreateHBITMAP(IWICBitmapSource *ipBitmap) { - // Track scroll position + // initialize return value + HBITMAP hbmp = NULL; - static int nScrollY = 0; + // get image attributes and check for valid image + UINT width = 0; + UINT height = 0; - if (!gShow) - return; - if (!IsWindow(gSplashWnd)) - return; - HDC hDC = GetDC(gSplashWnd); + if (FAILED(ipBitmap->GetSize(&width, &height)) || width == 0 || height == 0) { + return hbmp; + } - if(gDCCredits == 0) { - CreateCredits(hDC, extended); - nScrollY = 0; + // prepare structure giving bitmap information (negative height indicates a top-down DIB) + BITMAPINFO bminfo; + ZeroMemory(&bminfo, sizeof(bminfo)); + bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bminfo.bmiHeader.biWidth = width; + bminfo.bmiHeader.biHeight = -((LONG) height); + bminfo.bmiHeader.biPlanes = 1; + bminfo.bmiHeader.biBitCount = 32; + bminfo.bmiHeader.biCompression = BI_RGB; + + // create a DIB section that can hold the image + void *pvImageBits = NULL; + HDC hdcScreen = GetDC(NULL); + hbmp = CreateDIBSection(hdcScreen, &bminfo, DIB_RGB_COLORS, &pvImageBits, NULL, 0); + ReleaseDC(NULL, hdcScreen); + + if (hbmp == NULL) { + return NULL; + } + // extract the image into the HBITMAP + const UINT cbStride = width * 4; + const UINT cbImage = cbStride * height; + + if (FAILED(ipBitmap->CopyPixels(NULL, cbStride, cbImage, static_cast(pvImageBits)))) { + // couldn't extract image; delete HBITMAP + DeleteObject(hbmp); + hbmp = NULL; } + return hbmp; +} - BitBlt(gDCScreen, 0, 0, gCreditsBmpWidth, gCreditsBmpHeight, gDCCredits, - 0, nScrollY, SRCCOPY); - BitBlt(hDC, gCreditsRect.left, gCreditsRect.top, - (gCreditsRect.right - gCreditsRect.left), - (gCreditsRect.bottom - gCreditsRect.top), - gDCScreen, 0, 0, SRCCOPY); +//////////////////////////////////////////////////////////////////////////////// +/// Loads the PNG containing the splash image into a HBITMAP. - GdiFlush(); +HBITMAP LoadSplashImage(LPCWSTR file_name) +{ + HBITMAP hbmpSplash = NULL; - if (extended) { - // delay scrolling by the specified time - Sleep(100); + // load the PNG image data into a stream + IStream *ipImageStream = FromFile(file_name); - if (nScrollY == 0) - Sleep(2000); + if (ipImageStream == NULL) { + return hbmpSplash; + } + // load the bitmap with WIC + IWICBitmapSource *ipBitmap = LoadBitmapFromStream(ipImageStream); - // continue scrolling - nScrollY += 1; - if (nScrollY > (int) (gCreditsBmpHeight - 2*gCreditsHeight)) - nScrollY = -int(gCreditsHeight); + if (ipBitmap == NULL) { + ipImageStream->Release(); + return NULL; } -} + // create a HBITMAP containing the image + hbmpSplash = CreateHBITMAP(ipBitmap); + ipBitmap->Release(); -/////////////////////////////////////////////////////////////////////////////// -// Foward declarations of functions included in this code module: -ATOM MyRegisterClass(HINSTANCE hInstance); -LRESULT CALLBACK SplashWndProc(HWND, UINT, WPARAM, LPARAM); + ipImageStream->Release(); + return hbmpSplash; +} +//////////////////////////////////////////////////////////////////////////////// +/// Destroy our splash screen window. -void *OpenGraphic(char *name) +void DestroySplashScreen() { - IPicture *Ipic = 0; - SIZE sizeInHiMetric,sizeInPix; - const int HIMETRIC_PER_INCH = 2540; - HDC hDCScreen = GetDC(0); - HRESULT hr; - int nPixelsPerInchX = GetDeviceCaps(hDCScreen, LOGPIXELSX); - int nPixelsPerInchY = GetDeviceCaps(hDCScreen, LOGPIXELSY); - wchar_t OlePathName[512]; - - ReleaseDC(0, hDCScreen); - mbstowcs(OlePathName,name,strlen(name)+1); - hr = OleLoadPicturePath(OlePathName, 0, 0, 0, IID_IPicture, - (void **)(&Ipic)); - if (hr) - return 0; - if (Ipic) { - // get width and height of picture - hr = Ipic->get_Width(&sizeInHiMetric.cx); - if (!SUCCEEDED(hr)) - return 0; - Ipic->get_Height(&sizeInHiMetric.cy); - if (!SUCCEEDED(hr)) - return 0; - - // convert himetric to pixels - sizeInPix.cx = (nPixelsPerInchX * sizeInHiMetric.cx + - HIMETRIC_PER_INCH / 2) / HIMETRIC_PER_INCH; - sizeInPix.cy = (nPixelsPerInchY * sizeInHiMetric.cy + - HIMETRIC_PER_INCH / 2) / HIMETRIC_PER_INCH; - gImageInfo.sizeInPix = sizeInPix; - gImageInfo.sizeInHiMetric = sizeInHiMetric; - gImageInfo.Ipic = Ipic; - gImageInfo.Path = name; - return Ipic; + if (IsWindow(gSplashWnd)) { + DestroyWindow(gSplashWnd); + gSplashWnd = 0; + UnregisterClass("SplashWindow", gInst); } - return 0; } -void DisplayGraphic(HWND hwnd,HDC pDC) +/////////////////////////////////////////////////////////////////////////// +/// Message handler for the splash screen window. + +LRESULT CALLBACK SplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - IPicture *Ipic = gImageInfo.Ipic; - DWORD dwAttr = 0; - HBITMAP Bmp,BmpOld; - RECT rc; - HRESULT hr; - HPALETTE pPalMemOld; - - if (Ipic != 0) { - // get palette - OLE_HANDLE hPal = 0; - HPALETTE hPalOld=0, hPalMemOld=0; - hr = Ipic->get_hPal(&hPal); - - if (!SUCCEEDED(hr)) - return; - if (hPal != 0) { - hPalOld = SelectPalette(pDC,(HPALETTE)hPal,FALSE); - RealizePalette(pDC); - } + switch (message) { + case WM_CREATE: + if(!gAbout) + SetTimer(hWnd, ID_SPLASHSCREEN, gDelayVal, 0); + break; - // Fit the image to the size of the client area. Change this - // For more sophisticated scaling - GetClientRect(hwnd,&rc); - // transparent? - if (SUCCEEDED(Ipic->get_Attributes(&dwAttr)) || - (dwAttr & PICTURE_TRANSPARENT)) { - // use an off-screen DC to prevent flickering - HDC MemDC = CreateCompatibleDC(pDC); - Bmp = CreateCompatibleBitmap(pDC,gImageInfo.sizeInPix.cx,gImageInfo.sizeInPix.cy); - - BmpOld = (HBITMAP)SelectObject(MemDC,Bmp); - pPalMemOld = 0; - if (hPal != 0) { - hPalMemOld = SelectPalette(MemDC,(HPALETTE)hPal, FALSE); - RealizePalette(MemDC); + case WM_TIMER: + if (wParam == ID_SPLASHSCREEN) { + KillTimer (hWnd, ID_SPLASHSCREEN); + DestroySplashScreen(); } + break; - // display picture using IPicture::Render - hr = Ipic->Render(MemDC, 0, 0, rc.right, rc.bottom, 0, - gImageInfo.sizeInHiMetric.cy, - gImageInfo.sizeInHiMetric.cx, - -gImageInfo.sizeInHiMetric.cy, &rc); - - BitBlt(pDC,0, 0, gImageInfo.sizeInPix.cx, gImageInfo.sizeInPix.cy, - MemDC, 0, 0, SRCCOPY); - - SelectObject(MemDC,BmpOld); - - if (pPalMemOld) - SelectPalette(MemDC,pPalMemOld, FALSE); - DeleteObject(Bmp); - DeleteDC(MemDC); - - } - else { - // display picture using IPicture::Render - Ipic->Render(pDC, 0, 0, rc.right, rc.bottom, 0, - gImageInfo.sizeInHiMetric.cy, - gImageInfo.sizeInHiMetric.cx, - -gImageInfo.sizeInHiMetric.cy, &rc); - } + case WM_DESTROY: + PostQuitMessage(0); - if (hPalOld != 0) - SelectPalette(pDC,hPalOld, FALSE); - if (hPal) - DeleteObject((HPALETTE)hPal); + default: + return DefWindowProc(hWnd, message, wParam, lParam); } + return 0; } -void CloseImage(void *Ipict) +/////////////////////////////////////////////////////////////////////////// +/// Registers a window class for the splash and splash owner windows. + +void RegisterWindowClass(HINSTANCE g_hInstance) { - IPicture *ip = (IPicture *)Ipict; - - if (ip == 0) - ip = gImageInfo.Ipic; - if (ip == 0) - return; - ip->Release(); - memset(&gImageInfo,0,sizeof(gImageInfo)); + WNDCLASS wc = { 0 }; + wc.lpfnWndProc = (WNDPROC)SplashWndProc;//DefWindowProc; + wc.hInstance = g_hInstance; + //wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(_T("SPLASH"))); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.lpszClassName = _T("SplashWindow"); + RegisterClass(&wc); } -//////////////////////////////////////////////////////////////////////////////// -// Splashscreen functions -//////////////////////////////////////////////////////////////////////////////// -// -// -void DestroySplashScreen() +/////////////////////////////////////////////////////////////////////////// +/// Create the splash owner window and the splash window. + +HWND CreateSplashWindow(HINSTANCE g_hInstance) { - // Destroy the window - if (IsWindow(gSplashWnd)) { - DestroyWindow(gSplashWnd); - gSplashWnd = 0; - UnregisterClass("RootSplashScreen", gInst); - } - if(gDCScreen != 0 && gBmpOldScreen != 0) { - SelectObject(gDCScreen, gBmpOldScreen); - DeleteObject(gBmpScreen); - } - if(gDCCredits != 0 && gBmpOldCredits != 0) { - SelectObject(gDCCredits, gBmpOldCredits); - DeleteObject(gBmpCredits); - } - DeleteDC(gDCCredits); - gDCCredits = 0; - DeleteDC(gDCScreen); - gDCScreen = 0; - CloseImage(gImageInfo.Ipic); + return CreateWindowEx(WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST, + _T("SplashWindow"), NULL, WS_POPUP | WS_VISIBLE, + 0, 0, 0, 0, NULL, NULL, g_hInstance, NULL); } -//////////////////////////////////////////////////////////////////////////////// -// -// -BOOL CreateSplashScreen(HWND hParent) +/////////////////////////////////////////////////////////////////////////// +/// Call UpdateLayeredWindow to set a bitmap (with alpha) as the content of +/// the splash window. + +void SetSplashImage(HWND hwndSplash, HBITMAP hbmpSplash) { - int xScreen; - int yScreen; - // Crenter the splashscreen - xScreen = GetSystemMetrics(SM_CXFULLSCREEN); - yScreen = GetSystemMetrics(SM_CYFULLSCREEN); - - gStayUp = true; - - gSplashWnd = CreateWindowEx( - WS_EX_TOOLWINDOW, - "RootSplashScreen", - 0, - WS_POPUP | WS_VISIBLE, - (xScreen - 360)/2, - (yScreen - 240)/2, - 360, 240, - hParent, - 0, - gInst, - 0); - - return (gSplashWnd != 0); + // get the size of the bitmap + BITMAP bm; + GetObject(hbmpSplash, sizeof(bm), &bm); + SIZE sizeSplash = { bm.bmWidth, bm.bmHeight }; + + // get the primary monitor's info + POINT ptZero = { 0 }; + HMONITOR hmonPrimary = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY); + MONITORINFO monitorinfo = { 0 }; + monitorinfo.cbSize = sizeof(monitorinfo); + GetMonitorInfo(hmonPrimary, &monitorinfo); + + // center the splash screen in the middle of the primary work area + const RECT &rcWork = monitorinfo.rcWork; + POINT ptOrigin; + ptOrigin.x = rcWork.left + (rcWork.right - rcWork.left - sizeSplash.cx - 93) / 2; + ptOrigin.y = rcWork.top + (rcWork.bottom - rcWork.top - sizeSplash.cy - 104) / 2; + + // create a memory DC holding the splash bitmap + HDC hdcScreen = GetDC(NULL); + HDC hdcMem = CreateCompatibleDC(hdcScreen); + HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcMem, hbmpSplash); + + // use the source image's alpha channel for blending + BLENDFUNCTION blend = { 0 }; + blend.BlendOp = AC_SRC_OVER; + blend.SourceConstantAlpha = 255; + blend.AlphaFormat = AC_SRC_ALPHA; + + SetBkMode(hdcMem, TRANSPARENT); + HFONT hFont = CreateFont(14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Arial\0"); + HFONT hOldFont = (HFONT)SelectObject(hdcMem, hFont); + DrawVersion(hdcMem, hFont, RGB(255,255,255)); + DrawCredits(hdcMem, hFont, RGB(176,210,249)); + SelectObject(hdcMem, hOldFont); + DeleteObject(hFont); + + // paint the window (in the right location) with the alpha-blended bitmap + UpdateLayeredWindow(hwndSplash, hdcScreen, &ptOrigin, &sizeSplash, + hdcMem, &ptZero, RGB(0, 0, 0), &blend, ULW_ALPHA); + + // delete temporary objects + SelectObject(hdcMem, hbmpOld); + DeleteDC(hdcMem); + ReleaseDC(NULL, hdcScreen); } - //////////////////////////////////////////////////////////////////////////////// -// -// -BOOL PreTranslateMessage(MSG* pMsg) +/// check for keybord or mouse event and destroy the splash screen accordingly. + +bool PreTranslateMessage(MSG* pMsg) { if (!IsWindow(gSplashWnd)) return FALSE; @@ -541,168 +519,35 @@ BOOL PreTranslateMessage(MSG* pMsg) return FALSE; // message not handled } -void CreateSplash(DWORD time, BOOL extended) +//////////////////////////////////////////////////////////////////////////////// +/// Create our splash screen. + +void CreateSplash(DWORD time, bool extended) { MSG msg; - MyRegisterClass(gInst); gShow = FALSE; - if(extended) - gAbout = true; - if(time > 0) { - gDelayVal = time * 1000; - } + if (extended) gAbout = true; + if (time > 0) gDelayVal = time * 1000; else return; - if (extended) - ReadContributors(); - - // Create the splash screen - CreateSplashScreen(0); - + RegisterWindowClass(gInst); + + if (!_wgetenv(L"ROOTSYS")) return; + std::wstring RootSysDir = _wgetenv(L"ROOTSYS"); + std::wstring splash_picture = RootSysDir + L"\\icons\\Root6Splash.png"; + CoInitialize(0); + HBITMAP bkg_img = LoadSplashImage(splash_picture.c_str()); + gSplashWnd = CreateSplashWindow(gInst); + SetSplashImage(gSplashWnd, bkg_img); + DeleteObject(bkg_img); + CoUninitialize(); // Main message loop: - while (gStayUp) { - if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { - PreTranslateMessage(&msg); - TranslateMessage(&msg); - DispatchMessage(&msg); - } - if(gShow) { - if(extended) { - ScrollCredits(extended); - } - else { - ScrollCredits(extended); - gShow = false; - } - } + while (GetMessage(&msg, 0, 0, 0)) { + PreTranslateMessage(&msg); + TranslateMessage(&msg); + DispatchMessage(&msg); } - DestroySplashScreen(); } -/////////////////////////////////////////////////////////////////////////////// -// -// FUNCTION: MyRegisterClass() -// -// PURPOSE: Registers the window class. -// -// COMMENTS: -// -// This function and its usage is only necessary if you want this code -// to be compatible with Win32 systems prior to the 'RegisterClassEx' -// function that was added to Windows 95. It is important to call this function -// so that the application will get 'well formed' small icons associated -// with it. -// -ATOM MyRegisterClass(HINSTANCE hInstance) -{ - WNDCLASSEX wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = (WNDPROC)SplashWndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = 0; - wcex.hCursor = LoadCursor(0, IDC_ARROW); - wcex.hbrBackground = 0; - wcex.lpszMenuName = 0; - wcex.lpszClassName = "RootSplashScreen"; - wcex.hIconSm = 0; - return RegisterClassEx(&wcex); -} - - - -//////////////////////////////////////////////////////////////////////////// -// Message handler for splash screen. -// -LRESULT CALLBACK SplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - PAINTSTRUCT ps; - HDC hDC; - LOGFONT lf; - static HFONT hFont; - const char bmpDir[] = "\\icons\\Splash.gif"; - HWND hwndFound; // this is what is returned to the caller - char pszNewWindowTitle[1024]; // contains fabricated WindowTitle - char pszOldWindowTitle[1024]; // contains original WindowTitle - char FullBmpDir[256]; - char *RootSysDir; - int xScreen; - int yScreen; - - switch (message) { - case WM_CREATE: - if(!gAbout) - SetTimer(hWnd, ID_SPLASHSCREEN, gDelayVal, 0); - RootSysDir = getenv("ROOTSYS"); - sprintf(FullBmpDir,"%s%s",RootSysDir,bmpDir); - // Retrieve a handle identifying the file. - OpenGraphic(FullBmpDir); - hDC = GetDC(hWnd); - DisplayGraphic(hWnd, hDC); - SetBkMode(hDC, TRANSPARENT); - memset((void*)&lf, 0, sizeof(lf)); - lf.lfHeight = 14; - lf.lfWeight = 400; - lf.lfQuality = NONANTIALIASED_QUALITY; - strcpy(lf.lfFaceName, "Arial"); - hFont = CreateFontIndirect(&lf); - xScreen = GetSystemMetrics(SM_CXFULLSCREEN); - yScreen = GetSystemMetrics(SM_CYFULLSCREEN); - SetWindowPos(hWnd, HWND_TOPMOST, (xScreen - gImageInfo.sizeInPix.cx)/2, - (yScreen - gImageInfo.sizeInPix.cy)/2, gImageInfo.sizeInPix.cx, - gImageInfo.sizeInPix.cy, 0 ); - break; - - case WM_TIMER: - if (wParam == ID_SPLASHSCREEN) { - KillTimer (hWnd, ID_SPLASHSCREEN); - DestroySplashScreen(); - } - break; - - case WM_DESTROY: - gStayUp = false; - PostQuitMessage(0); - - case WM_PAINT: - hDC = BeginPaint(hWnd, &ps); - RECT rt; - GetClientRect(hWnd, &rt); - RootSysDir = getenv("ROOTSYS"); - sprintf(FullBmpDir,"%s%s",RootSysDir,bmpDir); - OpenGraphic(FullBmpDir); - hDC = GetDC(hWnd); - DisplayGraphic(hWnd, hDC); - SetBkMode(hDC, TRANSPARENT); - if(hFont) - SelectObject(hDC, hFont); - DrawVersion(hDC); - EndPaint(hWnd, &ps); - gShow = TRUE; - // fetch current window title - GetConsoleTitle(pszOldWindowTitle, 1024); - // format a "unique" NewWindowTitle - wsprintf(pszNewWindowTitle,"%d/%d", GetTickCount(), GetCurrentProcessId()); - // change current window title - SetConsoleTitle(pszNewWindowTitle); - // ensure window title has been updated - Sleep(40); - // look for NewWindowTitle - hwndFound=FindWindow(NULL, pszNewWindowTitle); - // restore original window title - ShowWindow(hwndFound, SW_RESTORE); - SetForegroundWindow(hwndFound); - SetConsoleTitle("ROOT session"); - break; - - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - return 0; -} #endif diff --git a/documentation/doxygen/Doxyfile b/documentation/doxygen/Doxyfile index f6a3898b5361a..4f03c07807ac6 100644 --- a/documentation/doxygen/Doxyfile +++ b/documentation/doxygen/Doxyfile @@ -835,7 +835,6 @@ INPUT = . \ ../../hist/ \ ../../html/ \ ../../io/castor/ \ - ../../io/chirp/ \ ../../io/dcache/ \ ../../io/gfal/ \ ../../io/hdfs/ \ @@ -852,7 +851,6 @@ INPUT = . \ ../../net/auth/ \ ../../net/bonjour/ \ ../../net/davix/ \ - ../../net/glite/ \ ../../net/http/ \ ../../net/krb5auth/ \ ../../net/ldap/ \ @@ -872,7 +870,6 @@ INPUT = . \ # ../../core/lzma/ # ../../core/newdelete/ # ../../core/textinput/ -# ../../graf2d/ios/ # ../../graf2d/qt/ \ # ../../graf2d/mathtext/ # ../../graf3d/ftgl/ diff --git a/documentation/doxygen/images/TDF_Graph.png b/documentation/doxygen/images/TDF_Graph.png index 7cedb65955e31..c93d78df0328a 100644 Binary files a/documentation/doxygen/images/TDF_Graph.png and b/documentation/doxygen/images/TDF_Graph.png differ diff --git a/documentation/doxygen/images/eve_assembly.png b/documentation/doxygen/images/eve_assembly.png index 5e940a30a0f3f..b8d710630fde4 100644 Binary files a/documentation/doxygen/images/eve_assembly.png and b/documentation/doxygen/images/eve_assembly.png differ diff --git a/documentation/doxygen/images/eve_boxset.png b/documentation/doxygen/images/eve_boxset.png index 0d45c474795ba..c9b0c8026fcc4 100644 Binary files a/documentation/doxygen/images/eve_boxset.png and b/documentation/doxygen/images/eve_boxset.png differ diff --git a/documentation/doxygen/images/eve_boxset_cones.png b/documentation/doxygen/images/eve_boxset_cones.png index 10b463c220fc4..5da70955c15ac 100644 Binary files a/documentation/doxygen/images/eve_boxset_cones.png and b/documentation/doxygen/images/eve_boxset_cones.png differ diff --git a/documentation/doxygen/images/eve_quadset.png b/documentation/doxygen/images/eve_quadset.png index a5928901740f6..61f763d07b03f 100644 Binary files a/documentation/doxygen/images/eve_quadset.png and b/documentation/doxygen/images/eve_quadset.png differ diff --git a/documentation/doxygen/images/eve_triangleset.png b/documentation/doxygen/images/eve_triangleset.png index 88f660d3a4128..5ea75ccac1ff3 100644 Binary files a/documentation/doxygen/images/eve_triangleset.png and b/documentation/doxygen/images/eve_triangleset.png differ diff --git a/documentation/primer/macros/macro7.C b/documentation/primer/macros/macro7.C index 262ec00edae36..d29f9a36bb37e 100644 --- a/documentation/primer/macros/macro7.C +++ b/documentation/primer/macros/macro7.C @@ -2,30 +2,31 @@ // together with its profiles and projections void macro7(){ - gStyle->SetPalette(kBird); - gStyle->SetOptStat(0); - gStyle->SetOptTitle(0); + gStyle->SetPalette(kBird); + gStyle->SetOptStat(0); + gStyle->SetOptTitle(0); - TH2F bidi_h("bidi_h","2D Histo;Gaussian Vals;Exp. Vals", - 30,-5,5, // X axis - 30,0,10); // Y axis + auto bidi_h = new TH2F("bidi_h","2D Histo;Gaussian Vals;Exp. Vals", + 30,-5,5, // X axis + 30,0,10); // Y axis - TRandom3 rgen; - for (int i=0;i<500000;i++) - bidi_h.Fill(rgen.Gaus(0,2),10-rgen.Exp(4),.1); + TRandom3 rgen; + for (int i=0;i<500000;i++) { + bidi_h->Fill(rgen.Gaus(0,2),10-rgen.Exp(4),.1); + } - auto c=new TCanvas("Canvas","Canvas",800,800); - c->Divide(2,2); - c->cd(1);bidi_h.DrawClone("Cont1"); - c->cd(2);bidi_h.DrawClone("Colz"); - c->cd(3);bidi_h.DrawClone("lego2"); - c->cd(4);bidi_h.DrawClone("surf3"); + auto c=new TCanvas("Canvas","Canvas",800,800); + c->Divide(2,2); + c->cd(1); bidi_h->Draw("Cont1"); + c->cd(2); bidi_h->Draw("Colz"); + c->cd(3); bidi_h->Draw("Lego2"); + c->cd(4); bidi_h->Draw("Surf3"); - // Profiles and Projections - auto c2=new TCanvas("Canvas2","Canvas2",800,800); - c2->Divide(2,2); - c2->cd(1);bidi_h.ProjectionX()->DrawClone(); - c2->cd(2);bidi_h.ProjectionY()->DrawClone(); - c2->cd(3);bidi_h.ProfileX()->DrawClone(); - c2->cd(4);bidi_h.ProfileY()->DrawClone(); + // Profiles and Projections + auto c2=new TCanvas("Canvas2","Canvas2",800,800); + c2->Divide(2,2); + c2->cd(1); bidi_h->ProjectionX()->Draw(); + c2->cd(2); bidi_h->ProjectionY()->Draw(); + c2->cd(3); bidi_h->ProfileX()->Draw(); + c2->cd(4); bidi_h->ProfileY()->Draw(); } diff --git a/etc/plugins/TFile/P060_TChirpFile.C b/etc/plugins/TFile/P060_TChirpFile.C deleted file mode 100644 index 8c46fba11d938..0000000000000 --- a/etc/plugins/TFile/P060_TChirpFile.C +++ /dev/null @@ -1,5 +0,0 @@ -void P060_TChirpFile() -{ - gPluginMgr->AddHandler("TFile", "^chirp:", "TChirpFile", - "Chirp", "TChirpFile(const char*,Option_t*,const char*,Int_t)"); -} diff --git a/etc/system.plugins-ios b/etc/system.plugins-ios deleted file mode 100644 index b088e541ee88b..0000000000000 --- a/etc/system.plugins-ios +++ /dev/null @@ -1,155 +0,0 @@ -# This file has been generated using: -# make plugins-ios -# On Thu May 5 17:23:11 CEST 2011 -# DON'T MAKE CHANGES AS THEY WILL GET LOST NEXT TIME THE FILE IS GENERATED -Plugin.ROOT@@Math@@DistSampler: Unuran TUnuranSampler Unuran "TUnuranSampler( )" -+Plugin.ROOT@@Math@@DistSampler: Foam TFoamSampler Foam "TFoamSampler( )" -Plugin.ROOT@@Math@@IRootFinderMethod: Brent ROOT::Math::Roots::Brent MathMore "Brent()" -+Plugin.ROOT@@Math@@IRootFinderMethod: Bisection ROOT::Math::Roots::Bisection MathMore "Bisection()" -+Plugin.ROOT@@Math@@IRootFinderMethod: FalsePos ROOT::Math::Roots::FalsePos MathMore "FalsePos()" -+Plugin.ROOT@@Math@@IRootFinderMethod: Newton ROOT::Math::Roots::Newton MathMore "Newton()" -+Plugin.ROOT@@Math@@IRootFinderMethod: Secant ROOT::Math::Roots::Secant MathMore "Secant()" -+Plugin.ROOT@@Math@@IRootFinderMethod: Steffenson ROOT::Math::Roots::Steffenson MathMore "Steffenson()" -Plugin.ROOT@@Math@@Minimizer: Minuit2 ROOT::Minuit2::Minuit2Minimizer Minuit2 "Minuit2Minimizer(const char *)" -+Plugin.ROOT@@Math@@Minimizer: Minuit TMinuitMinimizer Minuit "TMinuitMinimizer(const char *)" -+Plugin.ROOT@@Math@@Minimizer: GSLMultiMin ROOT::Math::GSLMinimizer MathMore "GSLMinimizer(const char *)" -+Plugin.ROOT@@Math@@Minimizer: GSLMultiFit ROOT::Math::GSLNLSMinimizer MathMore "GSLNLSMinimizer(int)" -+Plugin.ROOT@@Math@@Minimizer: GSLSimAn ROOT::Math::GSLSimAnMinimizer MathMore "GSLSimAnMinimizer(int)" -+Plugin.ROOT@@Math@@Minimizer: Linear TLinearMinimizer Minuit "TLinearMinimizer(const char *)" -+Plugin.ROOT@@Math@@Minimizer: Fumili TFumiliMinimizer Fumili "TFumiliMinimizer(int)" -+Plugin.ROOT@@Math@@Minimizer: Genetic ROOT::Math::GeneticMinimizer Genetic "GeneticMinimizer(int)" -Plugin.ROOT@@Math@@VirtualIntegrator: GSLIntegrator ROOT::Math::GSLIntegrator MathMore "GSLIntegrator(const char *, int, double, double, unsigned int)" -+Plugin.ROOT@@Math@@VirtualIntegrator: GSLMCIntegrator ROOT::Math::GSLMCIntegrator MathMore "GSLMCIntegrator(const char *, double, double, unsigned int)" -Plugin.TAFS: * TAFS AFSAuth "TAFS(const char*,const char*,Int_t)" -Plugin.TApplication: ^remote TApplicationRemote Net "TApplicationRemote(const char *,Int_t,const char *)" -+Plugin.TApplication: ^server TApplicationServer Net "TApplicationServer(Int_t *,char **,FILE *,const char*)" -Plugin.TArchiveFile: .+[.]zip$ TZIPFile Core "TZIPFile(const char*,const char*,TFile*)" -Plugin.TBrowserImp: TRootBrowser TRootBrowser Gui "NewBrowser(TBrowser *, const char *, UInt_t, UInt_t)" -+Plugin.TBrowserImp: TRootBrowserLite TRootBrowserLite Gui "NewBrowser(TBrowser *, const char *, UInt_t, UInt_t)" -Plugin.TChain: ^proof TProofChain Proof "TProofChain(TChain *, Bool_t)" -Plugin.TDataProgressDialog: * TDataProgressDialog PeacGui "TDataProgressDialog(TProof*,const char*,Int_t,Long64_t)" -Plugin.TDataSetManager: ^file TDataSetManagerFile Proof "TDataSetManagerFile(const char *,const char *,const char *)" -Plugin.TFile: ^http: TWebFile Net "TWebFile(const char*,Option_t*)" -+Plugin.TFile: ^rfio: TRFIOFile RFIO "TRFIOFile(const char*,Option_t*,const char*,Int_t)" -+Plugin.TFile: ^castor: TCastorFile RCastor "TCastorFile(const char*,Option_t*,const char*,Int_t,Int_t)" -+Plugin.TFile: ^dcache: TDCacheFile DCache "TDCacheFile(const char*,Option_t*,const char*,Int_t)" -+Plugin.TFile: ^dcap: TDCacheFile DCache "TDCacheFile(const char*,Option_t*,const char*,Int_t)" -+Plugin.TFile: ^gsidcap: TDCacheFile DCache "TDCacheFile(const char*,Option_t*,const char*,Int_t)" -+Plugin.TFile: ^gfal: TGFALFile GFAL "TGFALFile(const char*,Option_t*,const char*,Int_t)" -+Plugin.TFile: ^chirp: TChirpFile Chirp "TChirpFile(const char*,Option_t*,const char*,Int_t)" -+Plugin.TFile: ^alien: TAlienFile RAliEn "Open(const char*,Option_t*,const char*,Int_t,Bool_t)" -+Plugin.TFile: .+[.]xml$ TXMLFile XMLIO "TXMLFile(const char*,Option_t*,const char*,Int_t)" -+Plugin.TFile: ^mysql: TSQLFile SQL "TSQLFile(const char*,Option_t*,const char*,const char*)" -+Plugin.TFile: ^oracle: TSQLFile SQL "TSQLFile(const char*,Option_t*,const char*,const char*)" -+Plugin.TFile: ^root: TXNetFile Netx "TXNetFile(const char*,Option_t*,const char*,Int_t,Int_t,Bool_t)" -+Plugin.TFile: ^hdfs: THDFSFile HDFS "THDFSFile(const char*,Option_t*,const char*,Int_t)" -+Plugin.TFile: ^rootd: TNetFile Net "TNetFile(const char*,Option_t*,const char*,Int_t,Int_t)" -+Plugin.TFile: ^rootup: TNetFile Net "TNetFile(const char*,Option_t*,const char*,Int_t,Int_t)" -+Plugin.TFile: ^roots: TNetFile Net "TNetFile(const char*,Option_t*,const char*,Int_t,Int_t)" -+Plugin.TFile: ^rootk: TNetFile Net "TNetFile(const char*,Option_t*,const char*,Int_t,Int_t)" -+Plugin.TFile: ^rootg: TNetFile Net "TNetFile(const char*,Option_t*,const char*,Int_t,Int_t)" -+Plugin.TFile: ^rooth: TNetFile Net "TNetFile(const char*,Option_t*,const char*,Int_t,Int_t)" -+Plugin.TFile: ^rootug: TNetFile Net "TNetFile(const char*,Option_t*,const char*,Int_t,Int_t)" -Plugin.TFileDrawMap: * TFileDrawMap TreePlayer "TFileDrawMap(const TFile*, const char*, const char*)" -Plugin.TFileStager: ^root: TXNetFileStager Netx "TXNetFileStager(const char *)" -+Plugin.TFileStager: ^rootd: TNetFileStager Net "TNetFileStager(const char *)" -+Plugin.TFileStager: ^rootup: TNetFileStager Net "TNetFileStager(const char *)" -+Plugin.TFileStager: ^roots: TNetFileStager Net "TNetFileStager(const char *)" -+Plugin.TFileStager: ^rootk: TNetFileStager Net "TNetFileStager(const char *)" -+Plugin.TFileStager: ^rootg: TNetFileStager Net "TNetFileStager(const char *)" -+Plugin.TFileStager: ^rooth: TNetFileStager Net "TNetFileStager(const char *)" -+Plugin.TFileStager: ^rootug: TNetFileStager Net "TNetFileStager(const char *)" -Plugin.TFitEditor: * TFitEditor FitPanel "GetInstance(TVirtualPad*, TObject*)" -Plugin.TGeoManagerEditor: * TGeoManagerEditor GeomBuilder "LoadLib()" -Plugin.TGLHistPainter: * TGLHistPainter RGL "TGLHistPainter(TH1*)" -Plugin.TGLManager: x11 TX11GLManager RGL "TX11GLManager()" -+Plugin.TGLManager: win32 TGWin32GLManager RGL "TGWin32GLManager()" -Plugin.TGPasswdDialog: * TGPasswdDialog Gui "TGPasswdDialog(const char*,char*,Int_t,UInt_t,UInt_t)" -Plugin.TGrid: ^glite TGLite RgLite "TGLite(const char*,const char*,const char*,const char*)" -Plugin.TGuiBuilder: * TRootGuiBuilder GuiBld "TRootGuiBuilder()" -Plugin.TGuiFactory: root TRootGuiFactory Gui "TRootGuiFactory()" -+Plugin.TGuiFactory: qt TQtRootGuiFactory QtRoot "TQtRootGuiFactory()" -Plugin.TImage: * TASImage ASImage "TASImage()" -Plugin.TImagePlugin: ps TASPluginGS ASPluginGS "TASPluginGS(const char*)" -+Plugin.TImagePlugin: eps TASPluginGS ASPluginGS "TASPluginGS(const char*)" -+Plugin.TImagePlugin: pdf TASPluginGS ASPluginGS "TASPluginGS(const char*)" -Plugin.TMinuitGraph: * TGraph Graf "TGraph(Int_t,const Double_t*,const Double_t*)" -Plugin.TPaletteEditor: * TASPaletteEditor ASImageGui "TASPaletteEditor(TAttImage*,UInt_t,UInt_t)" -Plugin.TProof: ^condor: TProofCondor Proof "TProofCondor(const char*,const char*,const char*,Int_t,const char*)" -+Plugin.TProof: ^sm: TProofSuperMaster Proof "TProofSuperMaster(const char*,const char*,const char*,Int_t,const char*)" -+Plugin.TProof: ^peac: TProofPEAC Peac "TProofPEAC(const char*,const char*,const char*,Int_t,const char*)" -+Plugin.TProof: * TProof Proof "TProof(const char*,const char*,const char*,Int_t,const char *)" -Plugin.TProofMgr: ^xpd TXProofMgr Proofx "TXProofMgr(const char *,Int_t,const char *)" -Plugin.TProofProgressDialog: * TProofProgressDialog SessionViewer "TProofProgressDialog(TProof*,const char*,Int_t,Long64_t,Long64_t)" -Plugin.TProofProgressLog: * TProofProgressLog SessionViewer "TProofProgressLog(const char*,Int_t,Long64_t,Long64_t)" -Plugin.TProofServ: ^xpd TXProofServ Proofx "TXProofServ(Int_t *,char **)" -Plugin.TSessionViewer: * TSessionViewer TreeViewer "TSessionViewer()" -Plugin.TSlave: ^xpd TXSlave Proofx "TXSlave(const char *,const char *,Int_t,const char *, TProof *,Int_t,const char *,const char *)" -Plugin.TSQLServer: ^mysql: TMySQLServer RMySQL "TMySQLServer(const char*,const char*,const char*)" -+Plugin.TSQLServer: ^pgsql: TPgSQLServer PgSQL "TPgSQLServer(const char*,const char*,const char*)" -+Plugin.TSQLServer: ^sapdb: TSapDBServer SapDB "TSapDBServer(const char*,const char*,const char*)" -+Plugin.TSQLServer: ^oracle: TOracleServer Oracle "TOracleServer(const char*,const char*,const char*)" -+Plugin.TSQLServer: ^odbc: TODBCServer RODBC "TODBCServer(const char*,const char*,const char*)" -+Plugin.TSQLServer: ^odbcn: TODBCServer RODBC "TODBCServer(const char*,const char*,const char*)" -+Plugin.TSQLServer: ^odbcd: TODBCServer RODBC "TODBCServer(const char*,const char*,const char*)" -Plugin.TSystem: ^rfio: TRFIOSystem RFIO "TRFIOSystem()" -+Plugin.TSystem: ^castor: TRFIOSystem RFIO "TRFIOSystem()" -+Plugin.TSystem: ^dcache: TDCacheSystem DCache "TDCacheSystem()" -+Plugin.TSystem: ^dcap: TDCacheSystem DCache "TDCacheSystem()" -+Plugin.TSystem: ^gsidcap: TDCacheSystem DCache "TDCacheSystem()" -+Plugin.TSystem: ^alien: TAlienSystem RAliEn "TAlienSystem()" -+Plugin.TSystem: ^root: TXNetSystem Netx "TXNetSystem(const char *,Bool_t)" -+Plugin.TSystem: ^http: TWebSystem Net "TWebSystem()" -+Plugin.TSystem: ^hdfs: THDFSSystem HDFS "THDFSSystem()" -+Plugin.TSystem: ^rootd: TNetSystem Net "TNetSystem(const char *,Bool_t)" -+Plugin.TSystem: ^rootup: TNetSystem Net "TNetSystem(const char *,Bool_t)" -+Plugin.TSystem: ^roots: TNetSystem Net "TNetSystem(const char *,Bool_t)" -+Plugin.TSystem: ^rootk: TNetSystem Net "TNetSystem(const char *,Bool_t)" -+Plugin.TSystem: ^rootg: TNetSystem Net "TNetSystem(const char *,Bool_t)" -+Plugin.TSystem: ^rooth: TNetSystem Net "TNetSystem(const char *,Bool_t)" -+Plugin.TSystem: ^rootug: TNetSystem Net "TNetSystem(const char *,Bool_t)" -Plugin.TView: * TView3D Graf3d "TView3D(Int_t, const Double_t*, const Double_t*)" -Plugin.TViewerX3D: x11 TViewerX3D X3d "TViewerX3D(TVirtualPad*,Option_t*,const char*,UInt_t,UInt_t)" -+Plugin.TViewerX3D: qt TQtViewerX3D QtX3d "TQtViewerX3D(TVirtualPad*,Option_t*,const char*,UInt_t,UInt_t)" -Plugin.TVirtualAuth: Root TRootAuth RootAuth "TRootAuth()" -Plugin.TVirtualDragManager: * TGuiBldDragManager GuiBld "TGuiBldDragManager()" -Plugin.TVirtualFFT: fftwc2c TFFTComplex FFTW "TFFTComplex(Int_t, Int_t *,Bool_t)" -+Plugin.TVirtualFFT: fftwc2r TFFTComplexReal FFTW "TFFTComplexReal(Int_t,Int_t *, Bool_t)" -+Plugin.TVirtualFFT: fftwr2c TFFTRealComplex FFTW "TFFTRealComplex(Int_t,Int_t *, Bool_t)" -+Plugin.TVirtualFFT: fftwr2r TFFTReal FFTW "TFFTReal(Int_t, Int_t *,Bool_t)" -Plugin.TVirtualFitter: Minuit TFitter Minuit "TFitter(Int_t)" -+Plugin.TVirtualFitter: Fumili TFumili Fumili "TFumili(Int_t)" -+Plugin.TVirtualFitter: Minuit2 TFitterMinuit Minuit2 "TFitterMinuit(Int_t)" -+Plugin.TVirtualFitter: Fumili2 TFitterFumili Minuit2 "TFitterFumili(Int_t)" -Plugin.TVirtualGeoPainter: * TGeoPainter GeomPainter "TGeoPainter(TGeoManager*)" -Plugin.TVirtualGeoConverter: * TGeoVGConverter ConverterVG "TGeoVGConverter(TGeoManager*)" -Plugin.TVirtualGLImp: x11 TX11GL RGL "TX11GL()" -+Plugin.TVirtualGLImp: win32 TGWin32GL RGL "TGWin32GL()" -Plugin.TVirtualGraphPainter: * TGraphPainter GraphPainter "TGraphPainter()" -Plugin.TVirtualHistPainter: * THistPainter HistPainter "THistPainter()" -Plugin.TVirtualMonitoringWriter: MonaLisa TMonaLisaWriter MonaLisa "TMonaLisaWriter(const char *,const char *,const char *,const char *,const char *)" -+Plugin.TVirtualMonitoringWriter: SQL TSQLMonitoringWriter Net "TSQLMonitoringWriter(const char *,const char *,const char *,const char *)" -Plugin.TVirtualPad: * TPad Gpad "TPad()" -Plugin.TVirtualPadEditor: Ged TGedEditor Ged "TGedEditor(TCanvas*)" -Plugin.TVirtualPadPainter: gl TGLPadPainter RGL "TGLPadPainter()" -Plugin.TVirtualProofPlayer: base TProofPlayer ProofPlayer "TProofPlayer(TProof*)" -+Plugin.TVirtualProofPlayer: remote TProofPlayerRemote ProofPlayer "TProofPlayerRemote(TProof*)" -+Plugin.TVirtualProofPlayer: local TProofPlayerLocal ProofPlayer "TProofPlayerLocal(TProof*)" -+Plugin.TVirtualProofPlayer: slave TProofPlayerSlave ProofPlayer "TProofPlayerSlave(TSocket*)" -+Plugin.TVirtualProofPlayer: sm TProofPlayerSuperMaster ProofPlayer "TProofPlayerSuperMaster(TProof*)" -+Plugin.TVirtualProofPlayer: lite TProofPlayerLite ProofPlayer "TProofPlayerLite(TProof*)" -Plugin.TVirtualPS: ps TPostScript Postscript "TPostScript()" -+Plugin.TVirtualPS: svg TSVG Postscript "TSVG()" -+Plugin.TVirtualPS: pdf TPDF Postscript "TPDF()" -+Plugin.TVirtualPS: image TImageDump Postscript "TImageDump()" -Plugin.TVirtualStreamerInfo: * TStreamerInfo RIO "TStreamerInfo()" -Plugin.TVirtualTreePlayer: * TTreePlayer TreePlayer "TTreePlayer()" -Plugin.TVirtualTreeViewer: * TTreeViewer TreeViewer "TTreeViewer(const TTree*)" -Plugin.TVirtualViewer3D: x3d TViewerX3D X3d "TViewerX3D(TVirtualPad*)" -+Plugin.TVirtualViewer3D: ogl TGLSAViewer RGL "TGLSAViewer(TVirtualPad*)" -+Plugin.TVirtualViewer3D: gl TGLViewer RGL "TGLViewer(TVirtualPad*)" -Plugin.TVirtualX: x11 TGX11 GX11 "TGX11(const char*,const char*)" -+Plugin.TVirtualX: x11ttf TGX11TTF GX11TTF "TGX11TTF()" -+Plugin.TVirtualX: win32 TGWin32 Win32 "TGWin32(const char*,const char*)" -+Plugin.TVirtualX: win32gdk TGWin32 Win32gdk "TGWin32(const char*,const char*)" -+Plugin.TVirtualX: qt TGQt GQt "TGQt(const char*,const char*)" diff --git a/geom/gdml/src/TGDMLParse.cxx b/geom/gdml/src/TGDMLParse.cxx index 774d6a56e922b..2b3636aaed1f2 100644 --- a/geom/gdml/src/TGDMLParse.cxx +++ b/geom/gdml/src/TGDMLParse.cxx @@ -1751,7 +1751,7 @@ XMLNodePointer_t TGDMLParse::VolProcess(TXMLEngine* gdml, XMLNodePointer_t node) else if (strcmp(gdml->GetNodeName(child), "auxiliary") == 0) { TString auxType, auxUnit, auxValue; if(!auxmap) { - printf("Auxiliary values for volume %s\n",vol->GetName()); + // printf("Auxiliary values for volume %s\n",vol->GetName()); auxmap = new TMap(); vol->SetUserExtension(new TGeoRCExtension(auxmap)); } @@ -1764,7 +1764,7 @@ XMLNodePointer_t TGDMLParse::VolProcess(TXMLEngine* gdml, XMLNodePointer_t node) } if (!auxUnit.IsNull()) auxValue = TString::Format("%s*%s", auxValue.Data(), auxUnit.Data()); auxmap->Add(new TObjString(auxType),new TObjString(auxValue)); - printf(" %s: %s\n", auxType.Data(), auxValue.Data()); + // printf(" %s: %s\n", auxType.Data(), auxValue.Data()); } child = gdml->GetNext(child); diff --git a/geom/geom/src/TGeoElement.cxx b/geom/geom/src/TGeoElement.cxx index c71e18b6f7f88..cf158bb5350e5 100644 --- a/geom/geom/src/TGeoElement.cxx +++ b/geom/geom/src/TGeoElement.cxx @@ -175,6 +175,8 @@ void TGeoElement::ComputeLradTsaiFactor() static const Double_t Lrad_light[] = {5.31 , 4.79 , 4.74 , 4.71} ; static const Double_t Lprad_light[] = {6.144 , 5.621 , 5.805 , 5.924} ; + fRadTsai = 0.0; + if (fZ == 0) return; const Double_t logZ3 = TMath::Log(fZ)/3.; Double_t Lrad, Lprad; diff --git a/geom/geom/src/TGeoNavigator.cxx b/geom/geom/src/TGeoNavigator.cxx index 07d7754aa7a50..d3fae795c962c 100644 --- a/geom/geom/src/TGeoNavigator.cxx +++ b/geom/geom/src/TGeoNavigator.cxx @@ -638,13 +638,15 @@ TGeoNode *TGeoNavigator::CrossBoundaryAndLocate(Bool_t downwards, TGeoNode *skip } if (skipnode) { - if ((current == skipnode) && (level == fLevel) ) { + if (current == skipnode) { samepath = kTRUE; - level = TMath::Min(level, 10); - for (Int_t i=1; i+; -#pragma link C++ class ROOT::Experimental::Detail::TCheckedMenuItem+; -#pragma link C++ class ROOT::Experimental::Detail::TMenuArgument+; -#pragma link C++ class std::vector+; -#pragma link C++ class ROOT::Experimental::Detail::TArgsMenuItem+; -#pragma link C++ class ROOT::Experimental::TMenuItems+; -#pragma link C++ class ROOT::Experimental::TObjectDrawingOpts+; -#pragma link C++ class ROOT::Experimental::TObjectDrawable+; -#pragma link C++ class ROOT::Experimental::TObjectDisplayItem+; -#pragma link C++ class ROOT::Experimental::TPadUserAxisBase+; -#pragma link C++ class ROOT::Experimental::TPadCartesianUserAxis+; -#pragma link C++ struct ROOT::Experimental::Internal::TPadHorizVert+; -#pragma link C++ struct ROOT::Experimental::TPadExtent+; -#pragma link C++ struct ROOT::Experimental::TPadPos+; -#pragma link C++ class ROOT::Experimental::TDrawingAttr+; -#pragma link C++ class std::vector>+; -#pragma link C++ class ROOT::Experimental::TPadBase+; -#pragma link C++ class ROOT::Experimental::TPadDrawingOpts+; -#pragma link C++ class ROOT::Experimental::TPad+; -#pragma link C++ class ROOT::Experimental::TPadDrawable+; -#pragma link C++ class ROOT::Experimental::TCanvas+; -#pragma link C++ class ROOT::Experimental::TFrame+; -#pragma link C++ class ROOT::Experimental::TPadLength+; -#pragma link C++ class ROOT::Experimental::TPadLength::Pixel+; -#pragma link C++ class ROOT::Experimental::TPadLength::Normal+; -#pragma link C++ class ROOT::Experimental::TPadLength::User+; -#pragma link C++ class ROOT::Experimental::TPadLength::CoordSysBase+; -#pragma link C++ class ROOT::Experimental::TPadLength::CoordSysBase+; -#pragma link C++ class ROOT::Experimental::TPadLength::CoordSysBase+; +#pragma link C++ class ROOT::Experimental::RPadDisplayItem+; +#pragma link C++ class ROOT::Experimental::Detail::RMenuItem+; +#pragma link C++ class std::vector+; +#pragma link C++ class ROOT::Experimental::Detail::RCheckedMenuItem+; +#pragma link C++ class ROOT::Experimental::Detail::RMenuArgument+; +#pragma link C++ class std::vector+; +#pragma link C++ class ROOT::Experimental::Detail::RArgsMenuItem+; +#pragma link C++ class ROOT::Experimental::RMenuItems+; +#pragma link C++ class ROOT::Experimental::RObjectDrawingOpts+; +#pragma link C++ class ROOT::Experimental::RObjectDrawable+; +#pragma link C++ class ROOT::Experimental::RObjectDisplayItem+; +#pragma link C++ class ROOT::Experimental::RPadUserAxisBase+; +#pragma link C++ class ROOT::Experimental::RPadCartesianUserAxis+; +#pragma link C++ struct ROOT::Experimental::Internal::RPadHorizVert+; +#pragma link C++ struct ROOT::Experimental::RPadExtent+; +#pragma link C++ struct ROOT::Experimental::RPadPos+; +#pragma link C++ class ROOT::Experimental::RDrawingAttr+; +#pragma link C++ class std::vector>+; +#pragma link C++ class ROOT::Experimental::RPadBase+; +#pragma link C++ class ROOT::Experimental::RPadDrawingOpts+; +#pragma link C++ class ROOT::Experimental::RPad+; +#pragma link C++ class ROOT::Experimental::RPadDrawable+; +#pragma link C++ class ROOT::Experimental::RCanvas+; +#pragma link C++ class ROOT::Experimental::RFrame+; +#pragma link C++ class ROOT::Experimental::RPadLength+; +#pragma link C++ class ROOT::Experimental::RPadLength::Pixel+; +#pragma link C++ class ROOT::Experimental::RPadLength::Normal+; +#pragma link C++ class ROOT::Experimental::RPadLength::User+; +#pragma link C++ class ROOT::Experimental::RPadLength::CoordSysBase+; +#pragma link C++ class ROOT::Experimental::RPadLength::CoordSysBase+; +#pragma link C++ class ROOT::Experimental::RPadLength::CoordSysBase+; #endif diff --git a/graf2d/gpadv7/v7/inc/ROOT/TCanvas.hxx b/graf2d/gpadv7/v7/inc/ROOT/RCanvas.hxx similarity index 72% rename from graf2d/gpadv7/v7/inc/ROOT/TCanvas.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RCanvas.hxx index 731cd7d4bfdb0..a2277c80a7d9f 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TCanvas.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RCanvas.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TCanvas.hxx +/// \file ROOT/RCanvas.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2015-07-08 @@ -13,11 +13,11 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TCanvas -#define ROOT7_TCanvas +#ifndef ROOT7_RCanvas +#define ROOT7_RCanvas -#include "ROOT/TPad.hxx" -#include "ROOT/TVirtualCanvasPainter.hxx" +#include "ROOT/RPad.hxx" +#include "ROOT/RVirtualCanvasPainter.hxx" #include #include @@ -26,18 +26,18 @@ namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TCanvas - A window's topmost `TPad`. +/** \class ROOT::Experimental::RCanvas + A window's topmost `RPad`. */ -class TCanvas: public TPadBase { -friend class TPadBase; /// use for ID generation +class RCanvas: public RPadBase { +friend class RPadBase; /// use for ID generation private: /// Title of the canvas. std::string fTitle; /// Size of the canvas in pixels, - std::array fSize; + std::array fSize; /// Modify counter, incremented every time canvas is changed uint64_t fModified; /// fPainter; /// fPainter; /// Create(const std::string &title); + static std::shared_ptr Create(const std::string &title); - /// Create a temporary TCanvas; for long-lived ones please use Create(). - TCanvas() = default; + /// Create a temporary RCanvas; for long-lived ones please use Create(). + RCanvas() = default; - ~TCanvas() = default; + ~RCanvas() = default; - const TCanvas *GetCanvas() const override { return this; } + const RCanvas *GetCanvas() const override { return this; } /// Access to the top-most canvas, if any (non-const version). - TCanvas *GetCanvas() override { return this; } + RCanvas *GetCanvas() override { return this; } /// Return canvas pixel size as array with two elements - width and height - const std::array &GetSize() const { return fSize; } + const std::array &GetSize() const { return fSize; } /// Set canvas pixel size as array with two elements - width and height - void SetSize(const std::array &sz) { fSize = sz; } + void SetSize(const std::array &sz) { fSize = sz; } /// Set canvas pixel size - width and height - void SetSize(const TPadLength::Pixel &width, const TPadLength::Pixel &height) + void SetSize(const RPadLength::Pixel &width, const RPadLength::Pixel &height) { fSize[0] = width; fSize[1] = height; @@ -115,12 +115,12 @@ public: void SetTitle(const std::string &title) { fTitle = title; } /// Convert a `Pixel` position to Canvas-normalized positions. - std::array PixelsToNormal(const std::array &pos) const final + std::array PixelsToNormal(const std::array &pos) const final { return {{pos[0] / fSize[0], pos[1] / fSize[1]}}; } - static const std::vector> &GetCanvases(); + static const std::vector> &GetCanvases(); }; } // namespace Experimental diff --git a/graf2d/gpadv7/v7/inc/ROOT/TFrame.hxx b/graf2d/gpadv7/v7/inc/ROOT/RFrame.hxx similarity index 61% rename from graf2d/gpadv7/v7/inc/ROOT/TFrame.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RFrame.hxx index 8cd00e44fdaec..281a53a4cc41e 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TFrame.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RFrame.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TFrame.hxx +/// \file ROOT/RFrame.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-09-26 @@ -13,61 +13,61 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TFrame -#define ROOT7_TFrame +#ifndef ROOT7_RFrame +#define ROOT7_RFrame -#include "ROOT/TDrawingAttr.hxx" -#include "ROOT/TDrawingOptsBase.hxx" -#include "ROOT/TPadExtent.hxx" -#include "ROOT/TPadPos.hxx" -#include "ROOT/TPadUserAxis.hxx" -#include "ROOT/TPalette.hxx" +#include "ROOT/RDrawingAttr.hxx" +#include "ROOT/RDrawingOptsBase.hxx" +#include "ROOT/RPadExtent.hxx" +#include "ROOT/RPadPos.hxx" +#include "ROOT/RPadUserAxis.hxx" +#include "ROOT/RPalette.hxx" #include namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TFrame +/** \class ROOT::Experimental::RFrame Holds a user coordinate system with a palette. */ -class TFrame { +class RFrame { public: - class DrawingOpts: public TDrawingOptsBase { + class DrawingOpts: public RDrawingOptsBase { public: - /// Position of the frame in parent TPad coordinates. - TDrawingAttr fPos{*this, "frame.pos", 0.1_normal, 0.1_normal}; - /// Size of the frame in parent TPad coordinates. - TDrawingAttr fSize{*this, "frame.size", 0.8_normal, 0.8_normal}; + /// Position of the frame in parent RPad coordinates. + RDrawingAttr fPos{*this, "frame.pos", 0.1_normal, 0.1_normal}; + /// Size of the frame in parent RPad coordinates. + RDrawingAttr fSize{*this, "frame.size", 0.8_normal, 0.8_normal}; }; private: /// Mapping of user coordinates to normal coordinates, one entry per dimension. - std::vector> fUserCoord; + std::vector> fUserCoord; /// Palette used to visualize user coordinates. - TPalette fPalette; + RPalette fPalette; - /// Offset with respect to parent TPad. - TPadPos fPos; + /// Offset with respect to parent RPad. + RPadPos fPos; - /// Size of the frame, in parent TPad coordinates. - TPadExtent fSize; + /// Size of the frame, in parent RPad coordinates. + RPadExtent fSize; public: // Default constructor - TFrame() + RFrame() { GrowToDimensions(2); } /// Constructor taking user coordinate system, position and extent. - explicit TFrame(std::vector> &&coords, const DrawingOpts &opts); + explicit RFrame(std::vector> &&coords, const DrawingOpts &opts); // Constructor taking position and extent. - explicit TFrame(const DrawingOpts &opts) - : TFrame({}, opts) + explicit RFrame(const DrawingOpts &opts) + : RFrame({}, opts) {} /// Create `nDimensions` default axes for the user coordinate system. @@ -77,13 +77,13 @@ public: size_t GetNDimensions() const { return fUserCoord.size(); } /// Get the current user coordinate system for a given dimension. - TPadUserAxisBase &GetUserAxis(size_t dimension) const { return *fUserCoord[dimension]; } + RPadUserAxisBase &GetUserAxis(size_t dimension) const { return *fUserCoord[dimension]; } /// Set the user coordinate system. - void SetUserAxis(std::vector> &&axes) { fUserCoord = std::move(axes); } + void SetUserAxis(std::vector> &&axes) { fUserCoord = std::move(axes); } /// Convert user coordinates to normal coordinates. - std::array UserToNormal(const std::array &pos) const + std::array UserToNormal(const std::array &pos) const { return {{fUserCoord[0]->ToNormal(pos[0]), fUserCoord[1]->ToNormal(pos[1])}}; } diff --git a/graf2d/gpadv7/v7/inc/ROOT/TMenuItem.hxx b/graf2d/gpadv7/v7/inc/ROOT/RMenuItem.hxx similarity index 70% rename from graf2d/gpadv7/v7/inc/ROOT/TMenuItem.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RMenuItem.hxx index a5918cc338439..93d87d0f20ccc 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TMenuItem.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RMenuItem.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TMenuItem.h +/// \file ROOT/RMenuItem.hxx /// \ingroup Base ROOT7 /// \author Sergey Linev /// \date 2017-06-29 @@ -13,8 +13,8 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TMenuItem -#define ROOT7_TMenuItem +#ifndef ROOT7_RMenuItem +#define ROOT7_RMenuItem #include #include @@ -25,26 +25,26 @@ namespace ROOT { namespace Experimental { namespace Detail { -/** \class TMenuItem +/** \class RMenuItem Class contains info for producing menu item on the JS side. */ -class TMenuItem { +class RMenuItem { protected: std::string fName; ///< name of the menu item std::string fTitle; ///< title of menu item std::string fExec; ///< execute when item is activated public: /** Default constructor */ - TMenuItem() = default; + RMenuItem() = default; /** Create menu item with the name and title * name used to display item in the object context menu, * title shown as hint info for that item */ - TMenuItem(const std::string &name, const std::string &title) : fName(name), fTitle(title), fExec() {} + RMenuItem(const std::string &name, const std::string &title) : fName(name), fTitle(title), fExec() {} - /** virtual destructor need for vtable, used when vector of TMenuItem* is stored */ - virtual ~TMenuItem() {} + /** virtual destructor need for vtable, used when vector of RMenuItem* is stored */ + virtual ~RMenuItem() {} /** Set execution string with all required arguments, * which will be executed when menu item is selected */ @@ -57,21 +57,21 @@ public: const std::string &GetExec() const { return fExec; } }; -class TCheckedMenuItem : public TMenuItem { +class RCheckedMenuItem : public RMenuItem { protected: bool fChecked = false; ///< -1 not exists, 0 - off, 1 - on public: /** Default constructor */ - TCheckedMenuItem() = default; + RCheckedMenuItem() = default; /** Create checked menu item */ - TCheckedMenuItem(const std::string &name, const std::string &title, bool checked = false) - : TMenuItem(name, title), fChecked(checked) + RCheckedMenuItem(const std::string &name, const std::string &title, bool checked = false) + : RMenuItem(name, title), fChecked(checked) { } - /** virtual destructor need for vtable, used when vector of TMenuItem* is stored */ - virtual ~TCheckedMenuItem() {} + /** virtual destructor need for vtable, used when vector of RMenuItem* is stored */ + virtual ~RCheckedMenuItem() {} /** Set checked state for the item, default is none */ void SetChecked(bool on = true) { fChecked = on; } @@ -79,7 +79,7 @@ public: bool IsChecked() const { return fChecked; } }; -class TMenuArgument { +class RMenuArgument { protected: std::string fName; ///< name of call argument std::string fTitle; ///< title of call argument @@ -87,9 +87,9 @@ protected: std::string fDefault; ///< default value public: /** Default constructor */ - TMenuArgument() = default; + RMenuArgument() = default; - TMenuArgument(const std::string &name, const std::string &title, const std::string &typname, + RMenuArgument(const std::string &name, const std::string &title, const std::string &typname, const std::string &dflt = "") : fName(name), fTitle(title), fTypeName(typname), fDefault(dflt) { @@ -98,47 +98,47 @@ public: void SetDefault(const std::string &dflt) { fDefault = dflt; } }; -class TArgsMenuItem : public TMenuItem { +class RArgsMenuItem : public RMenuItem { protected: - std::vector fArgs; + std::vector fArgs; public: /** Default constructor */ - TArgsMenuItem() = default; + RArgsMenuItem() = default; - TArgsMenuItem(const std::string &name, const std::string &title) : TMenuItem(name, title) {} + RArgsMenuItem(const std::string &name, const std::string &title) : RMenuItem(name, title) {} - /** virtual destructor need for vtable, used when vector of TMenuItem* is stored */ - virtual ~TArgsMenuItem() {} + /** virtual destructor need for vtable, used when vector of RMenuItem* is stored */ + virtual ~RArgsMenuItem() {} - void AddArg(const TMenuArgument &arg) { fArgs.push_back(arg); } + void AddArg(const RMenuArgument &arg) { fArgs.push_back(arg); } }; } // namespace Detail /////////////////////////////////////////////////////////////////////// -class TMenuItems { +class RMenuItems { protected: - std::vector fItems; ///< list of items in the menu + std::vector fItems; ///< list of items in the menu public: /** Default constructor */ - TMenuItems() = default; + RMenuItems() = default; - ~TMenuItems() { Cleanup(); } + ~RMenuItems() { Cleanup(); } - void Add(Detail::TMenuItem *item) { fItems.push_back(item); } + void Add(Detail::RMenuItem *item) { fItems.push_back(item); } void AddMenuItem(const std::string &name, const std::string &title, const std::string &exec) { - Detail::TMenuItem *item = new Detail::TMenuItem(name, title); + Detail::RMenuItem *item = new Detail::RMenuItem(name, title); item->SetExec(exec); Add(item); } void AddChkMenuItem(const std::string &name, const std::string &title, bool checked, const std::string &toggle) { - Detail::TCheckedMenuItem *item = new Detail::TCheckedMenuItem(name, title, checked); + Detail::RCheckedMenuItem *item = new Detail::RCheckedMenuItem(name, title, checked); item->SetExec(toggle); Add(item); } diff --git a/graf2d/gpadv7/v7/inc/ROOT/TObjectDrawable.hxx b/graf2d/gpadv7/v7/inc/ROOT/RObjectDrawable.hxx similarity index 62% rename from graf2d/gpadv7/v7/inc/ROOT/TObjectDrawable.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RObjectDrawable.hxx index 04ce46dd4974c..9c9e46fb71270 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TObjectDrawable.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RObjectDrawable.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TDisplayItem.h +/// \file ROOT/RObjectDrawable.hxx /// \ingroup Base ROOT7 /// \author Sergey Linev /// \date 2017-05-31 @@ -13,13 +13,13 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TObjectDrawable -#define ROOT7_TObjectDrawable +#ifndef ROOT7_RObjectDrawable +#define ROOT7_RObjectDrawable -#include -#include +#include +#include #include "ROOT/RStringView.hxx" -#include "ROOT/TDisplayItem.hxx" +#include "ROOT/RDisplayItem.hxx" #include #include @@ -30,50 +30,50 @@ class TObject; namespace ROOT { namespace Experimental { -class TPadBase; +class RPadBase; -/// \class ROOT::Experimental::Internal::TObjectDrawingOpts Drawing options for TObject. -class TObjectDrawingOpts : public TDrawingOptsBase { +/// \class ROOT::Experimental::Internal::RObjectDrawingOpts Drawing options for TObject. +class RObjectDrawingOpts : public RDrawingOptsBase { std::string fOpts; ///< The drawing options public: - TObjectDrawingOpts(const std::string &opts = "") : fOpts(opts) {} + RObjectDrawingOpts(const std::string &opts = "") : fOpts(opts) {} const std::string &GetOptionString() const { return fOpts; } }; -/// \class ROOT::Experimental::Internal::TObjectDrawable +/// \class ROOT::Experimental::Internal::RObjectDrawable /// Provides v7 drawing facilities for TObject types (TGraph etc). -class TObjectDrawable : public TDrawableBase { +class RObjectDrawable : public RDrawableBase { const std::shared_ptr fObj; ///< The object to be painted - TObjectDrawingOpts fOpts; + RObjectDrawingOpts fOpts; public: - TObjectDrawable() = default; + RObjectDrawable() = default; - TObjectDrawable(const std::shared_ptr &obj, const std::string &opt) : fObj(obj), fOpts(opt) {} + RObjectDrawable(const std::shared_ptr &obj, const std::string &opt) : fObj(obj), fOpts(opt) {} /// Paint the object - void Paint(Internal::TPadPainter &canv) final; + void Paint(Internal::RPadPainter &canv) final; /// Fill menu items for the object - void PopulateMenu(TMenuItems &) final; + void PopulateMenu(RMenuItems &) final; /// Get the options - a string! - const TObjectDrawingOpts &GetOptions() const { return fOpts; } + const RObjectDrawingOpts &GetOptions() const { return fOpts; } - TObjectDrawingOpts &GetOptions() { return fOpts; } + RObjectDrawingOpts &GetOptions() { return fOpts; } /// Executes menu item void Execute(const std::string &) final; }; -class TObjectDisplayItem : public TDisplayItem { +class RObjectDisplayItem : public RDisplayItem { protected: const TObject *fObject; ///< object to draw std::string fOption; ///< v6 draw options public: - TObjectDisplayItem(TObject *obj, const std::string &opt) : fObject(obj), fOption(opt) {} + RObjectDisplayItem(TObject *obj, const std::string &opt) : fObject(obj), fOption(opt) {} }; } // namespace Experimental @@ -81,10 +81,10 @@ public: /// Interface to graphics taking a shared_ptr. /// Must be on global scope, else lookup cannot find it (no ADL for TObject). -inline std::unique_ptr +inline std::unique_ptr GetDrawable(const std::shared_ptr &obj, const std::string &opt = "") { - return std::make_unique(obj, opt); + return std::make_unique(obj, opt); } #endif diff --git a/graf2d/gpadv7/v7/inc/ROOT/TPad.hxx b/graf2d/gpadv7/v7/inc/ROOT/RPad.hxx similarity index 60% rename from graf2d/gpadv7/v7/inc/ROOT/TPad.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RPad.hxx index b00721a3c533c..e93d86ac5732b 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TPad.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RPad.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TPad.hxx +/// \file ROOT/RPad.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-07-06 @@ -13,49 +13,49 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TPad -#define ROOT7_TPad +#ifndef ROOT7_RPad +#define ROOT7_RPad #include #include -#include "ROOT/TDrawable.hxx" -#include "ROOT/TDrawingAttr.hxx" -#include "ROOT/TDrawingOptsBase.hxx" -#include "ROOT/TFrame.hxx" -#include "ROOT/TPadExtent.hxx" -#include "ROOT/TPadPos.hxx" -#include "ROOT/TPadUserAxis.hxx" +#include "ROOT/RDrawable.hxx" +#include "ROOT/RDrawingAttr.hxx" +#include "ROOT/RDrawingOptsBase.hxx" +#include "ROOT/RFrame.hxx" +#include "ROOT/RPadExtent.hxx" +#include "ROOT/RPadPos.hxx" +#include "ROOT/RPadUserAxis.hxx" #include "ROOT/TypeTraits.hxx" namespace ROOT { namespace Experimental { -class TPad; -class TCanvas; +class RPad; +class RCanvas; -/** \class ROOT::Experimental::TPadBase - Base class for graphic containers for `TDrawable`-s. +/** \class ROOT::Experimental::RPadBase + Base class for graphic containers for `RDrawable`-s. */ -class TPadBase { +class RPadBase { public: - using Primitives_t = std::vector>; + using Primitives_t = std::vector>; private: /// Content of the pad. Primitives_t fPrimitives; - /// TFrame with user coordinate system, if used by this pad. - std::unique_ptr fFrame; + /// RFrame with user coordinate system, if used by this pad. + std::unique_ptr fFrame; /// Disable copy construction. - TPadBase(const TPadBase &) = delete; + RPadBase(const RPadBase &) = delete; /// Disable assignment. - TPadBase &operator=(const TPadBase &) = delete; + RPadBase &operator=(const RPadBase &) = delete; - void AssignUniqueID(std::shared_ptr &ptr); + void AssignUniqueID(std::shared_ptr &ptr); /// Adds a `DRAWABLE` to `fPrimitives`, returning a `shared_ptr` to `DRAWABLE::GetOptions()`. template @@ -73,18 +73,18 @@ private: } protected: - /// Allow derived classes to default construct a TPadBase. - TPadBase() = default; + /// Allow derived classes to default construct a RPadBase. + RPadBase() = default; public: - virtual ~TPadBase(); + virtual ~RPadBase(); /// Divide this pad into a grid of subpads with padding in between. /// \param nHoriz Number of horizontal pads. /// \param nVert Number of vertical pads. /// \param padding Padding between pads. /// \returns vector of vector (ret[x][y]) of created pads. - std::vector> Divide(int nHoriz, int nVert, const TPadExtent &padding = {}); + std::vector> Divide(int nHoriz, int nVert, const RPadExtent &padding = {}); /// Add something to be painted. /// The pad observes what's lifetime through a weak pointer. @@ -115,16 +115,16 @@ public: } /// Remove an object from the list of primitives. - bool Remove(TDrawingOptsBase& opts) { + bool Remove(RDrawingOptsBase& opts) { auto iter = std::find_if(fPrimitives.begin(), fPrimitives.end(), - [&opts](const std::shared_ptr& drawable) { return &drawable->GetOptionsBase() == &opts; }); + [&opts](const std::shared_ptr& drawable) { return &drawable->GetOptionsBase() == &opts; }); if (iter == fPrimitives.end()) return false; iter->reset(); return true; } - std::shared_ptr FindDrawable(const std::string &id) const; + std::shared_ptr FindDrawable(const std::string &id) const; /// Wipe the pad by clearing the list of primitives. void Wipe() @@ -134,21 +134,21 @@ public: void CreateFrameIfNeeded(); - TFrame *GetOrCreateFrame(); - const TFrame *GetFrame() const { return fFrame.get(); } + RFrame *GetOrCreateFrame(); + const RFrame *GetFrame() const { return fFrame.get(); } - TPadUserAxisBase* GetOrCreateAxis(size_t dimension); - TPadUserAxisBase* GetAxis(size_t dimension) const; + RPadUserAxisBase* GetOrCreateAxis(size_t dimension); + RPadUserAxisBase* GetAxis(size_t dimension) const; void SetAxisBounds(int dimension, double begin, double end); - void SetAxisBound(int dimension, TPadUserAxisBase::EAxisBoundsKind boundsKind, double bound); + void SetAxisBound(int dimension, RPadUserAxisBase::EAxisBoundsKind boundsKind, double bound); void SetAxisAutoBounds(int dimension); void SetAllAxisBounds(const std::vector> &vecBeginAndEnd); /// Simple struct representing an axis bound. struct BoundKindAndValue { - TPadUserAxisBase::EAxisBoundsKind fKind = TPadUserAxisBase::kAxisBoundsAuto; + RPadUserAxisBase::EAxisBoundsKind fKind = RPadUserAxisBase::kAxisBoundsAuto; double fBound = 0.; }; void SetAllAxisBound(const std::vector &vecBoundAndKind); @@ -158,69 +158,69 @@ public: const Primitives_t &GetPrimitives() const { return fPrimitives; } /// Convert a `Pixel` position to Canvas-normalized positions. - virtual std::array PixelsToNormal(const std::array &pos) const = 0; + virtual std::array PixelsToNormal(const std::array &pos) const = 0; /// Access to the top-most canvas, if any (const version). - virtual const TCanvas *GetCanvas() const = 0; + virtual const RCanvas *GetCanvas() const = 0; /// Access to the top-most canvas, if any (non-const version). - virtual TCanvas *GetCanvas() = 0; + virtual RCanvas *GetCanvas() = 0; /// Convert user coordinates to normal coordinates. - std::array UserToNormal(const std::array &pos) const + std::array UserToNormal(const std::array &pos) const { return fFrame->UserToNormal(pos); } }; -class TPadDrawable; +class RPadDrawable; -/** \class ROOT::Experimental::TPad - Graphic container for `TDrawable`-s. +/** \class ROOT::Experimental::RPad + Graphic container for `RDrawable`-s. */ -class TPad: public TPadBase { +class RPad: public RPadBase { private: /// Pad containing this pad as a sub-pad. - TPadBase *fParent = nullptr; /// The parent pad, if this pad has one. + RPadBase *fParent = nullptr; /// The parent pad, if this pad has one. /// Size of the pad in the parent's (!) coordinate system. - TPadExtent fSize = {1._normal, 1._normal}; // {640_px, 400_px}; + RPadExtent fSize = {1._normal, 1._normal}; // {640_px, 400_px}; public: - friend std::unique_ptr GetDrawable(std::unique_ptr &&pad); + friend std::unique_ptr GetDrawable(std::unique_ptr &&pad); /// Create a topmost, non-paintable pad. - TPad() = default; + RPad() = default; /// Create a child pad. - TPad(TPadBase &parent, const TPadExtent &size): fParent(&parent), fSize(size) {} + RPad(RPadBase &parent, const RPadExtent &size): fParent(&parent), fSize(size) {} /// Destructor to have a vtable. - virtual ~TPad(); + virtual ~RPad(); /// Access to the parent pad (const version). - const TPadBase *GetParent() const { return fParent; } + const RPadBase *GetParent() const { return fParent; } /// Access to the parent pad (non-const version). - TPadBase *GetParent() { return fParent; } + RPadBase *GetParent() { return fParent; } /// Access to the top-most canvas (const version). - const TCanvas *GetCanvas() const override { return fParent ? fParent->GetCanvas() : nullptr; } + const RCanvas *GetCanvas() const override { return fParent ? fParent->GetCanvas() : nullptr; } /// Access to the top-most canvas (non-const version). - TCanvas *GetCanvas() override { return fParent ? fParent->GetCanvas() : nullptr; } + RCanvas *GetCanvas() override { return fParent ? fParent->GetCanvas() : nullptr; } /// Get the size of the pad in parent (!) coordinates. - const TPadExtent &GetSize() const { return fSize; } + const RPadExtent &GetSize() const { return fSize; } /// Convert a `Pixel` position to Canvas-normalized positions. - std::array PixelsToNormal(const std::array &pos) const override + std::array PixelsToNormal(const std::array &pos) const override { - std::array posInParentNormal = fParent->PixelsToNormal(pos); - std::array myPixelInNormal = + std::array posInParentNormal = fParent->PixelsToNormal(pos); + std::array myPixelInNormal = fParent->PixelsToNormal({{fSize.fHoriz.fPixel, fSize.fVert.fPixel}}); - std::array myUserInNormal = + std::array myUserInNormal = fParent->UserToNormal({{fSize.fHoriz.fUser, fSize.fVert.fUser}}); // If the parent says pos is at 0.6 in normal coords, and our size converted to normal is 0.2, then pos in our // coord system is 3.0! @@ -228,71 +228,71 @@ public: posInParentNormal[1] / (fSize.fVert.fNormal + myPixelInNormal[1] + myUserInNormal[1])}}; } - /// Convert a TPadPos to [x, y] of normalized coordinates. - std::array ToNormal(const Internal::TPadHorizVert &pos) const + /// Convert a RPadPos to [x, y] of normalized coordinates. + std::array ToNormal(const Internal::RPadHorizVert &pos) const { - std::array pixelsInNormal = PixelsToNormal({{pos.fHoriz.fPixel, pos.fVert.fPixel}}); - std::array userInNormal = UserToNormal({{pos.fHoriz.fUser, pos.fVert.fUser}}); + std::array pixelsInNormal = PixelsToNormal({{pos.fHoriz.fPixel, pos.fVert.fPixel}}); + std::array userInNormal = UserToNormal({{pos.fHoriz.fUser, pos.fVert.fUser}}); return {{pos.fHoriz.fNormal + pixelsInNormal[0] + userInNormal[0], pos.fVert.fNormal + pixelsInNormal[1] + userInNormal[1]}}; } }; -/** \class TPadDrawingOpts - Drawing options for a TPad +/** \class RPadDrawingOpts + Drawing options for a RPad */ -class TPadDrawingOpts: public TDrawingOptsBase { - TDrawingAttr fPos{*this, "PadOffset"}; ///< Offset with respect to parent TPad. +class RPadDrawingOpts: public RDrawingOptsBase { + RDrawingAttr fPos{*this, "PadOffset"}; ///< Offset with respect to parent RPad. public: - TPadDrawingOpts() = default; + RPadDrawingOpts() = default; /// Construct the drawing options. - TPadDrawingOpts(const TPadPos& pos): fPos(*this, "PadOffset", pos) {} + RPadDrawingOpts(const RPadPos& pos): fPos(*this, "PadOffset", pos) {} /// Set the position of this pad with respect to the parent pad. - TPadDrawingOpts &At(const TPadPos &pos) + RPadDrawingOpts &At(const RPadPos &pos) { fPos = pos; return *this; } - TDrawingAttr &GetOffset() { return fPos; } - const TDrawingAttr &GetOffset() const { return fPos; } + RDrawingAttr &GetOffset() { return fPos; } + const RDrawingAttr &GetOffset() const { return fPos; } }; -/** \class TPadDrawable - Draw a TPad, by drawing its contained graphical elements at the pad offset in the parent pad.' +/** \class RPadDrawable + Draw a RPad, by drawing its contained graphical elements at the pad offset in the parent pad.' */ -class TPadDrawable: public TDrawableBase { +class RPadDrawable: public RDrawableBase { private: - const std::shared_ptr fPad; ///< The pad to be painted - TPadDrawingOpts fOpts; ///< The drawing options. + const std::shared_ptr fPad; ///< The pad to be painted + RPadDrawingOpts fOpts; ///< The drawing options. public: /// Move a sub-pad into this (i.e. parent's) list of drawables. - TPadDrawable(std::shared_ptr pPad, const TPadDrawingOpts& opts = {}); + RPadDrawable(std::shared_ptr pPad, const RPadDrawingOpts& opts = {}); /// Paint primitives from the pad. - void Paint(Internal::TPadPainter &) final; + void Paint(Internal::RPadPainter &) final; - TPad *Get() const { return fPad.get(); } + RPad *Get() const { return fPad.get(); } /// Drawing options. - TPadDrawingOpts &GetOptions() { return fOpts; } + RPadDrawingOpts &GetOptions() { return fOpts; } }; template -inline std::shared_ptr GetDrawable(std::unique_ptr &&pad, ARGS... args) +inline std::shared_ptr GetDrawable(std::unique_ptr &&pad, ARGS... args) { - return std::make_shared(std::move(pad), TPadDrawingOpts(args...)); + return std::make_shared(std::move(pad), RPadDrawingOpts(args...)); } template -inline std::shared_ptr GetDrawable(const std::shared_ptr &pad, ARGS... args) +inline std::shared_ptr GetDrawable(const std::shared_ptr &pad, ARGS... args) { - return std::make_shared(pad, TPadDrawingOpts(args...)); + return std::make_shared(pad, RPadDrawingOpts(args...)); } } // namespace Experimental diff --git a/graf2d/gpadv7/v7/inc/ROOT/TPadDisplayItem.hxx b/graf2d/gpadv7/v7/inc/ROOT/RPadDisplayItem.hxx similarity index 64% rename from graf2d/gpadv7/v7/inc/ROOT/TPadDisplayItem.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RPadDisplayItem.hxx index 0ac1f5266bb33..ba00a3446c1e1 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TPadDisplayItem.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RPadDisplayItem.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TDisplayItem.h +/// \file ROOT/RPadDisplayItem.hxx /// \ingroup Base ROOT7 /// \author Sergey Linev /// \date 2017-05-31 @@ -13,14 +13,11 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TPadDisplayItem -#define ROOT7_TPadDisplayItem - -#include - -#include - -#include +#ifndef ROOT7_RPadDisplayItem +#define ROOT7_RPadDisplayItem +#include +#include +#include namespace ROOT { namespace Experimental { @@ -29,25 +26,25 @@ namespace Experimental { /// Includes different graphical properties of the pad itself plus /// list of created items for all primitives -class TPadDisplayItem : public TDisplayItem { +class RPadDisplayItem : public RDisplayItem { public: // list of snapshot for primitives in pad - using PadPrimitives_t = std::vector>; + using PadPrimitives_t = std::vector>; protected: - const TFrame *fFrame{nullptr}; ///< temporary pointer on frame object - const TPadDrawingOpts *fDrawOpts{nullptr}; ///< temporary pointer on pad drawing options - const TPadExtent *fSize{nullptr}; ///< temporary pointer on pad size attributes + const RFrame *fFrame{nullptr}; ///< temporary pointer on frame object + const RPadDrawingOpts *fDrawOpts{nullptr}; ///< temporary pointer on pad drawing options + const RPadExtent *fSize{nullptr}; ///< temporary pointer on pad size attributes PadPrimitives_t fPrimitives; ///< display items for all primitives in the pad public: - TPadDisplayItem() = default; - virtual ~TPadDisplayItem() {} - void SetFrame(const TFrame *f) { fFrame = f; } - void SetDrawOpts(const TPadDrawingOpts *opts) { fDrawOpts = opts; } - void SetSize(const TPadExtent *sz) { fSize = sz; } + RPadDisplayItem() = default; + virtual ~RPadDisplayItem() {} + void SetFrame(const RFrame *f) { fFrame = f; } + void SetDrawOpts(const RPadDrawingOpts *opts) { fDrawOpts = opts; } + void SetSize(const RPadExtent *sz) { fSize = sz; } PadPrimitives_t &GetPrimitives() { return fPrimitives; } - void Add(std::unique_ptr &&item) { fPrimitives.push_back(std::move(item)); } + void Add(std::unique_ptr &&item) { fPrimitives.push_back(std::move(item)); } void Clear() { fPrimitives.clear(); diff --git a/graf2d/gpadv7/v7/inc/ROOT/TPadExtent.hxx b/graf2d/gpadv7/v7/inc/ROOT/RPadExtent.hxx similarity index 60% rename from graf2d/gpadv7/v7/inc/ROOT/TPadExtent.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RPadExtent.hxx index 631ddb82fb6c4..955a347ff9785 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TPadExtent.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RPadExtent.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TPadExtent.hxx +/// \file ROOT/RPadExtent.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-07-07 @@ -13,10 +13,10 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TPadExtent -#define ROOT7_TPadExtent +#ifndef ROOT7_RPadExtent +#define ROOT7_RPadExtent -#include "ROOT/TPadLength.hxx" +#include "ROOT/RPadLength.hxx" #include @@ -24,48 +24,48 @@ namespace ROOT { namespace Experimental { namespace Internal { -/** \class ROOT::Experimental::Internal::TPadHorizVert - A 2D (horizontal and vertical) combination of `TPadLength`s. +/** \class ROOT::Experimental::Internal::RPadHorizVert + A 2D (horizontal and vertical) combination of `RPadLength`s. */ -struct TPadHorizVert { - TPadLength fHoriz; ///< Horizontal position - TPadLength fVert; ///< Vertical position +struct RPadHorizVert { + RPadLength fHoriz; ///< Horizontal position + RPadLength fVert; ///< Vertical position - TPadHorizVert() = default; - TPadHorizVert(const std::array &hv): fHoriz(hv[0]), fVert(hv[1]) {} - TPadHorizVert(const TPadLength &horiz, const TPadLength &vert): fHoriz(horiz), fVert(vert) {} + RPadHorizVert() = default; + RPadHorizVert(const std::array &hv): fHoriz(hv[0]), fVert(hv[1]) {} + RPadHorizVert(const RPadLength &horiz, const RPadLength &vert): fHoriz(horiz), fVert(vert) {} }; }; // namespace Internal -/** \class ROOT::Experimental::TPadExtent - An extent / size (horizontal and vertical) in a `TPad`. +/** \class ROOT::Experimental::RPadExtent + An extent / size (horizontal and vertical) in a `RPad`. */ -struct TPadExtent: Internal::TPadHorizVert { - using Internal::TPadHorizVert::TPadHorizVert; +struct RPadExtent: Internal::RPadHorizVert { + using Internal::RPadHorizVert::RPadHorizVert; - /// Add two `TPadExtent`s. - friend TPadExtent operator+(TPadExtent lhs, const TPadExtent &rhs) + /// Add two `RPadExtent`s. + friend RPadExtent operator+(RPadExtent lhs, const RPadExtent &rhs) { return {lhs.fHoriz + rhs.fHoriz, lhs.fVert + rhs.fVert}; } - /// Subtract two `TPadExtent`s. - friend TPadExtent operator-(TPadExtent lhs, const TPadExtent &rhs) + /// Subtract two `RPadExtent`s. + friend RPadExtent operator-(RPadExtent lhs, const RPadExtent &rhs) { return {lhs.fHoriz - rhs.fHoriz, lhs.fVert - rhs.fVert}; } - /// Add a `TPadExtent`. - TPadExtent &operator+=(const TPadExtent &rhs) + /// Add a `RPadExtent`. + RPadExtent &operator+=(const RPadExtent &rhs) { fHoriz += rhs.fHoriz; fVert += rhs.fVert; return *this; }; - /// Subtract a `TPadExtent`. - TPadExtent &operator-=(const TPadExtent &rhs) + /// Subtract a `RPadExtent`. + RPadExtent &operator-=(const RPadExtent &rhs) { fHoriz -= rhs.fHoriz; fVert -= rhs.fVert; @@ -73,16 +73,16 @@ struct TPadExtent: Internal::TPadHorizVert { }; /** \class ScaleFactor - A scale factor (separate factors for horizontal and vertical) for scaling a `TPadLength`. + A scale factor (separate factors for horizontal and vertical) for scaling a `RPadLength`. */ struct ScaleFactor { double fHoriz; ///< Horizontal scale factor double fVert; ///< Vertical scale factor }; - /// Scale a `TPadHorizVert` horizonally and vertically. + /// Scale a `RPadHorizVert` horizonally and vertically. /// \param scale - the scale factor, - TPadExtent &operator*=(const ScaleFactor &scale) + RPadExtent &operator*=(const ScaleFactor &scale) { fHoriz *= scale.fHoriz; fVert *= scale.fVert; @@ -90,14 +90,14 @@ struct TPadExtent: Internal::TPadHorizVert { }; }; -/// Initialize a TPadExtent from a style string. +/// Initialize a RPadExtent from a style string. /// Syntax: X, Y /// where X and Y are a series of numbers separated by "+", where each number is followed by one of /// `px`, `user`, `normal` to specify an extent in pixel, user or normal coordinates. Spaces between /// any part is allowed. -/// Example: `100 px + 0.1 user, 0.5 normal` is a `TPadExtent{100_px + 0.1_user, 0.5_normal}`. +/// Example: `100 px + 0.1 user, 0.5 normal` is a `RPadExtent{100_px + 0.1_user, 0.5_normal}`. -void InitializeAttrFromString(const std::string &name, const std::string &attrStrVal, TPadExtent& val); +void InitializeAttrFromString(const std::string &name, const std::string &attrStrVal, RPadExtent& val); } // namespace Experimental } // namespace ROOT diff --git a/graf2d/gpadv7/v7/inc/ROOT/TPadLength.hxx b/graf2d/gpadv7/v7/inc/ROOT/RPadLength.hxx similarity index 66% rename from graf2d/gpadv7/v7/inc/ROOT/TPadLength.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RPadLength.hxx index 0ef3238a2a403..7e0606b7de486 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TPadLength.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RPadLength.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TPadLength.hxx +/// \file ROOT/RPadLength.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-07-06 @@ -13,17 +13,17 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TPadLength -#define ROOT7_TPadLength +#ifndef ROOT7_RPadLength +#define ROOT7_RPadLength namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TPadLength - A coordinate in a `TPad`. +/** \class ROOT::Experimental::RPadLength + A coordinate in a `RPad`. */ -class TPadLength { +class RPadLength { public: template struct CoordSysBase { @@ -63,13 +63,13 @@ public: // no ==, != }; - /// \defgroup PadCoordSystems TPad coordinate systems - /// These define typesafe coordinates used by TPad to identify which coordinate system a coordinate is referring to. - /// The origin (0,0) is in the `TPad`'s bottom left corner for all of them. + /// \defgroup PadCoordSystems RPad coordinate systems + /// These define typesafe coordinates used by RPad to identify which coordinate system a coordinate is referring to. + /// The origin (0,0) is in the `RPad`'s bottom left corner for all of them. /// \{ /** \class Normal - A normalized coordinate: 0 in the left, bottom corner, 1 in the top, right corner of the `TPad`. Resizing the pad + A normalized coordinate: 0 in the left, bottom corner, 1 in the top, right corner of the `RPad`. Resizing the pad will resize the objects with it. */ struct Normal: CoordSysBase { @@ -77,7 +77,7 @@ public: }; /** \class Pixel - A pixel coordinate: 0 in the left, bottom corner, 1 in the top, right corner of the `TPad`. Resizing the pad will + A pixel coordinate: 0 in the left, bottom corner, 1 in the top, right corner of the `RPad`. Resizing the pad will keep the pixel-position of the objects positioned in `Pixel` coordinates. */ struct Pixel: CoordSysBase { @@ -85,7 +85,7 @@ public: }; /** \class User - A user coordinate, as defined by the EUserCoordSystem parameter of the `TPad`. + A user coordinate, as defined by the EUserCoordSystem parameter of the `RPad`. */ struct User: CoordSysBase { using CoordSysBase::CoordSysBase; @@ -102,39 +102,39 @@ public: User fUser; /// Default constructor, initializing all coordinate parts to `0.`. - TPadLength() = default; + RPadLength() = default; /// Constructor from a `Normal` coordinate. - TPadLength(Normal normal): fNormal(normal) {} + RPadLength(Normal normal): fNormal(normal) {} /// Constructor from a `Pixel` coordinate. - TPadLength(Pixel px): fPixel(px) {} + RPadLength(Pixel px): fPixel(px) {} /// Constructor from a `User` coordinate. - TPadLength(User user): fUser(user) {} + RPadLength(User user): fUser(user) {} /// Sort-of aggregate initialization constructor taking normal, pixel and user parts. - TPadLength(Normal normal, Pixel px, User user): fNormal(normal), fPixel(px), fUser(user) {} + RPadLength(Normal normal, Pixel px, User user): fNormal(normal), fPixel(px), fUser(user) {} - /// Add two `TPadLength`s. - friend TPadLength operator+(TPadLength lhs, const TPadLength &rhs) + /// Add two `RPadLength`s. + friend RPadLength operator+(RPadLength lhs, const RPadLength &rhs) { - return TPadLength{lhs.fNormal + rhs.fNormal, lhs.fPixel + rhs.fPixel, lhs.fUser + rhs.fUser}; + return RPadLength{lhs.fNormal + rhs.fNormal, lhs.fPixel + rhs.fPixel, lhs.fUser + rhs.fUser}; } - /// Subtract two `TPadLength`s. - friend TPadLength operator-(TPadLength lhs, const TPadLength &rhs) + /// Subtract two `RPadLength`s. + friend RPadLength operator-(RPadLength lhs, const RPadLength &rhs) { - return TPadLength{lhs.fNormal - rhs.fNormal, lhs.fPixel - rhs.fPixel, lhs.fUser - rhs.fUser}; + return RPadLength{lhs.fNormal - rhs.fNormal, lhs.fPixel - rhs.fPixel, lhs.fUser - rhs.fUser}; } /// Unary -. - TPadLength operator-() { - return TPadLength(-fNormal, -fPixel, -fUser); + RPadLength operator-() { + return RPadLength(-fNormal, -fPixel, -fUser); } - /// Add a `TPadLength`. - TPadLength &operator+=(const TPadLength &rhs) + /// Add a `RPadLength`. + RPadLength &operator+=(const RPadLength &rhs) { fNormal += rhs.fNormal; fPixel += rhs.fPixel; @@ -142,8 +142,8 @@ public: return *this; }; - /// Subtract a `TPadLength`. - TPadLength &operator-=(const TPadLength &rhs) + /// Subtract a `RPadLength`. + RPadLength &operator-=(const RPadLength &rhs) { fNormal -= rhs.fNormal; fPixel -= rhs.fPixel; @@ -151,7 +151,7 @@ public: return *this; }; - TPadLength &operator*=(double scale) + RPadLength &operator*=(double scale) { fNormal *= scale; fPixel *= scale; @@ -160,52 +160,52 @@ public: } }; -/// User-defined literal for `TPadLength::Normal` +/// User-defined literal for `RPadLength::Normal` /// /// Use as /// ``` /// using namespace ROOT::Experimental; -/// TLine(0.1_normal, 0.0_normal, TLineExtent(0.2_normal, 0.5_normal)); +/// RLine(0.1_normal, 0.0_normal, RLineExtent(0.2_normal, 0.5_normal)); /// ``` -inline TPadLength::Normal operator"" _normal(long double val) +inline RPadLength::Normal operator"" _normal(long double val) { - return TPadLength::Normal{(double)val}; + return RPadLength::Normal{(double)val}; } -inline TPadLength::Normal operator"" _normal(unsigned long long int val) +inline RPadLength::Normal operator"" _normal(unsigned long long int val) { - return TPadLength::Normal{(double)val}; + return RPadLength::Normal{(double)val}; } -/// User-defined literal for `TPadLength::Pixel` +/// User-defined literal for `RPadLength::Pixel` /// /// Use as /// ``` /// using namespace ROOT::Experimental; -/// TLine(100_px, 0_px, TLineExtent(20_px, 50_px)); +/// RLine(100_px, 0_px, RLineExtent(20_px, 50_px)); /// ``` -inline TPadLength::Pixel operator"" _px(long double val) +inline RPadLength::Pixel operator"" _px(long double val) { - return TPadLength::Pixel{(double)val}; + return RPadLength::Pixel{(double)val}; } -inline TPadLength::Pixel operator"" _px(unsigned long long int val) +inline RPadLength::Pixel operator"" _px(unsigned long long int val) { - return TPadLength::Pixel{(double)val}; + return RPadLength::Pixel{(double)val}; } -/// User-defined literal for `TPadLength::User` +/// User-defined literal for `RPadLength::User` /// /// Use as /// ``` /// using namespace ROOT::Experimental; -/// TLine(0.1_user, 0.0_user, TLineExtent(0.2_user, 0.5_user)); +/// RLine(0.1_user, 0.0_user, RLineExtent(0.2_user, 0.5_user)); /// ``` -inline TPadLength::User operator"" _user(long double val) +inline RPadLength::User operator"" _user(long double val) { - return TPadLength::User{(double)val}; + return RPadLength::User{(double)val}; } -inline TPadLength::User operator"" _user(unsigned long long int val) +inline RPadLength::User operator"" _user(unsigned long long int val) { - return TPadLength::User{(double)val}; + return RPadLength::User{(double)val}; } } // namespace Experimental diff --git a/graf2d/gpadv7/v7/inc/ROOT/TPadPainter.hxx b/graf2d/gpadv7/v7/inc/ROOT/RPadPainter.hxx similarity index 68% rename from graf2d/gpadv7/v7/inc/ROOT/TPadPainter.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RPadPainter.hxx index 9dcd91444de19..af03b03edbcea 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TPadPainter.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RPadPainter.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TPadPainter.hxx +/// \file ROOT/RPadPainter.hxx /// \ingroup Gpad ROOT7 /// \author Sergey Linev /// \date 2018-03-12 @@ -13,10 +13,10 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TPadPainter -#define ROOT7_TPadPainter +#ifndef ROOT7_RPadPainter +#define ROOT7_RPadPainter -#include "ROOT/TDisplayItem.hxx" +#include "ROOT/RDisplayItem.hxx" #include #include @@ -24,41 +24,41 @@ namespace ROOT { namespace Experimental { -class TPadDisplayItem; -class TPadDrawable; -class TPadBase; +class RPadDisplayItem; +class RPadDrawable; +class RPadBase; namespace Internal { -/** \class ROOT::Experimental::Internal::TPadPainter +/** \class ROOT::Experimental::Internal::RPadPainter Abstract interface for object painting on the pad/canvas. */ -class TPadPainter { +class RPadPainter { -friend class ROOT::Experimental::TPadDrawable; +friend class ROOT::Experimental::RPadDrawable; protected: - std::unique_ptr fPadDisplayItem; /// fPadDisplayItem; /// &&item); + virtual void AddDisplayItem(std::unique_ptr &&item); }; } // namespace Internal } // namespace Experimental } // namespace ROOT -#endif // ROOT7_TPadPainter +#endif // ROOT7_RPadPainter diff --git a/graf2d/gpadv7/v7/inc/ROOT/TPadPos.hxx b/graf2d/gpadv7/v7/inc/ROOT/RPadPos.hxx similarity index 52% rename from graf2d/gpadv7/v7/inc/ROOT/TPadPos.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RPadPos.hxx index a05a0963b1be9..e0ab42b76dfa6 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TPadPos.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RPadPos.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TPadPos.hxx +/// \file ROOT/RPadPos.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-07-07 @@ -13,58 +13,58 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TPadPos -#define ROOT7_TPadPos +#ifndef ROOT7_RPadPos +#define ROOT7_RPadPos -#include "ROOT/TPadExtent.hxx" +#include "ROOT/RPadExtent.hxx" namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TPadPos - A position (horizontal and vertical) in a `TPad`. +/** \class ROOT::Experimental::RPadPos + A position (horizontal and vertical) in a `RPad`. */ -struct TPadPos: Internal::TPadHorizVert { - using Internal::TPadHorizVert::TPadHorizVert; - TPadPos() = default; - TPadPos(const TPadExtent& extent): Internal::TPadHorizVert(extent) {} +struct RPadPos: Internal::RPadHorizVert { + using Internal::RPadHorizVert::RPadHorizVert; + RPadPos() = default; + RPadPos(const RPadExtent& extent): Internal::RPadHorizVert(extent) {} - /// Add a `TPadExtent`. - friend TPadPos operator+(const TPadPos &lhs, const TPadExtent &rhs) + /// Add a `RPadExtent`. + friend RPadPos operator+(const RPadPos &lhs, const RPadExtent &rhs) { - return TPadPos{lhs.fHoriz + rhs.fHoriz, lhs.fVert + rhs.fVert}; + return RPadPos{lhs.fHoriz + rhs.fHoriz, lhs.fVert + rhs.fVert}; } - /// Add to a `TPadExtent`. - friend TPadPos operator+(const TPadExtent &lhs, const TPadPos &rhs) + /// Add to a `RPadExtent`. + friend RPadPos operator+(const RPadExtent &lhs, const RPadPos &rhs) { - return TPadPos{lhs.fHoriz + rhs.fHoriz, lhs.fVert + rhs.fVert}; + return RPadPos{lhs.fHoriz + rhs.fHoriz, lhs.fVert + rhs.fVert}; } - /// Subtract a `TPadExtent`. - friend TPadPos operator-(const TPadPos &lhs, const TPadExtent &rhs) + /// Subtract a `RPadExtent`. + friend RPadPos operator-(const RPadPos &lhs, const RPadExtent &rhs) { - return TPadPos{lhs.fHoriz - rhs.fHoriz, lhs.fVert - rhs.fVert}; + return RPadPos{lhs.fHoriz - rhs.fHoriz, lhs.fVert - rhs.fVert}; } - /// Subtract from a `TPadPos`s. Is this really needed? + /// Subtract from a `RPadPos`s. Is this really needed? /* - friend TPadPos operator-(const TPadExtent &rhs, const TPadPos &lhs) + friend RPadPos operator-(const RPadExtent &rhs, const RPadPos &lhs) { - return TPadPos{lhs.fHoriz - rhs.fHoriz, lhs.fVert - rhs.fVert}; + return RPadPos{lhs.fHoriz - rhs.fHoriz, lhs.fVert - rhs.fVert}; } */ - /// Add a `TPadExtent`. - TPadPos &operator+=(const TPadExtent &rhs) + /// Add a `RPadExtent`. + RPadPos &operator+=(const RPadExtent &rhs) { fHoriz += rhs.fHoriz; fVert += rhs.fVert; return *this; }; - /// Subtract a `TPadExtent`. - TPadPos &operator-=(const TPadExtent &rhs) + /// Subtract a `RPadExtent`. + RPadPos &operator-=(const RPadExtent &rhs) { fHoriz -= rhs.fHoriz; fVert -= rhs.fVert; @@ -72,16 +72,16 @@ struct TPadPos: Internal::TPadHorizVert { }; /** \class ScaleFactor - A scale factor (separate factors for horizontal and vertical) for scaling a `TPadLength`. + A scale factor (separate factors for horizontal and vertical) for scaling a `RPadLength`. */ struct ScaleFactor { double fHoriz; ///< Horizontal scale factor double fVert; ///< Vertical scale factor }; - /// Scale a `TPadHorizVert` horizontally and vertically. + /// Scale a `RPadHorizVert` horizontally and vertically. /// \param scale - the scale factor, - TPadPos &operator*=(const ScaleFactor &scale) + RPadPos &operator*=(const ScaleFactor &scale) { fHoriz *= scale.fHoriz; fVert *= scale.fVert; @@ -89,8 +89,8 @@ struct TPadPos: Internal::TPadHorizVert { }; }; -/// Initialize a TPadPos from a style string. -void InitializeAttrFromString(const std::string &name, const std::string &attrStrVal, TPadPos& val); +/// Initialize a RPadPos from a style string. +void InitializeAttrFromString(const std::string &name, const std::string &attrStrVal, RPadPos& val); } // namespace Experimental } // namespace ROOT diff --git a/graf2d/gpadv7/v7/inc/ROOT/TPadUserAxis.hxx b/graf2d/gpadv7/v7/inc/ROOT/RPadUserAxis.hxx similarity index 79% rename from graf2d/gpadv7/v7/inc/ROOT/TPadUserAxis.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RPadUserAxis.hxx index 307cbe983f4fe..b30804689aff2 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TPadUserAxis.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RPadUserAxis.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TPadUserAxis.hxx +/// \file ROOT/RPadUserAxis.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-07-15 @@ -13,10 +13,10 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TPadUserAxis -#define ROOT7_TPadUserAxis +#ifndef ROOT7_RPadUserAxis +#define ROOT7_RPadUserAxis -#include +#include #include #include @@ -24,11 +24,11 @@ namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::Internal::TPadUserAxisBase - Base class for user coordinates (e.g. for histograms) used by `TPad` and `TCanvas`. +/** \class ROOT::Experimental::Internal::RPadUserAxisBase + Base class for user coordinates (e.g. for histograms) used by `RPad` and `RCanvas`. */ -class TPadUserAxisBase { +class RPadUserAxisBase { public: /// Types of axis bounds to respect by the painter. Non-fixed ones will be updated by /// the painter once the first paint has happened. @@ -50,21 +50,21 @@ private: double fEnd = 1.; protected: - /// Allow derived classes to default construct a TPadUserAxisBase. - TPadUserAxisBase() = default; + /// Allow derived classes to default construct a RPadUserAxisBase. + RPadUserAxisBase() = default; /// Construct a cartesian axis from min and max, setting fBoundsKind to kAxisBoundsMinMax. - TPadUserAxisBase(double begin, double end): fBoundsKind(kAxisBoundsBeginEnd), fBegin(begin), fEnd(end) {} + RPadUserAxisBase(double begin, double end): fBoundsKind(kAxisBoundsBeginEnd), fBegin(begin), fEnd(end) {} /// Construct a cartesian axis with min or max, depending on the boundKind parameter. - TPadUserAxisBase(EAxisBoundsKind boundKind, double bound): + RPadUserAxisBase(EAxisBoundsKind boundKind, double bound): fBoundsKind(boundKind), fBegin(bound), fEnd(bound) {} /// Disable spliced copy construction. - TPadUserAxisBase(const TPadUserAxisBase &) = default; + RPadUserAxisBase(const RPadUserAxisBase &) = default; /// Disable spliced assignment. - TPadUserAxisBase &operator=(const TPadUserAxisBase &) = default; + RPadUserAxisBase &operator=(const RPadUserAxisBase &) = default; /// For (pos-min)/(max-min) calculations, return a sensible, div-by-0 protected denominator. double GetSensibleDenominator() const @@ -75,7 +75,7 @@ protected: } public: - virtual ~TPadUserAxisBase(); + virtual ~RPadUserAxisBase(); EAxisBoundsKind GetBoundsKind() const { return static_cast(fBoundsKind); } bool RespectBegin() const { return fBoundsKind & kAxisBoundsBegin; } @@ -97,30 +97,30 @@ public: void SetEnd(double end) { fBoundsKind |= kAxisBoundsEnd; fEnd = end; } /// Convert user coordinates to normal coordinates. - virtual TPadLength::Normal ToNormal(const TPadLength::User &) const = 0; + virtual RPadLength::Normal ToNormal(const RPadLength::User &) const = 0; }; -class TPadCartesianUserAxis: public TPadUserAxisBase { +class RPadCartesianUserAxis: public RPadUserAxisBase { private: /// Whether this axis should be painted as log scale. bool fLogScale = false; public: /// Construct a cartesian axis with automatic axis bounds. - TPadCartesianUserAxis() = default; + RPadCartesianUserAxis() = default; /// Construct a cartesian axis from min and max, setting fBoundsKind to kAxisBoundsMinMax. - TPadCartesianUserAxis(double begin, double end): TPadUserAxisBase(begin, end) {} + RPadCartesianUserAxis(double begin, double end): RPadUserAxisBase(begin, end) {} /// Construct a cartesian axis with min or max, depending on the boundKind parameter. - TPadCartesianUserAxis(EAxisBoundsKind boundKind, double bound): - TPadUserAxisBase(boundKind, bound) {} + RPadCartesianUserAxis(EAxisBoundsKind boundKind, double bound): + RPadUserAxisBase(boundKind, bound) {} bool IsLogScale() const { return fLogScale; } void SetLogScale(bool logScale = true) { fLogScale = logScale; } /// Convert user coordinates to normal coordinates. - TPadLength::Normal ToNormal(const TPadLength::User &usercoord) const override; + RPadLength::Normal ToNormal(const RPadLength::User &usercoord) const override; }; } // namespace Experimental diff --git a/graf2d/gpadv7/v7/inc/ROOT/TVirtualCanvasPainter.hxx b/graf2d/gpadv7/v7/inc/ROOT/RVirtualCanvasPainter.hxx similarity index 77% rename from graf2d/gpadv7/v7/inc/ROOT/TVirtualCanvasPainter.hxx rename to graf2d/gpadv7/v7/inc/ROOT/RVirtualCanvasPainter.hxx index 26fbfd0e5411c..d1a6f1e4ed4a7 100644 --- a/graf2d/gpadv7/v7/inc/ROOT/TVirtualCanvasPainter.hxx +++ b/graf2d/gpadv7/v7/inc/ROOT/RVirtualCanvasPainter.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TVirtualCanvasPainter.hxx +/// \file ROOT/RVirtualCanvasPainter.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-05-31 @@ -13,10 +13,10 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TVirtualCanvasPainter -#define ROOT7_TVirtualCanvasPainter +#ifndef ROOT7_RVirtualCanvasPainter +#define ROOT7_RVirtualCanvasPainter -#include "ROOT/TPadPainter.hxx" +#include "ROOT/RPadPainter.hxx" #include #include @@ -26,21 +26,21 @@ namespace Experimental { using CanvasCallback_t = std::function; -class TCanvas; +class RCanvas; class TWebWindow; namespace Internal { -/** \class ROOT::Experimental::Internal::TVirtualCanvasPainter +/** \class ROOT::Experimental::Internal::RVirtualCanvasPainter Abstract interface for painting a canvas. */ -class TVirtualCanvasPainter : public TPadPainter { +class RVirtualCanvasPainter : public RPadPainter { protected: class Generator { public: - /// Abstract interface to create a TVirtualCanvasPainter implementation. - virtual std::unique_ptr Create(const TCanvas &canv) const = 0; + /// Abstract interface to create a RVirtualCanvasPainter implementation. + virtual std::unique_ptr Create(const RCanvas &canv) const = 0; /// Default destructor. virtual ~Generator(); }; @@ -50,7 +50,7 @@ protected: public: /// Default destructor. - virtual ~TVirtualCanvasPainter(); + virtual ~RVirtualCanvasPainter(); /// indicate that canvas changed, provides current version of the canvas virtual void CanvasUpdated(uint64_t, bool, CanvasCallback_t) = 0; @@ -68,10 +68,10 @@ public: virtual bool AddPanel(std::shared_ptr) { return false; } /// Loads the plugin that implements this class. - static std::unique_ptr Create(const TCanvas &canv); + static std::unique_ptr Create(const RCanvas &canv); }; } // namespace Internal } // namespace Experimental } // namespace ROOT -#endif // ROOT7_TVirtualCanvasPainter +#endif // ROOT7_RVirtualCanvasPainter diff --git a/graf2d/gpadv7/v7/src/TCanvas.cxx b/graf2d/gpadv7/v7/src/RCanvas.cxx similarity index 81% rename from graf2d/gpadv7/v7/src/TCanvas.cxx rename to graf2d/gpadv7/v7/src/RCanvas.cxx index 8e5786866b65e..3d3a9b396385c 100644 --- a/graf2d/gpadv7/v7/src/TCanvas.cxx +++ b/graf2d/gpadv7/v7/src/RCanvas.cxx @@ -1,4 +1,4 @@ -/// \file TCanvas.cxx +/// \file RCanvas.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2015-07-10 @@ -13,7 +13,7 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TCanvas.hxx" +#include "ROOT/RCanvas.hxx" #include "ROOT/TLogger.hxx" @@ -25,19 +25,19 @@ #include "TROOT.h" namespace { -static std::vector> &GetHeldCanvases() +static std::vector> &GetHeldCanvases() { - static std::vector> sCanvases; + static std::vector> sCanvases; return sCanvases; } } // namespace -const std::vector> &ROOT::Experimental::TCanvas::GetCanvases() +const std::vector> &ROOT::Experimental::RCanvas::GetCanvases() { return GetHeldCanvases(); } -// void ROOT::Experimental::TCanvas::Paint() { +// void ROOT::Experimental::RCanvas::Paint() { // for (auto&& drw: fPrimitives) { // drw->Paint(*this); // } @@ -46,7 +46,7 @@ const std::vector> &ROOT::Experimen /////////////////////////////////////////////////////////////////////////////////////// /// Generates unique ID inside the canvas -std::string ROOT::Experimental::TCanvas::GenerateUniqueId() +std::string ROOT::Experimental::RCanvas::GenerateUniqueId() { return std::to_string(fIdCounter++); } @@ -54,12 +54,12 @@ std::string ROOT::Experimental::TCanvas::GenerateUniqueId() /////////////////////////////////////////////////////////////////////////////////////// /// Returns true is canvas was modified since last painting -bool ROOT::Experimental::TCanvas::IsModified() const +bool ROOT::Experimental::RCanvas::IsModified() const { return fPainter ? fPainter->IsCanvasModified(fModified) : fModified; } -void ROOT::Experimental::TCanvas::Update(bool async, CanvasCallback_t callback) +void ROOT::Experimental::RCanvas::Update(bool async, CanvasCallback_t callback) { if (fPainter) fPainter->CanvasUpdated(fModified, async, callback); @@ -71,9 +71,9 @@ void ROOT::Experimental::TCanvas::Update(bool async, CanvasCallback_t callback) // } } -std::shared_ptr ROOT::Experimental::TCanvas::Create(const std::string &title) +std::shared_ptr ROOT::Experimental::RCanvas::Create(const std::string &title) { - auto pCanvas = std::make_shared(); + auto pCanvas = std::make_shared(); pCanvas->SetTitle(title); GetHeldCanvases().emplace_back(pCanvas); return pCanvas; @@ -93,7 +93,7 @@ std::shared_ptr ROOT::Experimental::TCanvas::Create /// /// Canvas can be displayed in several different places -void ROOT::Experimental::TCanvas::Show(const std::string &where) +void ROOT::Experimental::RCanvas::Show(const std::string &where) { if (fPainter) { bool isany = (fPainter->NumDisplays() > 0); @@ -108,7 +108,7 @@ void ROOT::Experimental::TCanvas::Show(const std::string &where) fModified = 1; // 0 is special value, means no changes and no drawings if (!fPainter) - fPainter = Internal::TVirtualCanvasPainter::Create(*this); + fPainter = Internal::RVirtualCanvasPainter::Create(*this); if (fPainter) { fPainter->NewDisplay(where); @@ -119,7 +119,7 @@ void ROOT::Experimental::TCanvas::Show(const std::string &where) ////////////////////////////////////////////////////////////////////////// /// Close all canvas displays -void ROOT::Experimental::TCanvas::Hide() +void ROOT::Experimental::RCanvas::Hide() { if (fPainter) delete fPainter.release(); @@ -131,11 +131,11 @@ void ROOT::Experimental::TCanvas::Hide() /// \param async specifies if file can be created asynchronous to the caller thread /// When operation completed, callback function is called -void ROOT::Experimental::TCanvas::SaveAs(const std::string &filename, bool async, CanvasCallback_t callback) +void ROOT::Experimental::RCanvas::SaveAs(const std::string &filename, bool async, CanvasCallback_t callback) { if (filename.find(".json") != std::string::npos) { - if (!fPainter) fPainter = Internal::TVirtualCanvasPainter::Create(*this); + if (!fPainter) fPainter = Internal::RVirtualCanvasPainter::Create(*this); fPainter->DoWhenReady("JSON", filename, async, callback); return; } diff --git a/graf2d/gpadv7/v7/src/TFrame.cxx b/graf2d/gpadv7/v7/src/RFrame.cxx similarity index 77% rename from graf2d/gpadv7/v7/src/TFrame.cxx rename to graf2d/gpadv7/v7/src/RFrame.cxx index 5dac2d46e60d4..c731aca4113d1 100644 --- a/graf2d/gpadv7/v7/src/TFrame.cxx +++ b/graf2d/gpadv7/v7/src/RFrame.cxx @@ -1,4 +1,4 @@ -/// \file TFrame.cxx +/// \file RFrame.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-09-26 @@ -13,18 +13,18 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TFrame.hxx" +#include "ROOT/RFrame.hxx" #include "ROOT/TLogger.hxx" -#include "ROOT/TPadUserAxis.hxx" +#include "ROOT/RPadUserAxis.hxx" #include -ROOT::Experimental::TFrame::TFrame(std::vector> &&coords, const DrawingOpts &opts) - : fUserCoord(std::move(coords)), fPalette(TPalette::GetPalette("default")), fPos(opts.fPos.Get()), fSize(opts.fSize.Get()) +ROOT::Experimental::RFrame::RFrame(std::vector> &&coords, const DrawingOpts &opts) + : fUserCoord(std::move(coords)), fPalette(RPalette::GetPalette("default")), fPos(opts.fPos.Get()), fSize(opts.fSize.Get()) {} -void ROOT::Experimental::TFrame::GrowToDimensions(size_t nDimensions) +void ROOT::Experimental::RFrame::GrowToDimensions(size_t nDimensions) { std::size_t oldSize = fUserCoord.size(); if (oldSize >= nDimensions) @@ -32,5 +32,5 @@ void ROOT::Experimental::TFrame::GrowToDimensions(size_t nDimensions) fUserCoord.resize(nDimensions); for (std::size_t idx = oldSize; idx < nDimensions; ++idx) if (!fUserCoord[idx]) - fUserCoord[idx].reset(new TPadCartesianUserAxis); + fUserCoord[idx].reset(new RPadCartesianUserAxis); } diff --git a/graf2d/gpadv7/v7/src/TMenuItem.cxx b/graf2d/gpadv7/v7/src/RMenuItem.cxx similarity index 88% rename from graf2d/gpadv7/v7/src/TMenuItem.cxx rename to graf2d/gpadv7/v7/src/RMenuItem.cxx index 8b4b378e048d7..e018b206a7bd5 100644 --- a/graf2d/gpadv7/v7/src/TMenuItem.cxx +++ b/graf2d/gpadv7/v7/src/RMenuItem.cxx @@ -1,4 +1,4 @@ -/// \file TMenuItem.cxx +/// \file RMenuItem.cxx /// \ingroup Base ROOT7 /// \author Sergey Linev /// \date 2017-07-18 @@ -13,7 +13,7 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TMenuItem.hxx" +#include "ROOT/RMenuItem.hxx" #include "TROOT.h" #include "TClass.h" @@ -23,14 +23,14 @@ #include "TMethodCall.h" #include "TBufferJSON.h" -void ROOT::Experimental::TMenuItems::Cleanup() +void ROOT::Experimental::RMenuItems::Cleanup() { for (unsigned n = 0; n < fItems.size(); ++n) delete fItems[n]; fItems.clear(); } -void ROOT::Experimental::TMenuItems::PopulateObjectMenu(void *obj, TClass *cl) +void ROOT::Experimental::RMenuItems::PopulateObjectMenu(void *obj, TClass *cl) { Cleanup(); @@ -81,14 +81,14 @@ void ROOT::Experimental::TMenuItems::PopulateObjectMenu(void *obj, TClass *cl) if (!args || (args->GetSize() == 0)) { AddMenuItem(m->GetName(), m->GetTitle(), Form("%s()", m->GetName())); } else { - Detail::TArgsMenuItem *item = new Detail::TArgsMenuItem(m->GetName(), m->GetTitle()); + Detail::RArgsMenuItem *item = new Detail::RArgsMenuItem(m->GetName(), m->GetTitle()); item->SetExec(Form("%s()", m->GetName())); TIter args_iter(args); TMethodArg *arg = 0; while ((arg = dynamic_cast(args_iter())) != 0) { - Detail::TMenuArgument menu_arg(arg->GetName(), arg->GetTitle(), arg->GetFullTypeName()); + Detail::RMenuArgument menu_arg(arg->GetName(), arg->GetTitle(), arg->GetFullTypeName()); if (arg->GetDefault()) menu_arg.SetDefault(arg->GetDefault()); item->AddArg(menu_arg); } @@ -101,11 +101,11 @@ void ROOT::Experimental::TMenuItems::PopulateObjectMenu(void *obj, TClass *cl) delete lst; } -std::string ROOT::Experimental::TMenuItems::ProduceJSON() +std::string ROOT::Experimental::RMenuItems::ProduceJSON() { - TClass *cl = gROOT->GetClass("std::vector"); + TClass *cl = gROOT->GetClass("std::vector"); - // FIXME: got problem with std::list, can be generic TBufferJSON + // FIXME: got problem with std::list, can be generic TBufferJSON TString res = TBufferJSON::ConvertToJSON(&fItems, cl); // printf("Got JSON %s\n", res.Data()); diff --git a/graf2d/gpadv7/v7/src/TObjectDrawable.cxx b/graf2d/gpadv7/v7/src/RObjectDrawable.cxx similarity index 71% rename from graf2d/gpadv7/v7/src/TObjectDrawable.cxx rename to graf2d/gpadv7/v7/src/RObjectDrawable.cxx index 506a739b132a4..119e13d120ca6 100644 --- a/graf2d/gpadv7/v7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/v7/src/RObjectDrawable.cxx @@ -1,4 +1,4 @@ -/// \file TObjectDrawable.cxx +/// \file RObjectDrawable.cxx /// \ingroup CanvasPainter ROOT7 /// \author Axel Naumann /// \date 2017-05-31 @@ -13,24 +13,24 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include +#include -#include +#include #include -#include -#include +#include +#include #include "TClass.h" #include "TROOT.h" #include -void ROOT::Experimental::TObjectDrawable::Paint(Internal::TPadPainter &pad) +void ROOT::Experimental::RObjectDrawable::Paint(Internal::RPadPainter &pad) { - pad.AddDisplayItem(std::make_unique(fObj.get(), fOpts.GetOptionString())); + pad.AddDisplayItem(std::make_unique(fObj.get(), fOpts.GetOptionString())); } -void ROOT::Experimental::TObjectDrawable::PopulateMenu(TMenuItems &items) +void ROOT::Experimental::RObjectDrawable::PopulateMenu(RMenuItems &items) { TObject *obj = fObj.get(); @@ -38,12 +38,12 @@ void ROOT::Experimental::TObjectDrawable::PopulateMenu(TMenuItems &items) items.PopulateObjectMenu(obj, obj->IsA()); } -void ROOT::Experimental::TObjectDrawable::Execute(const std::string &exec) +void ROOT::Experimental::RObjectDrawable::Execute(const std::string &exec) { TObject *obj = fObj.get(); TString cmd; cmd.Form("((%s*) %p)->%s;", obj->ClassName(), obj, exec.c_str()); - printf("TObjectDrawable::Execute Obj %s Cmd %s\n", obj->GetName(), cmd.Data()); + printf("RObjectDrawable::Execute Obj %s Cmd %s\n", obj->GetName(), cmd.Data()); gROOT->ProcessLine(cmd); } diff --git a/graf2d/gpadv7/v7/src/TPad.cxx b/graf2d/gpadv7/v7/src/RPad.cxx similarity index 74% rename from graf2d/gpadv7/v7/src/TPad.cxx rename to graf2d/gpadv7/v7/src/RPad.cxx index 68bfedc5fb50a..8cf82b5bf4886 100644 --- a/graf2d/gpadv7/v7/src/TPad.cxx +++ b/graf2d/gpadv7/v7/src/RPad.cxx @@ -1,4 +1,4 @@ -/// \file TPad.cxx +/// \file RPad.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-07-07 @@ -13,26 +13,26 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TPad.hxx" +#include "ROOT/RPad.hxx" #include "ROOT/TLogger.hxx" -#include "ROOT/TPadExtent.hxx" -#include "ROOT/TPadPos.hxx" -#include -#include -#include +#include "ROOT/RPadExtent.hxx" +#include "ROOT/RPadPos.hxx" +#include +#include +#include #include #include -ROOT::Experimental::TPadBase::~TPadBase() = default; +ROOT::Experimental::RPadBase::~RPadBase() = default; -void ROOT::Experimental::TPadBase::AssignUniqueID(std::shared_ptr &ptr) +void ROOT::Experimental::RPadBase::AssignUniqueID(std::shared_ptr &ptr) { if (!ptr) return; - TCanvas *canv = GetCanvas(); + RCanvas *canv = GetCanvas(); if (!canv) { R__ERROR_HERE("Gpad") << "Cannot access canvas when unique object id should be assigned"; return; @@ -41,14 +41,14 @@ void ROOT::Experimental::TPadBase::AssignUniqueID(std::shared_ptr &pt ptr->fId = canv->GenerateUniqueId(); } -std::shared_ptr ROOT::Experimental::TPadBase::FindDrawable(const std::string &id) const +std::shared_ptr ROOT::Experimental::RPadBase::FindDrawable(const std::string &id) const { for (auto &&drawable : GetPrimitives()) { if (drawable->GetId() == id) return drawable; - TPadDrawable *pad_draw = dynamic_cast (drawable.get()); + RPadDrawable *pad_draw = dynamic_cast (drawable.get()); if (!pad_draw || !pad_draw->Get()) continue; auto subelem = pad_draw->Get()->FindDrawable(id); @@ -61,10 +61,10 @@ std::shared_ptr ROOT::Experimental::TPadBase::Fin return nullptr; } -std::vector> -ROOT::Experimental::TPadBase::Divide(int nHoriz, int nVert, const TPadExtent &padding /*= {}*/) +std::vector> +ROOT::Experimental::RPadBase::Divide(int nHoriz, int nVert, const RPadExtent &padding /*= {}*/) { - std::vector> ret; + std::vector> ret; if (!nHoriz) R__ERROR_HERE("Gpad") << "Cannot divide into 0 horizontal sub-pads!"; if (!nVert) @@ -73,11 +73,11 @@ ROOT::Experimental::TPadBase::Divide(int nHoriz, int nVert, const TPadExtent &pa return ret; // Start with the whole (sub-)pad: - TPadExtent offset{1._normal, 1._normal}; + RPadExtent offset{1._normal, 1._normal}; /// We need n Pads plus n-1 padding. Thus each `(subPadSize + padding)` is `(parentPadSize + padding) / n`. offset = (offset + padding); offset *= {1. / nHoriz, 1. / nVert}; - const TPadExtent size = offset - padding; + const RPadExtent size = offset - padding; printf("SIZES %5.2f %5.2f\n", size.fHoriz.fNormal.fVal, size.fVert.fNormal.fVal); @@ -85,9 +85,9 @@ ROOT::Experimental::TPadBase::Divide(int nHoriz, int nVert, const TPadExtent &pa for (int iHoriz = 0; iHoriz < nHoriz; ++iHoriz) { ret[iHoriz].resize(nVert); for (int iVert = 0; iVert < nVert; ++iVert) { - TPadPos subPos = offset; + RPadPos subPos = offset; subPos *= {1. * iHoriz, 1. * iVert}; - auto uniqPad = std::make_unique(*this, size); + auto uniqPad = std::make_unique(*this, size); ret[iHoriz][iVert] = uniqPad.get(); Draw(std::move(uniqPad), subPos); @@ -97,25 +97,25 @@ ROOT::Experimental::TPadBase::Divide(int nHoriz, int nVert, const TPadExtent &pa return ret; } -ROOT::Experimental::TFrame *ROOT::Experimental::TPadBase::GetOrCreateFrame() +ROOT::Experimental::RFrame *ROOT::Experimental::RPadBase::GetOrCreateFrame() { CreateFrameIfNeeded(); return fFrame.get(); } -void ROOT::Experimental::TPadBase::CreateFrameIfNeeded() +void ROOT::Experimental::RPadBase::CreateFrameIfNeeded() { if (!fFrame) { - fFrame = std::make_unique(); + fFrame = std::make_unique(); } } ///////////////////////////////////////////////////////////////////////////////////////////////// -/// Get a pad axis from the TFrame. -/// \param dimension - Index of the dimension of the TFrame user coordinate system. +/// Get a pad axis from the RFrame. +/// \param dimension - Index of the dimension of the RFrame user coordinate system. -ROOT::Experimental::TPadUserAxisBase* ROOT::Experimental::TPadBase::GetAxis(size_t dimension) const +ROOT::Experimental::RPadUserAxisBase* ROOT::Experimental::RPadBase::GetAxis(size_t dimension) const { if (fFrame && dimension < fFrame->GetNDimensions()) return &fFrame->GetUserAxis(dimension); @@ -123,10 +123,10 @@ ROOT::Experimental::TPadUserAxisBase* ROOT::Experimental::TPadBase::GetAxis(size } ///////////////////////////////////////////////////////////////////////////////////////////////// -/// Get a pad axis from the TFrame. -/// \param dimension - Index of the dimension of the TFrame user coordinate system. +/// Get a pad axis from the RFrame. +/// \param dimension - Index of the dimension of the RFrame user coordinate system. -ROOT::Experimental::TPadUserAxisBase* ROOT::Experimental::TPadBase::GetOrCreateAxis(size_t dimension) +ROOT::Experimental::RPadUserAxisBase* ROOT::Experimental::RPadBase::GetOrCreateAxis(size_t dimension) { GetOrCreateFrame()->GrowToDimensions(dimension); return &fFrame->GetUserAxis(dimension); @@ -135,7 +135,7 @@ ROOT::Experimental::TPadUserAxisBase* ROOT::Experimental::TPadBase::GetOrCreateA ///////////////////////////////////////////////////////////////////////////////////////////////// /// Set the range of an axis as begin, end. -void ROOT::Experimental::TPadBase::SetAxisBounds(int dimension, double begin, double end) +void ROOT::Experimental::RPadBase::SetAxisBounds(int dimension, double begin, double end) { GetOrCreateFrame()->GrowToDimensions(dimension); GetAxis(dimension)->SetBounds(begin, end); @@ -144,7 +144,7 @@ void ROOT::Experimental::TPadBase::SetAxisBounds(int dimension, double begin, do ///////////////////////////////////////////////////////////////////////////////////////////////// /// Set the range of an axis as bound kind and bound (up or down). -void ROOT::Experimental::TPadBase::SetAxisBound(int dimension, TPadUserAxisBase::EAxisBoundsKind boundsKind, double bound) +void ROOT::Experimental::RPadBase::SetAxisBound(int dimension, RPadUserAxisBase::EAxisBoundsKind boundsKind, double bound) { GetOrCreateFrame()->GrowToDimensions(dimension); GetAxis(dimension)->SetBound(boundsKind, bound); @@ -153,7 +153,7 @@ void ROOT::Experimental::TPadBase::SetAxisBound(int dimension, TPadUserAxisBase: ///////////////////////////////////////////////////////////////////////////////////////////////// /// Set the range of an axis as bound kind and bound (up or down). -void ROOT::Experimental::TPadBase::SetAxisAutoBounds(int dimension) +void ROOT::Experimental::RPadBase::SetAxisAutoBounds(int dimension) { GetOrCreateFrame()->GrowToDimensions(dimension); GetAxis(dimension)->SetAutoBounds(); @@ -162,7 +162,7 @@ void ROOT::Experimental::TPadBase::SetAxisAutoBounds(int dimension) ///////////////////////////////////////////////////////////////////////////////////////////////// /// Set the range of an axis as bound kind and bound (up or down). -void ROOT::Experimental::TPadBase::SetAllAxisBounds(const std::vector> &vecBeginAndEnd) +void ROOT::Experimental::RPadBase::SetAllAxisBounds(const std::vector> &vecBeginAndEnd) { GetOrCreateFrame()->GrowToDimensions(vecBeginAndEnd.size()); if (vecBeginAndEnd.size() != fFrame->GetNDimensions()) { @@ -179,7 +179,7 @@ void ROOT::Experimental::TPadBase::SetAllAxisBounds(const std::vector &vecBoundAndKind) +void ROOT::Experimental::RPadBase::SetAllAxisBound(const std::vector &vecBoundAndKind) { GetOrCreateFrame()->GrowToDimensions(vecBoundAndKind.size()); if (vecBoundAndKind.size() != fFrame->GetNDimensions()) { @@ -196,7 +196,7 @@ void ROOT::Experimental::TPadBase::SetAllAxisBound(const std::vectorGetNDimensions(); i < n; ++i) fFrame->GetUserAxis(i).SetAutoBounds(); @@ -206,19 +206,19 @@ void ROOT::Experimental::TPadBase::SetAllAxisAutoBounds() ///////////////////////////////////////////////////////////////////////////////////////////////// -ROOT::Experimental::TPad::~TPad() = default; +ROOT::Experimental::RPad::~RPad() = default; ///////////////////////////////////////////////////////////////////////////////////////////////// -ROOT::Experimental::TPadDrawable::TPadDrawable(std::shared_ptr pPad, const TPadDrawingOpts &opts /*= {}*/) +ROOT::Experimental::RPadDrawable::RPadDrawable(std::shared_ptr pPad, const RPadDrawingOpts &opts /*= {}*/) : fPad(std::move(pPad)), fOpts(opts) { } /// Paint the pad. -void ROOT::Experimental::TPadDrawable::Paint(Internal::TPadPainter &toppad) +void ROOT::Experimental::RPadDrawable::Paint(Internal::RPadPainter &toppad) { - Internal::TPadPainter painter; + Internal::RPadPainter painter; painter.PaintDrawables(*fPad.get()); diff --git a/graf2d/gpadv7/v7/src/TPadExtent.cxx b/graf2d/gpadv7/v7/src/RPadExtent.cxx similarity index 87% rename from graf2d/gpadv7/v7/src/TPadExtent.cxx rename to graf2d/gpadv7/v7/src/RPadExtent.cxx index 4b61f6075ca54..fd0bad8252267 100644 --- a/graf2d/gpadv7/v7/src/TPadExtent.cxx +++ b/graf2d/gpadv7/v7/src/RPadExtent.cxx @@ -1,4 +1,4 @@ -/// \file TPadExtent.cxx +/// \file RPadExtent.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2018-02-08 @@ -13,20 +13,20 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TPadExtent.hxx" +#include "ROOT/RPadExtent.hxx" #include //////////////////////////////////////////////////////////////////////////////// -/// Initialize a TPadExtent from a style string. +/// Initialize a RPadExtent from a style string. /// Syntax: X, Y /// where X and Y are a series of numbers separated by "+", where each number is /// followed by one of `px`, `user`, `normal` to specify an extent in pixel, /// user or normal coordinates. Spaces between any part is allowed. -/// Example: `100 px + 0.1 user, 0.5 normal` is a `TPadExtent{100_px + 0.1_user, 0.5_normal}`. +/// Example: `100 px + 0.1 user, 0.5 normal` is a `RPadExtent{100_px + 0.1_user, 0.5_normal}`. void ROOT::Experimental::InitializeAttrFromString(const std::string & /*name*/, const std::string & /*attrStrVal*/, - ROOT::Experimental::TPadExtent& /*val*/) + ROOT::Experimental::RPadExtent& /*val*/) { R__ERROR_HERE("Gpad") << "Not yet implemented!"; } diff --git a/graf2d/gpadv7/v7/src/TPadPainter.cxx b/graf2d/gpadv7/v7/src/RPadPainter.cxx similarity index 57% rename from graf2d/gpadv7/v7/src/TPadPainter.cxx rename to graf2d/gpadv7/v7/src/RPadPainter.cxx index 99ffc39c53035..230f619604f40 100644 --- a/graf2d/gpadv7/v7/src/TPadPainter.cxx +++ b/graf2d/gpadv7/v7/src/RPadPainter.cxx @@ -1,32 +1,32 @@ -/// \file TPadPainter.cxx +/// \file RPadPainter.cxx /// \ingroup Gpad ROOT7 /// \author Sergey Linev /// \date 2018-03-12 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback /// is welcome! -#include +#include -#include -#include +#include +#include /// destructor -ROOT::Experimental::Internal::TPadPainter::~TPadPainter() +ROOT::Experimental::Internal::RPadPainter::~RPadPainter() { // defined here, while TPadDisplayItem only included here } -void ROOT::Experimental::Internal::TPadPainter::AddDisplayItem(std::unique_ptr &&item) +void ROOT::Experimental::Internal::RPadPainter::AddDisplayItem(std::unique_ptr &&item) { item->SetObjectID(fCurrentDrawableId); fPadDisplayItem->Add(std::move(item)); } -void ROOT::Experimental::Internal::TPadPainter::PaintDrawables(const TPadBase &pad) +void ROOT::Experimental::Internal::RPadPainter::PaintDrawables(const RPadBase &pad) { - fPadDisplayItem = std::make_unique(); + fPadDisplayItem = std::make_unique(); fPadDisplayItem->SetFrame(pad.GetFrame()); diff --git a/graf2d/gpadv7/v7/src/TPadPos.cxx b/graf2d/gpadv7/v7/src/RPadPos.cxx similarity index 84% rename from graf2d/gpadv7/v7/src/TPadPos.cxx rename to graf2d/gpadv7/v7/src/RPadPos.cxx index a71093c2ea4db..eff2f24622580 100644 --- a/graf2d/gpadv7/v7/src/TPadPos.cxx +++ b/graf2d/gpadv7/v7/src/RPadPos.cxx @@ -1,4 +1,4 @@ -/// \file TPadPos.cxx +/// \file RPadPos.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2018-02-08 @@ -13,21 +13,21 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TPadPos.hxx" +#include "ROOT/RPadPos.hxx" #include //////////////////////////////////////////////////////////////////////////////// -/// Initialize a TPadPos from a style string. +/// Initialize a RPadPos from a style string. /// Syntax: X, Y /// where X and Y are a series of numbers separated by "+", where each number is /// followed by one of `px`, `user`, `normal` to specify an extent in pixel, /// user or normal coordinates. Spaces between any part is allowed. -/// Example: `100 px + 0.1 user, 0.5 normal` is a `TPadPos{100_px + 0.1_user, 0.5_normal}`. +/// Example: `100 px + 0.1 user, 0.5 normal` is a `RPadPos{100_px + 0.1_user, 0.5_normal}`. void ROOT::Experimental::InitializeAttrFromString(const std::string & /*name*/, - const std::string & /*attrStrVal*/, TPadPos & /*val*/) + const std::string & /*attrStrVal*/, RPadPos & /*val*/) { - // Use InitializeAttrFromString(TPadExtent)! + // Use InitializeAttrFromString(RPadExtent)! R__ERROR_HERE("Gpad") << "Not yet implemented!"; } diff --git a/graf2d/gpadv7/v7/src/TPadUserAxis.cxx b/graf2d/gpadv7/v7/src/RPadUserAxis.cxx similarity index 60% rename from graf2d/gpadv7/v7/src/TPadUserAxis.cxx rename to graf2d/gpadv7/v7/src/RPadUserAxis.cxx index 31e2fbea4ec0d..4c0807dd11129 100644 --- a/graf2d/gpadv7/v7/src/TPadUserAxis.cxx +++ b/graf2d/gpadv7/v7/src/RPadUserAxis.cxx @@ -1,19 +1,19 @@ -/// \file TPadUserAxis.cxx +/// \file RPadUserAxis.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-08-14 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback /// is welcome! -#include +#include // pin vtable -ROOT::Experimental::TPadUserAxisBase::~TPadUserAxisBase() +ROOT::Experimental::RPadUserAxisBase::~RPadUserAxisBase() { } -ROOT::Experimental::TPadLength::Normal -ROOT::Experimental::TPadCartesianUserAxis::ToNormal(const TPadLength::User &usercoord) const +ROOT::Experimental::RPadLength::Normal +ROOT::Experimental::RPadCartesianUserAxis::ToNormal(const RPadLength::User &usercoord) const { return (usercoord.fVal - GetBegin()) / GetSensibleDenominator(); } diff --git a/graf2d/gpadv7/v7/src/TVirtualCanvasPainter.cxx b/graf2d/gpadv7/v7/src/RVirtualCanvasPainter.cxx similarity index 72% rename from graf2d/gpadv7/v7/src/TVirtualCanvasPainter.cxx rename to graf2d/gpadv7/v7/src/RVirtualCanvasPainter.cxx index 405862a7fc402..b32a57b107f21 100644 --- a/graf2d/gpadv7/v7/src/TVirtualCanvasPainter.cxx +++ b/graf2d/gpadv7/v7/src/RVirtualCanvasPainter.cxx @@ -1,4 +1,4 @@ -/// \file TVirtualCanvasPainter.cxx +/// \file RVirtualCanvasPainter.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-05-31 @@ -13,7 +13,7 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include +#include #include #include // TSystem::Load @@ -29,29 +29,29 @@ static void LoadCanvasPainterLibrary() { /// The implementation is here to pin the vtable. -ROOT::Experimental::Internal::TVirtualCanvasPainter::~TVirtualCanvasPainter() = default; +ROOT::Experimental::Internal::RVirtualCanvasPainter::~RVirtualCanvasPainter() = default; -std::unique_ptr - &ROOT::Experimental::Internal::TVirtualCanvasPainter::GetGenerator() +std::unique_ptr + &ROOT::Experimental::Internal::RVirtualCanvasPainter::GetGenerator() { /// The generator for implementations. static std::unique_ptr generator; return generator; } -std::unique_ptr ROOT::Experimental::Internal:: - TVirtualCanvasPainter::Create(const TCanvas &canv) +std::unique_ptr ROOT::Experimental::Internal:: + RVirtualCanvasPainter::Create(const RCanvas &canv) { if (!GetGenerator()) { LoadCanvasPainterLibrary(); if (!GetGenerator()) { - R__ERROR_HERE("Gpad") << "TVirtualCanvasPainter::Generator failed to register!"; - throw std::runtime_error("TVirtualCanvasPainter::Generator failed to initialize"); + R__ERROR_HERE("Gpad") << "RVirtualCanvasPainter::Generator failed to register!"; + throw std::runtime_error("RVirtualCanvasPainter::Generator failed to initialize"); } } return GetGenerator()->Create(canv); } /// The implementation is here to pin the vtable. -ROOT::Experimental::Internal::TVirtualCanvasPainter::Generator::~Generator() = default; +ROOT::Experimental::Internal::RVirtualCanvasPainter::Generator::~Generator() = default; diff --git a/graf2d/gpadv7/v7/test/coords.cxx b/graf2d/gpadv7/v7/test/coords.cxx index 0fa95ad5a3ae2..a15893fcc46e3 100644 --- a/graf2d/gpadv7/v7/test/coords.cxx +++ b/graf2d/gpadv7/v7/test/coords.cxx @@ -11,34 +11,34 @@ #include "gtest/gtest.h" -#include "ROOT/TPadLength.hxx" +#include "ROOT/RPadLength.hxx" // Test addition / subtraction of coords TEST(PadCoord, AddSubtract) { using namespace ROOT::Experimental; - TPadLength cn{0.3_normal}; + RPadLength cn{0.3_normal}; EXPECT_DOUBLE_EQ(0.3, cn.fNormal.fVal); EXPECT_DOUBLE_EQ(0., cn.fPixel.fVal); EXPECT_DOUBLE_EQ(0., cn.fUser.fVal); - TPadLength cn1{0.4_normal}; + RPadLength cn1{0.4_normal}; cn += cn1; EXPECT_DOUBLE_EQ(0.7, cn.fNormal.fVal); EXPECT_DOUBLE_EQ(0., cn.fPixel.fVal); EXPECT_DOUBLE_EQ(0., cn.fUser.fVal); - TPadLength cp{120_px}; + RPadLength cp{120_px}; EXPECT_DOUBLE_EQ(120., cp.fPixel.fVal); EXPECT_DOUBLE_EQ(0., cp.fNormal.fVal); EXPECT_DOUBLE_EQ(0., cp.fUser.fVal); - TPadLength sum = cn + cp; + RPadLength sum = cn + cp; EXPECT_DOUBLE_EQ(0.7, sum.fNormal.fVal); EXPECT_DOUBLE_EQ(120., sum.fPixel.fVal); EXPECT_DOUBLE_EQ(0., sum.fUser.fVal); - sum -= TPadLength(0.2_user); + sum -= RPadLength(0.2_user); EXPECT_DOUBLE_EQ(0.7, sum.fNormal.fVal); EXPECT_DOUBLE_EQ(120., sum.fPixel.fVal); EXPECT_DOUBLE_EQ(-0.2, sum.fUser.fVal); @@ -48,7 +48,7 @@ TEST(PadCoord, AddSubtract) { EXPECT_DOUBLE_EQ(12., sum.fPixel.fVal); EXPECT_DOUBLE_EQ(-0.02, sum.fUser.fVal); - TPadLength subtr(0.07_normal, 12_px, -0.02_user); + RPadLength subtr(0.07_normal, 12_px, -0.02_user); EXPECT_DOUBLE_EQ(0.07, subtr.fNormal.fVal); EXPECT_DOUBLE_EQ(12., subtr.fPixel.fVal); EXPECT_DOUBLE_EQ(-0.02, subtr.fUser.fVal); diff --git a/graf2d/gpadv7/v7/test/extent.cxx b/graf2d/gpadv7/v7/test/extent.cxx index 9e724aca8f84d..07002dd3ca3df 100644 --- a/graf2d/gpadv7/v7/test/extent.cxx +++ b/graf2d/gpadv7/v7/test/extent.cxx @@ -11,13 +11,13 @@ #include "gtest/gtest.h" -#include "ROOT/TPadExtent.hxx" +#include "ROOT/RPadExtent.hxx" // Test addition of Extents TEST(PadExtent, Add) { using namespace ROOT::Experimental; - TPadExtent cn{0.3_normal, 40_px}; + RPadExtent cn{0.3_normal, 40_px}; EXPECT_DOUBLE_EQ(0.3, cn.fHoriz.fNormal.fVal); EXPECT_DOUBLE_EQ(0., cn.fHoriz.fPixel.fVal); EXPECT_DOUBLE_EQ(0., cn.fHoriz.fUser.fVal); @@ -25,7 +25,7 @@ TEST(PadExtent, Add) { EXPECT_DOUBLE_EQ(40., cn.fVert.fPixel.fVal); EXPECT_DOUBLE_EQ(0., cn.fVert.fUser.fVal); - TPadExtent cn1{0.4_normal, 20_px}; + RPadExtent cn1{0.4_normal, 20_px}; cn += cn1; EXPECT_DOUBLE_EQ(0.7, cn.fHoriz.fNormal.fVal); EXPECT_DOUBLE_EQ(0., cn.fHoriz.fPixel.fVal); @@ -34,7 +34,7 @@ TEST(PadExtent, Add) { EXPECT_DOUBLE_EQ(60., cn.fVert.fPixel.fVal); EXPECT_DOUBLE_EQ(0., cn.fVert.fUser.fVal); - TPadExtent cp{120_px, 0.42_normal}; + RPadExtent cp{120_px, 0.42_normal}; EXPECT_DOUBLE_EQ(120., cp.fHoriz.fPixel.fVal); EXPECT_DOUBLE_EQ(0., cp.fHoriz.fNormal.fVal); EXPECT_DOUBLE_EQ(0., cp.fHoriz.fUser.fVal); @@ -42,7 +42,7 @@ TEST(PadExtent, Add) { EXPECT_DOUBLE_EQ(0., cp.fVert.fPixel.fVal); EXPECT_DOUBLE_EQ(0., cp.fVert.fUser.fVal); - TPadExtent sum = cn + cp; + RPadExtent sum = cn + cp; EXPECT_DOUBLE_EQ(120., sum.fHoriz.fPixel.fVal); EXPECT_DOUBLE_EQ(0.7, sum.fHoriz.fNormal.fVal); EXPECT_DOUBLE_EQ(0., sum.fHoriz.fUser.fVal); @@ -50,7 +50,7 @@ TEST(PadExtent, Add) { EXPECT_DOUBLE_EQ(60., sum.fVert.fPixel.fVal); EXPECT_DOUBLE_EQ(0., sum.fVert.fUser.fVal); - sum -= TPadExtent(0.2_user, 12_px); + sum -= RPadExtent(0.2_user, 12_px); EXPECT_DOUBLE_EQ(120., sum.fHoriz.fPixel.fVal); EXPECT_DOUBLE_EQ(0.7, sum.fHoriz.fNormal.fVal); EXPECT_DOUBLE_EQ(-0.2, sum.fHoriz.fUser.fVal); @@ -66,7 +66,7 @@ TEST(PadExtent, Add) { EXPECT_DOUBLE_EQ(480., sum.fVert.fPixel.fVal); EXPECT_DOUBLE_EQ(0., sum.fVert.fUser.fVal); - TPadExtent subtr({0.07_normal, 12_px, -0.02_user}, + RPadExtent subtr({0.07_normal, 12_px, -0.02_user}, {4.2_normal, 480_px, 0._user}); EXPECT_DOUBLE_EQ(12., subtr.fHoriz.fPixel.fVal); EXPECT_DOUBLE_EQ(0.07, subtr.fHoriz.fNormal.fVal); diff --git a/graf2d/graf/src/TCandle.cxx b/graf2d/graf/src/TCandle.cxx index d3e59ad8c7724..a13b5b0d82909 100644 --- a/graf2d/graf/src/TCandle.cxx +++ b/graf2d/graf/src/TCandle.cxx @@ -277,11 +277,11 @@ int TCandle::ParseOption(char * opt) { fOption = (CandleOption)(fOption + fallbackCandle); if (preset != ' ' && direction != ' ') - strncpy(l," ",8); + memcpy(l," ",8); else if (preset != ' ' || direction != ' ') - strncpy(l," ",7); + memcpy(l," ",7); else - strncpy(l," ",6); + memcpy(l," ",6); Bool_t useIndivOption = false; @@ -296,7 +296,7 @@ int TCandle::ParseOption(char * opt) { strlcpy(indivOption, brOpen, brClose-brOpen+2); //Now the string "(....)" including brackets is in this array sscanf(indivOption,"(%d)", (int*) &fOption); if (isHorizontal) {fOption = (CandleOption)(fOption + kHorizontal);} - strncpy(brOpen," ",brClose-brOpen+1); //Cleanup + memcpy(brOpen," ",brClose-brOpen+1); //Cleanup sprintf(fOptionStr,"CANDLE%c(%ld)",direction,(long)fOption); } else { @@ -335,11 +335,11 @@ int TCandle::ParseOption(char * opt) { fOption = (CandleOption)(fOption + fallbackCandle); if (preset != ' ' && direction != ' ') - strncpy(l," ",8); + memcpy(l," ",8); else if (preset != ' ' || direction != ' ') - strncpy(l," ",7); + memcpy(l," ",7); else - strncpy(l," ",6); + memcpy(l," ",6); Bool_t useIndivOption = false; @@ -354,7 +354,7 @@ int TCandle::ParseOption(char * opt) { strlcpy(indivOption, brOpen, brClose-brOpen +2); //Now the string "(....)" including brackets is in this array sscanf(indivOption,"(%d)", (int*) &fOption); if (isHorizontal) {fOption = (CandleOption)(fOption + kHorizontal);} - strncpy(brOpen," ",brClose-brOpen+1); //Cleanup + memcpy(brOpen," ",brClose-brOpen+1); //Cleanup sprintf(fOptionStr,"VIOLIN%c(%ld)",direction,(long)fOption); diff --git a/graf2d/graf/src/TGaxis.cxx b/graf2d/graf/src/TGaxis.cxx index 1005a92b233cb..5bc44a3f143a1 100644 --- a/graf2d/graf/src/TGaxis.cxx +++ b/graf2d/graf/src/TGaxis.cxx @@ -1821,11 +1821,12 @@ void TGaxis::PaintAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t yma if2++; } coded = &chcoded[0]; - if (if1 > 14) if1=14; - if (if2 > 14) if2=14; - if (if2>0) snprintf(coded,8,"%%%d.%df",if1,if2); - else { - if (if1 < -100) if1 = -100; // Silence a warning with gcc + if (if1 > 14) if1 = 14; + if (if2 > 14) if2 = 14; + if (if1 < 0) if1 = 0; + if (if2 > 0) { + snprintf(coded,8,"%%%d.%df",if1,if2); + } else { snprintf(coded,8,"%%%d.%df",if1+1,1); } @@ -1965,7 +1966,7 @@ void TGaxis::PaintAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t yma if (!optionY || (x0 == x1)) { if (!optionText) { if (first > last) strncpy(chtemp, " ", 256); - else strncpy(chtemp, &label[first], 256); + else strncpy(chtemp, &label[first], 255); if (fNModLabs) ChangeLabelAttributes(k+1, nlabels, textaxis, chtemp); typolabel = chtemp; if (!optionTime) typolabel.ReplaceAll("-", "#minus"); diff --git a/graf2d/graf/src/TGraphPolargram.cxx b/graf2d/graf/src/TGraphPolargram.cxx index 2b362a7c90a4c..030f3947e6b79 100644 --- a/graf2d/graf/src/TGraphPolargram.cxx +++ b/graf2d/graf/src/TGraphPolargram.cxx @@ -33,10 +33,9 @@ Begin_Macro(source) theta[ipt] = fp1->Eval(r[ipt]); } TGraphPolar * grP1 = new TGraphPolar(1000,r,theta); + grP1->SetTitle(""); grP1->SetLineColor(2); grP1->Draw("AOL"); - - return CPol; } End_Macro */ @@ -648,8 +647,8 @@ void TGraphPolargram::PaintRadialDivisions(Bool_t drawaxis) Int_t ndivminor = 0; chopt[0] = 0; - strncat(chopt, "SDH", 3); - if (fNdivRad < 0) strncat(chopt, "N",1); + strncat(chopt, "SDH", 4); + if (fNdivRad < 0) strncat(chopt, "N",2); if(drawaxis){ // Paint axis. TGaxis axis; diff --git a/graf2d/ios/inc/IOSFillPatterns.h b/graf2d/ios/inc/IOSFillPatterns.h deleted file mode 100644 index 94bdffa90daa8..0000000000000 --- a/graf2d/ios/inc/IOSFillPatterns.h +++ /dev/null @@ -1,54 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_IOSFillPatterns -#define ROOT_IOSFillPatterns - -////////////////////////////////////////////////////////////////////////// -// // -// FillPatterns // -// // -// Predefined fill styles (patterns). // -// // -////////////////////////////////////////////////////////////////////////// - - -#include - -namespace ROOT { -namespace iOS { -namespace GraphicUtils { - -// -//Must be 25, now only 18. To be added. -// - -//TODO: remaining patterns are required. -enum { - kPredefinedFillPatterns = 18 -}; - -//Pattern generator function type. Parameter of type CGFloat * -//is an rgb tuple. Attention! rgb pointer should be valid while -//you are using pattern - it will be passed into pattern drawing callback -//funciton. -typedef CGPatternRef (*PatternGenerator_t)(CGFloat *); -//Array of pointers to functions, generating patterns. -extern PatternGenerator_t gPatternGenerators[kPredefinedFillPatterns]; - -extern const unsigned solidFillStyle; //1001 -extern const unsigned stippleBase; //3000 - -}//GraphicUtils -}//namespace iOS -}//namespace ROOT - -#endif diff --git a/graf2d/ios/inc/IOSGraphicUtils.h b/graf2d/ios/inc/IOSGraphicUtils.h deleted file mode 100644 index ccab8ce21f242..0000000000000 --- a/graf2d/ios/inc/IOSGraphicUtils.h +++ /dev/null @@ -1,55 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_IOSGraphicUtils -#define ROOT_IOSGraphicUtils - -////////////////////////////////////////////////////////////////////////// -// // -// GraphicUtils // -// // -// Aux. functions and classes. // -// // -////////////////////////////////////////////////////////////////////////// - -#include "Rtypes.h" - -namespace ROOT { -namespace iOS { -namespace GraphicUtils { - -//Generic graphic utils. -void GetColorForIndex(Color_t colorIndex, Float_t &r, Float_t &g, Float_t &b); - - -//Encode object's ID (unsigned integer) as an RGB triplet. -class IDEncoder { -public: - IDEncoder(UInt_t radix, UInt_t channelSize); - - Bool_t IdToColor(UInt_t objId, Float_t *rgb) const; - UInt_t ColorToId(UInt_t r, UInt_t g, UInt_t b) const; - -private: - UInt_t FixValue(UInt_t val) const; - - const UInt_t fRadix; - const UInt_t fRadix2; - const UInt_t fChannelSize; - const UInt_t fStepSize; - const UInt_t fMaxID; -}; - -} //namespace GraphicUtils -} //namespace iOS -} //namespace ROOT - -#endif diff --git a/graf2d/ios/inc/IOSLineStyles.h b/graf2d/ios/inc/IOSLineStyles.h deleted file mode 100644 index ca06e69339fd9..0000000000000 --- a/graf2d/ios/inc/IOSLineStyles.h +++ /dev/null @@ -1,42 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 17/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_IOSLineStyles -#define ROOT_IOSLineStyles - -////////////////////////////////////////////////////////////////////////// -// // -// Line styles. // -// // -// Predefined line styles. // -// // -////////////////////////////////////////////////////////////////////////// - -#include - -namespace ROOT { -namespace iOS { -namespace GraphicUtils { - -/* -enum { - kFixedLineStyles = 10 -}; -*/ - -extern const unsigned linePatternLengths[10]; -extern const CGFloat dashLinePatterns[10][8]; - -} -} -} - -#endif diff --git a/graf2d/ios/inc/IOSMarkers.h b/graf2d/ios/inc/IOSMarkers.h deleted file mode 100644 index 3487d2395453f..0000000000000 --- a/graf2d/ios/inc/IOSMarkers.h +++ /dev/null @@ -1,42 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_IOSMarkers -#define ROOT_IOSMarkers - -////////////////////////////////////////////////////////////////////////// -// // -// IOSMarkers // -// // -// Aux. functions to draw poly-markers. // -// // -////////////////////////////////////////////////////////////////////////// - -#include - -#include - -#include "Rtypes.h" - -#include "TPoint.h" - -namespace ROOT { -namespace iOS { -namespace GraphicUtils { - -void DrawPolyMarker(CGContextRef ctx, const std::vector &marker, Size_t markerSize, Style_t markerStyle); -void DrawPolyMarker(CGContextRef ctx, unsigned nPoints, const TPoint *marker, Size_t markerSize, Style_t markerStyle); - -} -} -} - -#endif diff --git a/graf2d/ios/inc/IOSPad.h b/graf2d/ios/inc/IOSPad.h deleted file mode 100644 index e6f00854b2963..0000000000000 --- a/graf2d/ios/inc/IOSPad.h +++ /dev/null @@ -1,403 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_IOSPad -#define ROOT_IOSPad - -////////////////////////////////////////////////////////////////////////// -// // -// IOSPad // -// // -// This class is a pad for iOS. // -// I use this class instead of original TPad/TCanvas to // -// keep it as simple and clean as possible, and to be able // -// to extend this class for iOS only. // -// // -////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -#include - -#include "TList.h" - -#include "IOSTextOperations.h" - -#include "IOSPainter.h" - -#include "IOSPadStub.h" - -namespace ROOT { -namespace iOS { - -// TODO: class needs verification and clean-up. -// Some parts from original TPad (coordinate conversions/painting algorithms) -// were copy & pasted at the beginning, will be re-written and fixed. - -class Pad : public PadStub { -public: - // Pad status bits - enum EStatusBits { - kFraming = BIT(6), - kHori = BIT(9), - kClipFrame = BIT(10), - kPrintingPS = BIT(11), - kCannotMove = BIT(12), - kClearAfterCR = BIT(14) - }; - - void GetTextExtent(UInt_t &w, UInt_t &h, const char *text); - void SetContext(CGContextRef ctx); - - Pad(UInt_t w, UInt_t h); - ~Pad(); - - //Final-overriders for TVirtualPad class. - const char *GetName() const; - const char *GetTitle() const; - - void Clear(Option_t * = ""); - - //Coordinates, conversions, ranges. - void AbsCoordinates(Bool_t set) {fAbsCoord = set;} - - Double_t AbsPixeltoX(Int_t px) {return fAbsPixeltoXk + px * fPixeltoX;} - Double_t AbsPixeltoY(Int_t py) {return fAbsPixeltoYk + py * fPixeltoY;} - - Double_t GetXlowNDC() const {return fXlowNDC;} - Double_t GetYlowNDC() const {return fYlowNDC;} - - Double_t GetWNDC() const {return fWNDC;} - Double_t GetHNDC() const {return fHNDC;} - - void SetViewWH(UInt_t w, UInt_t h); - - - UInt_t GetWw() const; - UInt_t GetWh() const; - - Double_t GetAbsXlowNDC() const {return fAbsXlowNDC;} - Double_t GetAbsYlowNDC() const {return fAbsYlowNDC;} - - Double_t GetAbsWNDC() const {return fAbsWNDC;} - Double_t GetAbsHNDC() const {return fAbsHNDC;} - - Double_t GetAspectRatio() const { return fAspectRatio; } - void SetFixedAspectRatio(Bool_t fixed = kTRUE); - Bool_t HasFixedAspectRatio() const {return fFixedAspectRatio;} - - Double_t GetUxmin() const {return fUxmin;} - Double_t GetUymin() const {return fUymin;} - Double_t GetUxmax() const {return fUxmax;} - Double_t GetUymax() const {return fUymax;} - - void SetGrid(Int_t valuex = 1, Int_t valuey = 1) {fGridx = valuex; fGridy = valuey; } - - void SetGridx(Int_t value = 1) {fGridx = value;} - Bool_t GetGridx() const {return fGridx;} - - void SetGridy(Int_t value = 1) {fGridy = value;} - Bool_t GetGridy() const {return fGridy;} - - void SetTicks(Int_t valuex = 1, Int_t valuey = 1) {fTickx = valuex; fTicky = valuey;} - - void SetTickx(Int_t value = 1) {fTickx = value;} - Int_t GetTickx() const {return fTickx;} - - void SetTicky(Int_t value = 1) {fTicky = value;} - Int_t GetTicky() const {return fTicky;} - - Double_t GetX1() const { return fX1; } - Double_t GetX2() const { return fX2; } - Double_t GetY1() const { return fY1; } - Double_t GetY2() const { return fY2; } - - Double_t PadtoX(Double_t x) const; - Double_t PadtoY(Double_t y) const; - Double_t XtoPad(Double_t x) const; - Double_t YtoPad(Double_t y) const; - - Int_t UtoAbsPixel(Double_t u) const {return Int_t(fUtoAbsPixelk + u * fUtoPixel);} - Int_t VtoAbsPixel(Double_t v) const {return Int_t(fVtoAbsPixelk + v * fVtoPixel);} - - Int_t UtoPixel(Double_t u) const; - Int_t VtoPixel(Double_t v) const; - - Int_t XtoAbsPixel(Double_t x) const; - Int_t YtoAbsPixel(Double_t y) const; - - Int_t XtoPixel(Double_t x) const; - Int_t YtoPixel(Double_t y) const; - - Double_t PixeltoX(Int_t px); - Double_t PixeltoY(Int_t py); - - void SetLogx(Int_t value = 1); - Int_t GetLogx() const {return fLogx;} - - void SetLogy(Int_t value = 1); - Int_t GetLogy() const {return fLogy;} - - void SetLogz(Int_t value = 1); - Int_t GetLogz() const {return fLogz;} - - void SetPad(const char *name, const char *title, - Double_t xlow, Double_t ylow, Double_t xup, - Double_t yup, Color_t color=35, - Short_t bordersize=5, Short_t bordermode=-1); - void SetPad(Double_t xlow, Double_t ylow, Double_t xup, Double_t yup); - - void SetTheta(Double_t theta=30) {fTheta = theta;} - Double_t GetTheta() const {return fTheta;} - - void SetPhi(Double_t phi=30) {fPhi = phi;} - Double_t GetPhi() const {return fPhi;} - - void SetVertical(Bool_t vert=kTRUE); - - void GetRange(Double_t &x1, Double_t &y1, Double_t &x2, Double_t &y2); - void Range(Double_t x1, Double_t y1, Double_t x2, Double_t y2); - - void GetRangeAxis(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax); - void RangeAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax); - - void GetPadPar(Double_t &xlow, Double_t &ylow, Double_t &xup, Double_t &yup); - - //Pad's properties. - void SetFillStyle(Style_t fstyle); - - Bool_t IsBatch() const {return kFALSE;} - - void SetEditable(Bool_t mode = kTRUE); - Bool_t IsEditable() const {return fEditable;} - - Bool_t IsFolder() const {return kTRUE;} - Bool_t IsModified() const {return kFALSE;} - Bool_t IsRetained() const {return kTRUE;} - Bool_t IsVertical() const {return !TestBit(kHori);} - - void SetBorderMode(Short_t bordermode) {fBorderMode = bordermode; } - Short_t GetBorderMode() const {return fBorderMode;} - - void SetBorderSize(Short_t bordersize) {fBorderSize = bordersize; } - Short_t GetBorderSize() const {return fBorderSize;} - - //Misc. pad operations. - TVirtualPad* cd(Int_t dummyNumber = -1); - - void SetView(TView *view = 0); - - void ResizePad(Option_t *option=""); - - TFrame *GetFrame(); - - TList *GetListOfPrimitives() const {return &fPrimitives;} - TList *GetListOfExecs() const {return &fExecs;} - - TObject *GetPrimitive(const char *name) const; - TView *GetView() const {return fView;} - - //Graphics. - void Paint(Option_t *option=""); - void PaintBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Option_t *option=""); - void PaintFillArea(Int_t n, Float_t *x, Float_t *y, Option_t *option=""); - void PaintFillArea(Int_t n, Double_t *x, Double_t *y, Option_t *option=""); - - void PaintPadFrame(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax); - void PaintLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2); - void PaintLineNDC(Double_t u1, Double_t v1,Double_t u2, Double_t v2); - void PaintLine3D(Float_t *p1, Float_t *p2); - void PaintLine3D(Double_t *p1, Double_t *p2); - void PaintPolyLine(Int_t n, Float_t *x, Float_t *y, Option_t *option=""); - void PaintPolyLine(Int_t n, Double_t *x, Double_t *y, Option_t *option=""); - void PaintPolyLine3D(Int_t n, Double_t *p); - void PaintPolyLineNDC(Int_t n, Double_t *x, Double_t *y, Option_t *option=""); - void PaintPolyMarker(Int_t n, Float_t *x, Float_t *y, Option_t *option=""); - void PaintPolyMarker(Int_t n, Double_t *x, Double_t *y, Option_t *option=""); - - void PaintText(Double_t x, Double_t y, const char *text); - void PaintText(Double_t x, Double_t y, const wchar_t *text); - void PaintTextNDC(Double_t u, Double_t v, const char *text); - void PaintTextNDC(Double_t u, Double_t v, const wchar_t *text); - - void RedrawAxis(Option_t *option=""); - TH1F *DrawFrame(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, const char *title); - - // - TVirtualViewer3D *GetViewer3D(Option_t *opt); - - - // - Bool_t PadInSelectionMode() const - { - return fInSelectionMode; - } - - Bool_t PadInHighlightMode() const - { - return fInHighlightMode; - } - - //This is a temporary hack, will be removed when selection - //is done correctly. - void ExecuteRotateView(Int_t evType, Int_t px, Int_t py); - void ExecuteEventAxis(Int_t, Int_t, Int_t, TAxis *); - - Bool_t SelectionIsValid()const; - void InvalidateSelection(Bool_t invalidateBufferOnly = kFALSE); - - void PaintForSelection(); - void SetSelectionBuffer(UInt_t w, UInt_t h, unsigned char *buff); - void Pick(Int_t px, Int_t py); - void Unpick(); - TObject *ObjectInPoint(Int_t px, Int_t py); - - TObject *GetSelected() const; - - void PaintShadowForSelected() const; - void PaintSelected() const; - - void PushTopLevelSelectable(TObject *top); - - void PushSelectableObject(TObject *obj); - - void PopTopLevelSelectable(); - - //New special function. - void PaintThumbnail(); - - void SetPaintOption(const TObject *obj, const char *option); - -private: - //Painter based on CoreGraphics. - mutable Painter fPainter; - - //View's width and height (from UIKit). - UInt_t fViewW; - UInt_t fViewH; - - //Standard pad's coordinates and coefficients. - Double_t fX1; // X of lower X coordinate - Double_t fY1; // Y of lower Y coordinate - Double_t fX2; // X of upper X coordinate - Double_t fY2; // Y of upper Y coordinate - - Double_t fXtoAbsPixelk; // Conversion coefficient for X World to absolute pixel - Double_t fXtoPixelk; // Conversion coefficient for X World to pixel - Double_t fXtoPixel; // xpixel = fXtoPixelk + fXtoPixel*xworld - Double_t fYtoAbsPixelk; // Conversion coefficient for Y World to absolute pixel - Double_t fYtoPixelk; // Conversion coefficient for Y World to pixel - Double_t fYtoPixel; // ypixel = fYtoPixelk + fYtoPixel*yworld - - Double_t fUtoAbsPixelk; // Conversion coefficient for U NDC to absolute pixel - Double_t fUtoPixelk; // Conversion coefficient for U NDC to pixel - Double_t fUtoPixel; // xpixel = fUtoPixelk + fUtoPixel*undc - Double_t fVtoAbsPixelk; // Conversion coefficient for V NDC to absolute pixel - Double_t fVtoPixelk; // Conversion coefficient for V NDC to pixel - Double_t fVtoPixel; // ypixel = fVtoPixelk + fVtoPixel*vndc - - Double_t fAbsPixeltoXk; // Conversion coefficient for absolute pixel to X World - Double_t fPixeltoXk; // Conversion coefficient for pixel to X World - Double_t fPixeltoX; // xworld = fPixeltoXk + fPixeltoX*xpixel - Double_t fAbsPixeltoYk; // Conversion coefficient for absolute pixel to Y World - Double_t fPixeltoYk; // Conversion coefficient for pixel to Y World - Double_t fPixeltoY; // yworld = fPixeltoYk + fPixeltoY*ypixel - - Double_t fXlowNDC; // X bottom left corner of pad in NDC [0,1] - Double_t fYlowNDC; // Y bottom left corner of pad in NDC [0,1] - Double_t fWNDC; // Width of pad along X in NDC - Double_t fHNDC; // Height of pad along Y in NDC - - Double_t fAbsXlowNDC; // Absolute X top left corner of pad in NDC [0,1] - Double_t fAbsYlowNDC; // Absolute Y top left corner of pad in NDC [0,1] - Double_t fAbsWNDC; // Absolute Width of pad along X in NDC - Double_t fAbsHNDC; // Absolute Height of pad along Y in NDC - - Double_t fUxmin; // Minimum value on the X axis - Double_t fUymin; // Minimum value on the Y axis - Double_t fUxmax; // Maximum value on the X axis - Double_t fUymax; // Maximum value on the Y axis - - Double_t fTheta; // theta angle to view as lego/surface - Double_t fPhi; // phi angle to view as lego/surface - - Double_t fAspectRatio; // ratio of w/h in case of fixed ratio - - Int_t fTickx; // Set to 1 if tick marks along X - Int_t fTicky; // Set to 1 if tick marks along Y - Int_t fLogx; // (=0 if X linear scale, =1 if log scale) - Int_t fLogy; // (=0 if Y linear scale, =1 if log scale) - Int_t fLogz; // (=0 if Z linear scale, =1 if log scale) - Short_t fBorderSize; // pad bordersize in pixels - Short_t fBorderMode; // Bordermode (-1=down, 0 = no border, 1=up) - - Bool_t fGridx; // Set to true if grid along X - Bool_t fGridy; // Set to true if grid along Y - Bool_t fAbsCoord; // Use absolute coordinates - Bool_t fEditable; // True if canvas is editable - Bool_t fFixedAspectRatio; // True if fixed aspect ratio - - mutable TList fPrimitives; // List of primitives in a pad. - mutable TList fExecs; // List of commands to be executed when a pad event occurs (empty on iOS). - - TFrame *fFrame; // Pointer to 2-D frame (if one exists) - TView *fView; // Pointer to 3-D view (if one exists) - - // - TVirtualViewer3D *fViewer3D; - - //Selection trick now! - Bool_t fSelectionIsValid; - UInt_t fSelectionAreaWidth; - std::vector fSelectionBuffer; - - TObject *fSelected; - TObject *fParentOfSelected; - - mutable Bool_t fInSelectionMode; - mutable Bool_t fInHighlightMode; - - typedef std::pair Parent_t; - std::vector fParentPainters; - - typedef std::pair ObjectPair_t; - std::vector fSelectables; - - UInt_t fObjectID; - //This requires special processing at the moment. - Bool_t fContains3DObject; - - const char *GetSelectedParentDrawOption()const; - const char *GetSelectedDrawOption()const; - - //Non-overriders. - TObject *FindObject(const char *name) const; - TObject *FindObject(const TObject *obj) const; - - Int_t Clip(Float_t *x, Float_t *y, Float_t xclipl, Float_t yclipb, Float_t xclipr, Float_t yclipt); - Int_t Clip(Double_t *x, Double_t *y, Double_t xclipl, Double_t yclipb, Double_t xclipr, Double_t yclipt); - Int_t ClippingCode(Double_t x, Double_t y, Double_t xcl1, Double_t ycl1, Double_t xcl2, Double_t ycl2); - Int_t ClipPolygon(Int_t n, Double_t *x, Double_t *y, Int_t nn, Double_t *xc, Double_t *yc, Double_t xclipl, Double_t yclipb, Double_t xclipr, Double_t yclipt); - - void PaintBorder(Color_t color, Bool_t tops); - void PaintFillAreaHatches(Int_t n, Double_t *x, Double_t *y, Int_t FillStyle); - void PaintHatches(Double_t dy, Double_t angle, Int_t nn, Double_t *xx, Double_t *yy); - - Pad(const Pad &pad); - Pad &operator=(const Pad &rhs); -}; - -}//namespace iOS -}//namespace ROOT - -#endif diff --git a/graf2d/ios/inc/IOSPadStub.h b/graf2d/ios/inc/IOSPadStub.h deleted file mode 100644 index 9c0981b2cec3f..0000000000000 --- a/graf2d/ios/inc/IOSPadStub.h +++ /dev/null @@ -1,112 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_IOSPadStub -#define ROOT_IOSPadStub - -////////////////////////////////////////////////////////////////////////// -// // -// IOSPadStub // -// // -// TVirtualPad interface is huge: ~150 public virtual member functions, // -// mixture of different interfaces in fact. // -// We do not need these 68 functions, but I have to implement them // -// (they are pure virtual), so, we have a "stub" class with // -// empty virtual functions. // -// // -////////////////////////////////////////////////////////////////////////// - -#include "TVirtualPad.h" - -namespace ROOT { -namespace iOS { - -class PadStub : public TVirtualPad { -public: - TLegend *BuildLegend(Double_t x1, Double_t y1, Double_t x2, Double_t y2, const char *title); - void Close(Option_t *); - void AddExec(const char *, const char *); - void CopyPixmap(); - void CopyPixmaps(); - void DeleteExec(const char *); - void Divide(Int_t, Int_t, Float_t, Float_t, Int_t); - void Draw(Option_t *); - void DrawClassObject(const TObject *, Option_t *); - void SetBatch(Bool_t batch); - Int_t GetCanvasID() const; - TCanvasImp *GetCanvasImp() const; - Int_t GetEvent() const; - Int_t GetEventX() const; - Int_t GetEventY() const; - Int_t GetNumber() const; - TVirtualPad *GetPad(Int_t subpadnumber) const; - TObject *GetPadPointer() const; - TVirtualPad *GetPadSave() const; - TVirtualPad *GetSelectedPad() const; - TObject *GetView3D() const; - void ResetView3D(TObject *); - TCanvas *GetCanvas() const; - TVirtualPad *GetVirtCanvas() const; - Int_t GetPadPaint() const; - Int_t GetPixmapID() const; - Bool_t HasCrosshair() const; - void SetCrosshair(Int_t); - void SetAttFillPS(Color_t, Style_t); - void SetAttLinePS(Color_t, Style_t, Width_t); - void SetAttMarkerPS(Color_t, Style_t, Size_t); - void SetAttTextPS(Int_t, Float_t, Color_t, Style_t, Float_t); - void PaintBorderPS(Double_t, Double_t, Double_t, Double_t, Int_t, Int_t, Int_t, Int_t); - //PaintText with a parameter of a type wchar_t is a special version - //used by mathtext. It relies strongly on ttf and actually requires - //ttf. NOOP at the moment (whence it's here, in a 'stub' class). - virtual void PaintText(Double_t, Double_t, const wchar_t *); - virtual void PaintTextNDC(Double_t, Double_t, const wchar_t *); - // - Int_t GetGLDevice(); - void SetCopyGLDevice(Bool_t); - void Pop(); - void Print(const char *) const; - void Print(const char *, Option_t *); - TVirtualPad *GetMother() const; - TObject *CreateToolTip(const TBox *, const char *, Long_t); - void DeleteToolTip(TObject *); - void ResetToolTip(TObject *); - void CloseToolTip(TObject *); - void SetToolTipText(const char *, Long_t); - void HighLight(Color_t, Bool_t); - Color_t GetHighLightColor() const; - void ls(Option_t *option) const; - void Modified(Bool_t flag); - Bool_t OpaqueMoving() const; - Bool_t OpaqueResizing() const; - void PaintModified(); - void RecursiveRemove(TObject *obj); - void SaveAs(const char *,Option_t *) const; - void SetCanvas(TCanvas *); - void SetCanvasSize(UInt_t, UInt_t); - void SetCursor(ECursor cursor); - void SetDoubleBuffer(Int_t mode); - void SetName(const char *); - void SetTitle(const char *); - void SetSelected(TObject *); - void ShowGuidelines(TObject *, Int_t, char, bool); - void Update(); - TObject *WaitPrimitive(const char *, const char *); - void ReleaseViewer3D(Option_t *); - Bool_t HasViewer3D() const; - - TVirtualPadPainter *GetPainter(); -}; - -}//namespace iOS -}//namespace ROOT - -#endif diff --git a/graf2d/ios/inc/IOSPainter.h b/graf2d/ios/inc/IOSPainter.h deleted file mode 100644 index 7b15a3e724bf0..0000000000000 --- a/graf2d/ios/inc/IOSPainter.h +++ /dev/null @@ -1,142 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_IOSPainter -#define ROOT_IOSPainter - -////////////////////////////////////////////////////////////////////////// -// // -// IOSPainter // -// // -// Graphics operations required by IOSPad are implemented in // -// IOSPainter. Uses CoreGraphics and CoreText. // -// // -////////////////////////////////////////////////////////////////////////// - -#include - -#include - - -#include "TVirtualPadPainter.h" -#include "IOSTextOperations.h" -#include "IOSGraphicUtils.h" -#include "TPoint.h" - -namespace ROOT { -namespace iOS { - -// -//SpaceConverter converts coordinates from pad's user space into UIView's userspace. -// - -class SpaceConverter { -public: - SpaceConverter(); - SpaceConverter(UInt_t viewW, Double_t xMin, Double_t xMax, - UInt_t viewH, Double_t yMin, Double_t yMax); - - void SetConverter(UInt_t viewW, Double_t xMin, Double_t xMax, - UInt_t viewH, Double_t yMin, Double_t yMax); - - Double_t XToView(Double_t x)const; - Double_t YToView(Double_t y)const; - -private: - Double_t fXMin; - Double_t fXConv; - - Double_t fYMin; - Double_t fYConv; -}; - -class Painter { -public: - enum EMode { - kPaintToSelectionBuffer, //A pad draws the scene into the selection buffer. - kPaintToView, //Normal painting (normal colors and styles). - kPaintShadow, //Poor man's shadows for selected object (for iPad3). - kPaintSelected, //Only selected object is painted. - kPaintThumbnail //Paint into small picture, low level of details. - }; - - - Painter(); - - //Now, drawing primitives. - void DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2); - void DrawLineNDC(Double_t u1, Double_t v1, Double_t u2, Double_t v2); - - void DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, TVirtualPadPainter::EBoxMode mode); - - void DrawFillArea(Int_t n, const Double_t *x, const Double_t *y); - void DrawFillArea(Int_t n, const Float_t *x, const Float_t *y); - - void DrawPolyLine(Int_t n, const Double_t *x, const Double_t *y); - void DrawPolyLine(Int_t n, const Float_t *x, const Float_t *y); - void DrawPolyLineNDC(Int_t n, const Double_t *u, const Double_t *v); - - void DrawPolyMarker(Int_t n, const Double_t *x, const Double_t *y); - void DrawPolyMarker(Int_t n, const Float_t *x, const Float_t *y); - - void DrawText(Double_t x, Double_t y, const char *text, TVirtualPadPainter::ETextMode mode); - void DrawTextNDC(Double_t u, Double_t v, const char *text, TVirtualPadPainter::ETextMode mode); - - void SetContext(CGContextRef ctx); - void SetTransform(UInt_t w, Double_t xMin, Double_t xMax, UInt_t h, Double_t yMin, Double_t yMax); - - void SetPainterMode(EMode mode); - void SetCurrentObjectID(UInt_t objId); - - void GetTextExtent(UInt_t &w, UInt_t &h, const char *text); - -private: - - void SetStrokeParameters()const; - void SetPolygonParameters()const; - void SetMarkerColor()const; - Bool_t PolygonHasStipple()const; - - // - void FillBoxWithPattern(Double_t x1, Double_t y1, Double_t x2, Double_t y2)const; - void FillBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2)const; - void DrawBoxOutline(Double_t x1, Double_t y1, Double_t x2, Double_t y2)const; - - void FillAreaWithPattern(Int_t n, const Double_t *x, const Double_t *y)const; - void FillArea(Int_t n, const Double_t *x, const Double_t *y)const; - - void DrawText(Double_t x, Double_t y, const CTLineGuard &ctLine); - - // - FontManager fFontManager; - CGContextRef fCtx;//Quartz context. - SpaceConverter fConverter; - - typedef std::vector::size_type size_type; - std::vector fPolyMarker;//Buffer for converted poly-marker coordinates. - - //Staff for picking. - EMode fPainterMode; - UInt_t fCurrentObjectID; - GraphicUtils::IDEncoder fEncoder; - - void SetLineColorForCurrentObjectID() const; - void SetPolygonColorForCurrentObjectID() const; - void SetLineColorHighlighted() const; - - Painter(const Painter &rhs); - Painter &operator = (const Painter &rhs); -}; - -}//iOS -}//namespace ROOT - -#endif diff --git a/graf2d/ios/inc/IOSResourceManagement.h b/graf2d/ios/inc/IOSResourceManagement.h deleted file mode 100644 index 216f0f14ac3c3..0000000000000 --- a/graf2d/ios/inc/IOSResourceManagement.h +++ /dev/null @@ -1,187 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_ResourceManagement -#define ROOT_ResourceManagement - -////////////////////////////////////////////////////////////////////////// -// // -// Resource management // -// // -// Set of classes to simplify and automate resource and memory // -// management with Core Foundation, Core Text, Core Graphics etc. // -// Apple has reference counting system, but it's a good old C, // -// and you have to remember to release counters yourself. // -// // -////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include - -#include "Rtypes.h" - -namespace ROOT { -namespace iOS { -namespace Util { - - -class NonCopyable { -protected: - NonCopyable(){}; -private: - NonCopyable(const NonCopyable &rhs); - NonCopyable &operator = (const NonCopyable &rhs); -}; - -//Class calls user's function to release resource. -template -class RefGuardGeneric : NonCopyable { -public: - explicit RefGuardGeneric(RefType ref) : fRef(ref), fActive(kTRUE) - { - } - - ~RefGuardGeneric() - { - if (fActive) - release(fRef); - } - - RefType Get()const - { - return fRef; - } - - RefType Release() - { - fActive = kFALSE; - return fRef; - } - -private: - - RefType fRef; - Bool_t fActive; -}; - -//Simple class to call CFRelease on some CFTypeRef. -template -class RefGuard : NonCopyable { -public: - explicit RefGuard(RefType ref) : fRef(ref), fActive(kTRUE) - { - } - - ~RefGuard() - { - if (fActive) - CFRelease(fRef); - } - - RefType Get()const - { - return fRef; - } - - RefType Release() - { - fActive = kFALSE; - return fRef; - } - -private: - - RefType fRef; - bool fActive; -}; - - -//Very similar to RefGuardGeneric, but calls CFRelease -class CFStringGuard : NonCopyable { -public: - CFStringGuard(const char *text); - ~CFStringGuard(); - - CFStringRef Get()const; -private: - CFStringRef fCFString; -}; - -//Save and restore CGContextRef's state. -class CGStateGuard : NonCopyable { -public: - CGStateGuard(CGContextRef ctx); - ~CGStateGuard(); - -private: - CGContextRef fCtx; -}; - -//Same as RefGuardGeneric, but can -//be copied. -template -class SmartRef { -public: - SmartRef(RefType ref, bool initRetain = kFALSE) - : fRef(ref) - { - if (initRetain) - CFRetain(fRef); - } - - SmartRef(const SmartRef &rhs) - : fRef(rhs.fRef) - { - CFRetain(fRef); - } - - SmartRef &operator = (const SmartRef &rhs) - { - if (fRef != rhs.fRef) { - release(fRef); - fRef = rhs.fRef; - CFRetain(fRef); - } - - return *this; - } - - SmartRef &operator = (RefType ref) - { - if (fRef != ref) { - release(fRef); - fRef = ref; - CFRetain(fRef); - } - - return *this; - } - - ~SmartRef() - { - release(fRef); - } - - RefType Get()const - { - return fRef; - } -private: - RefType fRef; -}; - -}//namespace Util -}//namespace iOS -}//namespace ROOT - -#endif diff --git a/graf2d/ios/inc/IOSSelectionMarkers.h b/graf2d/ios/inc/IOSSelectionMarkers.h deleted file mode 100644 index ec968115e04c1..0000000000000 --- a/graf2d/ios/inc/IOSSelectionMarkers.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ROOT_IOSSelectionMarkers -#define ROOT_IOSSelectionMarkers - -#include -#include - -namespace ROOT { -namespace iOS { -namespace GraphicUtils { - -void DrawSelectionMarker(CGContextRef ctx, const CGPoint &point); -void DrawBoxSelectionMarkers(CGContextRef ctx, const CGRect &box); - -} -} -} - -#endif diff --git a/graf2d/ios/inc/IOSTextOperations.h b/graf2d/ios/inc/IOSTextOperations.h deleted file mode 100644 index 9a6d081de4db6..0000000000000 --- a/graf2d/ios/inc/IOSTextOperations.h +++ /dev/null @@ -1,98 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_TextOperations -#define ROOT_TextOperations - -////////////////////////////////////////////////////////////////////////// -// // -// IOSTextOperations // -// // -// Font management for iOS and Core Text. // -// To be extended or completely changed in a future. // -// // -////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include -#include - -#include "IOSResourceManagement.h" - -#include "Rtypes.h" - -namespace ROOT { -namespace iOS { - -class CTLineGuard : public Util::NonCopyable { - friend class Painter; - -public: - CTLineGuard(const char *textLine, CTFontRef font); - CTLineGuard(const char *textLine, CTFontRef font, Color_t color); - CTLineGuard(const char *textLine, CTFontRef font, const std::vector &symbolMap); - ~CTLineGuard(); - - void GetBounds(UInt_t &w, UInt_t &h)const; - -private: - - void Init(const char *textLine, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values); - void Init(const std::vector &textLine, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values); - - CTLineRef fCTLine; //Core Text line, created from Attributed string. -}; - -class FontManager : public Util::NonCopyable { -public: - enum FontManagerDefaults { - fmdNOfFonts = 13 - }; - - FontManager(); - ~FontManager(); - - //Select the existing font or create a new one and select it. - CTFontRef SelectFont(Font_t fontIndex, Float_t fontSize); - - //Typographical bounds (whatever it means), - //for the current selected font and text. - void GetTextBounds(UInt_t &w, UInt_t &h, const char *text)const; - // - double GetAscent()const; - double GetDescent()const; - double GetLeading()const; - - const std::vector &GetSymbolMap()const - { - return fSymbolMap; - } - -private: - typedef std::map FontMap_t; - typedef FontMap_t::iterator FontMapIter_t; - typedef FontMap_t::const_iterator FontMapConstIter_t; - - FontMap_t fFonts[fmdNOfFonts]; - CTFontRef fSelectedFont; - - std::vector fSymbolMap; - - void InitSymbolMap(); -}; - -}//namespace iOS -}//namespace ROOT - - -#endif diff --git a/graf2d/ios/inc/TGIOS.h b/graf2d/ios/inc/TGIOS.h deleted file mode 100644 index d5870e6f7a35d..0000000000000 --- a/graf2d/ios/inc/TGIOS.h +++ /dev/null @@ -1,63 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 19/10/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_TGIOS -#define ROOT_TGIOS - -#include "TVirtualX.h" - -////////////////////////////////////////////////////////////////////////// -// // -// TGIOS. // -// // -// TVirtualX for iOS. No window management, no graphics, just have // -// to implement correctly functions from TAttXXX base classes // -// (TVirtualX intentionally overrides some of them and has // -// empty implementations). But on iOS I do not have TGWin32 or // -// TGX11 and graphic primitives try to use gVirtualX to pass // -// different attributes like color, line width, etc. to the // -// painting code. // -// // -////////////////////////////////////////////////////////////////////////// - -namespace ROOT { -namespace iOS { - -class TGIOS : public TVirtualX { -public: - TGIOS(); - TGIOS(const char *name, const char *title); - - void SetLineColor(Color_t cindex); - void SetLineStyle(Style_t linestyle); - void SetLineWidth(Width_t width); - void SetFillColor(Color_t cindex); - void SetFillStyle(Style_t style); - void SetMarkerColor(Color_t cindex); - void SetMarkerSize(Float_t markersize); - void SetMarkerStyle(Style_t markerstyle); - void SetTextAlign(Short_t talign); - void SetTextColor(Color_t cindex); - void SetTextFont(Font_t fontnumber); - void SetTextSize(Float_t textsize); - - void GetTextExtent(UInt_t &w, UInt_t &h, char *mess); - - using TVirtualX::SetTextFont; -private: - TGIOS(const TGIOS &rhs); - TGIOS &operator = (const TGIOS &rhs); -}; - -} -} - -#endif diff --git a/graf2d/ios/src/IOSFillPatterns.cxx b/graf2d/ios/src/IOSFillPatterns.cxx deleted file mode 100644 index 0a5fb329e1d7d..0000000000000 --- a/graf2d/ios/src/IOSFillPatterns.cxx +++ /dev/null @@ -1,720 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#include - -#include "IOSFillPatterns.h" - -namespace ROOT { -namespace iOS { -namespace GraphicUtils { - -const unsigned solidFillStyle = 1001; -const unsigned stippleBase = 3000; - -//TODO. Remove all this nightmarish functions and use bitmaps. - -// -// Fill patterns, defined in RStipples.h. -// Pattern in RStipple.h is 32x32. -// Order is: say, the first two numbers are 1: 0x42 2: 0x42 -// NUMBER: 1 2 -// BITS: 0100 0010 0100 0010 //bits from lower to higher. -// IN HEX 2 4 2 4 - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_1(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 0.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 1.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_1(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_1; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 2.f, 2.f), CGAffineTransformIdentity, 2.f, 2.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_2(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(2.f, 0.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 3.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_2(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_2; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 4.f, 4.f), CGAffineTransformIdentity, 4.f, 4.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_3(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 0.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 2.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_3(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_3; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 4.f, 4.f), CGAffineTransformIdentity, 4.f, 4.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_4(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 4.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 0.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_4(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_4; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 8.f, 8.f), CGAffineTransformIdentity, 8.f, 8.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_5(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 0.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 4.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 7.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_5(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_5; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 8.f, 8.f), CGAffineTransformIdentity, 8.f, 8.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_6(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(2.f, 0.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 3.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_6(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_6; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 4.f, 4.f), CGAffineTransformIdentity, 4.f, 4.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_7(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 1.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_7(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_7; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 4.f, 4.f), CGAffineTransformIdentity, 4.f, 4.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_8(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - //0x11 - CGContextFillRect(ctx, CGRectMake(0.f, 0.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 0.f, 1.f, 1.f)); - - //0xb8 - CGContextFillRect(ctx, CGRectMake(0.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 1.f, 1.f, 1.f)); - - //0x7c - CGContextFillRect(ctx, CGRectMake(0.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 2.f, 1.f, 1.f)); - - //0x3a - CGContextFillRect(ctx, CGRectMake(0.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 3.f, 1.f, 1.f)); - - //0x11 - CGContextFillRect(ctx, CGRectMake(0.f, 4.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 4.f, 1.f, 1.f)); - - //0xa3 - CGContextFillRect(ctx, CGRectMake(1.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 5.f, 1.f, 1.f)); - - //0xc7 - CGContextFillRect(ctx, CGRectMake(2.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 6.f, 1.f, 1.f)); - - //0x8b - CGContextFillRect(ctx, CGRectMake(3.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 7.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_8(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_8; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 8.f, 8.f), CGAffineTransformIdentity, 8.f, 8.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_9(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 0.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 2.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(4.f, 4.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 5.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(3.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 6.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(0.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 7.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_9(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_9; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 8.f, 8.f), CGAffineTransformIdentity, 8.f, 8.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_10(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 0.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 3.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(1.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 3.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(4.f, 4.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 6.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(0.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 7.f, 1.f, 1.f)); - -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_10(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_10; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 8.f, 8.f), CGAffineTransformIdentity, 8.f, 8.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_11(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 4.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 4.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 4.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 7.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(0.f, 10.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 14.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 11.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 13.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 12.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 9.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 10.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 11.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 12.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 13.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 14.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 15.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 12.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 11.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 13.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 10.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 14.f, 1.f, 1.f)); - -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_11(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_11; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 8.f, 16.f), CGAffineTransformIdentity, 8.f, 16.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_12(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 11.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 12.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 13.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(1.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 10.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 14.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(2.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 4.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 9.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 15.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(3.f, 9.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 15.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(4.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 4.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 9.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 15.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(5.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 6.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 10.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 14.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(6.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 11.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 12.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 13.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(7.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 7.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_12(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_12; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 8.f, 16.f), CGAffineTransformIdentity, 8.f, 16.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_13(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 7.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(1.f, 0.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 6.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(2.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 5.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(3.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 4.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(4.f, 3.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(5.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 4.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(6.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 5.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(7.f, 0.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 6.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_13(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_13; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 8.f, 8.f), CGAffineTransformIdentity, 8.f, 8.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_14(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - for (unsigned i = 0; i < 16; ++i) { - CGContextFillRect(ctx, CGRectMake(0.f, i, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(12.f, i, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(i, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(i, 15.f, 1.f, 1.f)); - } - - for (unsigned i = 0; i < 8; ++i) { - CGContextFillRect(ctx, CGRectMake(i, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(i + 4, 11.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 8.f + i, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(8.f, 4.f + i, 1.f, 1.f)); - } - -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_14(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_14; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 16.f, 16.f), CGAffineTransformIdentity, 16.f, 16.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_15(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 6.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(1.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 7.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(2.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 6.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(3.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 3.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(4.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 6.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(5.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 7.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(6.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 6.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(7.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 3.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_15(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_15; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 8.f, 8.f), CGAffineTransformIdentity, 8.f, 8.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_16(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(0.f, 6.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(1.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 7.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(3.f, 7.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(4.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(4.f, 6.f, 1.f, 1.f)); - - CGContextFillRect(ctx, CGRectMake(5.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(5.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(6.f, 5.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 1.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(7.f, 5.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_16(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_16; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 8.f, 8.f), CGAffineTransformIdentity, 8.f, 8.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -void draw_pattern_17(void *color, CGContextRef ctx) -{ - const float *rgb = static_cast(color); - const float alpha = 1.f; - CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha); - - CGContextFillRect(ctx, CGRectMake(0.f, 3.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(1.f, 2.f, 1.f, 1.f)); - CGContextFillRect(ctx, CGRectMake(2.f, 1.f, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_17(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_17; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 4.f, 4.f), CGAffineTransformIdentity, 4.f, 4.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGPatternRef create_pattern_18(float *rgb) -{ - CGPatternCallbacks patternCallbacks; - patternCallbacks.version = 0; - patternCallbacks.drawPattern = draw_pattern_17; - patternCallbacks.releaseInfo = 0; - - return CGPatternCreate(rgb, CGRectMake(0.f, 0.f, 4.f, 4.f), CGAffineTransformMakeScale(-1.f, 1.f), 4.f, 4.f, kCGPatternTilingConstantSpacingMinimalDistortion, 1, &patternCallbacks); -} - -PatternGenerator_t gPatternGenerators[kPredefinedFillPatterns] = {create_pattern_1, - create_pattern_2, - create_pattern_3, - create_pattern_4, - create_pattern_5, - create_pattern_6, - create_pattern_7, - create_pattern_8, - create_pattern_9, - create_pattern_10, - create_pattern_11, - create_pattern_12, - create_pattern_13, - create_pattern_14, - create_pattern_15, - create_pattern_16, - create_pattern_17, - create_pattern_18}; - -}//namespace GraphicUtils -}//namespace iOS -}//namespace ROOT diff --git a/graf2d/ios/src/IOSGraphicUtils.cxx b/graf2d/ios/src/IOSGraphicUtils.cxx deleted file mode 100644 index 216386a0b5709..0000000000000 --- a/graf2d/ios/src/IOSGraphicUtils.cxx +++ /dev/null @@ -1,92 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#include "TAttMarker.h" -#include "TVirtualX.h" -#include "TColor.h" -#include "TROOT.h" - -#include "IOSGraphicUtils.h" - -namespace ROOT { -namespace iOS { -namespace GraphicUtils { - -//////////////////////////////////////////////////////////////////////////////// - -void GetColorForIndex(Color_t colorIndex, Float_t &r, Float_t &g, Float_t &b) -{ - if (const TColor *color = gROOT->GetColor(colorIndex)) - color->GetRGB(r, g, b); -} - -//IDEncoder. -//////////////////////////////////////////////////////////////////////////////// - -IDEncoder::IDEncoder(UInt_t radix, UInt_t channelSize) - : fRadix(radix), - fRadix2(radix * radix), - fChannelSize(channelSize), - fStepSize(channelSize / (radix - 1)), - fMaxID(radix * radix * radix) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -Bool_t IDEncoder::IdToColor(UInt_t id, Float_t *rgb) const -{ - if (id >= fMaxID) - return kFALSE; - - const UInt_t red = id / fRadix2; - const UInt_t green = (id - red * fRadix2) / fRadix; - const UInt_t blue = (id - red * fRadix2 - green * fRadix) % fRadix; - - rgb[0] = red * fStepSize / Float_t(fChannelSize); - rgb[1] = green * fStepSize / Float_t(fChannelSize); - rgb[2] = blue * fStepSize / Float_t(fChannelSize); - - return kTRUE; -} - -//////////////////////////////////////////////////////////////////////////////// - -UInt_t IDEncoder::ColorToId(UInt_t r, UInt_t g, UInt_t b) const -{ - const UInt_t red = FixValue(r); - const UInt_t green = FixValue(g); - const UInt_t blue = FixValue(b); - - return fRadix2 * red + fRadix * green + blue; -} - -//////////////////////////////////////////////////////////////////////////////// - -UInt_t IDEncoder::FixValue(UInt_t val) const -{ - const UInt_t orig = val / fStepSize; - - if (orig * fStepSize != val) { - const UInt_t top = (orig + 1) * fStepSize - val; - const UInt_t bottom = val - orig * fStepSize; - - if (top > bottom || orig + 1 >= fRadix) - return orig; - - return orig + 1; - } else - return orig; -} - -}//namespace GraphicUtils -}//namespace iOS -}//namespace ROOT diff --git a/graf2d/ios/src/IOSLineStyles.cxx b/graf2d/ios/src/IOSLineStyles.cxx deleted file mode 100644 index 3044ec1388b33..0000000000000 --- a/graf2d/ios/src/IOSLineStyles.cxx +++ /dev/null @@ -1,37 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 17/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#include "IOSLineStyles.h" - -namespace ROOT { -namespace iOS { -namespace GraphicUtils { -//For fixed line style, number of elements in a pattern is not bigger than 8. -const unsigned linePatternLengths[] = {1, 2, 2, 4, 4, 8, 2, 6, 2, 4}; - -//Line pattern specyfies length of painted and unpainted fragments, for example, -//{2.f, 2.f} draw 2 pixels, skip to pixels (and repeat). -const CGFloat dashLinePatterns[10][8] = { - {1}, //Style 1: 1 element, solid line - {3.f, 3.f}, //Style 2: 2 elements (paint one, skip the second). - {1.f, 2.f}, //Style 3: 2 elements. - {3.f, 4.f, 1.f, 4.f}, //Style 4: 4 elements. - {5.f, 3.f, 1.f, 3.f}, //Style 5: 4 elements. - {5.f, 3.f, 1.f, 3.f, 1.f, 3.f, 1.f, 3.f},//Style 6: 8 elements - {5.f, 5.f}, //Style 7: 2 elements. - {5.f, 3.f, 1.f, 3.f, 1.f, 3.f}, //Style 8: 6 elements. - {20.f, 5.f}, //Style 9: 2 elements. - {20.f, 8.f, 1.f, 8.f} //Style 10: 4 elements. - }; - -}//namespace GraphicUtils -}//namespace iOS -}//namespace ROOT diff --git a/graf2d/ios/src/IOSMarkers.cxx b/graf2d/ios/src/IOSMarkers.cxx deleted file mode 100644 index 561e8ebc34cc4..0000000000000 --- a/graf2d/ios/src/IOSMarkers.cxx +++ /dev/null @@ -1,1037 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#include "TAttMarker.h" - -#include "IOSGraphicUtils.h" -#include "IOSMarkers.h" - -namespace ROOT { -namespace iOS { -namespace GraphicUtils { - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerDot(CGContextRef ctx, unsigned n, const TPoint *xy) -{ - for (unsigned i = 0; i < n; ++i) - CGContextFillRect(ctx, CGRectMake(xy[i].fX, xy[i].fY, 1.f, 1.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerPlus(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Double_t im = 4 * markerSize + 0.5; - - for (UInt_t i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, -im + x, y); - CGContextAddLineToPoint(ctx, im + x, y); - CGContextStrokePath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x, -im + y); - CGContextAddLineToPoint(ctx, x, im + y); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerStar(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - Double_t im = 4 * markerSize + 0.5; - - TPoint star[8]; - star[0].fX = -im; star[0].fY = 0; - star[1].fX = im; star[1].fY = 0; - star[2].fX = 0 ; star[2].fY = -im; - star[3].fX = 0 ; star[3].fY = im; - - im = 0.707 * im + 0.5; - star[4].fX = -im; star[4].fY = -im; - star[5].fX = im; star[5].fY = im; - star[6].fX = -im; star[6].fY = im; - star[7].fX = im; star[7].fY = -im; - - for (UInt_t i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, star[0].fX + x, star[0].fY + y); - CGContextAddLineToPoint(ctx, star[1].fX + x, star[1].fY + y); - CGContextStrokePath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, star[2].fX + x, star[2].fY + y); - CGContextAddLineToPoint(ctx, star[3].fX + x, star[3].fY + y); - CGContextStrokePath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, star[4].fX + x, star[4].fY + y); - CGContextAddLineToPoint(ctx, star[5].fX + x, star[5].fY + y); - CGContextStrokePath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, star[6].fX + x, star[6].fY + y); - CGContextAddLineToPoint(ctx, star[7].fX + x, star[7].fY + y); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenCircle(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - Double_t r = 4 * markerSize + 0.5; - if (r > 100.) - r = 100.;//as in TGX11. - - const Double_t d = 2 * r; - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - const CGRect rect = CGRectMake(x - r, y - r, d, d); - CGContextStrokeEllipseInRect(ctx, rect); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerX(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Double_t im = 0.707 * (4 * markerSize + 0.5) + 0.5; - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, -im + x, -im + y); - CGContextAddLineToPoint(ctx, im + x, im + y); - CGContextStrokePath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, -im + x, im + y); - CGContextAddLineToPoint(ctx, im + x, -im + y); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFullDotSmall(CGContextRef ctx, unsigned n, const TPoint *xy) -{ - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, -1. + x, y); - CGContextAddLineToPoint(ctx, x + 1., y); - CGContextStrokePath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x, -1. + y); - CGContextAddLineToPoint(ctx, x, 1. + y); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFullDotMedium(CGContextRef ctx, unsigned n, const TPoint *xy) -{ - for (unsigned i = 0; i < n; ++i) - CGContextFillRect(ctx, CGRectMake(xy[i].fX - 1, xy[i].fY - 1, 3.f, 3.f)); -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFullDotLarge(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - Double_t radius = 4 * markerSize + 0.5; - if (radius > 100.) - radius = 100;//as in TGX11. - - const Double_t d = 2 * radius; - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - const CGRect rect = CGRectMake(x - radius, y - radius, d, d); - CGContextFillEllipseInRect(ctx, rect); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFullSquare(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Double_t im = 4 * markerSize + 0.5; - for (unsigned i = 0; i < n; ++i) { - const CGRect rect = CGRectMake(xy[i].fX - im, xy[i].fY - im, im * 2, im * 2); - CGContextFillRect(ctx, rect); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenSquare(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Double_t im = 4 * markerSize + 0.5; - for (unsigned i = 0; i < n; ++i) { - const CGRect rect = CGRectMake(xy[i].fX - im, xy[i].fY - im, im * 2, im * 2); - CGContextStrokeRect(ctx, rect); - } -} - - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFullTriangleUp(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Double_t im = 4 * markerSize + 0.5; - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y - im); - CGContextAddLineToPoint(ctx, x + im, y - im); - CGContextAddLineToPoint(ctx, x, im + y); - CGContextFillPath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenTriangleUp(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Double_t im = 4 * markerSize + 0.5; - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y - im); - CGContextAddLineToPoint(ctx, x + im, y - im); - CGContextAddLineToPoint(ctx, x, im + y); - CGContextAddLineToPoint(ctx, x - im, y - im); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenTriangleDown(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y + im); - CGContextAddLineToPoint(ctx, x, y - im); - CGContextAddLineToPoint(ctx, im + x, y + im); - CGContextAddLineToPoint(ctx, x - im, y + im); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFullTriangleDown(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y + im); - CGContextAddLineToPoint(ctx, x, y - im); - CGContextAddLineToPoint(ctx, im + x, y + im); - CGContextFillPath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFullDiamond(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t imx = Int_t(2.66 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - imx, y); - CGContextAddLineToPoint(ctx, x, y - im); - CGContextAddLineToPoint(ctx, x + imx, y); - CGContextAddLineToPoint(ctx, x, y + im); - CGContextDrawPath(ctx, kCGPathFillStroke); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenDiamond(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t imx = Int_t(2.66 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - imx, y); - CGContextAddLineToPoint(ctx, x, y - im); - CGContextAddLineToPoint(ctx, x + imx, y); - CGContextAddLineToPoint(ctx, x, y + im); - CGContextAddLineToPoint(ctx, x - imx, y); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFullCross(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t imx = Int_t(1.33 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y - imx); - CGContextAddLineToPoint(ctx, x - imx, y - imx); - CGContextAddLineToPoint(ctx, x - imx, y - im); - CGContextAddLineToPoint(ctx, x + imx, y - im); - CGContextAddLineToPoint(ctx, x + imx, y - imx); - CGContextAddLineToPoint(ctx, x + im, y - imx); - CGContextAddLineToPoint(ctx, x + im, y + imx); - CGContextAddLineToPoint(ctx, x + imx, y + imx); - CGContextAddLineToPoint(ctx, x + imx, y + im); - CGContextAddLineToPoint(ctx, x - imx, y + im); - CGContextAddLineToPoint(ctx, x - imx, y + imx); - CGContextAddLineToPoint(ctx, x - im, y + imx); - CGContextAddLineToPoint(ctx, x - im, y - imx); - CGContextFillPath(ctx); - } -} - - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenCross(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t imx = Int_t(1.33 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y - imx); - CGContextAddLineToPoint(ctx, x - imx, y - imx); - CGContextAddLineToPoint(ctx, x - imx, y - im); - CGContextAddLineToPoint(ctx, x + imx, y - im); - CGContextAddLineToPoint(ctx, x + imx, y - imx); - CGContextAddLineToPoint(ctx, x + im, y - imx); - CGContextAddLineToPoint(ctx, x + im, y + imx); - CGContextAddLineToPoint(ctx, x + imx, y + imx); - CGContextAddLineToPoint(ctx, x + imx, y + im); - CGContextAddLineToPoint(ctx, x - imx, y + im); - CGContextAddLineToPoint(ctx, x - imx, y + imx); - CGContextAddLineToPoint(ctx, x - im, y + imx); - CGContextAddLineToPoint(ctx, x - im, y - imx); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// HIGZ full star pentagone - -void DrawMarkerFullStar(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im1 = Int_t(0.66 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - const Int_t im3 = Int_t(2.66 * markerSize + 0.5); - const Int_t im4 = Int_t(1.33 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y - im4); - CGContextAddLineToPoint(ctx, x - im2, y + im1); - CGContextAddLineToPoint(ctx, x - im4, y - im4); - CGContextFillPath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im2, y + im1);//1 - CGContextAddLineToPoint(ctx, x - im3, y + im);//2 - CGContextAddLineToPoint(ctx, x, y + im2);//3 - CGContextFillPath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x, y + im2);//3 - CGContextAddLineToPoint(ctx, x + im3, y + im);//4 - CGContextAddLineToPoint(ctx, x + im2, y + im1);//5 - CGContextFillPath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x + im2, y + im1);//5 - CGContextAddLineToPoint(ctx, x + im, y - im4);//6 - CGContextAddLineToPoint(ctx,x + im4, y - im4);//7 - CGContextFillPath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x + im4, y - im4);//7 - CGContextAddLineToPoint(ctx, x, y - im);//8 - CGContextAddLineToPoint(ctx, x - im4, y - im4);//9 - CGContextFillPath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im4, y - im4);//9 - CGContextAddLineToPoint(ctx, x - im2, y + im1);//1 - CGContextAddLineToPoint(ctx, x, y + im2);//3 - CGContextFillPath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im4, y - im4);//9 - CGContextAddLineToPoint(ctx, x, y + im2);//3 - CGContextAddLineToPoint(ctx, x + im2, y + im1);//5 - CGContextFillPath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im4, y - im4);//9 - CGContextAddLineToPoint(ctx, x + im2, y + im1);//5 - CGContextAddLineToPoint(ctx, x + im4, y - im4);//7 - CGContextFillPath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenStar(CGContextRef ctx, unsigned n, const TPoint *xy, Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im1 = Int_t(0.66 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - const Int_t im3 = Int_t(2.66 * markerSize + 0.5); - const Int_t im4 = Int_t(1.33 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y - im4); - CGContextAddLineToPoint(ctx, x - im2, y + im1); - CGContextAddLineToPoint(ctx, x - im3, y + im); - CGContextAddLineToPoint(ctx, x, y + im2); - CGContextAddLineToPoint(ctx, x + im3, y + im); - CGContextAddLineToPoint(ctx, x + im2, y + im1); - CGContextAddLineToPoint(ctx, x + im, y - im4); - CGContextAddLineToPoint(ctx, x + im4, y - im4); - CGContextAddLineToPoint(ctx, x, y - im); - CGContextAddLineToPoint(ctx, x - im4, y - im4); - CGContextAddLineToPoint(ctx, x - im, y - im4); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenSquareDiagonal(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y - im); - CGContextAddLineToPoint(ctx, x + im, y - im); - CGContextAddLineToPoint(ctx, x + im, y + im); - CGContextAddLineToPoint(ctx, x - im, y + im); - CGContextAddLineToPoint(ctx, x - im, y - im); - CGContextAddLineToPoint(ctx, x + im, y + im); - CGContextStrokePath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y + im); - CGContextAddLineToPoint(ctx, x + im, y - im); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenDiamondCross(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y ); - CGContextAddLineToPoint(ctx, x , y - im); - CGContextAddLineToPoint(ctx, x + im, y ); - CGContextAddLineToPoint(ctx, x , y + im); - CGContextAddLineToPoint(ctx, x - im, y ); - CGContextAddLineToPoint(ctx, x + im, y ); - CGContextStrokePath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y + im); - CGContextAddLineToPoint(ctx, x , y - im); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenThreeTriangles(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x - im, y ); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x + im, y ); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x , y ); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOctagonCross(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x - im, y ); - CGContextAddLineToPoint(ctx, x - im, y -im2); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x + im, y -im2); - CGContextAddLineToPoint(ctx, x + im, y +im2); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x - im, y +im2); - CGContextAddLineToPoint(ctx, x - im, y ); - CGContextAddLineToPoint(ctx, x + im, y ); - CGContextStrokePath(ctx); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y - im); - CGContextAddLineToPoint(ctx, x , y + im); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFilledThreeTriangles(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x - im, y ); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x + im, y ); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x , y ); - CGContextFillPath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenFourTrianglesX(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x + im, y +im2); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x + im, y -im2); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x - im, y -im2); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x - im, y +im2); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x , y ); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFilledFourTrianglesX(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x + im, y +im2); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x + im, y -im2); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x - im, y -im2); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x - im, y +im2); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x , y ); - CGContextFillPath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenDoubleDiamond(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im4 = Int_t(markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y + im); - CGContextAddLineToPoint(ctx, x -im4, y +im4); - CGContextAddLineToPoint(ctx, x - im, y ); - CGContextAddLineToPoint(ctx, x -im4, y -im4); - CGContextAddLineToPoint(ctx, x , y - im); - CGContextAddLineToPoint(ctx, x +im4, y -im4); - CGContextAddLineToPoint(ctx, x + im, y ); - CGContextAddLineToPoint(ctx, x +im4, y +im4); - CGContextAddLineToPoint(ctx, x , y + im); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFilledDoubleDiamond(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im4 = Int_t(markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y + im); - CGContextAddLineToPoint(ctx, x -im4, y +im4); - CGContextAddLineToPoint(ctx, x - im, y ); - CGContextAddLineToPoint(ctx, x -im4, y -im4); - CGContextAddLineToPoint(ctx, x , y - im); - CGContextAddLineToPoint(ctx, x +im4, y -im4); - CGContextAddLineToPoint(ctx, x + im, y ); - CGContextAddLineToPoint(ctx, x +im4, y +im4); - CGContextAddLineToPoint(ctx, x , y + im); - CGContextFillPath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenFourTrianglesPlus(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - const Int_t im4 = Int_t(1.33 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x , y ); - CGContextAddLineToPoint(ctx, x + im, y +im2); - CGContextAddLineToPoint(ctx, x + im, y -im2); - CGContextAddLineToPoint(ctx, x - im, y +im2); - CGContextAddLineToPoint(ctx, x - im, y -im2); - CGContextAddLineToPoint(ctx, x , y ); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFilledFourTrianglesPlus(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - const Int_t im4 = Int_t(0.2 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x +im4, y +im4); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x -im4, y +im4); - CGContextAddLineToPoint(ctx, x - im, y +im2); - CGContextAddLineToPoint(ctx, x - im, y -im2); - CGContextAddLineToPoint(ctx, x -im4, y -im4); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x +im4, y -im4); - CGContextAddLineToPoint(ctx, x + im, y -im2); - CGContextAddLineToPoint(ctx, x + im, y +im2); - CGContextAddLineToPoint(ctx, x +im4, y +im4); - CGContextFillPath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerOpenCrossX(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y + im2); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x - im, y +im2); - CGContextAddLineToPoint(ctx, x -im2, y ); - CGContextAddLineToPoint(ctx, x - im, y -im2); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x , y -im2); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x + im, y -im2); - CGContextAddLineToPoint(ctx, x +im2, y ); - CGContextAddLineToPoint(ctx, x + im, y +im2); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x , y +im2); - CGContextStrokePath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFilledCrossX(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(2.0 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x -im2, y - im2*1.005); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x +im2, y -im2); - CGContextAddLineToPoint(ctx, x + im, y -im2); - CGContextAddLineToPoint(ctx, x + im, y +im2); - CGContextAddLineToPoint(ctx, x +im2, y +im2); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x -im2, y +im2); - CGContextAddLineToPoint(ctx, x - im, y +im2); - CGContextAddLineToPoint(ctx, x - im, y -im2); - CGContextAddLineToPoint(ctx, x -im2, y -im2*0.995); - CGContextAddLineToPoint(ctx, x -im2, y +im2); - CGContextAddLineToPoint(ctx, x +im2, y +im2); - CGContextAddLineToPoint(ctx, x +im2, y -im2); - CGContextAddLineToPoint(ctx, x -im2, y -im2*1.005); - CGContextFillPath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFourSuaresX(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(2.00 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x , y + im2*1.01); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x - im, y +im2); - CGContextAddLineToPoint(ctx, x -im2, y ); - CGContextAddLineToPoint(ctx, x - im, y -im2); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x , y -im2); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x + im, y -im2); - CGContextAddLineToPoint(ctx, x +im2, y ); - CGContextAddLineToPoint(ctx, x + im, y +im2); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x , y +im2*0.99); - CGContextAddLineToPoint(ctx, x +im2*0.99, y ); - CGContextAddLineToPoint(ctx, x , y -im2*0.99); - CGContextAddLineToPoint(ctx, x -im2*0.99, y ); - CGContextAddLineToPoint(ctx, x , y +im2*0.99); - CGContextFillPath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawMarkerFourSuaresPlus(CGContextRef ctx, unsigned n, const TPoint *xy, - Size_t markerSize) -{ - const Int_t im = Int_t(4 * markerSize + 0.5); - const Int_t im2 = Int_t(1.33 * markerSize + 0.5); - - for (unsigned i = 0; i < n; ++i) { - const Double_t x = xy[i].fX; - const Double_t y = xy[i].fY; - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, x -im2, y - im2*1.01); - CGContextAddLineToPoint(ctx, x -im2, y + im); - CGContextAddLineToPoint(ctx, x - im, y +im2); - CGContextAddLineToPoint(ctx, x -im2, y ); - CGContextAddLineToPoint(ctx, x - im, y -im2); - CGContextAddLineToPoint(ctx, x -im2, y - im); - CGContextAddLineToPoint(ctx, x , y -im2); - CGContextAddLineToPoint(ctx, x +im2, y - im); - CGContextAddLineToPoint(ctx, x + im, y -im2); - CGContextAddLineToPoint(ctx, x +im2, y ); - CGContextAddLineToPoint(ctx, x + im, y +im2); - CGContextAddLineToPoint(ctx, x +im2, y + im); - CGContextAddLineToPoint(ctx, x , y +im2*0.99); - CGContextAddLineToPoint(ctx, x +im2*0.99, y ); - CGContextAddLineToPoint(ctx, x , y -im2*0.99); - CGContextAddLineToPoint(ctx, x -im2*0.99, y ); - CGContextAddLineToPoint(ctx, x , y +im2*0.99); - CGContextFillPath(ctx); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawPolyMarker(CGContextRef ctx, unsigned nPoints, const TPoint *xy, Size_t markerSize, Style_t markerStyle) -{ - switch (markerStyle) { - case kDot: - DrawMarkerDot(ctx, nPoints, xy); - break; - case kPlus: - DrawMarkerPlus(ctx, nPoints, xy, markerSize); - break; - case kStar: - DrawMarkerStar(ctx, nPoints, xy, markerSize); - break; - case kCircle: - case kOpenCircle: - DrawMarkerOpenCircle(ctx, nPoints, xy, markerSize); - break; - case kMultiply: - DrawMarkerX(ctx, nPoints, xy, markerSize); - break; - case kFullDotSmall: - DrawMarkerFullDotSmall(ctx, nPoints, xy); - break; - case kFullDotMedium: - DrawMarkerFullDotMedium(ctx, nPoints, xy); - break; - case kFullDotLarge: - case kFullCircle: - DrawMarkerFullDotLarge(ctx, nPoints, xy, markerSize); - break; - case kFullSquare: - DrawMarkerFullSquare(ctx, nPoints, xy, markerSize); - break; - case kFullTriangleUp: - DrawMarkerFullTriangleUp(ctx, nPoints, xy, markerSize); - break; - case kFullTriangleDown: - DrawMarkerFullTriangleDown(ctx, nPoints, xy, markerSize); - break; - case kOpenSquare: - DrawMarkerOpenSquare(ctx, nPoints, xy, markerSize); - break; - case kOpenTriangleUp: - DrawMarkerOpenTriangleUp(ctx, nPoints, xy, markerSize); - break; - case kOpenTriangleDown: - DrawMarkerOpenTriangleDown(ctx, nPoints, xy, markerSize); - break; - case kOpenDiamond: - DrawMarkerOpenDiamond(ctx, nPoints, xy, markerSize); - break; - case kFullDiamond: - DrawMarkerFullDiamond(ctx, nPoints, xy, markerSize); - break; - case kOpenCross: - DrawMarkerOpenCross(ctx, nPoints, xy, markerSize); - break; - case kFullCross: - DrawMarkerFullCross(ctx, nPoints, xy, markerSize); - break; - case kFullStar: - DrawMarkerFullStar(ctx, nPoints, xy, markerSize); - break; - case kOpenStar: - DrawMarkerOpenStar(ctx, nPoints, xy, markerSize); - break; - case kOpenDiamondCross: // YS - DrawMarkerOpenDiamondCross(ctx, nPoints, xy, markerSize); - break; - case kOpenSquareDiagonal: // YS - DrawMarkerOpenSquareDiagonal(ctx, nPoints, xy, markerSize); - break; - case kOpenThreeTriangles: // YS - DrawMarkerOpenThreeTriangles(ctx, nPoints, xy, markerSize); - break; - case kOctagonCross: // YS - DrawMarkerOctagonCross(ctx, nPoints, xy, markerSize); - break; - case kFullThreeTriangles: // YS - DrawMarkerFilledThreeTriangles(ctx, nPoints, xy, markerSize); - break; - case kOpenFourTrianglesX: // YS - DrawMarkerOpenFourTrianglesX(ctx, nPoints, xy, markerSize); - break; - case kFullFourTrianglesX: // YS - DrawMarkerFilledFourTrianglesX(ctx, nPoints, xy, markerSize); - break; - case kOpenDoubleDiamond: // YS - DrawMarkerOpenDoubleDiamond(ctx, nPoints, xy, markerSize); - break; - case kFullDoubleDiamond: // YS - DrawMarkerFilledDoubleDiamond(ctx, nPoints, xy, markerSize); - break; - case kOpenFourTrianglesPlus: // YS - DrawMarkerOpenFourTrianglesPlus(ctx, nPoints, xy, markerSize); - break; - case kFullFourTrianglesPlus: // YS - DrawMarkerFilledFourTrianglesPlus(ctx, nPoints, xy, markerSize); - break; - case kOpenCrossX: // YS - DrawMarkerOpenCrossX(ctx, nPoints, xy, markerSize); - break; - case kFullCrossX: // YS - DrawMarkerFilledCrossX(ctx, nPoints, xy, markerSize); - break; - case kFourSquaresX: // YS - DrawMarkerFourSquaresX(ctx, nPoints, xy, markerSize); - break; - case kFourSquaresPlus: // YS - DrawMarkerFourSquaresPlus(ctx, nPoints, xy, markerSize); - break; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void DrawPolyMarker(CGContextRef ctx, const std::vector &xy, Size_t markerSize, Style_t markerStyle) -{ - DrawPolyMarker(ctx, xy.size(), &xy[0], markerSize, markerStyle); -} - -}//namespace GraphicUtils -}//namespace iOS -}//namespace ROOT diff --git a/graf2d/ios/src/IOSPad.cxx b/graf2d/ios/src/IOSPad.cxx deleted file mode 100644 index dbb1e8212e032..0000000000000 --- a/graf2d/ios/src/IOSPad.cxx +++ /dev/null @@ -1,2386 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#include -#include - -#include -#include -#include - -#include "TViewer3DPad.h" -#include "TMultiGraph.h" -#include "TVirtualX.h" -#include "TString.h" -#include "THStack.h" -#include "TFrame.h" -#include "TPoint.h" -#include "TColor.h" -#include "TGraph.h" -#include "TStyle.h" -#include "TView.h" -#include "TROOT.h" -#include "TMath.h" -#include "TH1.h" - -//Internal (module) includes. -#include "IOSGraphicUtils.h" -#include "IOSFillPatterns.h" -#include "IOSPad.h" - -namespace ROOT { -namespace iOS { - -//////////////////////////////////////////////////////////////////////////////// - -Pad::Pad(UInt_t w, UInt_t h) -{ - fViewW = w; - fViewH = h; - - fX1 = 0.; - fX2 = 1.; - fY1 = 0.; - fY2 = 1.; - - fUxmin = 0.; - fUymin = 0.; - fUxmax = 0.; - fUymax = 0.; - - fTheta = 30; - fPhi = 50; - - fAspectRatio = 0.; - - fTickx = gStyle->GetPadTickX(); - fTicky = gStyle->GetPadTickY(); - - fLogx = gStyle->GetOptLogx(); - fLogy = gStyle->GetOptLogy(); - fLogz = gStyle->GetOptLogz(); - - fBorderSize = 0; - fBorderMode = 0; - - fGridx = gStyle->GetPadGridX(); - fGridy = gStyle->GetPadGridY(); - - fAbsCoord = kFALSE; - fEditable = kTRUE; - fFixedAspectRatio = kFALSE; - - fFrame = 0; - fView = 0; - - fViewer3D = 0; - fSelectionIsValid = kFALSE; - fSelectionAreaWidth = w; - fSelected = 0; - fParentOfSelected = 0; - fInSelectionMode = kFALSE; - fInHighlightMode = kFALSE; - fObjectID = 1; - - fContains3DObject = kFALSE; - - cd(); - - // Set pad parameters and Compute conversion coefficients - SetPad("", "", 0., 0., 1., 1., 0, 0, 0); - - Range(0., 0., 1., 1.); -} - -//////////////////////////////////////////////////////////////////////////////// - -Pad::~Pad() -{ - delete fFrame; - delete fViewer3D; - //Absolutely not clear, if pad owns view or not, - //because I've seen code wich delete's and creates view outside pad - //and ignores pad. - //At the same time, there is a code in a pad, which can delete fView. - //What a mess! - delete fView; -} - -//////////////////////////////////////////////////////////////////////////////// - -const char *Pad::GetName() const -{ - return "iOSPad"; -} - -//////////////////////////////////////////////////////////////////////////////// - -const char *Pad::GetTitle() const -{ - return "iOSPad"; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::Clear(Option_t *) -{ - fSelectionIsValid = kFALSE; - fSelected = 0; - fParentOfSelected = 0; - fSelectables.clear(); - fParentPainters.clear(); - fSelectionBuffer.clear(); - fObjectID = 1; - - fPrimitives.SetOwner(kFALSE); - fPrimitives.Clear(); - - fContains3DObject = kFALSE; - - Range(0., 0., 1., 1.); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::SetViewWH(UInt_t viewW, UInt_t viewH) -{ - fViewW = viewW; - fViewH = viewH; - - ResizePad(); - - fPainter.SetTransform(fViewW, GetX1(), GetX2(), fViewH, GetY1(), GetY2()); -} - -//////////////////////////////////////////////////////////////////////////////// - -UInt_t Pad::GetWw() const -{ - return fViewW; -} - -//////////////////////////////////////////////////////////////////////////////// - -UInt_t Pad::GetWh() const -{ - return fViewH; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Fix pad aspect ratio to current value if fixed is true. - -void Pad::SetFixedAspectRatio(Bool_t fixed) -{ - if (fixed) { - if (!fFixedAspectRatio) { - if (fHNDC != 0.) - fAspectRatio = fWNDC / fHNDC; - else { - //cannot fix aspect ratio, height of pad is 0 - return; - } - fFixedAspectRatio = kTRUE; - } - } else { - fFixedAspectRatio = kFALSE; - fAspectRatio = 0; - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Convert x from pad to X. - -Double_t Pad::PadtoX(Double_t x) const -{ - if (fLogx && x < 50) - return Double_t(TMath::Exp(2.302585092994 * x)); - - return x; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Convert y from pad to Y. - -Double_t Pad::PadtoY(Double_t y) const -{ - if (fLogy && y < 50) - return Double_t(TMath::Exp(2.302585092994 * y)); - - return y; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Convert x from X to pad. - -Double_t Pad::XtoPad(Double_t x) const -{ - if (fLogx) { - if (x > 0) - x = TMath::Log10(x); - else - x = fUxmin; - } - - return x; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Convert y from Y to pad. - -Double_t Pad::YtoPad(Double_t y) const -{ - if (fLogy) { - if (y > 0) - y = TMath::Log10(y); - else - y = fUymin; - } - - return y; -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t Pad::UtoPixel(Double_t u) const -{ - Double_t val; - if (fAbsCoord) - val = fUtoAbsPixelk + u * fUtoPixel; - else - val = u * fUtoPixel; - - if (val < -kMaxPixel) - return -kMaxPixel; - - if (val > kMaxPixel) - return kMaxPixel; - - return Int_t(val); -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t Pad::VtoPixel(Double_t v) const -{ - Double_t val; - if (fAbsCoord) - val = fVtoAbsPixelk + v * fVtoPixel; - else - val = fVtoPixelk + v * fVtoPixel; - - if (val < -kMaxPixel) - return -kMaxPixel; - - if (val > kMaxPixel) - return kMaxPixel; - - return Int_t(val); -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t Pad::XtoAbsPixel(Double_t x) const -{ - const Double_t val = fXtoAbsPixelk + x * fXtoPixel; - if (val < -kMaxPixel) - return -kMaxPixel; - if (val > kMaxPixel) - return kMaxPixel; - - return Int_t(val); -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t Pad::YtoAbsPixel(Double_t y) const -{ - const Double_t val = fYtoAbsPixelk + y*fYtoPixel; - if (val < -kMaxPixel) - return -kMaxPixel; - if (val > kMaxPixel) - return kMaxPixel; - - return Int_t(val); -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t Pad::XtoPixel(Double_t x) const -{ - Double_t val; - if (fAbsCoord) - val = fXtoAbsPixelk + x * fXtoPixel; - else - val = fXtoPixelk + x * fXtoPixel; - - if (val < -kMaxPixel) - return -kMaxPixel; - if (val > kMaxPixel) - return kMaxPixel; - - return Int_t(val); -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t Pad::YtoPixel(Double_t y) const -{ - Double_t val; - if (fAbsCoord) - val = fYtoAbsPixelk + y * fYtoPixel; - else - val = fYtoPixelk + y * fYtoPixel; - - if (val < -kMaxPixel) - return -kMaxPixel; - if (val > kMaxPixel) - return kMaxPixel; - - return Int_t(val); -} - -//////////////////////////////////////////////////////////////////////////////// - -Double_t Pad::PixeltoX(Int_t px) -{ - if (fAbsCoord) - return fAbsPixeltoXk + px * fPixeltoX; - else - return fPixeltoXk + px * fPixeltoX; -} - -//////////////////////////////////////////////////////////////////////////////// - -Double_t Pad::PixeltoY(Int_t py) -{ - if (fAbsCoord) - return fAbsPixeltoYk + py * fPixeltoY; - else - return fPixeltoYk + py * fPixeltoY; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set Lin/Log scale for X -/// value = 0 X scale will be linear -/// value = 1 X scale will be logarithmic (base 10) -/// value > 1 reserved for possible support of base e or other - -void Pad::SetLogx(Int_t value) -{ - fLogx = value; - delete fView; - fView = 0; -} - - -//////////////////////////////////////////////////////////////////////////////// -/// Set Lin/Log scale for Y -/// value = 0 Y scale will be linear -/// value = 1 Y scale will be logarithmic (base 10) -/// value > 1 reserved for possible support of base e or other - -void Pad::SetLogy(Int_t value) -{ - fLogy = value; - delete fView; - fView=0; -} - - -//////////////////////////////////////////////////////////////////////////////// -/// Set Lin/Log scale for Z - -void Pad::SetLogz(Int_t value) -{ - fLogz = value; - delete fView; - fView=0; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set canvas range for pad and resize the pad. If the aspect ratio -/// was fixed before the call it will be un-fixed. - -void Pad::SetPad(Double_t xlow, Double_t ylow, Double_t xup, Double_t yup) -{ - // Reorder points to make sure xlow,ylow is bottom left point and - // xup,yup is top right point. - if (xup < xlow) - std::swap(xup, xlow); - - if (yup < ylow) - std::swap(yup, ylow); - - fXlowNDC = xlow; - fYlowNDC = ylow; - fWNDC = xup - xlow; - fHNDC = yup - ylow; - - SetFixedAspectRatio(kFALSE); - - ResizePad(); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set all pad parameters. - -void Pad::SetPad(const char *, const char *, Double_t xlow, Double_t ylow, Double_t xup, - Double_t yup, Color_t color, Short_t bordersize, Short_t bordermode) -{ - SetFillStyle(1001); - SetBottomMargin(gStyle->GetPadBottomMargin()); - SetTopMargin(gStyle->GetPadTopMargin()); - SetLeftMargin(gStyle->GetPadLeftMargin()); - SetRightMargin(gStyle->GetPadRightMargin()); - - if (color >= 0) - SetFillColor(color); - else - SetFillColor(gStyle->GetPadColor()); - - if (bordersize < 0) - fBorderSize = gStyle->GetPadBorderSize(); - else - fBorderSize = bordersize; - - if (bordermode < -1) - fBorderMode = gStyle->GetPadBorderMode(); - else - fBorderMode = bordermode; - - SetPad(xlow, ylow, xup, yup); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set pad vertical (default) or horizontal - -void Pad::SetVertical(Bool_t vert) -{ - if (vert) - ResetBit(kHori); - else - SetBit(kHori); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Return pad world coordinates range. - -void Pad::GetRange(Double_t &x1, Double_t &y1, Double_t &x2, Double_t &y2) -{ - x1 = fX1; - y1 = fY1; - x2 = fX2; - y2 = fY2; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set world coordinate system for the pad. -/// Emits signal "RangeChanged()", in the slot get the range -/// via GetRange(). - -void Pad::Range(Double_t x1, Double_t y1, Double_t x2, Double_t y2) -{ - if ((x1 >= x2) || (y1 >= y2)) { - //Error("Range", "illegal world coordinates range: x1=%f, y1=%f, x2=%f, y2=%f",x1,y1,x2,y2); - return; - } - - fUxmin = x1; - fUxmax = x2; - fUymin = y1; - fUymax = y2; - - if (fX1 == x1 && fY1 == y1 && fX2 == x2 && fY2 == y2) return; - - fX1 = x1; - fY1 = y1; - fX2 = x2; - fY2 = y2; - - // compute pad conversion coefficients - ResizePad(); - - fPainter.SetTransform(GetWw(), GetX1(), GetX2(), GetWh(), GetY1(), GetY2()); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Return pad axis coordinates range. - -void Pad::GetRangeAxis(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax) -{ - xmin = fUxmin; - ymin = fUymin; - xmax = fUxmax; - ymax = fUymax; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set axis coordinate system for the pad. -/// The axis coordinate system is a subset of the world coordinate system -/// xmin,ymin is the origin of the current coordinate system, -/// xmax is the end of the X axis, ymax is the end of the Y axis. -/// By default a margin of 10 per cent is left on all sides of the pad -/// Emits signal "RangeAxisChanged()", in the slot get the axis range -/// via GetRangeAxis(). - -void Pad::RangeAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax) -{ - if ((xmin >= xmax) || (ymin >= ymax)) { - //Error("RangeAxis", "illegal axis coordinates range: xmin=%f, ymin=%f, xmax=%f, ymax=%f", xmin, ymin, xmax, ymax); - return; - } - - fUxmin = xmin; - fUymin = ymin; - fUxmax = xmax; - fUymax = ymax; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Return lower and upper bounds of the pad in NDC coordinates. - -void Pad::GetPadPar(Double_t &xlow, Double_t &ylow, Double_t &xup, Double_t &yup) -{ - xlow = fXlowNDC; - ylow = fYlowNDC; - xup = fXlowNDC+fWNDC; - yup = fYlowNDC+fHNDC; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Overrride TAttFill::FillStyle for TPad because we want to handle style=0 -/// as style 4000. - -void Pad::SetFillStyle(Style_t fillStyle) -{ - if (!fillStyle) - fillStyle = 4000; - - TAttFill::SetFillStyle(fillStyle); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set pad editable yes/no -/// If a pad is not editable: -/// - one cannot modify the pad and its objects via the mouse. -/// - one cannot add new objects to the pad - -void Pad::SetEditable(Bool_t mode) -{ - fEditable = mode; -} - -//////////////////////////////////////////////////////////////////////////////// - -TVirtualPad *Pad::cd(Int_t) -{ - gPad = this; - fPainter.SetTransform(GetWw(), GetX1(), GetX2(), GetWh(), GetY1(), GetY2()); - - return this; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set the current TView. Delete previous view if view=0. -/// This code was taken from original TPad and it dies after -/// attempt to free memory - view was already deleted by THistPainter. -/// So, I simply assume, that pad does not own fView. - -void Pad::SetView(TView *view) -{ - /* - if (!view) - delete fView; - */ - fView = view; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Compute pad conversion coefficients. -/// -/// Conversion from x to px & y to py -/// ================================= -/// -/// x - xmin px - pxlow xrange = xmax-xmin -/// -------- = ---------- with -/// xrange pxrange pxrange = pxmax-pxmin -/// -/// pxrange(x-xmin) -/// ==> px = --------------- + pxlow = fXtoPixelk + fXtoPixel * x -/// xrange -/// -/// ==> fXtoPixelk = pxlow - pxrange*xmin/xrange -/// fXtoPixel = pxrange/xrange -/// where pxlow = fAbsXlowNDC*fCw -/// pxrange = fAbsWNDC*fCw -/// -/// -/// y - ymin py - pylow yrange = ymax-ymin -/// -------- = ---------- with -/// yrange pyrange pyrange = pymax-pymin -/// -/// pyrange(y-ymin) -/// ==> py = --------------- + pylow = fYtoPixelk + fYtoPixel * y -/// yrange -/// -/// ==> fYtoPixelk = pylow - pyrange*ymin/yrange -/// fYtoPixel = pyrange/yrange -/// where pylow = (1-fAbsYlowNDC)*fCh -/// pyrange = -fAbsHNDC*fCh -/// -///- Conversion from px to x & py to y -/// ================================= -/// -/// xrange(px-pxlow) -/// ==> x = ---------------- + xmin = fPixeltoXk + fPixeltoX * px -/// pxrange -///- -/// ==> fPixeltoXk = xmin - pxlow*xrange/pxrange -/// fPixeltoX = xrange/pxrange -/// -/// yrange(py-pylow) -/// ==> y = ---------------- + ymin = fPixeltoYk + fPixeltoY * py -/// pyrange -///- -/// ==> fPixeltoYk = ymin - pylow*yrange/pyrange -/// fPixeltoY = yrange/pyrange -/// -///----------------------------------------------------------------------- -/// -/// Computation of the coefficients in case of LOG scales -///- ===================================================== -/// -/// A, Conversion from pixel coordinates to world coordinates -/// -/// Log(x) - Log(xmin) Log(x/xmin) px - pxlow -/// u = --------------------- = ------------- = ----------- -/// Log(xmax) - Log(xmin) Log(xmax/xmin) pxrange -/// -/// ==> Log(x/xmin) = u*Log(xmax/xmin) -/// x = xmin*exp(u*Log(xmax/xmin) -/// Let alfa = Log(xmax/xmin)/fAbsWNDC -/// -/// x = xmin*exp(-alfa*pxlow) + exp(alfa*px) -/// x = fPixeltoXk*exp(fPixeltoX*px) -/// ==> fPixeltoXk = xmin*exp(-alfa*pxlow) -/// fPixeltoX = alfa -/// -/// Log(y) - Log(ymin) Log(y/ymin) pylow - py -/// v = --------------------- = ------------- = ----------- -/// Log(ymax) - Log(ymin) Log(ymax/ymin) pyrange -/// -/// Let beta = Log(ymax/ymin)/pyrange -/// Log(y/ymin) = beta*pylow - beta*py -/// y/ymin = exp(beta*pylow - beta*py) -/// y = ymin*exp(beta*pylow)*exp(-beta*py) -/// ==> y = fPixeltoYk*exp(fPixeltoY*py) -/// fPixeltoYk = ymin*exp(beta*pylow) -/// fPixeltoY = -beta -/// -///- B, Conversion from World coordinates to pixel coordinates -/// -/// px = pxlow + u*pxrange -/// = pxlow + Log(x/xmin)/alfa -/// = pxlow -Log(xmin)/alfa + Log(x)/alfa -/// = fXtoPixelk + fXtoPixel*Log(x) -/// ==> fXtoPixelk = pxlow -Log(xmin)/alfa -/// ==> fXtoPixel = 1/alfa -/// -/// py = pylow - Log(y/ymin)/beta -/// = fYtoPixelk + fYtoPixel*Log(y) -/// ==> fYtoPixelk = pylow - Log(ymin)/beta -/// fYtoPixel = 1/beta - -void Pad::ResizePad(Option_t *) -{ - // Recompute subpad positions in case pad has been moved/resized - fAbsXlowNDC = fXlowNDC; - fAbsYlowNDC = fYlowNDC; - fAbsWNDC = fWNDC; - fAbsHNDC = fHNDC; - Double_t ww = fViewW; - Double_t wh = fViewH; - Double_t pxlow = fAbsXlowNDC * ww; - Double_t pylow = (1-fAbsYlowNDC) * wh; - Double_t pxrange = fAbsWNDC * ww; - Double_t pyrange = -fAbsHNDC * wh; - // Linear X axis - Double_t rounding = 0.00005; - Double_t xrange = fX2 - fX1; - fXtoAbsPixelk = rounding + pxlow - pxrange*fX1/xrange; //origin at left - fXtoPixelk = rounding + -pxrange*fX1/xrange; - fXtoPixel = pxrange/xrange; - fAbsPixeltoXk = fX1 - pxlow*xrange/pxrange; - fPixeltoXk = fX1; - fPixeltoX = xrange/pxrange; - // Linear Y axis - Double_t yrange = fY2 - fY1; - fYtoAbsPixelk = rounding + pylow - pyrange*fY1/yrange; //origin at top - fYtoPixelk = rounding + -pyrange - pyrange*fY1/yrange; - fYtoPixel = pyrange/yrange; - fAbsPixeltoYk = fY1 - pylow*yrange/pyrange; - fPixeltoYk = fY1; - fPixeltoY = yrange/pyrange; - // Coefficients to convert from pad NDC coordinates to pixel coordinates - - fUtoAbsPixelk = rounding + pxlow; - fUtoPixelk = rounding; - fUtoPixel = pxrange; - fVtoAbsPixelk = rounding + pylow; - fVtoPixelk = -pyrange; - fVtoPixel = pyrange; - gVirtualX->SetLineWidth(-1); - gVirtualX->SetTextSize(-1); - if (fView) - fView->ResizePad(); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Get frame. -///Original TPad has a COMPLETE MESS here. I'm trying to fix this. - -TFrame *Pad::GetFrame() -{ - if (!fFrame) { - fFrame = new TFrame(0., 0., 1., 1.); - - Int_t framecolor = GetFrameFillColor(); - - if (!framecolor) - framecolor = GetFillColor(); - - fFrame->SetFillColor(framecolor); - fFrame->SetFillStyle(GetFrameFillStyle()); - fFrame->SetLineColor(GetFrameLineColor()); - fFrame->SetLineStyle(GetFrameLineStyle()); - fFrame->SetLineWidth(GetFrameLineWidth()); - fFrame->SetBorderSize(GetFrameBorderSize()); - fFrame->SetBorderMode(GetFrameBorderMode()); - } - - return fFrame; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Final-overrider for TVirtualPad. - -TObject *Pad::GetPrimitive(const char *name) const -{ - TIter next(&fPrimitives); - TObject *obj = 0; - - while ((obj=next())) { - if (!strcmp(name, obj->GetName())) - return obj; - - TObject *found = obj->FindObject(name); - if (found) - return found; - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::Paint(Option_t *) -{ - cd(); - - //First, fill pad's area with white - //- it's required in case this pad - //has some fill pattern. - gVirtualX->SetFillStyle(1001); - gVirtualX->SetFillColor(0); - PaintBox(fX1,fY1,fX2,fY2); - // - PaintBorder(GetFillColor(), kTRUE); - - TObjOptLink *lnk = (TObjOptLink*)GetListOfPrimitives()->FirstLink(); - TObject *obj; - - while (lnk) { - obj = lnk->GetObject(); - obj->Paint(lnk->GetOption()); - lnk = (TObjOptLink*)lnk->Next(); - - //This is the special case, which can not - //be processed in a generic way at the moment. - if (obj->InheritsFrom("TF2")) - fContains3DObject = kTRUE; - } - - Modified(kFALSE); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::PaintForSelection() -{ - fInSelectionMode = kTRUE; - fPainter.SetPainterMode(Painter::kPaintToSelectionBuffer); - // - fObjectID = 1; - fSelectables.clear(); - fParentPainters.clear(); - - TObjOptLink *lnk = (TObjOptLink*)GetListOfPrimitives()->FirstLink(); - TObject *obj; - - while (lnk) { - obj = lnk->GetObject(); - obj->Paint(lnk->GetOption()); - lnk = (TObjOptLink*)lnk->Next(); - } - // - fPainter.SetPainterMode(Painter::kPaintToView); - fInSelectionMode = kFALSE; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::PaintShadowForSelected() const -{ - fInHighlightMode = kTRUE; - fPainter.SetPainterMode(Painter::kPaintShadow); - - if (fParentOfSelected) { - fParentOfSelected->Paint(GetSelectedParentDrawOption()); - } else if (fSelected) { - fSelected->Paint(GetSelectedDrawOption()); - } - - fPainter.SetPainterMode(Painter::kPaintToView); - fInHighlightMode = kFALSE; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::PaintSelected() const -{ - fInHighlightMode = kTRUE; - - fPainter.SetPainterMode(Painter::kPaintSelected); - - if (fParentOfSelected) - fParentOfSelected->Paint(GetSelectedParentDrawOption()); - else if (fSelected) - fSelected->Paint(GetSelectedDrawOption()); - - fPainter.SetPainterMode(Painter::kPaintToView); - fInHighlightMode = kFALSE; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Paint box in CurrentPad World coordinates. -/// -/// if option[0] = 's' the box is forced to be paint with style=0 -/// if option[0] = 'l' the box contour is drawn - -void Pad::PaintBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Option_t *option) -{ - Int_t style0 = gVirtualX->GetFillStyle(); - Int_t style = style0; - - if (option[0] == 's') { - gVirtualX->SetFillStyle(0); - style = 0; - } - - if (style) { - if (style > 3000 && style < 4000) { - if (style < 3026) { - // draw stipples with fFillColor foreground - fPainter.DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled); - } - - if (style >= 3100 && style < 4000) { - Double_t xb[4], yb[4]; - xb[0] = x1; xb[1] = x1; xb[2] = x2; xb[3] = x2; - yb[0] = y1; yb[1] = y2; yb[2] = y2; yb[3] = y1; - PaintFillAreaHatches(4, xb, yb, style); - return; - } - //special case for TAttFillCanvas - if (gVirtualX->GetFillColor() == 10) { - gVirtualX->SetFillColor(1); - fPainter.DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled); - gVirtualX->SetFillColor(10); - } - } else if (style >= 4000 && style <= 4100) { - // For style >=4000 we make the window transparent. - // From 4000 to 4100 the window is 100% transparent to 100% opaque - //ignore this style option when this is the canvas itself - fPainter.DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled); - } else { - fPainter.DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled); - } - - if (option[0] == 'l') fPainter.DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow); - } else { - fPainter.DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow); - if (option[0] == 's') gVirtualX->SetFillStyle(style0); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Paint fill area in CurrentPad World coordinates. - -void Pad::PaintFillArea(Int_t, Float_t *, Float_t *, Option_t *) -{ - throw std::runtime_error("Dummy version for floats"); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Paint fill area in CurrentPad World coordinates. - -void Pad::PaintFillArea(Int_t nn, Double_t *xx, Double_t *yy, Option_t *) -{ - if (nn < 3) return; - Int_t n=0; - Double_t xmin,xmax,ymin,ymax; - if (TestBit(TGraph::kClipFrame)) { - xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax; - } else { - xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2; - } - - Int_t nc = 2*nn+1; - - std::vector x(nc); - std::vector y(nc); - - n = ClipPolygon(nn, xx, yy, nc, &x[0], &y[0], xmin, ymin, xmax, ymax); - if (!n) - return; - - // Paint the fill area with hatches - Int_t fillstyle = gVirtualX->GetFillStyle(); - - if (fillstyle >= 3100 && fillstyle < 4000) { - PaintFillAreaHatches(nn, &x[0], &y[0], fillstyle); - return; - } - - fPainter.DrawFillArea(n, &x[0], &y[0]); -} - -//////////////////////////////////////////////////////////////////////////////// -///Paint histogram/graph frame. -///Original TPad has a COMPLETE MESS here, I can -///not understand, how it was possible to write. -///Trying to fix it at least to something sane. - -void Pad::PaintPadFrame(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax) -{ - if (!fFrame) - GetFrame(); - - fFrame->SetX1(xmin); - fFrame->SetX2(xmax); - fFrame->SetY1(ymin); - fFrame->SetY2(ymax); - - if (gROOT->GetForceStyle()) - fFrame->UseCurrentStyle(); - - if (!GetListOfPrimitives()->FindObject(fFrame)) { - GetListOfPrimitives()->AddFirst(fFrame); - //fFrame->SetBit(kMustCleanup); - } - - fFrame->Paint(); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Paint line in CurrentPad World coordinates. - -void Pad::PaintLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2) -{ - Double_t x[2], y[2]; - x[0] = x1; x[1] = x2; y[0] = y1; y[1] = y2; - - //If line is totally clipped, return - if (TestBit(TGraph::kClipFrame)) { - if (Clip(x,y,fUxmin,fUymin,fUxmax,fUymax) == 2) return; - } else { - if (Clip(x,y,fX1,fY1,fX2,fY2) == 2) return; - } - - fPainter.DrawLine(x[0], y[0], x[1], y[1]); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::PaintLineNDC(Double_t u1, Double_t v1,Double_t u2, Double_t v2) -{ - const Double_t xRange = GetX2() - GetX1(); - const Double_t yRange = GetY2() - GetY1(); - - fPainter.DrawLine(GetX1() + u1 * xRange, GetY1() + v1 * yRange, - GetX1() + u2 * xRange, GetY1() + v2 * yRange); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Paint 3-D line in the CurrentPad. - -void Pad::PaintLine3D(Float_t *p1, Float_t *p2) -{ - if (!fView) return; - - // convert from 3-D to 2-D pad coordinate system - Double_t xpad[6]; - Double_t temp[3]; - Int_t i; - for (i=0;i<3;i++) temp[i] = p1[i]; - fView->WCtoNDC(temp, &xpad[0]); - for (i=0;i<3;i++) temp[i] = p2[i]; - fView->WCtoNDC(temp, &xpad[3]); - PaintLine(xpad[0],xpad[1],xpad[3],xpad[4]); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Paint 3-D line in the CurrentPad. - -void Pad::PaintLine3D(Double_t *p1, Double_t *p2) -{ - //take into account perspective view - if (!fView) return; - // convert from 3-D to 2-D pad coordinate system - Double_t xpad[6]; - Double_t temp[3]; - Int_t i; - for (i=0;i<3;i++) temp[i] = p1[i]; - fView->WCtoNDC(temp, &xpad[0]); - for (i=0;i<3;i++) temp[i] = p2[i]; - fView->WCtoNDC(temp, &xpad[3]); - PaintLine(xpad[0],xpad[1],xpad[3],xpad[4]); -} - - -//////////////////////////////////////////////////////////////////////////////// -/// Paint polyline in CurrentPad World coordinates. - -void Pad::PaintPolyLine(Int_t n, Float_t *x, Float_t *y, Option_t *) -{ - if (n < 2) return; - - Double_t xmin,xmax,ymin,ymax; - if (TestBit(TGraph::kClipFrame)) { - xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax; - } else { - xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2; - } - Int_t i, i1=-1,np=1; - for (i=0; i 0 || TestBit(TGraph::kClipFrame)) { - xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax; - } else { - xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2; - } - Int_t i,i1=-1,np=0; - for (i=0; i= xmin && x[i] <= xmax && y[i] >= ymin && y[i] <= ymax) { - np++; - if (i1 < 0) i1 = i; - if (i < n-1) continue; - } - if (np == 0) continue; - - fPainter.DrawPolyMarker(np, &x[i1], &y[i1]); - - i1 = -1; - np = 0; - } -} - - -//////////////////////////////////////////////////////////////////////////////// -/// Paint polymarker in CurrentPad World coordinates. - -void Pad::PaintPolyMarker(Int_t nn, Double_t *x, Double_t *y, Option_t *) -{ - Int_t n = TMath::Abs(nn); - Double_t xmin,xmax,ymin,ymax; - if (nn > 0 || TestBit(TGraph::kClipFrame)) { - xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax; - } else { - xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2; - } - Int_t i,i1=-1,np=0; - for (i=0; i= xmin && x[i] <= xmax && y[i] >= ymin && y[i] <= ymax) { - np++; - if (i1 < 0) i1 = i; - if (i < n-1) continue; - } - if (np == 0) continue; - - fPainter.DrawPolyMarker(np, &x[i1], &y[i1]); - - i1 = -1; - np = 0; - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Paint text in CurrentPad World coordinates. - -void Pad::PaintText(Double_t x, Double_t y, const char *text) -{ - fPainter.DrawText(x, y, text, TVirtualPadPainter::kClear); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::PaintText(Double_t, Double_t, const wchar_t *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -/// Paint text in CurrentPad NDC coordinates. - -void Pad::PaintTextNDC(Double_t u, Double_t v, const char *text) -{ - const Double_t xRange = GetX2() - GetX1(); - const Double_t yRange = GetY2() - GetY1(); - fPainter.DrawText(gPad->GetX1() + u * xRange, gPad->GetY1() + v * yRange, text, TVirtualPadPainter::kClear); -} - -//////////////////////////////////////////////////////////////////////////////// - -void PaintTextNDC(Double_t, Double_t, const wchar_t *) -{ -} - - -//////////////////////////////////////////////////////////////////////////////// -/// Draw a pad frame -/// -/// Compute real pad range taking into account all margins -/// Use services of TH1F class - -TH1F *Pad::DrawFrame(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, const char *title) -{ - Pad *padsav = (Pad*)gPad; - if (this != padsav) { - Warning("DrawFrame","Drawframe must be called for the current pad only"); - return padsav->DrawFrame(xmin,ymin,xmax,ymax,title); - } - - cd(); - - TH1F *hframe = (TH1F*)FindObject("hframe"); - if (hframe) delete hframe; - Int_t nbins = 1000; - //if log scale in X, use variable bin size linear with log(x) - //this gives a better precision when zooming on the axis - if (fLogx && xmin > 0 && xmax > xmin) { - Double_t xminl = TMath::Log(xmin); - Double_t xmaxl = TMath::Log(xmax); - Double_t dx = (xmaxl-xminl)/nbins; - Double_t *xbins = new Double_t[nbins+1]; - xbins[0] = xmin; - for (Int_t i=1;i<=nbins;i++) { - xbins[i] = TMath::Exp(xminl+i*dx); - } - hframe = new TH1F("hframe",title,nbins,xbins); - delete [] xbins; - } else { - hframe = new TH1F("hframe",title,nbins,xmin,xmax); - } - hframe->SetBit(TH1::kNoStats); - hframe->SetBit(kCanDelete); - hframe->SetMinimum(ymin); - hframe->SetMaximum(ymax); - hframe->GetYaxis()->SetLimits(ymin,ymax); - hframe->SetDirectory(0); - hframe->Draw(" "); - - Update(); - if (padsav) padsav->cd(); - return hframe; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Redraw the frame axis -/// Redrawing axis may be necessary in case of superimposed histograms -/// when one or more histograms have a fill color -/// Instead of calling this function, it may be more convenient -/// to call directly h1->Draw("sameaxis") where h1 is the pointer -/// to the first histogram drawn in the pad. -/// -/// By default, if the pad has the options gridx or/and gridy activated, -/// the grid is not drawn by this function. -/// if option="g" is specified, this will force the drawing of the grid -/// on top of the picture - -void Pad::RedrawAxis(Option_t *option) -{ - // get first histogram in the list of primitives - TString opt = option; - opt.ToLower(); - - - cd(); - - TIter next(&fPrimitives); - TObject *obj; - while ((obj = next())) { - if (obj->InheritsFrom(TH1::Class())) { - TH1 *hobj = (TH1*)obj; - if (opt.Contains("g")) hobj->DrawCopy("sameaxig"); - else hobj->DrawCopy("sameaxis"); - return; - } - if (obj->InheritsFrom(TMultiGraph::Class())) { - TMultiGraph *mg = (TMultiGraph*)obj; - if (mg) mg->GetHistogram()->DrawCopy("sameaxis"); - return; - } - if (obj->InheritsFrom(TGraph::Class())) { - TGraph *g = (TGraph*)obj; - if (g) g->GetHistogram()->DrawCopy("sameaxis"); - return; - } - if (obj->InheritsFrom(THStack::Class())) { - THStack *hs = (THStack*)obj; - if (hs) hs->GetHistogram()->DrawCopy("sameaxis"); - return; - } - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::GetTextExtent(UInt_t &w, UInt_t &h, const char *text) -{ - fPainter.GetTextExtent(w, h, text); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::SetContext(CGContextRef ctx) -{ - fPainter.SetContext(ctx); -} - -//////////////////////////////////////////////////////////////////////////////// -///Linear search :) But list is very short. - -const char *Pad::GetSelectedParentDrawOption()const -{ - TObjOptLink *lnk = (TObjOptLink*)GetListOfPrimitives()->FirstLink(); - while (lnk) { - TObject *obj = lnk->GetObject(); - if (obj == fParentOfSelected) - return lnk->GetOption(); - lnk = (TObjOptLink*)lnk->Next(); - } - - return ""; -} - -//////////////////////////////////////////////////////////////////////////////// -///Linear search :) But list is very short. - -const char *Pad::GetSelectedDrawOption()const -{ - TObjOptLink *lnk = (TObjOptLink*)GetListOfPrimitives()->FirstLink(); - while (lnk) { - TObject *obj = lnk->GetObject(); - if (obj == fSelected) - return lnk->GetOption(); - lnk = (TObjOptLink*)lnk->Next(); - } - - return ""; -} - -//////////////////////////////////////////////////////////////////////////////// - -TObject *Pad::FindObject(const char *name) const -{ - return fPrimitives.FindObject(name); -} - - -//////////////////////////////////////////////////////////////////////////////// - -TObject *Pad::FindObject(const TObject *obj) const -{ - return fPrimitives.FindObject(obj); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Clipping routine: Cohen Sutherland algorithm. -/// -/// If Clip ==2 the segment is outside the boundary. -/// If Clip ==1 the segment has one point outside the boundary. -/// If Clip ==0 the segment is inside the boundary. -/// -/// _Input parameters: -/// -/// x[2], y[2] : Segment coordinates -/// xclipl, yclipb, xclipr, yclipt : Clipping boundary -/// -/// _Output parameters: -/// -/// x[2], y[2] : New segment coordinates - -Int_t Pad::Clip(Float_t *x, Float_t *y, Float_t xclipl, Float_t yclipb, Float_t xclipr, Float_t yclipt) -{ - const Float_t kP=10000; - Int_t clip = 0; - - for (Int_t i=0;i<2;i++) { - if (TMath::Abs(xclipl-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipl; - if (TMath::Abs(xclipr-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipr; - if (TMath::Abs(yclipb-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipb; - if (TMath::Abs(yclipt-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipt; - } - - // Compute the first endpoint codes. - Int_t code1 = ClippingCode(x[0],y[0],xclipl,yclipb,xclipr,yclipt); - Int_t code2 = ClippingCode(x[1],y[1],xclipl,yclipb,xclipr,yclipt); - - Double_t xt=0, yt=0; - Int_t clipped = 0; //this variable could be used in a future version - while(code1 + code2) { - clipped = 1; - - // The line lies entirely outside the clipping boundary - if (code1&code2) { - clip = 2; - return clip; - } - - // The line is subdivided into several parts - Int_t ic = code1; - if (ic == 0) ic = code2; - if (ic & 0x1) { - yt = y[0] + (y[1]-y[0])*(xclipl-x[0])/(x[1]-x[0]); - xt = xclipl; - } - if (ic & 0x2) { - yt = y[0] + (y[1]-y[0])*(xclipr-x[0])/(x[1]-x[0]); - xt = xclipr; - } - if (ic & 0x4) { - xt = x[0] + (x[1]-x[0])*(yclipb-y[0])/(y[1]-y[0]); - yt = yclipb; - } - if (ic & 0x8) { - xt = x[0] + (x[1]-x[0])*(yclipt-y[0])/(y[1]-y[0]); - yt = yclipt; - } - if (ic == code1) { - x[0] = xt; - y[0] = yt; - code1 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt); - } else { - x[1] = xt; - y[1] = yt; - code2 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt); - } - } - clip = clipped; - return clip; -} - - -//////////////////////////////////////////////////////////////////////////////// -/// Clipping routine: Cohen Sutherland algorithm. -/// -/// If Clip ==2 the segment is outside the boundary. -/// If Clip ==1 the segment has one point outside the boundary. -/// If Clip ==0 the segment is inside the boundary. -/// -/// _Input parameters: -/// -/// x[2], y[2] : Segment coordinates -/// xclipl, yclipb, xclipr, yclipt : Clipping boundary -/// -/// _Output parameters: -/// -/// x[2], y[2] : New segment coordinates - -Int_t Pad::Clip(Double_t *x, Double_t *y, Double_t xclipl, Double_t yclipb, Double_t xclipr, Double_t yclipt) -{ - const Double_t kP=10000; - Int_t clip = 0; - - for (Int_t i=0;i<2;i++) { - if (TMath::Abs(xclipl-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipl; - if (TMath::Abs(xclipr-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipr; - if (TMath::Abs(yclipb-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipb; - if (TMath::Abs(yclipt-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipt; - } - - // Compute the first endpoint codes. - Int_t code1 = 0; - if (x[0] < xclipl) code1 = code1 | 0x1; - if (x[0] > xclipr) code1 = code1 | 0x2; - if (y[0] < yclipb) code1 = code1 | 0x4; - if (y[0] > yclipt) code1 = code1 | 0x8; - Int_t code2 = 0; - if (x[1] < xclipl) code2 = code2 | 0x1; - if (x[1] > xclipr) code2 = code2 | 0x2; - if (y[1] < yclipb) code2 = code2 | 0x4; - if (y[1] > yclipt) code2 = code2 | 0x8; - - Double_t xt=0, yt=0; - Int_t clipped = 0; //this variable could be used in a future version - while(code1 + code2) { - clipped = 1; - - // The line lies entirely outside the clipping boundary - if (code1&code2) { - clip = 2; - return clip; - } - - // The line is subdivided into several parts - Int_t ic = code1; - if (ic == 0) ic = code2; - if (ic & 0x1) { - yt = y[0] + (y[1]-y[0])*(xclipl-x[0])/(x[1]-x[0]); - xt = xclipl; - } - if (ic & 0x2) { - yt = y[0] + (y[1]-y[0])*(xclipr-x[0])/(x[1]-x[0]); - xt = xclipr; - } - if (ic & 0x4) { - xt = x[0] + (x[1]-x[0])*(yclipb-y[0])/(y[1]-y[0]); - yt = yclipb; - } - if (ic & 0x8) { - xt = x[0] + (x[1]-x[0])*(yclipt-y[0])/(y[1]-y[0]); - yt = yclipt; - } - if (ic == code1) { - x[0] = xt; - y[0] = yt; - code1 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt); - } else { - x[1] = xt; - y[1] = yt; - code2 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt); - } - } - clip = clipped; - return clip; -} - - -//////////////////////////////////////////////////////////////////////////////// -/// Compute the endpoint codes for TPad::Clip. - -Int_t Pad::ClippingCode(Double_t x, Double_t y, Double_t xcl1, Double_t ycl1, Double_t xcl2, Double_t ycl2) -{ - Int_t code = 0; - if (x < xcl1) code = code | 0x1; - if (x > xcl2) code = code | 0x2; - if (y < ycl1) code = code | 0x4; - if (y > ycl2) code = code | 0x8; - return code; -} - - -//////////////////////////////////////////////////////////////////////////////// -/// Clip polygon using the Sutherland-Hodgman algorithm. -/// -/// Input parameters: -/// -/// n: Number of points in the polygon to be clipped -/// x[n], y[n] : Polygon do be clipped vertices -/// xclipl, yclipb, xclipr, yclipt : Clipping boundary -/// -/// Output parameters: -/// -/// nn: number of points in xc and yc -/// xc, yc: clipped polygon vertices. The Int_t returned by this function is -/// the number of points in the clipped polygon. These vectors must -/// be allocated by the calling function. A size of 2*n for each is -/// enough. -/// -/// Sutherland and Hodgman's polygon-clipping algorithm uses a divide-and-conquer -/// strategy: It solves a series of simple and identical problems that, when -/// combined, solve the overall problem. The simple problem is to clip a polygon -/// against a single infinite clip edge. Four clip edges, each defining one boundary -/// of the clip rectangle, successively clip a polygon against a clip rectangle. -/// -/// Steps of Sutherland-Hodgman's polygon-clipping algorithm: -/// -/// * Polygons can be clipped against each edge of the window one at a time. -/// Windows/edge intersections, if any, are easy to find since the X or Y coordinates -/// are already known. -/// * Vertices which are kept after clipping against one window edge are saved for -/// clipping against the remaining edges. -/// * Note that the number of vertices usually changes and will often increases. -/// -/// The clip boundary determines a visible and invisible region. The edges from -/// vertex i to vertex i+1 can be one of four types: -/// -/// * Case 1 : Wholly inside visible region - save endpoint -/// * Case 2 : Exit visible region - save the intersection -/// * Case 3 : Wholly outside visible region - save nothing -/// * Case 4 : Enter visible region - save intersection and endpoint - -Int_t Pad::ClipPolygon(Int_t n, Double_t *x, Double_t *y, Int_t nn, Double_t *xc, Double_t *yc, Double_t xclipl, Double_t yclipb, Double_t xclipr, Double_t yclipt) -{ - Int_t nc, nc2; - Double_t x1, y1, x2, y2, slope; // Segment to be clipped - - std::vector xc2(nn); - std::vector yc2(nn); - - // Clip against the left boundary - x1 = x[n-1]; y1 = y[n-1]; - nc2 = 0; - Int_t i; - for (i=0; i= xclipl) { - if (x2 < xclipl) { - xc2[nc2] = xclipl; yc2[nc2++] = slope*(xclipl-x1)+y1; - } else { - xc2[nc2] = x2; yc2[nc2++] = y2; - } - } else { - if (x2 >= xclipl) { - xc2[nc2] = xclipl; yc2[nc2++] = slope*(xclipl-x1)+y1; - xc2[nc2] = x2; yc2[nc2++] = y2; - } - } - x1 = x2; y1 = y2; - } - - // Clip against the top boundary - x1 = xc2[nc2-1]; y1 = yc2[nc2-1]; - nc = 0; - for (i=0; i yclipt) { - xc[nc] = x1+(yclipt-y1)*slope; yc[nc++] = yclipt; - } else { - xc[nc] = x2; yc[nc++] = y2; - } - } else { - if (y2 <= yclipt) { - xc[nc] = x1+(yclipt-y1)*slope; yc[nc++] = yclipt; - xc[nc] = x2; yc[nc++] = y2; - } - } - x1 = x2; y1 = y2; - } - - // Clip against the right boundary - x1 = xc[nc-1]; y1 = yc[nc-1]; - nc2 = 0; - for (i=0; i xclipr) { - xc2[nc2] = xclipr; yc2[nc2++] = slope*(xclipr-x1)+y1; - } else { - xc2[nc2] = x2; yc2[nc2++] = y2; - } - } else { - if (x2 <= xclipr) { - xc2[nc2] = xclipr; yc2[nc2++] = slope*(xclipr-x1)+y1; - xc2[nc2] = x2; yc2[nc2++] = y2; - } - } - x1 = x2; y1 = y2; - } - - // Clip against the bottom boundary - x1 = xc2[nc2-1]; y1 = yc2[nc2-1]; - nc = 0; - for (i=0; i= yclipb) { - if (y2 < yclipb) { - xc[nc] = x1+(yclipb-y1)*slope; yc[nc++] = yclipb; - } else { - xc[nc] = x2; yc[nc++] = y2; - } - } else { - if (y2 >= yclipb) { - xc[nc] = x1+(yclipb-y1)*slope; yc[nc++] = yclipb; - xc[nc] = x2; yc[nc++] = y2; - } - } - x1 = x2; y1 = y2; - } - - if (nc < 3) nc =0; - return nc; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Paint the pad border. -/// Draw first a box as a normal filled box - -void Pad::PaintBorder(Color_t color, Bool_t tops) -{ - if(color >= 0) { - TAttLine::Modify(); //Change line attributes only if necessary - TAttFill::Modify(); //Change fill area attributes only if necessary - - PaintBox(fX1,fY1,fX2,fY2); - } - - if (color < 0) - color = -color; - // then paint 3d frame (depending on bordermode) - if (IsTransparent()) - return; - - // Paint a 3D frame around the pad. - if (!fBorderMode) - return; - - Int_t bordersize = fBorderSize; - if (bordersize <= 0) - bordersize = 2; - - const Double_t realBsX = bordersize / (GetAbsWNDC() * GetWw()) * (fX2 - fX1); - const Double_t realBsY = bordersize / (GetAbsHNDC() * GetWh()) * (fY2 - fY1); - - Short_t px1,py1,px2,py2; - Double_t xl, xt, yl, yt; - - // GetDarkColor() and GetLightColor() use GetFillColor() - Color_t oldcolor = GetFillColor(); - SetFillColor(color); - TAttFill::Modify(); - Color_t light = 0, dark = 0; - if (color != 0) { - light = TColor::GetColorBright(color); - dark = TColor::GetColorDark(color); - } - - // Compute real left bottom & top right of the box in pixels - px1 = XtoPixel(fX1); py1 = YtoPixel(fY1); - px2 = XtoPixel(fX2); py2 = YtoPixel(fY2); - if (px1 < px2) {xl = fX1; xt = fX2; } - else {xl = fX2; xt = fX1;} - if (py1 > py2) {yl = fY1; yt = fY2;} - else {yl = fY2; yt = fY1;} - - Double_t frameXs[7] = {}, frameYs[7] = {}; - - // Draw top&left part of the box - frameXs[0] = xl; frameYs[0] = yl; - frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY; - frameXs[2] = frameXs[1]; frameYs[2] = yt - realBsY; - frameXs[3] = xt - realBsX; frameYs[3] = frameYs[2]; - frameXs[4] = xt; frameYs[4] = yt; - frameXs[5] = xl; frameYs[5] = yt; - frameXs[6] = xl; frameYs[6] = yl; - - if (fBorderMode == -1) gVirtualX->SetFillColor(dark); - else gVirtualX->SetFillColor(light); - fPainter.DrawFillArea(7, frameXs, frameYs); - - // Draw bottom&right part of the box - frameXs[0] = xl; frameYs[0] = yl; - frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY; - frameXs[2] = xt - realBsX; frameYs[2] = frameYs[1]; - frameXs[3] = frameXs[2]; frameYs[3] = yt - realBsY; - frameXs[4] = xt; frameYs[4] = yt; - frameXs[5] = xt; frameYs[5] = yl; - frameXs[6] = xl; frameYs[6] = yl; - - if (fBorderMode == -1) gVirtualX->SetFillColor(light); - else gVirtualX->SetFillColor(dark); - fPainter.DrawFillArea(7, frameXs, frameYs); - - gVirtualX->SetFillColor(-1); - SetFillColor(oldcolor); - - if (!tops) - return; -} - -//////////////////////////////////////////////////////////////////////////////// -/// This function paints hatched fill area arcording to the FillStyle value -/// The convention for the Hatch is the following: -/// -/// FillStyle = 3ijk -/// -/// i (1-9) : specify the space between each hatch -/// 1 = minimum 9 = maximum -/// the final spacing is i*GetHatchesSpacing(). The hatches spacing -/// is set by SetHatchesSpacing() -/// -/// j (0-9) : specify angle between 0 and 90 degrees -/// -/// 0 = 0 -/// 1 = 10 -/// 2 = 20 -/// 3 = 30 -/// 4 = 45 -/// 5 = Not drawn -/// 6 = 60 -/// 7 = 70 -/// 8 = 80 -/// 9 = 90 -/// -/// k (0-9) : specify angle between 90 and 180 degrees -/// 0 = 180 -/// 1 = 170 -/// 2 = 160 -/// 3 = 150 -/// 4 = 135 -/// 5 = Not drawn -/// 6 = 120 -/// 7 = 110 -/// 8 = 100 -/// 9 = 90 - -void Pad::PaintFillAreaHatches(Int_t nn, Double_t *xx, Double_t *yy, Int_t FillStyle) -{ - static Double_t ang1[10] = {0., 10., 20., 30., 45.,5., 60., 70., 80., 90.}; - static Double_t ang2[10] = {180.,170.,160.,150.,135.,5.,120.,110.,100., 90.}; - - Int_t fasi = FillStyle%1000; - Int_t idSPA = (Int_t)(fasi/100); - Int_t iAng2 = (Int_t)((fasi-100*idSPA)/10); - Int_t iAng1 = fasi%10; - Double_t dy = 0.003*(Double_t)(idSPA)*gStyle->GetHatchesSpacing(); - Int_t lw = gStyle->GetHatchesLineWidth(); - Short_t lws = 0; - Int_t lss = 0; - Int_t lcs = 0; - - // Save the current line attributes - - lws = gVirtualX->GetLineWidth(); - lss = gVirtualX->GetLineStyle(); - lcs = gVirtualX->GetLineColor(); - - // Change the current line attributes to draw the hatches - gVirtualX->SetLineStyle(1); - gVirtualX->SetLineWidth(Short_t(lw)); - gVirtualX->SetLineColor(gVirtualX->GetFillColor()); - - // Draw the hatches - if (ang1[iAng1] != 5.) PaintHatches(dy, ang1[iAng1], nn, xx, yy); - if (ang2[iAng2] != 5.) PaintHatches(dy, ang2[iAng2], nn, xx, yy); - - // Restore the line attributes - gVirtualX->SetLineStyle(lss); - gVirtualX->SetLineWidth(lws); - gVirtualX->SetLineColor(lcs); -} - -//////////////////////////////////////////////////////////////////////////////// -/// This routine draw hatches inclined with the -/// angle "angle" and spaced of "dy" in normalized device -/// coordinates in the surface defined by n,xx,yy. - -void Pad::PaintHatches(Double_t dy, Double_t angle, - Int_t nn, Double_t *xx, Double_t *yy) -{ - Int_t i, i1, i2, nbi, m, inv; - Double_t ratiox, ratioy, ymin, ymax, yrot, ycur; - const Double_t angr = TMath::Pi()*(180-angle)/180.; - const Double_t epsil = 0.0001; - const Int_t maxnbi = 100; - Double_t xli[maxnbi], xlh[2], ylh[2], xt1, xt2, yt1, yt2; - Double_t ll, x, y, x1, x2, y1, y2, a, b, xi, xip, xin, yi, yip; - - Double_t rwxmin = gPad->GetX1(); - Double_t rwxmax = gPad->GetX2(); - Double_t rwymin = gPad->GetY1(); - Double_t rwymax = gPad->GetY2(); - ratiox = 1/(rwxmax-rwxmin); - ratioy = 1/(rwymax-rwymin); - - Double_t sina = TMath::Sin(angr), sinb; - Double_t cosa = TMath::Cos(angr), cosb; - if (TMath::Abs(cosa) <= epsil) cosa=0.; - if (TMath::Abs(sina) <= epsil) sina=0.; - sinb = -sina; - cosb = cosa; - - // Values needed to compute the hatches in TRUE normalized space (NDC) - Int_t iw = gPad->GetWw(); - Int_t ih = gPad->GetWh(); - Double_t x1p,y1p,x2p,y2p; - gPad->GetPadPar(x1p,y1p,x2p,y2p); - iw = (Int_t)(iw*x2p)-(Int_t)(iw*x1p); - ih = (Int_t)(ih*y2p)-(Int_t)(ih*y1p); - Double_t wndc = TMath::Min(1.,(Double_t)iw/(Double_t)ih); - Double_t hndc = TMath::Min(1.,(Double_t)ih/(Double_t)iw); - - // Search ymin and ymax - ymin = 1.; - ymax = 0.; - for (i=1; i<=nn; i++) { - x = wndc*ratiox*(xx[i-1]-rwxmin); - y = hndc*ratioy*(yy[i-1]-rwymin); - yrot = sina*x+cosa*y; - if (yrot > ymax) ymax = yrot; - if (yrot < ymin) ymin = yrot; - } - ymax = (Double_t)((Int_t)(ymax/dy))*dy; - - for (ycur=ymax; ycur>=ymin; ycur=ycur-dy) { - nbi = 0; - for (i=2; i<=nn+1; i++) { - i2 = i; - i1 = i-1; - if (i == nn+1) i2=1; - x1 = wndc*ratiox*(xx[i1-1]-rwxmin); - y1 = hndc*ratioy*(yy[i1-1]-rwymin); - x2 = wndc*ratiox*(xx[i2-1]-rwxmin); - y2 = hndc*ratioy*(yy[i2-1]-rwymin); - xt1 = cosa*x1-sina*y1; - yt1 = sina*x1+cosa*y1; - xt2 = cosa*x2-sina*y2; - yt2 = sina*x2+cosa*y2; - - // Line segment parallel to oy - if (xt1 == xt2) { - if (yt1 < yt2) { - yi = yt1; - yip = yt2; - } else { - yi = yt2; - yip = yt1; - } - if ((yi <= ycur) && (ycur < yip)) { - nbi++; - if (nbi >= maxnbi) return; - xli[nbi-1] = xt1; - } - continue; - } - - // Line segment parallel to ox - if (yt1 == yt2) { - if (yt1 == ycur) { - nbi++; - if (nbi >= maxnbi) return; - xli[nbi-1] = xt1; - nbi++; - if (nbi >= maxnbi) return; - xli[nbi-1] = xt2; - } - continue; - } - - // Other line segment - a = (yt1-yt2)/(xt1-xt2); - b = (yt2*xt1-xt2*yt1)/(xt1-xt2); - if (xt1 < xt2) { - xi = xt1; - xip = xt2; - } else { - xi = xt2; - xip = xt1; - } - xin = (ycur-b)/a; - if ((xi <= xin) && (xin < xip) && - (TMath::Min(yt1,yt2) <= ycur) && - (ycur < TMath::Max(yt1,yt2))) { - nbi++; - if (nbi >= maxnbi) return; - xli[nbi-1] = xin; - } - } - - // Sorting of the x coordinates intersections - inv = 0; - m = nbi-1; -L30: - for (i=1; i<=m; i++) { - if (xli[i] < xli[i-1]) { - inv++; - ll = xli[i-1]; - xli[i-1] = xli[i]; - xli[i] = ll; - } - } - m--; - if (inv == 0) goto L50; - inv = 0; - goto L30; - - // Draw the hatches -L50: - if (nbi%2 != 0) continue; - - for (i=1; i<=nbi; i=i+2) { - // Rotate back the hatches - xlh[0] = cosb*xli[i-1]-sinb*ycur; - ylh[0] = sinb*xli[i-1]+cosb*ycur; - xlh[1] = cosb*xli[i] -sinb*ycur; - ylh[1] = sinb*xli[i] +cosb*ycur; - // Convert hatches' positions from true NDC to WC - xlh[0] = (xlh[0]/wndc)*(rwxmax-rwxmin)+rwxmin; - ylh[0] = (ylh[0]/hndc)*(rwymax-rwymin)+rwymin; - xlh[1] = (xlh[1]/wndc)*(rwxmax-rwxmin)+rwxmin; - ylh[1] = (ylh[1]/hndc)*(rwymax-rwymin)+rwymin; - gPad->PaintLine(xlh[0], ylh[0], xlh[1], ylh[1]); - } - } -} - -//////////////////////////////////////////////////////////////////////////////// - -TVirtualViewer3D *Pad::GetViewer3D(Option_t *) -{ - if (!fViewer3D) - fViewer3D = new TViewer3DPad(*this); - return fViewer3D; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::ExecuteRotateView(Int_t evType, Int_t px, Int_t py) -{ - fView->ExecuteRotateView(evType, px, py); -} - -//////////////////////////////////////////////////////////////////////////////// -///This copy is a copy&paste&cut_half_of_guts from original TPad. -///I do not understand at the moment, why this code is here and not in TAxis. - -void Pad::ExecuteEventAxis(Int_t event, Int_t px, Int_t py, TAxis *axis) -{ - static Int_t axisNumber; - static Double_t ratio1, ratio2; - static Int_t px1old, py1old, px2old, py2old; - Int_t bin1, bin2; - Double_t temp, xmin,xmax; - - switch (event) { - - case kButton1Down: - axisNumber = 1; - if (!strcmp(axis->GetName(),"xaxis")) { - axisNumber = 1; - if (!IsVertical()) axisNumber = 2; - } - if (!strcmp(axis->GetName(),"yaxis")) { - axisNumber = 2; - if (!IsVertical()) axisNumber = 1; - } - if (!strcmp(axis->GetName(),"zaxis")) { - axisNumber = 3; - } - if (axisNumber == 1) { - ratio1 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin()); - px1old = XtoAbsPixel(GetUxmin()+ratio1*(GetUxmax() - GetUxmin())); - py1old = YtoAbsPixel(GetUymin()); - px2old = px1old; - py2old = YtoAbsPixel(GetUymax()); - } else if (axisNumber == 2) { - ratio1 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin()); - py1old = YtoAbsPixel(GetUymin()+ratio1*(GetUymax() - GetUymin())); - px1old = XtoAbsPixel(GetUxmin()); - px2old = XtoAbsPixel(GetUxmax()); - py2old = py1old; - } else { - ratio1 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin()); - py1old = YtoAbsPixel(GetUymin()+ratio1*(GetUymax() - GetUymin())); - px1old = XtoAbsPixel(GetUxmax()); - px2old = XtoAbsPixel(GetX2()); - py2old = py1old; - } - // No break !!! - - case kButton1Motion: - if (axisNumber == 1) { - ratio2 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin()); - px2old = XtoAbsPixel(GetUxmin()+ratio2*(GetUxmax() - GetUxmin())); - } else { - ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin()); - py2old = YtoAbsPixel(GetUymin()+ratio2*(GetUymax() - GetUymin())); - } - break; - - case kButton1Up: - - if (1) { - if (axisNumber == 1) { - ratio2 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin()); - xmin = GetUxmin() +ratio1*(GetUxmax() - GetUxmin()); - xmax = GetUxmin() +ratio2*(GetUxmax() - GetUxmin()); - } else if (axisNumber == 2) { - ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin()); - xmin = GetUymin() +ratio1*(GetUymax() - GetUymin()); - xmax = GetUymin() +ratio2*(GetUymax() - GetUymin()); - } else { - ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin()); - xmin = ratio1; - xmax = ratio2; - } - if (xmin > xmax) { - temp = xmin; - xmin = xmax; - xmax = temp; - temp = ratio1; - ratio1 = ratio2; - ratio2 = temp; - } - - // xmin and xmax need to be adjusted in case of CONT4. - - if (!strcmp(axis->GetName(),"xaxis")) axisNumber = 1; - if (!strcmp(axis->GetName(),"yaxis")) axisNumber = 2; - if (ratio2 - ratio1 > 0.05) { - //update object owning this axis - TH1 *hobj1 = (TH1*)axis->GetParent(); - bin1 = axis->FindFixBin(xmin); - bin2 = axis->FindFixBin(xmax); - if (axisNumber == 1) axis->SetRange(bin1,bin2); - if (axisNumber == 2 && hobj1) { - if (hobj1->GetDimension() == 1) { - if (hobj1->GetNormFactor() != 0) { - Double_t norm = hobj1->GetSumOfWeights()/hobj1->GetNormFactor(); - xmin *= norm; - xmax *= norm; - } - hobj1->SetMinimum(xmin); - hobj1->SetMaximum(xmax); - hobj1->SetBit(TH1::kIsZoomed); - } else { - axis->SetRange(bin1,bin2); - } - } - } - } - break; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -Bool_t Pad::SelectionIsValid() const -{ - return fSelectionIsValid; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::InvalidateSelection(Bool_t invalidateBufferOnly) -{ - fSelectionIsValid = kFALSE; - if (!invalidateBufferOnly) { - fSelected = 0; - fParentOfSelected = 0; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::SetSelectionBuffer(UInt_t w, UInt_t h, unsigned char *buff) -{ - fSelectionAreaWidth = w; - fSelectionIsValid = kTRUE; - fSelectionBuffer.assign(buff, buff + w * h * 4); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::Pick(Int_t px, Int_t py) -{ - if (fContains3DObject) {/* && fView) { - const Double_t dx = 0.05 * (fUxmax - fUxmin); - if ((AbsPixeltoX(px) > fUxmin + dx) && (AbsPixeltoX(px) < fUxmax - dx)) { - TObjOptLink *lnk = (TObjOptLink*)GetListOfPrimitives()->FirstLink(); - while (lnk) { - TObject *obj = lnk->GetObject(); - if (obj->InheritsFrom("TF2")) {//The only 3D object we can have now. - fSelected = obj; - fParentOfSelected = obj; - return; - } - } - } else { - fSelected = 0; - fParentOfSelected = 0; - return; - }*/ - fSelected = 0; - fParentOfSelected = 0; - return; - } - - const UInt_t offset = (py * fSelectionAreaWidth + px) * 4; - const unsigned red = fSelectionBuffer[offset + 1]; - const unsigned green = fSelectionBuffer[offset + 2]; - const unsigned blue = fSelectionBuffer[offset + 3]; - - GraphicUtils::IDEncoder enc(10, 255); - const UInt_t id = enc.ColorToId(red, green, blue); - if (id > 0 && id <= fSelectables.size()) { - const ObjectPair_t &found = fSelectables[id - 1]; - //fSelected = fSelectables[id]; - fSelected = found.first; - fParentOfSelected = found.second; - } else { - fSelected = 0; - fParentOfSelected = 0; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::Unpick() -{ - fSelected = 0; - fParentOfSelected = 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -TObject *Pad::ObjectInPoint(Int_t px, Int_t py) -{ - const UInt_t offset = (py * fSelectionAreaWidth + px) * 4; - const unsigned red = fSelectionBuffer[offset + 1]; - const unsigned green = fSelectionBuffer[offset + 2]; - const unsigned blue = fSelectionBuffer[offset + 3]; - - GraphicUtils::IDEncoder enc(10, 255); - const UInt_t id = enc.ColorToId(red, green, blue); - if (id > 0 && id <= fSelectables.size()) { - const ObjectPair_t &found = fSelectables[id - 1]; - return found.first; - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::PushTopLevelSelectable(TObject *top) -{ - if (!fInSelectionMode) - return; - Parent_t newTopLevel(top, fObjectID); - ObjectPair_t newPair(top, top); - fPainter.SetCurrentObjectID(fObjectID); - fObjectID++; - - fParentPainters.push_back(newTopLevel); - fSelectables.push_back(newPair); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::PushSelectableObject(TObject *obj) -{ - if (!fInSelectionMode) - return; - - ObjectPair_t newPair(obj, 0); - if (fParentPainters.size()) - newPair.second = fParentPainters.back().first; - fSelectables.push_back(newPair); - fPainter.SetCurrentObjectID(fObjectID); - fObjectID++; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::PopTopLevelSelectable() -{ - if (!fInSelectionMode) - return; - - if (fParentPainters.size()) - fParentPainters.pop_back(); - if (fParentPainters.size()) - fPainter.SetCurrentObjectID(fParentPainters.back().second); -} - -//////////////////////////////////////////////////////////////////////////////// - -TObject *Pad::GetSelected()const -{ - return fSelected; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::PaintThumbnail() -{ - cd(); - - fPainter.SetPainterMode(Painter::kPaintThumbnail); - - gVirtualX->SetFillStyle(1001); - gVirtualX->SetFillColor(0); - - PaintBox(fX1,fY1,fX2,fY2); - PaintBorder(GetFillColor(), kTRUE); - - TObjOptLink *lnk = (TObjOptLink*)GetListOfPrimitives()->FirstLink(); - TObject *obj; - - while (lnk) { - obj = lnk->GetObject(); - obj->Paint(lnk->GetOption()); - lnk = (TObjOptLink*)lnk->Next(); - } - - fPainter.SetPainterMode(Painter::kPaintToView); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Pad::SetPaintOption(const TObject *obj, const char *option) -{ - TObjOptLink *lnk = (TObjOptLink*)GetListOfPrimitives()->FirstLink(); - - while (lnk) { - TObject *nestedObj = lnk->GetObject(); - if (obj == nestedObj) { - lnk->SetOption(option); - break; - } - lnk = (TObjOptLink*)lnk->Next(); - } -} - -} -} diff --git a/graf2d/ios/src/IOSPadStub.cxx b/graf2d/ios/src/IOSPadStub.cxx deleted file mode 100644 index 5542f2a88aece..0000000000000 --- a/graf2d/ios/src/IOSPadStub.cxx +++ /dev/null @@ -1,452 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#include "IOSPadStub.h" - -namespace ROOT { -namespace iOS { - -//////////////////////////////////////////////////////////////////////////////// - -TLegend *PadStub::BuildLegend(Double_t, Double_t, Double_t, Double_t, const char *) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::Close(Option_t *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::AddExec(const char *, const char *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::CopyPixmap() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::CopyPixmaps() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::DeleteExec(const char *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::Divide(Int_t, Int_t, Float_t, Float_t, Int_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::Draw(Option_t *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::DrawClassObject(const TObject *, Option_t *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetBatch(Bool_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t PadStub::GetCanvasID() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -TCanvasImp *PadStub::GetCanvasImp() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t PadStub::GetEvent() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t PadStub::GetEventX() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t PadStub::GetEventY() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t PadStub::GetNumber() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -TVirtualPad *PadStub::GetPad(Int_t) const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -TObject *PadStub::GetPadPointer() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -TVirtualPad *PadStub::GetPadSave() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -TVirtualPad *PadStub::GetSelectedPad() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -TObject *PadStub::GetView3D() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::ResetView3D(TObject *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -TCanvas *PadStub::GetCanvas() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -TVirtualPad *PadStub::GetVirtCanvas() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t PadStub::GetPadPaint() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t PadStub::GetPixmapID() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -Bool_t PadStub::HasCrosshair() const -{ - return kFALSE; -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetCrosshair(Int_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetAttFillPS(Color_t, Style_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetAttLinePS(Color_t, Style_t, Width_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetAttMarkerPS(Color_t, Style_t, Size_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetAttTextPS(Int_t, Float_t, Color_t, Style_t, Float_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::PaintText(Double_t, Double_t, const wchar_t *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::PaintTextNDC(Double_t, Double_t, const wchar_t *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::PaintBorderPS(Double_t, Double_t, Double_t, Double_t, Int_t, Int_t, Int_t, Int_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t PadStub::GetGLDevice() -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetCopyGLDevice(Bool_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::Pop() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::Print(const char *) const -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::Print(const char *, Option_t *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -TVirtualPad *PadStub::GetMother() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -TObject *PadStub::CreateToolTip(const TBox *, const char *, Long_t) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::DeleteToolTip(TObject *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::ResetToolTip(TObject *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::CloseToolTip(TObject *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetToolTipText(const char *, Long_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::HighLight(Color_t, Bool_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -Color_t PadStub::GetHighLightColor() const -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::ls(Option_t *) const -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::Modified(Bool_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -Bool_t PadStub::OpaqueMoving() const -{ - return kFALSE; -} - -//////////////////////////////////////////////////////////////////////////////// - -Bool_t PadStub::OpaqueResizing() const -{ - return kFALSE; -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::PaintModified() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::RecursiveRemove(TObject *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SaveAs(const char *,Option_t *) const -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetCanvas(TCanvas *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetCanvasSize(UInt_t, UInt_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetCursor(ECursor) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetDoubleBuffer(Int_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetName(const char *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetTitle(const char *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::SetSelected(TObject *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::ShowGuidelines(TObject *, Int_t, char, bool) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::Update() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -TObject *PadStub::WaitPrimitive(const char *, const char *) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -void PadStub::ReleaseViewer3D(Option_t *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -Bool_t PadStub::HasViewer3D() const -{ - return kFALSE; -} - -//////////////////////////////////////////////////////////////////////////////// - -TVirtualPadPainter *PadStub::GetPainter() -{ - return 0; -} - -} -} diff --git a/graf2d/ios/src/IOSPainter.cxx b/graf2d/ios/src/IOSPainter.cxx deleted file mode 100644 index 4a276220ae833..0000000000000 --- a/graf2d/ios/src/IOSPainter.cxx +++ /dev/null @@ -1,651 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ -#include - -#include -#include -#include - -#include "TVirtualX.h" -#include "TMath.h" - -#include "IOSResourceManagement.h" -#include "IOSSelectionMarkers.h" -#include "IOSTextOperations.h" -#include "IOSGraphicUtils.h" -#include "IOSFillPatterns.h" -#include "IOSLineStyles.h" -#include "IOSPainter.h" -#include "IOSMarkers.h" - -namespace ROOT { -namespace iOS { - -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -void SetMarkerFillColor(CGContextRef ctx, Color_t colorIndex) -{ - Float_t r = 0.f, g = 0.f, b = 0.f, a = 1.f; - GraphicUtils::GetColorForIndex(colorIndex, r, g, b); - CGContextSetRGBFillColor(ctx, r, g, b, a); -} - -//////////////////////////////////////////////////////////////////////////////// - -void SetMarkerStrokeColor(CGContextRef ctx, Color_t colorIndex) -{ - Float_t r = 0.f, g = 0.f, b = 0.f, a = 1.f; - GraphicUtils::GetColorForIndex(colorIndex, r, g, b); - CGContextSetRGBStrokeColor(ctx, r, g, b, a); -} - -//////////////////////////////////////////////////////////////////////////////// - -bool MarkerIsFilledPolygon(Style_t markerStyle) -{ - switch (markerStyle) { - case kDot: - case kFullDotMedium: - case kFullDotLarge: - case kFullCircle: - case kFullSquare: - case kFullTriangleUp: - case kFullTriangleDown: - case kFullStar: - case kFullDiamond: - case kFullCross: - return true; - default: - return false; - } -} - -const CGFloat shadowColor[] = {0.1f, 0.1f, 0.1f, 0.2f}; - -} - -//////////////////////////////////////////////////////////////////////////////// -///Default ctor. - -SpaceConverter::SpaceConverter() - : fXMin(0.), - fXConv(1.), - fYMin(0.), - fYConv(1.) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -///Construct for conversion. - -SpaceConverter::SpaceConverter(UInt_t w, Double_t xMin, Double_t xMax, UInt_t h, Double_t yMin, Double_t yMax) -{ - SetConverter(w, xMin, xMax, h, yMin, yMax); -} - -//////////////////////////////////////////////////////////////////////////////// -///Set conversion coefficients. - -void SpaceConverter::SetConverter(UInt_t w, Double_t xMin, Double_t xMax, UInt_t h, Double_t yMin, Double_t yMax) -{ - fXMin = xMin; - fXConv = w / (xMax - xMin); - - fYMin = yMin; - fYConv = h / (yMax - yMin); -} - -//////////////////////////////////////////////////////////////////////////////// -///From pad's user space to view's user space. - -Double_t SpaceConverter::XToView(Double_t x)const -{ - return (x - fXMin) * fXConv; -} - -//////////////////////////////////////////////////////////////////////////////// -///From pad's user space to view's user space. - -Double_t SpaceConverter::YToView(Double_t y)const -{ - return (y - fYMin) * fYConv; -} - -//////////////////////////////////////////////////////////////////////////////// -///Default ctor. - -Painter::Painter() - : fCtx(0), - fPainterMode(kPaintToView), - fCurrentObjectID(0), - fEncoder(10, 255) //radix is 10, color channel value is 255. -{ -} - -//////////////////////////////////////////////////////////////////////////////// -///Painter can work in four modes: -///1. draw objects into a view; -///2. draw them into a bitmap file with a special color("selection mode"); -///3. draw highlighted object -///4. draw object's shadow - -void Painter::SetStrokeParameters()const -{ - //In selection mode line color is quite a special thing, it's used as - //object's identity. Line width is also different: to be selectable by tap gesture, - //line has to be very thick. - //In "shadow mode" or "highlight mode" it's just gray or pink and transparent. - - CGContextSetLineCap(fCtx, kCGLineCapRound); - CGContextSetLineJoin(fCtx, kCGLineJoinMiter); - - if (fPainterMode == kPaintToSelectionBuffer) { - SetLineColorForCurrentObjectID(); - //If line's width is less, it's already very difficult to pick. - CGContextSetLineWidth(fCtx, 40.f); - return; - } - - if (fPainterMode == kPaintShadow) { - CGContextSetRGBStrokeColor(fCtx, shadowColor[0], shadowColor[1], shadowColor[2], shadowColor[3]); - CGContextSetLineWidth(fCtx, 5.f); - return; - } - - if (gVirtualX->GetLineWidth() > 1.f) - CGContextSetLineWidth(fCtx, gVirtualX->GetLineWidth()); - - const Float_t alpha = 1.f;//Must come from gVirtualX. - Float_t red = 0.f, green = 0.f, blue = 0.f;//Black line by default. - - GraphicUtils::GetColorForIndex(gVirtualX->GetLineColor(), red, green, blue); - CGContextSetRGBStrokeColor(fCtx, red, green, blue, alpha); - - const Style_t lineStyle = gVirtualX->GetLineStyle(); - if (lineStyle > 1 && lineStyle <= 10) - CGContextSetLineDash(fCtx, 0., GraphicUtils::dashLinePatterns[lineStyle - 1], GraphicUtils::linePatternLengths[lineStyle - 1]); - else - CGContextSetLineDash(fCtx, 0., 0, 0); -} - -//////////////////////////////////////////////////////////////////////////////// -///In principle, stroke parameters (line style, width, color) must -///be specified externally, before DrawLine is called. -///Unfortunately, in ROOT gVirtualX->SetLineXXXX is called in every -///possible place and not only inside gPad, so I simply can not -///controll all places, there line parameters are set. So -///they are specified here. - -void Painter::DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2) -{ - const Util::CGStateGuard contextState(fCtx); - - SetStrokeParameters(); - - const Double_t x1p = fConverter.XToView(x1); - const Double_t x2p = fConverter.XToView(x2); - - const Double_t y1p = fConverter.YToView(y1); - const Double_t y2p = fConverter.YToView(y2); - - CGContextBeginPath(fCtx); - CGContextMoveToPoint(fCtx, x1p, y1p); - CGContextAddLineToPoint(fCtx, x2p, y2p); - CGContextStrokePath(fCtx); -} - -//////////////////////////////////////////////////////////////////////////////// -///Just an empty overrider. Pad does conversions required and -///calls DrawLine instead of this. - -void Painter::DrawLineNDC(Double_t, Double_t, Double_t, Double_t) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -///TODO: check, if stroke parameters also should -///be specified for polygon. - -void Painter::SetPolygonParameters()const -{ - if (fPainterMode == kPaintToSelectionBuffer) { - SetStrokeParameters(); - SetPolygonColorForCurrentObjectID(); - return; - } - - if (fPainterMode == kPaintShadow) { - CGContextSetRGBFillColor(fCtx, shadowColor[0], shadowColor[1], shadowColor[2], shadowColor[3]); - CGContextSetRGBStrokeColor(fCtx, shadowColor[0], shadowColor[1], shadowColor[2], shadowColor[3]); - return; - } - - const Float_t alpha = 1.f;//must be in gVirtualX. - Float_t red = 1.f, green = 1.f, blue = 1.f;//White by default. - - GraphicUtils::GetColorForIndex(gVirtualX->GetFillColor(), red, green, blue); - CGContextSetRGBFillColor(fCtx, red, green, blue, alpha); - //Without the next two lines and without kCGPathFillStroke I - //have bad pictures for surfaces (hell knows, what they calculate). - CGContextSetRGBStrokeColor(fCtx, red, green, blue, alpha); - CGContextSetLineWidth(fCtx, 1.f); -} - -//////////////////////////////////////////////////////////////////////////////// - -Bool_t Painter::PolygonHasStipple()const -{ - const Style_t fillStyle = gVirtualX->GetFillStyle() / 1000; - const Style_t pattern = gVirtualX->GetFillStyle() % 1000; - - return fillStyle == 3 && pattern >= 1 && pattern <= GraphicUtils::kPredefinedFillPatterns; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::FillBoxWithPattern(Double_t x1, Double_t y1, Double_t x2, Double_t y2)const -{ - const Util::CGStateGuard state(fCtx); - // - Util::RefGuardGeneric patternColorSpace(CGColorSpaceCreatePattern(0)); - CGContextSetFillColorSpace(fCtx, patternColorSpace.Get()); - - //patternIndex < kPredefinedFillPatterns, this is assumed by previous call - //to PolygonHasStipples. - CGFloat rgb[3] = {}; - Float_t r, g, b; - GraphicUtils::GetColorForIndex(gVirtualX->GetFillColor(), r, g, b); - rgb[0] = r; rgb[1] = g; rgb[2] = b; - const Style_t patternIndex = gVirtualX->GetFillStyle() % 1000 - 1; - const Util::SmartRef pattern(GraphicUtils::gPatternGenerators[patternIndex](rgb)); - - const CGFloat alpha = 1.f; - CGContextSetFillPattern(fCtx, pattern.Get(), &alpha); - - CGContextFillRect(fCtx, CGRectMake(x1, y1, x2 - x1, y2 - y1)); -} - -//////////////////////////////////////////////////////////////////////////////// -///Box with solid fill style. - -void Painter::FillBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2)const -{ - const Util::CGStateGuard contextGuard(fCtx); - SetPolygonParameters(); - - CGContextFillRect(fCtx, CGRectMake(x1, y1, x2 - x1, y2 - y1)); -} - -//////////////////////////////////////////////////////////////////////////////// -///Hollow box. - -void Painter::DrawBoxOutline(Double_t x1, Double_t y1, Double_t x2, Double_t y2)const -{ - const Util::CGStateGuard contextGuard(fCtx); - - const CGRect rect = CGRectMake(x1, y1, x2 - x1, y2 - y1); - - SetStrokeParameters(); - CGContextStrokeRect(fCtx, rect); - - if (fPainterMode == kPaintSelected) - GraphicUtils::DrawBoxSelectionMarkers(fCtx, rect); - -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, TVirtualPadPainter::EBoxMode mode) -{ - const Double_t x1p = fConverter.XToView(x1); - const Double_t y1p = fConverter.YToView(y1); - const Double_t x2p = fConverter.XToView(x2); - const Double_t y2p = fConverter.YToView(y2); - - if (fPainterMode == kPaintSelected || fPainterMode == kPaintShadow) - return DrawBoxOutline(x1p, y1p, x2p, y2p); - - if (fPainterMode == kPaintToSelectionBuffer && PolygonHasStipple()) - return DrawBoxOutline(x1p, y1p, x2p, y2p); - - if (mode == TVirtualPadPainter::kFilled) - PolygonHasStipple() ? FillBoxWithPattern(x1p, y1p, x2p, y2p) : FillBox(x1p, y1p, x2p, y2p); - else - DrawBoxOutline(x1p, y1p, x2p, y2p); -} - -namespace -{ - -//////////////////////////////////////////////////////////////////////////////// - -template -void draw_polygon(CGContextRef ctx, UInt_t n, const PointCoordinate *x, const PointCoordinate *y, const SpaceConverter & sc, Bool_t withStroke = kTRUE) -{ - CGContextBeginPath(ctx); - - CGContextMoveToPoint(ctx, sc.XToView(x[0]), sc.YToView(y[0])); - for (UInt_t i = 1; i < n; ++i) - CGContextAddLineToPoint(ctx, sc.XToView(x[i]), sc.YToView(y[i])); - CGContextClosePath(ctx); - - if (!withStroke) - CGContextFillPath(ctx); - else - CGContextDrawPath(ctx, kCGPathFillStroke); -} - -//////////////////////////////////////////////////////////////////////////////// - -template -void draw_polyline(CGContextRef ctx, UInt_t n, const PointCoordinate *x, const PointCoordinate *y, const SpaceConverter & sc, Bool_t showSelection = kFALSE) -{ - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, sc.XToView(x[0]), sc.YToView(y[0])); - for (UInt_t i = 1; i < n; ++i) - CGContextAddLineToPoint(ctx, sc.XToView(x[i]), sc.YToView(y[i])); - - CGContextStrokePath(ctx); - - if (showSelection) { - GraphicUtils::DrawSelectionMarker(ctx, CGPointMake(sc.XToView(x[0]), sc.YToView(y[0]))); - GraphicUtils::DrawSelectionMarker(ctx, CGPointMake(sc.XToView(x[n - 1]), sc.YToView(y[n - 1]))); - - const unsigned midPoint = n / 2; - if (midPoint) - GraphicUtils::DrawSelectionMarker(ctx, CGPointMake(sc.XToView(x[midPoint]), sc.YToView(y[midPoint]))); - } -} - -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::FillAreaWithPattern(Int_t n, const Double_t *x, const Double_t *y)const -{ - const Util::CGStateGuard state(fCtx); - // - Util::RefGuardGeneric patternColorSpace(CGColorSpaceCreatePattern(0)); - CGContextSetFillColorSpace(fCtx, patternColorSpace.Get()); - - CGFloat rgb[3] = {}; - Float_t r, g, b; - GraphicUtils::GetColorForIndex(gVirtualX->GetFillColor(), r, g, b); - rgb[0] = r; rgb[1] = g; rgb[2] = b; - const Style_t patternIndex = gVirtualX->GetFillStyle() % 1000 - 1; - const Util::SmartRef pattern(GraphicUtils::gPatternGenerators[patternIndex](rgb)); - - const CGFloat alpha = 1.f; - CGContextSetFillPattern(fCtx, pattern.Get(), &alpha); - - draw_polygon(fCtx, n, x, y, fConverter, kFALSE); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::FillArea(Int_t n, const Double_t *x, const Double_t *y)const -{ - const Util::CGStateGuard contextGuard(fCtx); - - SetPolygonParameters(); - draw_polygon(fCtx, n, x, y, fConverter); -} - -//////////////////////////////////////////////////////////////////////////////// -///Check, may be, that's a hollow area, if so, call DrawPolyline instead. - -void Painter::DrawFillArea(Int_t n, const Double_t *x, const Double_t *y) -{ - if (!gVirtualX->GetFillStyle()) - return DrawPolyLine(n, x, y); - - if (fPainterMode == kPaintShadow || fPainterMode == kPaintThumbnail) - return FillArea(n, x, y); - - if (fPainterMode == kPaintToSelectionBuffer && PolygonHasStipple()) - return DrawPolyLine(n, x, y); - - if (PolygonHasStipple()) - return FillAreaWithPattern(n, x, y); - - FillArea(n, x, y); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::DrawFillArea(Int_t, const Float_t *, const Float_t *) -{ -/* if (!gVirtualX->GetFillStyle()) - return DrawPolyLine(n, x, y); - - SetPolygonParameters(); - draw_polygon(fCtx, n, x, y, fConverter);*/ -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::DrawPolyLine(Int_t n, const Double_t *x, const Double_t *y) -{ - const Util::CGStateGuard contextGuard(fCtx); - - SetStrokeParameters(); - draw_polyline(fCtx, n, x, y, fConverter, fPainterMode == kPaintSelected); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::DrawPolyLine(Int_t n, const Float_t *x, const Float_t *y) -{ - const Util::CGStateGuard contextGuard(fCtx); - - SetStrokeParameters(); - draw_polyline(fCtx, n, x, y, fConverter, fPainterMode == kPaintSelected); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::DrawPolyLineNDC(Int_t, const Double_t *, const Double_t *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::SetMarkerColor()const -{ - if (MarkerIsFilledPolygon(gVirtualX->GetMarkerStyle())) { - if (fPainterMode == kPaintToView || fPainterMode == kPaintSelected) { - SetMarkerFillColor(fCtx, gVirtualX->GetMarkerColor()); - } else if (fPainterMode == kPaintShadow) { - CGContextSetRGBFillColor(fCtx, shadowColor[0], shadowColor[1], shadowColor[2], shadowColor[3]); - } - } else { - if (fPainterMode == kPaintToView || fPainterMode == kPaintSelected) { - SetMarkerStrokeColor(fCtx, gVirtualX->GetMarkerColor()); - } else if (fPainterMode == kPaintShadow) { - CGContextSetRGBStrokeColor(fCtx, shadowColor[0], shadowColor[1], shadowColor[2], shadowColor[3]); - CGContextSetLineWidth(fCtx, 5.f); - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -///Check the current painter's mode. -///Skip polymarker if draw thumbnails. - -void Painter::DrawPolyMarker(Int_t n, const Double_t *x, const Double_t *y) -{ - if (fPainterMode == kPaintThumbnail) - return; - - fPolyMarker.resize(n); - for (Int_t i = 0; i < n; ++i) { - TPoint &p = fPolyMarker[i]; - p.SetX(fConverter.XToView(x[i])); - p.SetY(fConverter.YToView(y[i])); - } - - const Util::CGStateGuard contextGuard(fCtx); - - if (fPainterMode == kPaintToSelectionBuffer) { - SetPolygonColorForCurrentObjectID(); - GraphicUtils::DrawPolyMarker(fCtx, fPolyMarker, 5.f, kFullDotLarge);//Draw large circles into picker's buffer. - } else { - SetMarkerColor(); - GraphicUtils::DrawPolyMarker(fCtx, fPolyMarker, gVirtualX->GetMarkerSize(), gVirtualX->GetMarkerStyle()); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::DrawPolyMarker(Int_t, const Float_t *, const Float_t *) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::DrawText(Double_t x, Double_t y, const CTLineGuard &ctLine) -{ - UInt_t w = 0, h = 0; - ctLine.GetBounds(w, h); - - x = fConverter.XToView(x); - y = fConverter.YToView(y); - - Double_t xc = 0., yc = 0.; - - const UInt_t hAlign = UInt_t(gVirtualX->GetTextAlign() / 10); - switch (hAlign) { - case 1: - xc = 0.5 * w; - break; - case 2: - break; - case 3: - xc = -0.5 * w; - break; - } - - const UInt_t vAlign = UInt_t(gVirtualX->GetTextAlign() % 10); - switch (vAlign) { - case 1: - yc = 0.5 * h; - break; - case 2: - break; - case 3: - yc = -0.5 * h; - break; - } - - CGContextSaveGState(fCtx); - - CGContextSetTextMatrix(fCtx, CGAffineTransformIdentity); - - CGContextSetTextPosition(fCtx, 0.f, 0.f); - CGContextTranslateCTM(fCtx, x, y); - CGContextRotateCTM(fCtx, gVirtualX->GetTextAngle() * TMath::DegToRad()); - CGContextTranslateCTM(fCtx, xc, yc); - CGContextTranslateCTM(fCtx, -0.5 * w, -0.5 * h); - - CTLineDraw(ctLine.fCTLine, fCtx); - CGContextRestoreGState(fCtx); -} - -//////////////////////////////////////////////////////////////////////////////// -///TODO: mode parameter. - -void Painter::DrawText(Double_t x, Double_t y, const char *text, TVirtualPadPainter::ETextMode /*mode*/) -{ - const Util::CGStateGuard contextGuard(fCtx); - - if (fPainterMode == kPaintToView || fPainterMode == kPaintThumbnail) { - CTFontRef currentFont = fFontManager.SelectFont(gVirtualX->GetTextFont(), gVirtualX->GetTextSize()); - if (gVirtualX->GetTextFont() / 10 - 1 == 11) { - CTLineGuard ctLine(text, currentFont, fFontManager.GetSymbolMap()); - DrawText(x, y, ctLine); - } else { - CTLineGuard ctLine(text, currentFont, gVirtualX->GetTextColor()); - DrawText(x, y, ctLine); - } - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::DrawTextNDC(Double_t, Double_t, const char *, TVirtualPadPainter::ETextMode) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::SetContext(CGContextRef ctx) -{ - fCtx = ctx; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::SetTransform(UInt_t w, Double_t xMin, Double_t xMax, UInt_t h, Double_t yMin, Double_t yMax) -{ - fConverter.SetConverter(w, xMin, xMax, h, yMin, yMax); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::SetPainterMode(EMode mode) -{ - fPainterMode = mode; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::SetCurrentObjectID(UInt_t objId) -{ - fCurrentObjectID = objId; -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::GetTextExtent(UInt_t &w, UInt_t &h, const char *text) -{ - fFontManager.SelectFont(gVirtualX->GetTextFont(), gVirtualX->GetTextSize()); - fFontManager.GetTextBounds(w, h, text); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::SetLineColorForCurrentObjectID() const -{ - Float_t rgb[3] = {}; - fEncoder.IdToColor(fCurrentObjectID, rgb); - CGContextSetRGBStrokeColor(fCtx, rgb[0], rgb[1], rgb[2], 1.f); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::SetPolygonColorForCurrentObjectID() const -{ - Float_t rgb[3] = {}; - fEncoder.IdToColor(fCurrentObjectID, rgb); - CGContextSetRGBFillColor(fCtx, rgb[0], rgb[1], rgb[2], 1.f); -} - -//////////////////////////////////////////////////////////////////////////////// - -void Painter::SetLineColorHighlighted() const -{ - CGContextSetRGBStrokeColor(fCtx, 1.f, 0.f, 0.5f, 0.5f); -} - -}//namespace iOS -}//namespace ROOT diff --git a/graf2d/ios/src/IOSResourceManagement.cxx b/graf2d/ios/src/IOSResourceManagement.cxx deleted file mode 100644 index 900503a96e919..0000000000000 --- a/graf2d/ios/src/IOSResourceManagement.cxx +++ /dev/null @@ -1,62 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#include - -#include "IOSResourceManagement.h" - -namespace ROOT { -namespace iOS { -namespace Util { - -//////////////////////////////////////////////////////////////////////////////// - -CFStringGuard::CFStringGuard(const char *text) - : fCFString(0) -{ - fCFString = CFStringCreateWithCString(kCFAllocatorDefault, text, kCFStringEncodingMacRoman); - if (!fCFString) - std::runtime_error("CFStringGuard: create failed"); -} - -//////////////////////////////////////////////////////////////////////////////// - -CFStringGuard::~CFStringGuard() -{ - CFRelease(fCFString); -} - -//////////////////////////////////////////////////////////////////////////////// - -CFStringRef CFStringGuard::Get()const -{ - return fCFString; -} - -//////////////////////////////////////////////////////////////////////////////// - -CGStateGuard::CGStateGuard(CGContextRef ctx) - : fCtx(ctx) -{ - CGContextSaveGState(ctx); -} - -//////////////////////////////////////////////////////////////////////////////// - -CGStateGuard::~CGStateGuard() -{ - CGContextRestoreGState(fCtx); -} - - -}//namespace Util -}//namespace iOS -}//namespace ROOT diff --git a/graf2d/ios/src/IOSSelectionMarkers.cxx b/graf2d/ios/src/IOSSelectionMarkers.cxx deleted file mode 100644 index 0bea36abcbc38..0000000000000 --- a/graf2d/ios/src/IOSSelectionMarkers.cxx +++ /dev/null @@ -1,36 +0,0 @@ -#include "IOSResourceManagement.h" -#include "IOSSelectionMarkers.h" - -namespace ROOT { -namespace iOS { -namespace GraphicUtils { - -//////////////////////////////////////////////////////////////////////////////// -/// - -void DrawSelectionMarker(CGContextRef ctx, const CGPoint &point) -{ - const CGFloat externalRadius = 5.f; - const CGFloat internalRadius = 4.f; - - const Util::CGStateGuard ctxGuard(ctx); - CGContextSetRGBFillColor(ctx, 1.f, 1.f, 1.f, 1.f); - CGContextFillEllipseInRect(ctx, CGRectMake(point.x - externalRadius, point.y - externalRadius, 2 * externalRadius, 2 * externalRadius)); - CGContextSetRGBFillColor(ctx, 0.f, 0.f, 1.f, 1.f); - CGContextFillEllipseInRect(ctx, CGRectMake(point.x - internalRadius, point.y - internalRadius, 2 * internalRadius, 2 * internalRadius)); -} - -//////////////////////////////////////////////////////////////////////////////// -/// - -void DrawBoxSelectionMarkers(CGContextRef ctx, const CGRect &box) -{ - DrawSelectionMarker(ctx, box.origin); - DrawSelectionMarker(ctx, CGPointMake(box.origin.x, box.origin.y + box.size.height)); - DrawSelectionMarker(ctx, CGPointMake(box.origin.x + box.size.width, box.origin.y)); - DrawSelectionMarker(ctx, CGPointMake(box.origin.x + box.size.width, box.origin.y + box.size.height)); -} - -} -} -} diff --git a/graf2d/ios/src/IOSTextOperations.cxx b/graf2d/ios/src/IOSTextOperations.cxx deleted file mode 100644 index 638105c328d31..0000000000000 --- a/graf2d/ios/src/IOSTextOperations.cxx +++ /dev/null @@ -1,448 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 14/8/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -#include "TVirtualX.h" -#include "TColor.h" -#include "TROOT.h" - -#include "IOSTextOperations.h" -#include "IOSGraphicUtils.h" - -namespace ROOT { -namespace iOS { - -const CFStringRef fixedFontNames[FontManager::fmdNOfFonts] = - { - CFSTR("TimesNewRomanPS-ItalicMT"), - CFSTR("TimesNewRomanPS-BoldMT"), - CFSTR("TimesNewRomanPS-BoldItalicMT"), - CFSTR("Helvetica"), - CFSTR("Helvetica-Oblique"), - CFSTR("Helvetica-Bold"), - CFSTR("Helvetica-BoldOblique"), - CFSTR("Courier"), - CFSTR("Courier-Oblique"), - CFSTR("Courier-Bold"), - CFSTR("Courier-BoldOblique"), - CFSTR("Helvetica"), - CFSTR("TimesNewRomanPSMT") - }; - -const char *cStrFontNames[FontManager::fmdNOfFonts] = - { - "TimesNewRomanPS-ItalicMT", - "TimesNewRomanPS-BoldMT", - "TimesNewRomanPS-BoldItalicMT", - "Helvetica", - "Helvetica-Oblique", - "Helvetica-Bold", - "Helvetica-BoldOblique", - "Courier", - "Courier-Oblique", - "Courier-Bold", - "Courier-BoldOblique", - "Helvetica", - "TimesNewRomanPSMT" - }; - -//////////////////////////////////////////////////////////////////////////////// -///Create attributed string with one attribue: the font. - -CTLineGuard::CTLineGuard(const char *textLine, CTFontRef font) - : fCTLine(0) -{ - CFStringRef keys[] = {kCTFontAttributeName}; - CFTypeRef values[] = {font}; - - Init(textLine, 1, keys, values); -} - -//////////////////////////////////////////////////////////////////////////////// -///Create attributed string with font and color. - -CTLineGuard::CTLineGuard(const char *textLine, CTFontRef font, Color_t /*color*/) - : fCTLine(0) -{ - Util::RefGuardGeneric rgbColorSpace(CGColorSpaceCreateDeviceRGB()); - if (!rgbColorSpace.Get()) - throw std::runtime_error("CTLineGuard: color space"); - - CGFloat rgba[] = {0.f, 0.f, 0.f, 1.f}; - Float_t r = 0.f, g = 0.f, b = 0.f; - GraphicUtils::GetColorForIndex(gVirtualX->GetTextColor(), r, g, b); - rgba[0] = r; rgba[1] = g; rgba[2] = b; - - Util::RefGuardGeneric textColor(CGColorCreate(rgbColorSpace.Get(), rgba)); - //Not clear from docs, if textColor.Get() can be 0. - - CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName}; - CFTypeRef values[] = {font, textColor.Get()}; - - Init(textLine, 2, keys, values); -} - -//////////////////////////////////////////////////////////////////////////////// -///Create attributed string with font and color. - -CTLineGuard::CTLineGuard(const char *textLine, CTFontRef font, const std::vector &symbolMap) - : fCTLine(0) -{ - Util::RefGuardGeneric rgbColorSpace(CGColorSpaceCreateDeviceRGB()); - if (!rgbColorSpace.Get()) - throw std::runtime_error("CTLineGuard: color space"); - - CGFloat rgba[] = {0.f, 0.f, 0.f, 1.f}; - Float_t r = 0.f, g = 0.f, b = 0.f; - GraphicUtils::GetColorForIndex(gVirtualX->GetTextColor(), r, g, b); - rgba[0] = r; rgba[1] = g; rgba[2] = b; - - Util::RefGuardGeneric textColor(CGColorCreate(rgbColorSpace.Get(), rgba)); - const unsigned length = std::strlen(textLine); - std::vector convertedLine(length); - for (unsigned i = 0; i < length; ++i) - convertedLine[i] = symbolMap[(unsigned char)textLine[i]]; - - CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName}; - CFTypeRef values[] = {font, textColor.Get()}; - - Init(convertedLine, 2, keys, values); -} - -//////////////////////////////////////////////////////////////////////////////// - -CTLineGuard::~CTLineGuard() -{ - CFRelease(fCTLine); -} - -//////////////////////////////////////////////////////////////////////////////// - -void CTLineGuard::GetBounds(UInt_t &w, UInt_t &h)const -{ - CGFloat ascent = 0.f, descent = 0.f, leading = 0.f; - w = UInt_t(CTLineGetTypographicBounds(fCTLine, &ascent, &descent, &leading)); - h = UInt_t(ascent);// + descent + leading); -} - -//////////////////////////////////////////////////////////////////////////////// - -void CTLineGuard::Init(const char *textLine, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values) -{ - Util::RefGuard stringAttribs( - CFDictionaryCreate(kCFAllocatorDefault, - (const void **)keys, - (const void **)values, - nAttribs, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks) - ); - - if (!stringAttribs.Get()) - throw std::runtime_error("CTLineGuard: null attribs"); - - Util::RefGuard wrappedCString(CFStringCreateWithCString(kCFAllocatorDefault, textLine, kCFStringEncodingMacRoman)); - if (!wrappedCString.Get()) - throw std::runtime_error("CTLineGuard: cstr wrapper"); - - Util::RefGuard attributedString(CFAttributedStringCreate(kCFAllocatorDefault, wrappedCString.Get(), stringAttribs.Get())); - fCTLine = CTLineCreateWithAttributedString(attributedString.Get()); - - if (!fCTLine) - throw std::runtime_error("CTLineGuard: attrib string"); -} - -//////////////////////////////////////////////////////////////////////////////// - -void CTLineGuard::Init(const std::vector &textLine, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values) -{ - Util::RefGuard stringAttribs( - CFDictionaryCreate(kCFAllocatorDefault, - (const void **)keys, - (const void **)values, - nAttribs, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks) - ); - - if (!stringAttribs.Get()) - throw std::runtime_error("CTLineGuard: null attribs"); - - Util::RefGuard wrappedCString(CFStringCreateWithCharacters(kCFAllocatorDefault, &textLine[0], textLine.size())); - if (!wrappedCString.Get()) - throw std::runtime_error("CTLineGuard: cstr wrapper"); - - Util::RefGuard attributedString(CFAttributedStringCreate(kCFAllocatorDefault, wrappedCString.Get(), stringAttribs.Get())); - fCTLine = CTLineCreateWithAttributedString(attributedString.Get()); - - if (!fCTLine) - throw std::runtime_error("CTLineGuard: attrib string"); -} - -//////////////////////////////////////////////////////////////////////////////// - -FontManager::FontManager() - : fSelectedFont(0) -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -FontManager::~FontManager() -{ - for (UInt_t i = 0; i < fmdNOfFonts; ++i) - for (FontMapIter_t it = fFonts[i].begin(); it != fFonts[i].end(); ++it) - CFRelease(it->second); -} - -//////////////////////////////////////////////////////////////////////////////// - -CTFontRef FontManager::SelectFont(Font_t fontIndex, Float_t fontSize) -{ - fontIndex /= 10; - - if (fontIndex > fmdNOfFonts || !fontIndex) - throw std::runtime_error("SelectFont: index"); - - fontIndex -= 1; - - if (fontIndex == 11 && !fSymbolMap.size()) - InitSymbolMap(); - - const UInt_t fixedSize = UInt_t(fontSize); - FontMapIter_t it = fFonts[fontIndex].find(fixedSize); - - if (it == fFonts[fontIndex].end()) { - //Insert the new font. - Util::RefGuard font(CTFontCreateWithName(fixedFontNames[fontIndex], fixedSize, 0)); - if (!font.Get()) //With Apple's lame documentation it's not clear, if function can return 0. - throw std::runtime_error(std::string("SelectFont: create") + cStrFontNames[fontIndex]); - - fFonts[fontIndex][fixedSize] = font.Get(); - return fSelectedFont = font.Release(); - } - - return fSelectedFont = it->second; -} - -//////////////////////////////////////////////////////////////////////////////// - -void FontManager::GetTextBounds(UInt_t &w, UInt_t &h, const char *text)const -{ - if (!fSelectedFont) - throw std::runtime_error("GetTextBounds: font not selected"); - - Font_t fontIndex = gVirtualX->GetTextFont() / 10 - 1; - - if (fontIndex == 11) { - CTLineGuard ctLine(text, fSelectedFont, fSymbolMap); - ctLine.GetBounds(w, h); - } else { - CTLineGuard ctLine(text, fSelectedFont); - ctLine.GetBounds(w, h); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -Double_t FontManager::GetAscent()const -{ - if (!fSelectedFont) - throw std::runtime_error("GetAscent"); - - return CTFontGetAscent(fSelectedFont); -} - -//////////////////////////////////////////////////////////////////////////////// - -Double_t FontManager::GetDescent()const -{ - if (!fSelectedFont) - throw std::runtime_error("GetDescent"); - - return CTFontGetDescent(fSelectedFont); -} - -//////////////////////////////////////////////////////////////////////////////// - -Double_t FontManager::GetLeading()const -{ - if (!fSelectedFont) - throw std::runtime_error("GetLeading"); - - return CTFontGetLeading(fSelectedFont); -} - -//////////////////////////////////////////////////////////////////////////////// - -void FontManager::InitSymbolMap() -{ - fSymbolMap.clear(); - fSymbolMap.resize(1 << std::numeric_limits::digits, 0); - - fSymbolMap[97] = 0x3B1; //alpha - fSymbolMap[98] = 0x3B2; //beta - fSymbolMap[103] = 0x3B3; //gamma - fSymbolMap[100] = 0x3B4; //delta - fSymbolMap[206] = 0x3F5; //epsilon - fSymbolMap[122] = 0x3B6; //zeta - fSymbolMap[104] = 0x3B7; //eta - fSymbolMap[113] = 0x3B8; //theta - fSymbolMap[105] = 0x3B9; //iota - fSymbolMap[107] = 0x3BA; //kappa - fSymbolMap[108] = 0x3BB; //lambda - fSymbolMap[109] = 0x3BC; //mu - fSymbolMap[110] = 0x3BD; //nu - fSymbolMap[120] = 0x3BE; //xi - fSymbolMap[111] = 0x3BF; //omicron - fSymbolMap[112] = 0x3C0; //pi - fSymbolMap[114] = 0x3C1; //rho - fSymbolMap[115] = 0x3C3; //sigma - fSymbolMap[116] = 0x3C4; //tau - fSymbolMap[117] = 0x3C5; //upsilon - fSymbolMap[102] = 0x3C6; //phi - fSymbolMap[99] = 0x3C7; //chi - fSymbolMap[121] = 0x3C8; //psi - fSymbolMap[119] = 0x3C9; //omega - - fSymbolMap[65] = 0x391; //Alpha - fSymbolMap[66] = 0x392; //Beta - fSymbolMap[71] = 0x393; //Gamma - fSymbolMap[68] = 0x394; //Delta - fSymbolMap[69] = 0x395; //Epsilon - fSymbolMap[90] = 0x396; //Zeta - fSymbolMap[72] = 0x397; //Eta - fSymbolMap[81] = 0x398; //Theta - fSymbolMap[73] = 0x399; //Iota - fSymbolMap[75] = 0x39A; //Kappa - fSymbolMap[76] = 0x39B; //Lambda - fSymbolMap[77] = 0x39C; //Mu - fSymbolMap[78] = 0x39D; //Nu - fSymbolMap[88] = 0x39E; //Xi - fSymbolMap[79] = 0x39F; //Omicron - fSymbolMap[80] = 0x3A0; //Pi - fSymbolMap[82] = 0x3A1; //Rho - fSymbolMap[83] = 0x3A3; //Sigma - fSymbolMap[84] = 0x3A4; //Tau - fSymbolMap[85] = 0x3A5; //Upsilon - fSymbolMap[70] = 0x3A6; //Phi - fSymbolMap[67] = 0x3A7; //Chi - fSymbolMap[89] = 0x3A8; //Psi - fSymbolMap[87] = 0x3A9; //Omega - - fSymbolMap[101] = 0x3B5; //varepsilon - fSymbolMap[74] = 0x3D1; //vartheta - fSymbolMap[86] = 0x3C2; //varsigma - fSymbolMap[161] = 0x3D2; //varUpsilon - fSymbolMap[106] = 0x3D5; //varphi??? - fSymbolMap[118] = 0x3D6; //varomega? - - fSymbolMap[167] = 0x2663; - fSymbolMap[195] = 0x2118; - fSymbolMap[163] = 0x2264; - fSymbolMap[187] = 0x2248; - fSymbolMap[206] = 0x2208; - fSymbolMap[201] = 0x2283; - fSymbolMap[199] = 0x2229; - fSymbolMap[211] = 0xA9; - fSymbolMap[212] = 0x2122; - fSymbolMap[180] = 0xD7; - fSymbolMap[183] = 0x2022; - fSymbolMap[166] = 0x192; - fSymbolMap[178] = 0x2033; - fSymbolMap[231] = 0x7C; - fSymbolMap[232] = 0x23A9; - fSymbolMap[175] = 0x2193; - fSymbolMap[171] = 0x2194; - fSymbolMap[223] = 0x21D3; - fSymbolMap[219] = 0x21D4; - fSymbolMap[234] = 0x23AA; - fSymbolMap[104] = 0x127; - - fSymbolMap[168] = 0x2666; - fSymbolMap[192] = 0x2135; - fSymbolMap[179] = 0x2265; - fSymbolMap[185] = 0x2260; - fSymbolMap[207] = 0x2209; - fSymbolMap[205] = 0x2286; - fSymbolMap[200] = 0x222A; - fSymbolMap[227] = 0xA9; - fSymbolMap[228] = 0x2122; - fSymbolMap[184] = 0xF7; - fSymbolMap[176] = 0xB0; - fSymbolMap[165] = 0x221E; - fSymbolMap[208] = 0x2220; - fSymbolMap[189] = 0x7C; - fSymbolMap[230] = 0x23A7; - fSymbolMap[172] = 0x2190; - fSymbolMap[196] = 0x2297; - fSymbolMap[220] = 0x21D0; - fSymbolMap[213] = 0x220F; - - fSymbolMap[169] = 0x2665; - fSymbolMap[193] = 0x2111; - fSymbolMap[225] = 0x3008; - fSymbolMap[186] = 0x2261; - fSymbolMap[204] = 0x2282; - fSymbolMap[202] = 0x2287; - fSymbolMap[217] = 0x2227; - fSymbolMap[210] = 0xAE; - fSymbolMap[197] = 0xC5; //no need - fSymbolMap[177] = 0xB1; - fSymbolMap[188] = 0x2026; - fSymbolMap[209] = 0x2207; - fSymbolMap[191] = 0x21B5; - fSymbolMap[190] = 0x2015;//WRONG - fSymbolMap[236] = 0x23A7; - fSymbolMap[173] = 0x2191; - fSymbolMap[197] = 0x2295; - fSymbolMap[221] = 0x21D1; - fSymbolMap[229] = 0x2211; - fSymbolMap[34] = 0x2200; - - fSymbolMap[170] = 0x2660; - fSymbolMap[194] = 0x211C; - fSymbolMap[241] = 0x3009; - fSymbolMap[181] = 0x221D; - fSymbolMap[203] = 0x2284; - fSymbolMap[198] = 0x2205; - fSymbolMap[218] = 0x2228; - fSymbolMap[226] = 0xAE; - fSymbolMap[229] = 0xE5; //no need - fSymbolMap[164] = 0x2044; - fSymbolMap[215] = 0x22C5; - fSymbolMap[182] = 0x2202; - fSymbolMap[216] = 0xAC; - fSymbolMap[237] = 0x23A8; - fSymbolMap[235] = 0x23A3; - fSymbolMap[174] = 0x2192; - fSymbolMap[214] = 0x221A; - fSymbolMap[222] = 0x21D2; - fSymbolMap[242] = 0x222B; - fSymbolMap[36] = 0x2203; -} - -}//namespace iOS -}//namespace ROOT diff --git a/graf2d/ios/src/TGIOS.cxx b/graf2d/ios/src/TGIOS.cxx deleted file mode 100644 index ddbe0295b0cf5..0000000000000 --- a/graf2d/ios/src/TGIOS.cxx +++ /dev/null @@ -1,161 +0,0 @@ -// @(#)root/graf2d:$Id$ -// Author: Timur Pocheptsov, 19/10/2011 - -/************************************************************************* - * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#include - -#include "IOSPad.h" -#include "TGIOS.h" - - -namespace ROOT { -namespace iOS { - -//////////////////////////////////////////////////////////////////////////////// -/// Default ctor. - -TGIOS::TGIOS() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -/// Ctor. - -TGIOS::TGIOS(const char *name, const char *title) - : TVirtualX(name, title) -{ -} - -//TAttLine. -//////////////////////////////////////////////////////////////////////////////// -/// Sets color index "cindex" for drawing lines. - -void TGIOS::SetLineColor(Color_t cindex) -{ - TAttLine::SetLineColor(cindex); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sets the line style. -/// -/// linestyle <= 1 solid -/// linestyle = 2 dashed -/// linestyle = 3 dotted -/// linestyle = 4 dashed-dotted - -void TGIOS::SetLineStyle(Style_t linestyle) -{ - TAttLine::SetLineStyle(linestyle); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sets the line width. -/// -/// width - the line width in pixels - -void TGIOS::SetLineWidth(Width_t width) -{ - TAttLine::SetLineWidth(width); -} - -//TAttFill. -//////////////////////////////////////////////////////////////////////////////// -/// Sets color index "cindex" for fill areas. - -void TGIOS::SetFillColor(Color_t cindex) -{ - TAttFill::SetFillColor(cindex); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sets fill area style. -/// -/// style - compound fill area interior style -/// style = 1000 * interiorstyle + styleindex - -void TGIOS::SetFillStyle(Style_t style) -{ - TAttFill::SetFillStyle(style); -} - -//TAttMarker. -//////////////////////////////////////////////////////////////////////////////// -/// Sets color index "cindex" for markers. - -void TGIOS::SetMarkerColor(Color_t cindex) -{ - TAttMarker::SetMarkerColor(cindex); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sets marker size index. -/// -/// markersize - the marker scale factor - -void TGIOS::SetMarkerSize(Float_t markersize) -{ - TAttMarker::SetMarkerSize(markersize); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sets marker style. - -void TGIOS::SetMarkerStyle(Style_t markerstyle) -{ - TAttMarker::SetMarkerStyle(markerstyle); -} - -//TAttText. -//////////////////////////////////////////////////////////////////////////////// -/// Sets the text alignment. -/// -/// talign = txalh horizontal text alignment -/// talign = txalv vertical text alignment - -void TGIOS::SetTextAlign(Short_t talign) -{ - TAttText::SetTextAlign(talign); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sets the color index "cindex" for text. - -void TGIOS::SetTextColor(Color_t cindex) -{ - TAttText::SetTextColor(cindex); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sets the current text font number. - -void TGIOS::SetTextFont(Font_t fontnumber) -{ - TAttText::SetTextFont(fontnumber); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sets the current text size to "textsize" - -void TGIOS::SetTextSize(Float_t textsize) -{ - TAttText::SetTextSize(textsize); -} - -//////////////////////////////////////////////////////////////////////////////// -///With all these global variables like gVirtualX and gPad, I have to use this trick. - -void TGIOS::GetTextExtent(UInt_t &w, UInt_t &h, char *textLine) -{ - Pad *p = static_cast(gPad); - p->GetTextExtent(w, h, textLine); -} - -} -} diff --git a/graf2d/primitives/CMakeLists.txt b/graf2d/primitives/CMakeLists.txt index f491eb70a900a..e5564309e0676 100644 --- a/graf2d/primitives/CMakeLists.txt +++ b/graf2d/primitives/CMakeLists.txt @@ -4,13 +4,12 @@ ############################################################################ -ROOT_GLOB_HEADERS(GPrim_v7_dict_headers ${CMAKE_CURRENT_SOURCE_DIR}/v7/inc/ROOT/T*.hxx) +ROOT_GLOB_HEADERS(GPrim_v7_dict_headers ${CMAKE_CURRENT_SOURCE_DIR}/v7/inc/ROOT/R*.hxx) ROOT_GLOB_SOURCES(src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} v7/src/*.cxx) ROOT_STANDARD_LIBRARY_PACKAGE(ROOTGraphicsPrimitives HEADERS ${GPrim_v7_dict_headers} SOURCES ${src} DICTIONARY_OPTIONS "-writeEmptyRootPCM" DEPENDENCIES RIO Core) -if(testing) - add_subdirectory(v7/test) -endif() + +ROOT_ADD_TEST_SUBDIRECTORY(v7/test) diff --git a/graf2d/primitives/inc/LinkDef.h b/graf2d/primitives/inc/LinkDef.h index 365a5e3e49717..cf66833be260f 100644 --- a/graf2d/primitives/inc/LinkDef.h +++ b/graf2d/primitives/inc/LinkDef.h @@ -14,31 +14,31 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class ROOT::Experimental::TDisplayItem+; -#pragma link C++ class ROOT::Experimental::TPalette+; -#pragma link C++ class ROOT::Experimental::TColor+; -#pragma link C++ class ROOT::Experimental::TStringEnumAttrBase+; -#pragma link C++ class ROOT::Experimental::TDrawingAttrBase+; -#pragma link C++ class ROOT::Experimental::TDrawingAttr+; -#pragma link C++ class ROOT::Experimental::TDrawingAttr+; -#pragma link C++ class ROOT::Experimental::TDrawingAttr+; -#pragma link C++ class ROOT::Experimental::TDrawingOptsBase+; -#pragma link C++ class ROOT::Experimental::TOrdinaryDisplayItem+; -#pragma link C++ class ROOT::Experimental::TText+; -#pragma link C++ class ROOT::Experimental::TText::DrawingOpts+; -#pragma link C++ class ROOT::Experimental::TDrawableBase+; -#pragma link C++ class ROOT::Experimental::Internal::TUniWeakPtr+; -#pragma link C++ class ROOT::Experimental::TOrdinaryDisplayItem+; -#pragma link C++ class ROOT::Experimental::TLine+; -#pragma link C++ class ROOT::Experimental::TLine::DrawingOpts+; -#pragma link C++ class ROOT::Experimental::TDrawableBase+; -#pragma link C++ class ROOT::Experimental::Internal::TUniWeakPtr+; -#pragma link C++ class ROOT::Experimental::TOrdinaryDisplayItem+; -#pragma link C++ class ROOT::Experimental::TMarker+; -#pragma link C++ class ROOT::Experimental::TMarker::DrawingOpts+; -#pragma link C++ class ROOT::Experimental::TDrawableBase+; -#pragma link C++ class ROOT::Experimental::Internal::TUniWeakPtr+; -#pragma link C++ class ROOT::Experimental::TOrdinaryDisplayItem+; -#pragma link C++ class ROOT::Experimental::TStyle+; +#pragma link C++ class ROOT::Experimental::RDisplayItem+; +#pragma link C++ class ROOT::Experimental::RPalette+; +#pragma link C++ class ROOT::Experimental::RColor+; +#pragma link C++ class ROOT::Experimental::RStringEnumAttrBase+; +#pragma link C++ class ROOT::Experimental::RDrawingAttrBase+; +#pragma link C++ class ROOT::Experimental::RDrawingAttr+; +#pragma link C++ class ROOT::Experimental::RDrawingAttr+; +#pragma link C++ class ROOT::Experimental::RDrawingAttr+; +#pragma link C++ class ROOT::Experimental::RDrawingOptsBase+; +#pragma link C++ class ROOT::Experimental::ROrdinaryDisplayItem+; +#pragma link C++ class ROOT::Experimental::RText+; +#pragma link C++ class ROOT::Experimental::RText::DrawingOpts+; +#pragma link C++ class ROOT::Experimental::RDrawableBase+; +#pragma link C++ class ROOT::Experimental::Internal::TUniWeakPtr+; +#pragma link C++ class ROOT::Experimental::ROrdinaryDisplayItem+; +#pragma link C++ class ROOT::Experimental::RLine+; +#pragma link C++ class ROOT::Experimental::RLine::DrawingOpts+; +#pragma link C++ class ROOT::Experimental::RDrawableBase+; +#pragma link C++ class ROOT::Experimental::Internal::TUniWeakPtr+; +#pragma link C++ class ROOT::Experimental::ROrdinaryDisplayItem+; +#pragma link C++ class ROOT::Experimental::RMarker+; +#pragma link C++ class ROOT::Experimental::RMarker::DrawingOpts+; +#pragma link C++ class ROOT::Experimental::RDrawableBase+; +#pragma link C++ class ROOT::Experimental::Internal::TUniWeakPtr+; +#pragma link C++ class ROOT::Experimental::ROrdinaryDisplayItem+; +#pragma link C++ class ROOT::Experimental::RStyle+; #endif diff --git a/graf2d/primitives/v7/inc/ROOT/TColor.hxx b/graf2d/primitives/v7/inc/ROOT/RColor.hxx similarity index 83% rename from graf2d/primitives/v7/inc/ROOT/TColor.hxx rename to graf2d/primitives/v7/inc/ROOT/RColor.hxx index d806f9ed21032..a7bdd0cf66f0c 100644 --- a/graf2d/primitives/v7/inc/ROOT/TColor.hxx +++ b/graf2d/primitives/v7/inc/ROOT/RColor.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TColor.hxx +/// \file ROOT/RColor.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-09-26 @@ -13,20 +13,20 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TColor -#define ROOT7_TColor +#ifndef ROOT7_RColor +#define ROOT7_RColor #include namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TColor - A color: Red|Green|Blue|Alpha, or a position in a TPalette +/** \class ROOT::Experimental::RColor + A color: Red|Green|Blue|Alpha, or a position in a RPalette */ -class TColor { +class RColor { public: - /** \class ROOT::Experimental::TColor::TAlpha + /** \class ROOT::Experimental::RColor::TAlpha The alpha value of a color: 0 is completely transparent, 1 is completely opaque. */ struct Alpha { @@ -40,8 +40,8 @@ public: enum class EKind { kRGBA, ///< The color is defined as specific RGBA values. - kPalettePos, ///< The color is defined as a value in the `TFrame`'s `TPalette`. - kAuto ///< The color will be set upon drawing the canvas choosing a `TPalette` color, see `TColor(Auto_t)` + kPalettePos, ///< The color is defined as a value in the `RFrame`'s `RPalette`. + kAuto ///< The color will be set upon drawing the canvas choosing a `RPalette` color, see `RColor(Auto_t)` }; private: @@ -70,43 +70,43 @@ public: using RGBA = std::array; // Default constructor: good old solid black. - constexpr TColor() = default; + constexpr RColor() = default; - /// Initialize a TColor with red, green, blue and alpha component. - constexpr TColor(float r, float g, float b, float alpha): fRedOrPalettePos(r), fGreen(g), fBlue(b), fAlpha(alpha) {} + /// Initialize a RColor with red, green, blue and alpha component. + constexpr RColor(float r, float g, float b, float alpha): fRedOrPalettePos(r), fGreen(g), fBlue(b), fAlpha(alpha) {} - /// Initialize a TColor with red, green, blue and alpha component. - constexpr TColor(float r, float g, float b, Alpha alpha = kOpaque): TColor(r, g, b, alpha.fVal) {} + /// Initialize a RColor with red, green, blue and alpha component. + constexpr RColor(float r, float g, float b, Alpha alpha = kOpaque): RColor(r, g, b, alpha.fVal) {} - /// Initialize a TColor with red, green, blue and alpha component as an array. - constexpr TColor(const RGBA &rgba): TColor(rgba[0], rgba[1], rgba[2], rgba[3]) {} + /// Initialize a RColor with red, green, blue and alpha component as an array. + constexpr RColor(const RGBA &rgba): RColor(rgba[0], rgba[1], rgba[2], rgba[3]) {} - /// Initialize a `TColor` with a `TPalette` ordinal. The actual color is determined from the pad's - /// (or rather its `TFrame`'s) `TPalette` - constexpr TColor(float paletteOrdinal): fRedOrPalettePos(paletteOrdinal), fKind(EKind::kPalettePos) {} + /// Initialize a `RColor` with a `RPalette` ordinal. The actual color is determined from the pad's + /// (or rather its `RFrame`'s) `RPalette` + constexpr RColor(float paletteOrdinal): fRedOrPalettePos(paletteOrdinal), fKind(EKind::kPalettePos) {} /**\class AutoTag Used to signal that this color shall be automatically chosen by the drawing routines, by picking a color - from the `TPad`'s (or rather its `TFrame`'s) current `TPalette`. + from the `RPad`'s (or rather its `RFrame`'s) current `RPalette`. */ class AutoTag {}; - /// Constructs an automatically assigned color. Call as `TColor col(TColor::kAuto)`. - constexpr TColor(AutoTag): fKind(EKind::kAuto) {} + /// Constructs an automatically assigned color. Call as `RColor col(RColor::kAuto)`. + constexpr RColor(AutoTag): fKind(EKind::kAuto) {} - /// Determine whether this TColor is storing RGBA (in contrast to an ordinal of a TPalette). + /// Determine whether this RColor is storing RGBA (in contrast to an ordinal of a RPalette). bool IsRGBA() const { return fKind == EKind::kRGBA; } - /// Determine whether this `TColor` is storing an ordinal of a TPalette (in contrast to RGBA). + /// Determine whether this `RColor` is storing an ordinal of a RPalette (in contrast to RGBA). bool IsPaletteOrdinal() const { return fKind == EKind::kPalettePos; } - /// Determine whether this `TColor` will be assigned a actual color upon drawing. + /// Determine whether this `RColor` will be assigned a actual color upon drawing. bool IsAuto() const { return fKind == EKind::kAuto; } /// If this is an ordinal in a palette, resolve the float GetPaletteOrdinal() const; - friend bool operator==(const TColor &lhs, const TColor &rhs) + friend bool operator==(const RColor &lhs, const RColor &rhs) { if (lhs.fKind != rhs.fKind) return false; @@ -180,7 +180,7 @@ public: fAlpha = (float)a; } - /// Return the Hue, Light, Saturation (HLS) definition of this TColor + /// Return the Hue, Light, Saturation (HLS) definition of this RColor void GetHLS(float &hue, float &light, float &satur) { hue = light = satur = 0.; if (AssertNotPalettePos()) { @@ -260,10 +260,10 @@ public: ///\} }; -// TODO: see also imagemagick's C++ interface for TColor operations! +// TODO: see also imagemagick's C++ interface for RColor operations! // https://www.imagemagick.org/api/magick++-classes.php -void InitializeAttrFromString(const std::string &name, const std::string &strval, TColor& val); +void InitializeAttrFromString(const std::string &name, const std::string &strval, RColor& val); } // namespace Experimental } // namespace ROOT diff --git a/graf2d/primitives/v7/inc/ROOT/TDisplayItem.hxx b/graf2d/primitives/v7/inc/ROOT/RDisplayItem.hxx similarity index 77% rename from graf2d/primitives/v7/inc/ROOT/TDisplayItem.hxx rename to graf2d/primitives/v7/inc/ROOT/RDisplayItem.hxx index 73da389392521..68ed1c9cc5ca7 100644 --- a/graf2d/primitives/v7/inc/ROOT/TDisplayItem.hxx +++ b/graf2d/primitives/v7/inc/ROOT/RDisplayItem.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TDisplayItem.h +/// \file ROOT/RDisplayItem.h /// \ingroup Base ROOT7 /// \author Sergey Linev /// \date 2017-05-31 @@ -13,8 +13,8 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TDisplayItem -#define ROOT7_TDisplayItem +#ifndef ROOT7_RDisplayItem +#define ROOT7_RDisplayItem #include #include @@ -22,20 +22,20 @@ namespace ROOT { namespace Experimental { -class TCanvas; -class TFrame; +class RCanvas; +class RFrame; -/** \class TDisplayItem +/** \class RDisplayItem Base class for painting data for JS. */ -class TDisplayItem { +class RDisplayItem { protected: std::string fObjectID; ///< unique object identifier public: - TDisplayItem() = default; - virtual ~TDisplayItem() {} + RDisplayItem() = default; + virtual ~RDisplayItem() {} void SetObjectID(const std::string &id) { fObjectID = id; } std::string GetObjectID() const { return fObjectID; } @@ -44,12 +44,12 @@ public: // direct pointer to some object without ownership template -class TOrdinaryDisplayItem : public TDisplayItem { +class ROrdinaryDisplayItem : public RDisplayItem { protected: const T *fObject{nullptr}; ///< direct pointer without ownership public: - TOrdinaryDisplayItem(const T *addr) : TDisplayItem(), fObject(addr) {} + ROrdinaryDisplayItem(const T *addr) : RDisplayItem(), fObject(addr) {} const T *GetObject() const { return fObject; } }; @@ -57,12 +57,12 @@ public: // unique pointer of specified class with ownership template -class TUniqueDisplayItem : public TDisplayItem { +class RUniqueDisplayItem : public RDisplayItem { protected: std::unique_ptr fObject; public: - TUniqueDisplayItem(T *addr) : TDisplayItem(), fObject(addr) {} + RUniqueDisplayItem(T *addr) : RDisplayItem(), fObject(addr) {} T *GetObject() const { return fObject.get(); } }; diff --git a/graf2d/primitives/v7/inc/ROOT/TDrawingAttr.hxx b/graf2d/primitives/v7/inc/ROOT/RDrawingAttr.hxx similarity index 76% rename from graf2d/primitives/v7/inc/ROOT/TDrawingAttr.hxx rename to graf2d/primitives/v7/inc/ROOT/RDrawingAttr.hxx index bcd3d6b093f55..cf320abc11e33 100644 --- a/graf2d/primitives/v7/inc/ROOT/TDrawingAttr.hxx +++ b/graf2d/primitives/v7/inc/ROOT/RDrawingAttr.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TDrawingAttr.hxx +/// \file ROOT/RDrawingAttr.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-09-26 @@ -13,10 +13,10 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TDrawingAttr -#define ROOT7_TDrawingAttr +#ifndef ROOT7_RDrawingAttr +#define ROOT7_RDrawingAttr -#include +#include #include #include @@ -25,7 +25,7 @@ namespace ROOT { namespace Experimental { -class TDrawingOptsBase; +class RDrawingOptsBase; ///\{ /// Initialize an attribute `val` from a string value. @@ -39,32 +39,32 @@ void InitializeAttrFromString(const std::string &name, const std::string &strval void InitializeAttrFromString(const std::string &name, const std::string &strval, std::string& val); ///\} -class TDrawingAttrBase { +class RDrawingAttrBase { /// The attribute name, as used in style files. std::string fName; protected: - const std::string &GetStyleClass(const TDrawingOptsBase& opts) const; + const std::string &GetStyleClass(const RDrawingOptsBase& opts) const; public: - TDrawingAttrBase() = default; - TDrawingAttrBase(const char* name): fName(name) {} + RDrawingAttrBase() = default; + RDrawingAttrBase(const char* name): fName(name) {} const std::string& GetName() const { return fName; } virtual void Snapshot() = 0; - virtual ~TDrawingAttrBase(); + virtual ~RDrawingAttrBase(); }; -/** \class ROOT::Experimental::TDrawingAttrOrRef - A wrapper for a graphics attribute, for instance a `TColor`. +/** \class ROOT::Experimental::RDrawingAttrOrRef + A wrapper for a graphics attribute, for instance a `RColor`. The `TTopmostPad` keeps track of shared attributes used by multiple drawing options by means of - `weak_ptr`s; `TDrawingAttrOrRef`s hold `shared_ptr`s to these. - The reference into the table of the shared attributes is wrapped into the reference of the `TDrawingAttrOrRef` - to make them type-safe (i.e. distinct for `TColor`, `long long` and `double`). + `weak_ptr`s; `RDrawingAttrOrRef`s hold `shared_ptr`s to these. + The reference into the table of the shared attributes is wrapped into the reference of the `RDrawingAttrOrRef` + to make them type-safe (i.e. distinct for `RColor`, `long long` and `double`). */ template -class TDrawingAttr: public TDrawingAttrBase { +class RDrawingAttr: public RDrawingAttrBase { private: /// The shared_ptr, shared with the relevant attribute table of `TTopmostPad`. std::shared_ptr fPtr; //! @@ -73,7 +73,7 @@ private: /// updated by `Snapshot()`. ATTR fAttr; - /// Whether this attribute is shared (through `TTopmostPad`'s attribute table) with other `TDrawingAttrOrRef` + /// Whether this attribute is shared (through `TTopmostPad`'s attribute table) with other `RDrawingAttrOrRef` /// objects. bool IsShared() const { return (bool) fPtr; } @@ -87,26 +87,26 @@ private: public: /// Construct a default, non-shared attribute. The default value gets read from the default style, /// given the attribute's name. - TDrawingAttr(TDrawingOptsBase& opts, const char *name): TDrawingAttrBase(name) { - InitializeAttrFromString(name, TStyle::GetCurrent().GetAttribute(name, GetStyleClass(opts)), fAttr); + RDrawingAttr(RDrawingOptsBase& opts, const char *name): RDrawingAttrBase(name) { + InitializeAttrFromString(name, RStyle::GetCurrent().GetAttribute(name, GetStyleClass(opts)), fAttr); } /// Construct a default, non-shared attribute. The default value gets read from the default style, /// given the attribute's name and arguments for the default attribute constructor, should no /// style entry be found. template - TDrawingAttr(TDrawingOptsBase& opts, const char *name, ARGS... args): TDrawingAttrBase(name), fAttr(args...) { - InitializeAttrFromString(name, TStyle::GetCurrent().GetAttribute(name, GetStyleClass(opts)), fAttr); + RDrawingAttr(RDrawingOptsBase& opts, const char *name, ARGS... args): RDrawingAttrBase(name), fAttr(args...) { + InitializeAttrFromString(name, RStyle::GetCurrent().GetAttribute(name, GetStyleClass(opts)), fAttr); } /// Construct a *non-shared* attribute, copying the attribute's value. - TDrawingAttr(const TDrawingAttr &other): TDrawingAttrBase(other), fAttr(other.Get()) {} + RDrawingAttr(const RDrawingAttr &other): RDrawingAttrBase(other), fAttr(other.Get()) {} /// Move an attribute. - TDrawingAttr(TDrawingAttr &&other) = default; + RDrawingAttr(RDrawingAttr &&other) = default; /// Create a shared attribute. - TDrawingAttr Share() { + RDrawingAttr Share() { return GetSharedPtr(); } @@ -136,13 +136,13 @@ public: explicit operator ATTR& () { return Get(); } /// Assign an ATTR. - TDrawingAttr& operator=(const ATTR& attr) { + RDrawingAttr& operator=(const ATTR& attr) { fPtr.reset(); fAttr = attr; return *this; } /// Move-assign an ATTR. - TDrawingAttr& operator=(ATTR&& attr) { + RDrawingAttr& operator=(ATTR&& attr) { fPtr.reset(); fAttr = attr; return *this; @@ -152,4 +152,4 @@ public: } // namespace Experimental } // namespace ROOT -#endif // ROOT7_TDrawingAttr +#endif // ROOT7_RDrawingAttr diff --git a/graf2d/primitives/v7/inc/ROOT/TDrawingOptsBase.hxx b/graf2d/primitives/v7/inc/ROOT/RDrawingOptsBase.hxx similarity index 80% rename from graf2d/primitives/v7/inc/ROOT/TDrawingOptsBase.hxx rename to graf2d/primitives/v7/inc/ROOT/RDrawingOptsBase.hxx index dde95ad917d52..b6d0dc7b54470 100644 --- a/graf2d/primitives/v7/inc/ROOT/TDrawingOptsBase.hxx +++ b/graf2d/primitives/v7/inc/ROOT/RDrawingOptsBase.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TDrawingOptionsBase.hxx +/// \file ROOT/RDrawingOptionsBase.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2018-02-12 @@ -13,26 +13,26 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TDrawingOptsBase -#define ROOT7_TDrawingOptsBase +#ifndef ROOT7_RDrawingOptsBase +#define ROOT7_RDrawingOptsBase #include #include namespace ROOT { namespace Experimental { -class TDrawingAttrBase; +class RDrawingAttrBase; -class TDrawingOptsBase { +class RDrawingOptsBase { /// Attribute style class of these options. std::string fStyleClass; public: /// Initialize the options with a (possibly empty) style class. - TDrawingOptsBase(const std::string &styleClass = {}): fStyleClass(styleClass) {} + RDrawingOptsBase(const std::string &styleClass = {}): fStyleClass(styleClass) {} - using VisitFunc_t = std::function; - virtual ~TDrawingOptsBase(); + using VisitFunc_t = std::function; + virtual ~RDrawingOptsBase(); /// Get the attribute style class of these options. const std::string &GetStyleClass() const { return fStyleClass; } @@ -47,4 +47,4 @@ public: } // namespace Experimental } // namespace ROOT -#endif // ROOT7_TDrawingOptsBase +#endif // ROOT7_RDrawingOptsBase diff --git a/graf2d/primitives/v7/inc/ROOT/TLine.hxx b/graf2d/primitives/v7/inc/ROOT/RLine.hxx similarity index 51% rename from graf2d/primitives/v7/inc/ROOT/TLine.hxx rename to graf2d/primitives/v7/inc/ROOT/RLine.hxx index 1f038590c8f4a..e90e8cb2f3871 100644 --- a/graf2d/primitives/v7/inc/ROOT/TLine.hxx +++ b/graf2d/primitives/v7/inc/ROOT/RLine.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TLine.hxx +/// \file ROOT/RLine.hxx /// \ingroup Graf ROOT7 /// \author Olivier Couet /// \date 2017-10-16 @@ -13,15 +13,14 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TLine -#define ROOT7_TLine +#ifndef ROOT7_RLine +#define ROOT7_RLine -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include @@ -29,42 +28,42 @@ namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TLine +/** \class ROOT::Experimental::RLine A simple line. */ -class TLine : public TDrawableBase { +class RLine : public RDrawableBase { public: -/** class ROOT::Experimental::TLine::DrawingOpts - Drawing options for TLine. +/** class ROOT::Experimental::RLine::DrawingOpts + Drawing options for RLine. */ -class DrawingOpts: public TDrawingOptsBase { - TDrawingAttr fColor{*this, "Line.Color", TColor::kBlack}; ///< The line color. - TDrawingAttr fWidth{*this, "Line.Width", 1}; ///< The line width. - TDrawingAttr fStyle{*this, "Line.Style", 1}; ///< The line style. - TDrawingAttr fOpacity{*this, "Line.Opacity", 1.}; ///< The line opacity. +class DrawingOpts: public RDrawingOptsBase { + RDrawingAttr fColor{*this, "Line.Color", RColor::kBlack}; ///< The line color. + RDrawingAttr fWidth{*this, "Line.Width", 1}; ///< The line width. + RDrawingAttr fStyle{*this, "Line.Style", 1}; ///< The line style. + RDrawingAttr fOpacity{*this, "Line.Opacity", 1.}; ///< The line opacity. public: /// The color of the line. - void SetLineColor(const TColor &col) { fColor = col; } - TDrawingAttr &GetLineColor() { return fColor; } - const TColor &GetLineColor() const { return fColor.Get(); } + void SetLineColor(const RColor &col) { fColor = col; } + RDrawingAttr &GetLineColor() { return fColor; } + const RColor &GetLineColor() const { return fColor.Get(); } ///The width of the line. void SetLineWidth(int width) { fWidth = width; } - TDrawingAttr &GetLineWidth() { return fWidth; } + RDrawingAttr &GetLineWidth() { return fWidth; } int GetLineWidth() const { return (int)fWidth; } ///The style of the line. void SetLineStyle(int style) { fStyle = style; } - TDrawingAttr &GetLineStyle() { return fStyle; } + RDrawingAttr &GetLineStyle() { return fStyle; } int GetLineStyle() const { return (int)fStyle; } ///The opacity of the line. void SetLineColorAlpha(float opacity) { fOpacity = opacity; } - TDrawingAttr &GetLineColorAlpha() { return fOpacity; } + RDrawingAttr &GetLineColorAlpha() { return fOpacity; } float GetLineColorAlpha() const { return (float)fOpacity; } }; @@ -73,39 +72,39 @@ private: /// Line's coordinates - TPadPos fP1; ///< 1st point - TPadPos fP2; ///< 2nd point + RPadPos fP1; ///< 1st point + RPadPos fP2; ///< 2nd point /// Line's attributes DrawingOpts fOpts; public: - TLine() = default; + RLine() = default; - TLine(const TPadPos& p1, const TPadPos& p2) : fP1(p1), fP2(p2) {} + RLine(const RPadPos& p1, const RPadPos& p2) : fP1(p1), fP2(p2) {} - void SetP1(const TPadPos& p1) { fP1 = p1; } - void SetP2(const TPadPos& p2) { fP2 = p2; } + void SetP1(const RPadPos& p1) { fP1 = p1; } + void SetP2(const RPadPos& p2) { fP2 = p2; } - const TPadPos& GetP1() const { return fP1; } - const TPadPos& GetP2() const { return fP2; } + const RPadPos& GetP1() const { return fP1; } + const RPadPos& GetP2() const { return fP2; } /// Get the drawing options. DrawingOpts &GetOptions() { return fOpts; } const DrawingOpts &GetOptions() const { return fOpts; } - void Paint(Internal::TPadPainter &topPad) final + void Paint(Internal::RPadPainter &topPad) final { topPad.AddDisplayItem( - std::make_unique>(this)); + std::make_unique>(this)); } }; -inline std::shared_ptr -GetDrawable(const std::shared_ptr &line) +inline std::shared_ptr +GetDrawable(const std::shared_ptr &line) { - /// A TLine is a TDrawable itself. + /// A RLine is a RDrawable itself. return line; } diff --git a/graf2d/primitives/v7/inc/ROOT/TMarker.hxx b/graf2d/primitives/v7/inc/ROOT/RMarker.hxx similarity index 54% rename from graf2d/primitives/v7/inc/ROOT/TMarker.hxx rename to graf2d/primitives/v7/inc/ROOT/RMarker.hxx index 32c28ca8b612a..7c0f474aa1430 100644 --- a/graf2d/primitives/v7/inc/ROOT/TMarker.hxx +++ b/graf2d/primitives/v7/inc/ROOT/RMarker.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TMarker.hxx +/// \file ROOT/RMarker.hxx /// \ingroup Graf ROOT7 /// \author Olivier Couet /// \date 2017-10-16 @@ -13,15 +13,14 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TMarker -#define ROOT7_TMarker +#ifndef ROOT7_RMarker +#define ROOT7_RMarker -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include @@ -29,42 +28,42 @@ namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TMarker +/** \class ROOT::Experimental::RMarker A simple marker. */ -class TMarker : public TDrawableBase { +class RMarker : public RDrawableBase { public: -/** class ROOT::Experimental::TMarker::DrawingOpts - Drawing options for TMarker. +/** class ROOT::Experimental::RMarker::DrawingOpts + Drawing options for RMarker. */ -class DrawingOpts: public TDrawingOptsBase { - TDrawingAttr fColor{*this, "Marker.Color", TColor::kBlack}; ///< The marker color. - TDrawingAttr fSize{*this, "Marker.Size", 1.}; ///< The marker size. - TDrawingAttr fStyle{*this, "Marker.Style", 1}; ///< The marker style. - TDrawingAttr fOpacity{*this, "Marker.Opacity", 1.}; ///< The marker opacity. +class DrawingOpts: public RDrawingOptsBase { + RDrawingAttr fColor{*this, "Marker.Color", RColor::kBlack}; ///< The marker color. + RDrawingAttr fSize{*this, "Marker.Size", 1.}; ///< The marker size. + RDrawingAttr fStyle{*this, "Marker.Style", 1}; ///< The marker style. + RDrawingAttr fOpacity{*this, "Marker.Opacity", 1.}; ///< The marker opacity. public: /// The color of the marker. - void SetMarkerColor(const TColor &col) { fColor = col; } - TDrawingAttr &GetMarkerColor() { return fColor; } - const TColor &GetMarkerColor() const { return fColor.Get(); } + void SetMarkerColor(const RColor &col) { fColor = col; } + RDrawingAttr &GetMarkerColor() { return fColor; } + const RColor &GetMarkerColor() const { return fColor.Get(); } ///The size of the marker. void SetMarkerSize(float size) { fSize = size; } - TDrawingAttr &GetMarkerSize() { return fSize; } + RDrawingAttr &GetMarkerSize() { return fSize; } int GetMarkerSize() const { return (float)fSize; } ///The style of the marker. void SetMarkerStyle(int style) { fStyle = style; } - TDrawingAttr &GetMarkerStyle() { return fStyle; } + RDrawingAttr &GetMarkerStyle() { return fStyle; } int GetMarkerStyle() const { return (int)fStyle; } ///The opacity of the marker. void SetMarkerColorAlpha(float opacity) { fOpacity = opacity; } - TDrawingAttr &GetMarkerColorAlpha() { return fOpacity; } + RDrawingAttr &GetMarkerColorAlpha() { return fOpacity; } float GetMarkerColorAlpha() const { return (float)fOpacity; } }; @@ -72,36 +71,36 @@ public: private: /// Marker's position - TPadPos fP; + RPadPos fP; /// Marker's attributes DrawingOpts fOpts; public: - TMarker() = default; + RMarker() = default; - TMarker(const TPadPos& p) : fP(p) {} + RMarker(const RPadPos& p) : fP(p) {} - void SetP(const TPadPos& p) { fP = p; } + void SetP(const RPadPos& p) { fP = p; } - const TPadPos& GetP() const { return fP; } + const RPadPos& GetP() const { return fP; } /// Get the drawing options. DrawingOpts &GetOptions() { return fOpts; } const DrawingOpts &GetOptions() const { return fOpts; } - void Paint(Internal::TPadPainter &topPad) final + void Paint(Internal::RPadPainter &topPad) final { topPad.AddDisplayItem( - std::make_unique>(this)); + std::make_unique>(this)); } }; -inline std::shared_ptr -GetDrawable(const std::shared_ptr &marker) +inline std::shared_ptr +GetDrawable(const std::shared_ptr &marker) { - /// A TMarker is a TDrawable itself. + /// A RMarker is a RDrawable itself. return marker; } diff --git a/graf2d/primitives/v7/inc/ROOT/TPalette.hxx b/graf2d/primitives/v7/inc/ROOT/RPalette.hxx similarity index 77% rename from graf2d/primitives/v7/inc/ROOT/TPalette.hxx rename to graf2d/primitives/v7/inc/ROOT/RPalette.hxx index c7c6bf5c34145..c9bf5c501360a 100644 --- a/graf2d/primitives/v7/inc/ROOT/TPalette.hxx +++ b/graf2d/primitives/v7/inc/ROOT/RPalette.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TPalette.hxx +/// \file ROOT/RPalette.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-09-26 @@ -13,11 +13,11 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TPalette -#define ROOT7_TPalette +#ifndef ROOT7_RPalette +#define ROOT7_RPalette #include -#include +#include #include #include @@ -25,8 +25,8 @@ namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TPalette - A set of colors. `TColor`s can be conveniently generated from this. +/** \class ROOT::Experimental::RPalette + A set of colors. `RColor`s can be conveniently generated from this. A palette associates a color with an ordinal number: for a normalized palette, this number ranges from 0..1. For user-valued palettes, the palette yields a color for @@ -35,14 +35,14 @@ namespace Experimental { A palette can be a smooth gradients by interpolation of support points, or a set of discrete colors. */ -class TPalette { +class RPalette { public: - /** \class ROOT::Experimental::TPalette::OrdinalAndColor + /** \class ROOT::Experimental::RPalette::OrdinalAndColor An ordinal value and its associated color. */ struct OrdinalAndColor { double fOrdinal; ///< The value associated with the color. - TColor fColor; ///< The color associated with the value. + RColor fColor; ///< The color associated with the value. /// Compare two `OrdinalAndColor`s, for sorting. friend bool operator<(const OrdinalAndColor &lhs, const OrdinalAndColor &rhs) @@ -63,8 +63,8 @@ private: /// Whether the palette's ordinal numbers are normalized. bool fNormalized = true; - TPalette(bool interpolate, bool knownNormalized, const std::vector &points); - TPalette(bool interpolate, const std::vector &points); + RPalette(bool interpolate, bool knownNormalized, const std::vector &points); + RPalette(bool interpolate, const std::vector &points); public: /// Tag type used to signal that the palette's colors should not be interpolated. @@ -72,34 +72,34 @@ public: }; /// Tag value used to signal that the palette's colors should not be interpolated. Can be passed to the - /// constructor: `TPalette palette(TPalette::kDiscrete, {{-100., TColor::kWhite}, {100., TColor::kRed}})` + /// constructor: `RPalette palette(RPalette::kDiscrete, {{-100., RColor::kWhite}, {100., RColor::kRed}})` static constexpr const Discrete_t kDiscrete{}; - TPalette() = default; + RPalette() = default; - /// Construct a TPalette from a vector of (ordinal|color) pairs as interpolation points. + /// Construct a RPalette from a vector of (ordinal|color) pairs as interpolation points. /// Palette colors will be these points for the ordinal, and interpolated in between the /// ordinal points. The points will be sorted. /// The palette is normalized if the lowest ordinal is 0. and the highest ordinal is 1.; /// otherwise, the palette is a user-valued palette. - TPalette(const std::vector &interpPoints): TPalette(true, false, interpPoints) {} + RPalette(const std::vector &interpPoints): RPalette(true, false, interpPoints) {} - /// Construct a TPalette from a vector of (ordinal|color) pairs. For a given value, the palette returns + /// Construct a RPalette from a vector of (ordinal|color) pairs. For a given value, the palette returns /// the color with an ordinal that is closest to the value. The points will be sorted. /// The palette is normalized if the lowest ordinal is 0. and the highest ordinal is 1.; /// otherwise, the palette is a user-valued palette. - TPalette(Discrete_t, const std::vector &points): TPalette(false, false, points) {} + RPalette(Discrete_t, const std::vector &points): RPalette(false, false, points) {} - /// Construct a normalized TPalette from a vector of colors as interpolation points. The ordinal associated + /// Construct a normalized RPalette from a vector of colors as interpolation points. The ordinal associated /// with each color is equidistant from 0..1, i.e. for three colors it will be 0., 0.5 and 1, respectively. /// Palette colors will be these points for the ordinal associated with the color, /// and interpolated in between the ordinal points. - TPalette(const std::vector &interpPoints): TPalette(true, interpPoints) {} + RPalette(const std::vector &interpPoints): RPalette(true, interpPoints) {} - /// Construct a normalized TPalette from a vector of colors. The ordinal associated + /// Construct a normalized RPalette from a vector of colors. The ordinal associated /// with each color is equidistant from 0..1, i.e. for three colors it will be 0., 0.5 and 1, respectively. /// For a given value, the palette returns the color with an ordinal that is closest to the value. - TPalette(Discrete_t, const std::vector &points): TPalette(false, points) {} + RPalette(Discrete_t, const std::vector &points): RPalette(false, points) {} /// Whether the palette is normalized, i.e. covers colors in the ordinal range 0..1. bool IsNormalized() const { return fNormalized; } @@ -112,10 +112,10 @@ public: /// Get the color associated with the ordinal value. The value is expected to be 0..1 for a normalized /// palette. - TColor GetColor(double ordinal); + RColor GetColor(double ordinal); - /// Given a TColor (that might either be a RGBA or a TPalette ordinal), get the RGBA-based color. - TColor ResolveRGBAColor(const TColor &col) + /// Given a RColor (that might either be a RGBA or a RPalette ordinal), get the RGBA-based color. + RColor ResolveRGBAColor(const RColor &col) { if (col.IsRGBA()) return col; @@ -127,11 +127,11 @@ public: /// Register a palette in the set of global palettes, making it available to `GetPalette()`. /// This function is not thread safe; any concurrent call to global Palette manipulation must be synchronized! - static void RegisterPalette(std::string_view name, const TPalette &palette); + static void RegisterPalette(std::string_view name, const RPalette &palette); /// Get a global palette by name. Returns an empty palette if no palette with that name is known. /// This function is not thread safe; any concurrent call to global Palette manipulation must be synchronized! - static const TPalette &GetPalette(std::string_view name); + static const RPalette &GetPalette(std::string_view name); ///\} }; diff --git a/graf2d/primitives/v7/inc/ROOT/TStringEnumAttr.hxx b/graf2d/primitives/v7/inc/ROOT/RStringEnumAttr.hxx similarity index 78% rename from graf2d/primitives/v7/inc/ROOT/TStringEnumAttr.hxx rename to graf2d/primitives/v7/inc/ROOT/RStringEnumAttr.hxx index a7cd3ee2953ce..e6420f86500c0 100644 --- a/graf2d/primitives/v7/inc/ROOT/TStringEnumAttr.hxx +++ b/graf2d/primitives/v7/inc/ROOT/RStringEnumAttr.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TStringAttr.hxx +/// \file ROOT/RStringEnumAttr.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2018-02-08 @@ -13,8 +13,8 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TStringEnumAttr -#define ROOT7_TStringEnumAttr +#ifndef ROOT7_RStringEnumAttr +#define ROOT7_RStringEnumAttr #include #include @@ -24,15 +24,15 @@ namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TStringAttrSet +/** \class ROOT::Experimental::RStringAttrSet Graphics attribute that consists of a string, selected from a set of options. This is the set of options. It's expected to be of static storage duration. */ -class TStringEnumAttrSet { +class RStringEnumAttrSet { std::vector fOptSet; ///< The set of options. public: - TStringEnumAttrSet(std::initializer_list il) + RStringEnumAttrSet(std::initializer_list il) { fOptSet.insert(fOptSet.end(), il.begin(), il.end()); } @@ -48,30 +48,30 @@ public: const std::string &operator[](std::size_t idx) const { return fOptSet[idx]; } }; -/** \class ROOT::Experimental::TStringEnumAttrBase - Base class for template TStringEnumAttr, erasing the underlying integral type. +/** \class ROOT::Experimental::RStringEnumAttrBase + Base class for template RStringEnumAttr, erasing the underlying integral type. */ -class TStringEnumAttrBase { +class RStringEnumAttrBase { protected: /// Selected option from fStringSet. std::size_t fIdx; /// Reference to the set of options. - const TStringEnumAttrSet *fStringSet; //! + const RStringEnumAttrSet *fStringSet; //! public: - TStringEnumAttrBase(std::size_t idx, const TStringEnumAttrSet &strSet): fIdx(idx), fStringSet(&strSet) {} + RStringEnumAttrBase(std::size_t idx, const RStringEnumAttrSet &strSet): fIdx(idx), fStringSet(&strSet) {} }; -/** \class ROOT::Experimental::TStringEnumAttr +/** \class ROOT::Experimental::RStringEnumAttr Graphics attribute that consists of a string, selected from a set of options. \tparam ENUM - underlying enum type (or `int` etc). */ template -class TStringEnumAttr: public TStringEnumAttrBase { +class RStringEnumAttr: public RStringEnumAttrBase { public: /// Construct the option from the set of strings and the selected option index. - TStringEnumAttr(ENUM idx, const TStringEnumAttrSet &strSet): TStringEnumAttrBase((std::size_t)idx, strSet) {} + RStringEnumAttr(ENUM idx, const RStringEnumAttrSet &strSet): RStringEnumAttrBase((std::size_t)idx, strSet) {} /// Set the index of the selected option. void SetIndex(ENUM idx) { fIdx = (std::size_t)idx; } @@ -88,7 +88,7 @@ public: ///\param[in] name - the attribute name, for diagnostic purposes. ///\param[in] strval - the attribute value as a string. ///\param[out] val - the value to be initialized. -void InitializeAttrFromString(const std::string &name, const std::string &strval, TStringEnumAttrBase& val); +void InitializeAttrFromString(const std::string &name, const std::string &strval, RStringEnumAttrBase& val); } // namespace Experimental } // namespace ROOT diff --git a/graf2d/primitives/v7/inc/ROOT/TStyle.hxx b/graf2d/primitives/v7/inc/ROOT/RStyle.hxx similarity index 78% rename from graf2d/primitives/v7/inc/ROOT/TStyle.hxx rename to graf2d/primitives/v7/inc/ROOT/RStyle.hxx index 5d6d86833a59c..b00589fa3ffa5 100644 --- a/graf2d/primitives/v7/inc/ROOT/TStyle.hxx +++ b/graf2d/primitives/v7/inc/ROOT/RStyle.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TStyle.hxx +/// \file ROOT/RStyle.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-10-10 @@ -13,10 +13,10 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TStyle -#define ROOT7_TStyle +#ifndef ROOT7_RStyle +#define ROOT7_RStyle -#include +#include #include @@ -27,11 +27,11 @@ namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TStyle +/** \class ROOT::Experimental::RStyle A set of defaults for graphics attributes, e.g. for histogram fill color, line width, frame offsets etc. */ -class TStyle { +class RStyle { public: /// A map of attribute name to string attribute values/ using Attrs_t = std::unordered_map; @@ -43,13 +43,13 @@ private: public: /// Default constructor, creating an unnamed, empty style. - TStyle() = default; + RStyle() = default; /// Creates a named but empty style. - explicit TStyle(std::string_view name): fName(name) {} + explicit RStyle(std::string_view name): fName(name) {} /// Constructor taking the style name and a set of attributes (e.g. read from the config files). - TStyle(std::string_view name, Attrs_t &&attrs): fName(name), fAttrs(std::move(attrs)) {} + RStyle(std::string_view name, Attrs_t &&attrs): fName(name), fAttrs(std::move(attrs)) {} /// Get this stryle's name. (No setter as that would upset the unordered_map.) const std::string &GetName() const { return fName; } @@ -62,19 +62,19 @@ public: std::string GetAttribute(const std::string &attrName, const std::string &className = {}) const; /// Move-register `style` in the global style collection, possibly replacing a global style with the same name. - static TStyle &Register(TStyle &&style); + static RStyle &Register(RStyle &&style); - /// Get the `TStyle` named `name` from the global style collection, or `nullptr` if that doesn't exist. - static TStyle *Get(std::string_view name); + /// Get the `RStyle` named `name` from the global style collection, or `nullptr` if that doesn't exist. + static RStyle *Get(std::string_view name); - /// Get the current TStyle. - static TStyle &GetCurrent(); + /// Get the current RStyle. + static RStyle &GetCurrent(); - /// Set the current TStyle by copying `style` into the static current style object. - static void SetCurrent(const TStyle &style) { GetCurrent() = style; } + /// Set the current RStyle by copying `style` into the static current style object. + static void SetCurrent(const RStyle &style) { GetCurrent() = style; } }; } // namespace Experimental } // namespace ROOT -#endif // ROOT7_TStyle +#endif // ROOT7_RStyle diff --git a/graf2d/primitives/v7/inc/ROOT/TText.hxx b/graf2d/primitives/v7/inc/ROOT/RText.hxx similarity index 55% rename from graf2d/primitives/v7/inc/ROOT/TText.hxx rename to graf2d/primitives/v7/inc/ROOT/RText.hxx index d75f0d85dcd13..8232449824212 100644 --- a/graf2d/primitives/v7/inc/ROOT/TText.hxx +++ b/graf2d/primitives/v7/inc/ROOT/RText.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TText.hxx +/// \file ROOT/RText.hxx /// \ingroup Graf ROOT7 /// \author Olivier Couet /// \date 2017-10-16 @@ -13,15 +13,14 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TText -#define ROOT7_TText +#ifndef ROOT7_RText +#define ROOT7_RText -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include @@ -30,49 +29,49 @@ namespace ROOT { namespace Experimental { -/** \class ROOT::Experimental::TText +/** \class ROOT::Experimental::RText A text. */ -class TText : public TDrawableBase { +class RText : public RDrawableBase { public: -/** class ROOT::Experimental::TText::DrawingOpts - Drawing options for TText. +/** class ROOT::Experimental::RText::DrawingOpts + Drawing options for RText. */ -class DrawingOpts: public TDrawingOptsBase { - TDrawingAttr fTextColor{*this, "Text.Color", TColor::kBlack}; ///< The text color. - TDrawingAttr fTextSize{*this, "Text.Size", 10.}; ///< The text size. - TDrawingAttr fTextAngle{*this, "Text.Angle", 0.}; ///< The text angle. - TDrawingAttr fTextAlign{*this, "Text.Align", 13.}; ///< The text align. - TDrawingAttr fTextFont{*this, "Text.Font", 42.}; ///< The text font. +class DrawingOpts: public RDrawingOptsBase { + RDrawingAttr fTextColor{*this, "Text.Color", RColor::kBlack}; ///< The text color. + RDrawingAttr fTextSize{*this, "Text.Size", 10.}; ///< The text size. + RDrawingAttr fTextAngle{*this, "Text.Angle", 0.}; ///< The text angle. + RDrawingAttr fTextAlign{*this, "Text.Align", 13.}; ///< The text align. + RDrawingAttr fTextFont{*this, "Text.Font", 42.}; ///< The text font. public: /// The color of the text. - void SetTextColor(const TColor &col) { fTextColor = col; } - TDrawingAttr &GetTextColor() { return fTextColor; } - const TColor &GetTextColor() const { return fTextColor.Get(); } + void SetTextColor(const RColor &col) { fTextColor = col; } + RDrawingAttr &GetTextColor() { return fTextColor; } + const RColor &GetTextColor() const { return fTextColor.Get(); } /// The text size. void SetTextSize(float size) { fTextSize = size; } - TDrawingAttr &GetTextSize() { return fTextSize; } + RDrawingAttr &GetTextSize() { return fTextSize; } float GetTextSize() const { return (float)fTextSize; } /// The text angle in degrees. void SetTextAngle(float angle) { fTextAngle = angle; } - TDrawingAttr &GetTextAngle() { return fTextAngle; } + RDrawingAttr &GetTextAngle() { return fTextAngle; } float GetTextAngle() const { return (float)fTextAngle; } ///The text align. void SetTextAlign(int align) { fTextAlign = align; } - TDrawingAttr &GetTextAlign() {return fTextAlign; } + RDrawingAttr &GetTextAlign() {return fTextAlign; } int GetTextAlign() const {return (int) fTextAlign; } ///The text font. void SetTextFont(int font) {fTextFont = font; } - TDrawingAttr &GetTextFont() {return fTextFont; } + RDrawingAttr &GetTextFont() {return fTextFont; } int GetTextFont() const {return (int) fTextFont; } }; @@ -84,42 +83,42 @@ private: std::string fText; /// Text's position - TPadPos fP; + RPadPos fP; /// Text's attributes DrawingOpts fOpts; public: - TText() = default; + RText() = default; - TText(const std::string &str) : fText(str) {} - TText(const TPadPos& p, const std::string &str) : fText(str), fP(p) {} + RText(const std::string &str) : fText(str) {} + RText(const RPadPos& p, const std::string &str) : fText(str), fP(p) {} void SetText(const std::string &txt) { fText = txt; } std::string GetText() const { return fText; } - void SetPosition(const TPadPos& p) {fP = p;} + void SetPosition(const RPadPos& p) {fP = p;} - const TPadPos& GetPosition() const { return fP; } + const RPadPos& GetPosition() const { return fP; } /// Get the drawing options. DrawingOpts &GetOptions() { return fOpts; } const DrawingOpts &GetOptions() const { return fOpts; } - void Paint(Internal::TPadPainter &pad) final + void Paint(Internal::RPadPainter &pad) final { pad.AddDisplayItem( - std::make_unique>(this)); + std::make_unique>(this)); } }; -inline std::shared_ptr -GetDrawable(const std::shared_ptr &text) +inline std::shared_ptr +GetDrawable(const std::shared_ptr &text) { - /// A TText is a TDrawable itself. + /// A RText is a RDrawable itself. return text; } diff --git a/graf2d/primitives/v7/src/TColor.cxx b/graf2d/primitives/v7/src/RColor.cxx similarity index 78% rename from graf2d/primitives/v7/src/TColor.cxx rename to graf2d/primitives/v7/src/RColor.cxx index 19e4986f5635a..b2507ecbc53bf 100644 --- a/graf2d/primitives/v7/src/TColor.cxx +++ b/graf2d/primitives/v7/src/RColor.cxx @@ -1,4 +1,4 @@ -/// \file TColor.cxx +/// \file RColor.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-09-27 @@ -13,7 +13,7 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TColor.hxx" +#include "ROOT/RColor.hxx" #include @@ -21,26 +21,26 @@ using namespace ROOT::Experimental; -// TColor constexpr values: -constexpr TColor::Alpha TColor::kOpaque; -constexpr TColor::Alpha TColor::kTransparent; -constexpr TColor::RGBA TColor::kRed; -constexpr TColor::RGBA TColor::kGreen; -constexpr TColor::RGBA TColor::kBlue; -constexpr TColor::RGBA TColor::kWhite; -constexpr TColor::RGBA TColor::kBlack; -constexpr TColor::RGBA TColor::kInvisible; -constexpr TColor::AutoTag TColor::kAuto; +// RColor constexpr values: +constexpr RColor::Alpha RColor::kOpaque; +constexpr RColor::Alpha RColor::kTransparent; +constexpr RColor::RGBA RColor::kRed; +constexpr RColor::RGBA RColor::kGreen; +constexpr RColor::RGBA RColor::kBlue; +constexpr RColor::RGBA RColor::kWhite; +constexpr RColor::RGBA RColor::kBlack; +constexpr RColor::RGBA RColor::kInvisible; +constexpr RColor::AutoTag RColor::kAuto; -float TColor::GetPaletteOrdinal() const +float RColor::GetPaletteOrdinal() const { if (fKind != EKind::kPalettePos) throw std::runtime_error("This color does not represent a palette ordinal!"); return fRedOrPalettePos; } -bool TColor::AssertNotPalettePos() const +bool RColor::AssertNotPalettePos() const { if (fKind == EKind::kPalettePos) { throw std::runtime_error("This color does not represent a palette ordinal!"); @@ -53,16 +53,16 @@ bool TColor::AssertNotPalettePos() const /// Initialize an attribute `val` from a string value. /// Colors can be specified as RGBA (red green blue alpha) or RRGGBBAA: /// %fa7f %ffa07bff # hash introduces a comment! -/// For all predefined colors in TColor, colors can be specified as name without leading 'k', e.g. `red` for -/// `TColor::kRed`. -/// Prints an error and returns `TColor::kBlack` if the attribute string cannot be parsed or if the attribute has no +/// For all predefined colors in RColor, colors can be specified as name without leading 'k', e.g. `red` for +/// `RColor::kRed`. +/// Prints an error and returns `RColor::kBlack` if the attribute string cannot be parsed or if the attribute has no /// entry in `fAttrs`. /// ///\param[in] name - the attribute name (for diagnostic purposes). ///\param[in] strval - the attribute value as a string. ///\param[out] val - the value to be initialized. -void ROOT::Experimental::InitializeAttrFromString(const std::string &name, const std::string &strval, TColor& val) +void ROOT::Experimental::InitializeAttrFromString(const std::string &name, const std::string &strval, RColor& val) { if (strval.empty()) return; @@ -70,7 +70,7 @@ void ROOT::Experimental::InitializeAttrFromString(const std::string &name, const if (strval[0] == '#') { auto rgbalen = strval.length() - 1; if (rgbalen != 3 && rgbalen != 4 && rgbalen != 6 && rgbalen != 8) { - R__ERROR_HERE("Graf2d") << "Invalid value for TColor default style " << name + R__ERROR_HERE("Graf2d") << "Invalid value for RColor default style " << name << " with value \"" << strval << "\": expect '#' followed by 3, 4, 6 or 8 hex digits (#rgb, #rgba, #rrggbbaa or #rrggbb)."; return; @@ -78,13 +78,13 @@ void ROOT::Experimental::InitializeAttrFromString(const std::string &name, const std::size_t pos; long long rgbaLL = std::stoll(strval.substr(1), &pos, /*base*/ 16); if (pos != 3 && pos != 4 && pos != 6 && pos != 8) { - R__ERROR_HERE("Graf2d") << "Invalid value while parsing default style value for TColor " << name + R__ERROR_HERE("Graf2d") << "Invalid value while parsing default style value for RColor " << name << " with value \"" << strval << "\": expect '#' followed by 3, 4, 6 or 8 hex digits (#rgb, #rgba, #rrggbbaa or #rrggbb)."; return; } if (pos != rgbalen) { - R__WARNING_HERE("Graf2d") << "Leftover characters while parsing default style value for TColor " << name + R__WARNING_HERE("Graf2d") << "Leftover characters while parsing default style value for RColor " << name << " with value \"" << strval << "\", remainder: \"" << strval.substr(pos - 1) << "\""; return; } @@ -101,6 +101,6 @@ void ROOT::Experimental::InitializeAttrFromString(const std::string &name, const // no alpha, set it to 255. rgba[3] = 1.; } - val = TColor(rgba[0]); + val = RColor(rgba[0]); } } diff --git a/graf2d/primitives/v7/src/TDisplayItem.cxx b/graf2d/primitives/v7/src/RDisplayItem.cxx similarity index 92% rename from graf2d/primitives/v7/src/TDisplayItem.cxx rename to graf2d/primitives/v7/src/RDisplayItem.cxx index 536c40072c763..297e696f550d8 100644 --- a/graf2d/primitives/v7/src/TDisplayItem.cxx +++ b/graf2d/primitives/v7/src/RDisplayItem.cxx @@ -1,4 +1,4 @@ -/// \file TDisplayItem.cxx +/// \file RDisplayItem.cxx /// \ingroup Base ROOT7 /// \author Sergey Linev /// \date 2017-05-31 @@ -13,4 +13,4 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TDisplayItem.hxx" +#include "ROOT/RDisplayItem.hxx" diff --git a/graf2d/primitives/v7/src/TDrawingAttr.cxx b/graf2d/primitives/v7/src/RDrawingAttr.cxx similarity index 91% rename from graf2d/primitives/v7/src/TDrawingAttr.cxx rename to graf2d/primitives/v7/src/RDrawingAttr.cxx index 42419f21d632f..9e5372381e2ee 100644 --- a/graf2d/primitives/v7/src/TDrawingAttr.cxx +++ b/graf2d/primitives/v7/src/RDrawingAttr.cxx @@ -1,4 +1,4 @@ -/// \file TDrawingAttrBase.cxx +/// \file RDrawingAttrBase.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-09-26 @@ -13,17 +13,17 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TDrawingAttr.hxx" +#include "ROOT/RDrawingAttr.hxx" -#include "ROOT/TDrawingOptsBase.hxx" +#include "ROOT/RDrawingOptsBase.hxx" #include "ROOT/TLogger.hxx" // pin vtable. -ROOT::Experimental::TDrawingAttrBase::~TDrawingAttrBase() = default; +ROOT::Experimental::RDrawingAttrBase::~RDrawingAttrBase() = default; -/// Get the style class currently active in the TDrawingOptsBase. -const std::string &ROOT::Experimental::TDrawingAttrBase::GetStyleClass(const TDrawingOptsBase& opts) const +/// Get the style class currently active in the RDrawingOptsBase. +const std::string &ROOT::Experimental::RDrawingAttrBase::GetStyleClass(const RDrawingOptsBase& opts) const { return opts.GetStyleClass(); } diff --git a/graf2d/primitives/v7/src/TDrawingOptsBase.cxx b/graf2d/primitives/v7/src/RDrawingOptsBase.cxx similarity index 73% rename from graf2d/primitives/v7/src/TDrawingOptsBase.cxx rename to graf2d/primitives/v7/src/RDrawingOptsBase.cxx index 77cfd9dd4b441..f8f2bce3163f4 100644 --- a/graf2d/primitives/v7/src/TDrawingOptsBase.cxx +++ b/graf2d/primitives/v7/src/RDrawingOptsBase.cxx @@ -1,4 +1,4 @@ -/// \file TDrawingOptsBase.cxx +/// \file RDrawingOptsBase.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2018-02-20 @@ -13,9 +13,9 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TDrawingOptsBase.hxx" +#include "ROOT/RDrawingOptsBase.hxx" -#include "ROOT/TDrawingAttr.hxx" +#include "ROOT/RDrawingAttr.hxx" #include "ROOT/TLogger.hxx" #include "TClass.h" @@ -24,11 +24,11 @@ // pin vtable. -ROOT::Experimental::TDrawingOptsBase::~TDrawingOptsBase() = default; +ROOT::Experimental::RDrawingOptsBase::~RDrawingOptsBase() = default; namespace { -class TAttrInspector: public TMemberInspector { - ROOT::Experimental::TDrawingOptsBase::VisitFunc_t fFunc; +class RAttrInspector: public TMemberInspector { + ROOT::Experimental::RDrawingOptsBase::VisitFunc_t fFunc; TClass* fClDrawingAttrBase = nullptr; bool fTriedToSetClDrawingAttrBase = false; @@ -36,14 +36,14 @@ class TAttrInspector: public TMemberInspector { if (fTriedToSetClDrawingAttrBase) return; fTriedToSetClDrawingAttrBase = true; - fClDrawingAttrBase = TClass::GetClass("ROOT::Experimental::TDrawingAttrBase"); + fClDrawingAttrBase = TClass::GetClass("ROOT::Experimental::RDrawingAttrBase"); if (!fClDrawingAttrBase) { - R__ERROR_HERE("Graf2s") << "Cannot find dictionary for class ROOT::Experimental::TDrawingAttrBase"; + R__ERROR_HERE("Graf2d") << "Cannot find dictionary for class ROOT::Experimental::RDrawingAttrBase"; } } bool InheritsFromDrawingAttrBase(const char *memberFullTypeName) { - static constexpr const char clNameAttrTag[] = "ROOT::Experimental::TDrawingAttr<"; + static constexpr const char clNameAttrTag[] = "ROOT::Experimental::RDrawingAttr<"; static constexpr const int lenNameAttrTag = sizeof(clNameAttrTag) - 1; if (!strncmp(memberFullTypeName, clNameAttrTag, lenNameAttrTag)) { return true; @@ -57,7 +57,7 @@ class TAttrInspector: public TMemberInspector { } public: - TAttrInspector(const ROOT::Experimental::TDrawingOptsBase::VisitFunc_t func): fFunc(func) {} + RAttrInspector(const ROOT::Experimental::RDrawingOptsBase::VisitFunc_t func): fFunc(func) {} using TMemberInspector::Inspect; void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t /*isTransient*/) { @@ -68,8 +68,8 @@ class TAttrInspector: public TMemberInspector { if (TDataMember* dm = cl->GetDataMember(name)) { if (const char* memberFullTypeName = dm->GetFullTypeName()) { if (InheritsFromDrawingAttrBase(memberFullTypeName)) { - auto pAttr = reinterpret_cast(addr); - fFunc(*const_cast(pAttr)); + auto pAttr = reinterpret_cast(addr); + fFunc(*const_cast(pAttr)); } } } @@ -78,22 +78,22 @@ class TAttrInspector: public TMemberInspector { } /// Invoke func with each attribute as argument. -void ROOT::Experimental::TDrawingOptsBase::VisitAttributes(const TDrawingOptsBase::VisitFunc_t &func) +void ROOT::Experimental::RDrawingOptsBase::VisitAttributes(const RDrawingOptsBase::VisitFunc_t &func) { TClass* clThis = TClass::GetClass(typeid(*this)); if (!clThis) { - R__ERROR_HERE("Graf2s") << "Cannot find dictionary for the derived class with typeid " << typeid(*this).name(); + R__ERROR_HERE("Graf2d") << "Cannot find dictionary for the derived class with typeid " << typeid(*this).name(); return; } - TAttrInspector insp(func); + RAttrInspector insp(func); if (!clThis->CallShowMembers(this, insp)) { - R__ERROR_HERE("Graf2s") << "Unable to inspect members of class with typeid " << typeid(*this).name(); + R__ERROR_HERE("Graf2d") << "Unable to inspect members of class with typeid " << typeid(*this).name(); return; } } /// Synchronize all shared attributes into their local copy. -void ROOT::Experimental::TDrawingOptsBase::Snapshot() { - VisitAttributes([](TDrawingAttrBase& attr) { attr.Snapshot(); }); +void ROOT::Experimental::RDrawingOptsBase::Snapshot() { + VisitAttributes([](RDrawingAttrBase& attr) { attr.Snapshot(); }); } diff --git a/graf2d/primitives/v7/src/TLine.cxx b/graf2d/primitives/v7/src/RLine.cxx similarity index 94% rename from graf2d/primitives/v7/src/TLine.cxx rename to graf2d/primitives/v7/src/RLine.cxx index 1b30554010214..4e4957641a210 100644 --- a/graf2d/primitives/v7/src/TLine.cxx +++ b/graf2d/primitives/v7/src/RLine.cxx @@ -1,4 +1,4 @@ -/// \file TLine.cxx +/// \file RLine.cxx /// \ingroup Graf ROOT7 /// \author Olivier Couet /// \date 2018-03-08 @@ -13,6 +13,6 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TLine.hxx" +#include "ROOT/RLine.hxx" using namespace ROOT::Experimental; diff --git a/graf2d/primitives/v7/src/TMarker.cxx b/graf2d/primitives/v7/src/RMarker.cxx similarity index 94% rename from graf2d/primitives/v7/src/TMarker.cxx rename to graf2d/primitives/v7/src/RMarker.cxx index 88a2bc7461c0f..f4e48a87c5907 100644 --- a/graf2d/primitives/v7/src/TMarker.cxx +++ b/graf2d/primitives/v7/src/RMarker.cxx @@ -1,4 +1,4 @@ -/// \file TMarker.cxx +/// \file RMarker.cxx /// \ingroup Graf ROOT7 /// \author Olivier Couet /// \date 2018-03-08 @@ -13,6 +13,6 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TMarker.hxx" +#include "ROOT/RMarker.hxx" using namespace ROOT::Experimental; diff --git a/graf2d/primitives/v7/src/TPalette.cxx b/graf2d/primitives/v7/src/RPalette.cxx similarity index 75% rename from graf2d/primitives/v7/src/TPalette.cxx rename to graf2d/primitives/v7/src/RPalette.cxx index 71d47ca51ba75..d3ed27b994f43 100644 --- a/graf2d/primitives/v7/src/TPalette.cxx +++ b/graf2d/primitives/v7/src/RPalette.cxx @@ -1,4 +1,4 @@ -/// \file TPalette.cxx +/// \file RPalette.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-09-27 @@ -13,7 +13,7 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TPalette.hxx" +#include "ROOT/RPalette.hxx" #include "ROOT/TLogger.hxx" @@ -24,7 +24,7 @@ using namespace ROOT::Experimental; -TPalette::TPalette(bool interpolate, bool knownNormalized, const std::vector &points) +RPalette::RPalette(bool interpolate, bool knownNormalized, const std::vector &points) : fColors(points), fInterpolate(interpolate), fNormalized(knownNormalized) { if (points.size() < 2) @@ -44,10 +44,10 @@ TPalette::TPalette(bool interpolate, bool knownNormalized, const std::vector AddOrdinals(const std::vector &points) +static std::vector AddOrdinals(const std::vector &points) { - std::vector ret(points.size()); - auto addOneOrdinal = [&](const TColor &col) -> TPalette::OrdinalAndColor { + std::vector ret(points.size()); + auto addOneOrdinal = [&](const RColor &col) -> RPalette::OrdinalAndColor { return {1. / (points.size() - 1) * (&col - points.data()), col}; }; std::transform(points.begin(), points.end(), ret.begin(), addOneOrdinal); @@ -55,11 +55,11 @@ static std::vector AddOrdinals(const std::vector &points) - : TPalette(interpolate, true, AddOrdinals(points)) +RPalette::RPalette(bool interpolate, const std::vector &points) + : RPalette(interpolate, true, AddOrdinals(points)) {} -TColor TPalette::GetColor(double ordinal) +RColor RPalette::GetColor(double ordinal) { if (fInterpolate) { R__ERROR_HERE("Gpad") << "Not yet implemented!"; @@ -72,16 +72,16 @@ TColor TPalette::GetColor(double ordinal) return (iColor - 1)->fColor; return iColor->fColor; } - return TColor{}; + return RColor{}; } namespace { -using GlobalPalettes_t = std::unordered_map; +using GlobalPalettes_t = std::unordered_map; static GlobalPalettes_t CreateDefaultPalettes() { GlobalPalettes_t ret; - ret["default"] = TPalette({TColor::kRed, TColor::kBlue}); - ret["bw"] = TPalette({TColor::kBlack, TColor::kWhite}); + ret["default"] = RPalette({RColor::kRed, RColor::kBlue}); + ret["bw"] = RPalette({RColor::kBlack, RColor::kWhite}); return ret; } @@ -92,14 +92,14 @@ static GlobalPalettes_t &GetGlobalPalettes() } } // unnamed namespace -void TPalette::RegisterPalette(std::string_view name, const TPalette &palette) +void RPalette::RegisterPalette(std::string_view name, const RPalette &palette) { GetGlobalPalettes()[std::string(name)] = palette; } -const TPalette &TPalette::GetPalette(std::string_view name) +const RPalette &RPalette::GetPalette(std::string_view name) { - static const TPalette sNoPaletteWithThatName; + static const RPalette sNoPaletteWithThatName; auto iGlobalPalette = GetGlobalPalettes().find(std::string(name)); if (iGlobalPalette == GetGlobalPalettes().end()) return sNoPaletteWithThatName; diff --git a/graf2d/primitives/v7/src/TStringEnumAttr.cxx b/graf2d/primitives/v7/src/RStringEnumAttr.cxx similarity index 93% rename from graf2d/primitives/v7/src/TStringEnumAttr.cxx rename to graf2d/primitives/v7/src/RStringEnumAttr.cxx index f4e8f7086c73d..6bf8d1b48a63b 100644 --- a/graf2d/primitives/v7/src/TStringEnumAttr.cxx +++ b/graf2d/primitives/v7/src/RStringEnumAttr.cxx @@ -1,4 +1,4 @@ -/// \file TStringEnumAttr.cxx +/// \file RStringEnumAttr.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2018-02-08 @@ -13,7 +13,7 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TStringEnumAttr.hxx" +#include "ROOT/RStringEnumAttr.hxx" #include "ROOT/TLogger.hxx" @@ -27,7 +27,7 @@ using namespace ROOT::Experimental; ///\param[out] val - the value to be initialized. void ROOT::Experimental::InitializeAttrFromString(const std::string & /*name*/, const std::string &strval, - ROOT::Experimental::TStringEnumAttrBase & /*val*/) + ROOT::Experimental::RStringEnumAttrBase & /*val*/) { if (strval.empty()) return; diff --git a/graf2d/primitives/v7/src/TStyle.cxx b/graf2d/primitives/v7/src/RStyle.cxx similarity index 71% rename from graf2d/primitives/v7/src/TStyle.cxx rename to graf2d/primitives/v7/src/RStyle.cxx index 1473cc6efb36f..8f15c98872577 100644 --- a/graf2d/primitives/v7/src/TStyle.cxx +++ b/graf2d/primitives/v7/src/RStyle.cxx @@ -1,4 +1,4 @@ -/// \file TStyle.cxx +/// \file RStyle.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-10-11 @@ -13,13 +13,13 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TStyle.hxx" +#include "ROOT/RStyle.hxx" #include "ROOT/TLogger.hxx" -#include "ROOT/TPadExtent.hxx" -#include "ROOT/TPadPos.hxx" +#include "ROOT/RPadExtent.hxx" +#include "ROOT/RPadPos.hxx" -#include "TStyleReader.hxx" // in src/ +#include "RStyleReader.hxx" // in src/ #include @@ -31,29 +31,29 @@ using namespace ROOT::Experimental; namespace { -static Internal::TStyleReader::AllStyles_t ReadGlobalDefaultStyles() +static Internal::RStyleReader::AllStyles_t ReadGlobalDefaultStyles() { - Internal::TStyleReader::AllStyles_t target; - Internal::TStyleReader reader(target); + Internal::RStyleReader::AllStyles_t target; + Internal::RStyleReader reader(target); reader.ReadDefaults(); return target; } -static Internal::TStyleReader::AllStyles_t &GetGlobalStyles() +static Internal::RStyleReader::AllStyles_t &GetGlobalStyles() { - static Internal::TStyleReader::AllStyles_t sStyles = ReadGlobalDefaultStyles(); + static Internal::RStyleReader::AllStyles_t sStyles = ReadGlobalDefaultStyles(); return sStyles; } } // unnamed namespace -TStyle &TStyle::Register(TStyle&& style) +RStyle &RStyle::Register(RStyle&& style) { - TStyle& ret = GetGlobalStyles()[style.GetName()]; + RStyle& ret = GetGlobalStyles()[style.GetName()]; ret = style; return ret; } -TStyle *TStyle::Get(std::string_view name) +RStyle *RStyle::Get(std::string_view name) { auto iStyle = GetGlobalStyles().find(std::string(name)); if (iStyle != GetGlobalStyles().end()) @@ -63,28 +63,28 @@ TStyle *TStyle::Get(std::string_view name) namespace { -static TStyle GetInitialCurrent() +static RStyle GetInitialCurrent() { static constexpr const char* kDefaultStyleName = "plain"; auto iDefStyle = GetGlobalStyles().find(std::string(kDefaultStyleName)); if (iDefStyle == GetGlobalStyles().end()) { R__ERROR_HERE("Gpad") << "Cannot find initial default style named \"" << kDefaultStyleName << "\", using an empty one."; - TStyle defStyle(kDefaultStyleName); - return TStyle::Register(std::move(defStyle)); + RStyle defStyle(kDefaultStyleName); + return RStyle::Register(std::move(defStyle)); } else { return iDefStyle->second; } } } -TStyle &TStyle::GetCurrent() +RStyle &RStyle::GetCurrent() { - static TStyle sCurrentStyle = GetInitialCurrent(); + static RStyle sCurrentStyle = GetInitialCurrent(); return sCurrentStyle; } -std::string TStyle::GetAttribute(const std::string &attrName, const std::string &/*className*/) const { +std::string RStyle::GetAttribute(const std::string &attrName, const std::string &/*className*/) const { std::string trailingPart(attrName); while (!trailingPart.empty()) { auto iter = fAttrs.find(trailingPart); diff --git a/graf2d/primitives/v7/src/TStyleReader.cxx b/graf2d/primitives/v7/src/RStyleReader.cxx similarity index 93% rename from graf2d/primitives/v7/src/TStyleReader.cxx rename to graf2d/primitives/v7/src/RStyleReader.cxx index 6771770f517f1..258522a3a2843 100644 --- a/graf2d/primitives/v7/src/TStyleReader.cxx +++ b/graf2d/primitives/v7/src/RStyleReader.cxx @@ -1,4 +1,4 @@ -/// \file TDrawingOptsReader.cxx +/// \file RDrawingOptsReader.cxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-09-26 @@ -13,9 +13,9 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "TStyleReader.hxx" // in src/ +#include "RStyleReader.hxx" // in src/ -#include +#include #include #include @@ -28,9 +28,9 @@ using namespace ROOT::Experimental; using namespace ROOT::Experimental::Internal; -void TStyleReader::ReadDefaults() +void RStyleReader::ReadDefaults() { - TStyleReader reader(fAttrs); + RStyleReader reader(fAttrs); reader.AddFromStyleFile(std::string(TROOT::GetEtcDir().Data()) + "/system.rootstylerc"); reader.AddFromStyleFile(gSystem->GetHomeDirectory() + "/.rootstylerc"); reader.AddFromStyleFile(".rootstylerc"); @@ -78,7 +78,7 @@ namespace { } } -bool TStyleReader::AddFromStyleFile(const std::string &filename) +bool RStyleReader::AddFromStyleFile(const std::string &filename) { std::ifstream in(filename); if (!in) diff --git a/graf2d/primitives/v7/src/TStyleReader.hxx b/graf2d/primitives/v7/src/RStyleReader.hxx similarity index 86% rename from graf2d/primitives/v7/src/TStyleReader.hxx rename to graf2d/primitives/v7/src/RStyleReader.hxx index 74f05dc3d7ff2..8792f9da6c3d8 100644 --- a/graf2d/primitives/v7/src/TStyleReader.hxx +++ b/graf2d/primitives/v7/src/RStyleReader.hxx @@ -1,4 +1,4 @@ -/// \file ROOT/TDrawingOptsReader.hxx +/// \file ROOT/RStyleReader.hxx /// \ingroup Gpad ROOT7 /// \author Axel Naumann /// \date 2017-09-29 @@ -13,11 +13,11 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#ifndef ROOT7_TStyleReader -#define ROOT7_TStyleReader +#ifndef ROOT7_RStyleReader +#define ROOT7_RStyleReader #include -#include +#include #include #include @@ -26,21 +26,21 @@ namespace ROOT { namespace Experimental { namespace Internal { -/** \class ROOT::Experimental::TStyleReader +/** \class ROOT::Experimental::RStyleReader Reads the attribute config values from `.rootstylerc`. If the style entry is not found there, tries `~/.rootstylerc` and finally `$ROOTSYS/etc/system.rootstylerc`. */ -class TStyleReader { +class RStyleReader { public: /// Key is the style name. - using AllStyles_t = std::unordered_map; + using AllStyles_t = std::unordered_map; private: /// Collection of attributes to read into. AllStyles_t &fAttrs; public: - TStyleReader(AllStyles_t &attrs): fAttrs(attrs) {} + RStyleReader(AllStyles_t &attrs): fAttrs(attrs) {} /// Reads the attribute config values from `.rootstylerc`. If the style entry is not found there, tries /// `~/.rootstylerc` and finally `$ROOTSYS/etc/system.rootstylerc`. diff --git a/graf2d/primitives/v7/src/TText.cxx b/graf2d/primitives/v7/src/RText.cxx similarity index 94% rename from graf2d/primitives/v7/src/TText.cxx rename to graf2d/primitives/v7/src/RText.cxx index 5d54b3fa92a44..d126b69691673 100644 --- a/graf2d/primitives/v7/src/TText.cxx +++ b/graf2d/primitives/v7/src/RText.cxx @@ -1,4 +1,4 @@ -/// \file TText.cxx +/// \file RText.cxx /// \ingroup Graf ROOT7 /// \author Olivier Couet /// \date 2017-07-07 @@ -13,6 +13,6 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TText.hxx" +#include "ROOT/RText.hxx" using namespace ROOT::Experimental; diff --git a/graf2d/primitives/v7/test/color.cxx b/graf2d/primitives/v7/test/color.cxx index 15252a8edb6aa..6b457fb9eb9f2 100644 --- a/graf2d/primitives/v7/test/color.cxx +++ b/graf2d/primitives/v7/test/color.cxx @@ -1,20 +1,20 @@ #include "gtest/gtest.h" -#include "ROOT/TColor.hxx" +#include "ROOT/RColor.hxx" // Predef TEST(ColorTest, Predef) { using namespace ROOT::Experimental; { - TColor col{TColor::kRed}; + RColor col{RColor::kRed}; EXPECT_FLOAT_EQ(col.GetRed(), 1.); EXPECT_FLOAT_EQ(col.GetGreen(), 0.); EXPECT_FLOAT_EQ(col.GetBlue(), 0.); EXPECT_FLOAT_EQ(col.GetAlpha(), 1.); } { - TColor col{TColor::kBlue}; - col.SetAlpha(TColor::kTransparent); + RColor col{RColor::kBlue}; + col.SetAlpha(RColor::kTransparent); EXPECT_FLOAT_EQ(col.GetRed(), 0.); EXPECT_FLOAT_EQ(col.GetGreen(), 0.); EXPECT_FLOAT_EQ(col.GetBlue(), 1.); diff --git a/graf2d/primitives/v7/test/palette.cxx b/graf2d/primitives/v7/test/palette.cxx index 44e3c70cc552a..9d7723fa28bd0 100644 --- a/graf2d/primitives/v7/test/palette.cxx +++ b/graf2d/primitives/v7/test/palette.cxx @@ -1,11 +1,11 @@ #include "gtest/gtest.h" -#include "ROOT/TPalette.hxx" +#include "ROOT/RPalette.hxx" // Test palette interpolation TEST(Palette, Interpolate) { using namespace ROOT::Experimental; - TPalette p1(TPalette::kDiscrete, {TColor::kWhite, TColor::kBlack}); - EXPECT_EQ(p1.GetColor(0.), TColor::kWhite); + RPalette p1(RPalette::kDiscrete, {RColor::kWhite, RColor::kBlack}); + EXPECT_EQ(p1.GetColor(0.), RColor::kWhite); } diff --git a/graf2d/win32gdk/src/TGWin32.cxx b/graf2d/win32gdk/src/TGWin32.cxx index 44b829cbc05cb..e2db4f5cb5122 100644 --- a/graf2d/win32gdk/src/TGWin32.cxx +++ b/graf2d/win32gdk/src/TGWin32.cxx @@ -191,6 +191,7 @@ static struct { // // Keep style values for line GdkGC // +static int gLineWidth = 0; static int gLineStyle = GDK_LINE_SOLID; static int gCapStyle = GDK_CAP_BUTT; static int gJoinStyle = GDK_JOIN_MITER; @@ -3262,7 +3263,7 @@ void TGWin32::SetLineType(int n, int *dash) { if (n <= 0) { gLineStyle = GDK_LINE_SOLID; - gdk_gc_set_line_attributes(gGCline, fLineWidth, + gdk_gc_set_line_attributes(gGCline, gLineWidth, (GdkLineStyle)gLineStyle, (GdkCapStyle) gCapStyle, (GdkJoinStyle) gJoinStyle); @@ -3276,7 +3277,8 @@ void TGWin32::SetLineType(int n, int *dash) } gDashOffset = 0; gLineStyle = GDK_LINE_ON_OFF_DASH; - gdk_gc_set_line_attributes(gGCdash, fLineWidth, + if (gLineWidth == 0) gLineWidth =1; + gdk_gc_set_line_attributes(gGCdash, gLineWidth, (GdkLineStyle) gLineStyle, (GdkCapStyle) gCapStyle, (GdkJoinStyle) gJoinStyle); @@ -3336,13 +3338,11 @@ void TGWin32::UpdateLineStyle() void TGWin32::SetLineWidth(Width_t width) { - if ((fLineWidth==width) || (width<0)) return; + if (fLineWidth == width) return; + fLineWidth = width; - if (width == 1) { - fLineWidth = 0; - } else { - fLineWidth = width; - } + if (width == 1 && gLineStyle == GDK_LINE_SOLID) gLineWidth = 0; + else gLineWidth = width; fPenModified = kTRUE; } @@ -3408,7 +3408,7 @@ void TGWin32::SetMarkerType(int type, int n, GdkPoint * xy) void TGWin32::SetMarkerStyle(Style_t markerstyle) { - if ((fMarkerStyle==markerstyle) || (markerstyle >= 35)) return; + if ((fMarkerStyle == markerstyle) || (markerstyle >= 50)) return; fMarkerStyle = TMath::Abs(markerstyle); fMarkerStyleModified = kTRUE; } diff --git a/graf3d/gl/src/TGLPadUtils.cxx b/graf3d/gl/src/TGLPadUtils.cxx index 31ee96759a97e..86dbcf0926d25 100644 --- a/graf3d/gl/src/TGLPadUtils.cxx +++ b/graf3d/gl/src/TGLPadUtils.cxx @@ -1170,6 +1170,11 @@ Tesselator::Tesselator(Bool_t dump) if (!tess) throw std::runtime_error("tesselator creation failed"); +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + if (!dump) { gluTessCallback(tess, (GLenum)GLU_BEGIN, (tess_t) glBegin); gluTessCallback(tess, (GLenum)GLU_END, (tess_t) glEnd); @@ -1180,6 +1185,10 @@ Tesselator::Tesselator(Bool_t dump) gluTessCallback(tess, (GLenum)GLU_VERTEX, (tess_t) Vertex); } +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif + gluTessProperty(tess, GLU_TESS_TOLERANCE, 1e-10); fTess = tess; } diff --git a/graf3d/gl/src/TGLUtil.cxx b/graf3d/gl/src/TGLUtil.cxx index 030512ad11489..16001cb5852dc 100644 --- a/graf3d/gl/src/TGLUtil.cxx +++ b/graf3d/gl/src/TGLUtil.cxx @@ -1478,9 +1478,19 @@ class TGLTesselatorWrap if (!fTess) throw std::bad_alloc(); +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + gluTessCallback(fTess, (GLenum)GLU_BEGIN, (tessfuncptr_t) glBegin); gluTessCallback(fTess, (GLenum)GLU_END, (tessfuncptr_t) glEnd); gluTessCallback(fTess, (GLenum)GLU_VERTEX, vertex_func); + +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif + } virtual ~TGLTesselatorWrap() @@ -1498,8 +1508,18 @@ class TGLTesselatorWrap GLUtesselator* TGLUtil::GetDrawTesselator3fv() { + +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex3fv); +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif + return singleton.fTess; } @@ -1509,8 +1529,18 @@ GLUtesselator* TGLUtil::GetDrawTesselator3fv() GLUtesselator* TGLUtil::GetDrawTesselator4fv() { + +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex4fv); +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif + return singleton.fTess; } @@ -1520,8 +1550,18 @@ GLUtesselator* TGLUtil::GetDrawTesselator4fv() GLUtesselator* TGLUtil::GetDrawTesselator3dv() { + +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex3dv); +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif + return singleton.fTess; } @@ -1531,8 +1571,18 @@ GLUtesselator* TGLUtil::GetDrawTesselator3dv() GLUtesselator* TGLUtil::GetDrawTesselator4dv() { + +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex4dv); +#if defined(__GNUC__) && __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif + return singleton.fTess; } diff --git a/graf3d/gviz3d/src/TStructViewerGUI.cxx b/graf3d/gviz3d/src/TStructViewerGUI.cxx index 440f3b1c1a846..9af36dc80b0e4 100644 --- a/graf3d/gviz3d/src/TStructViewerGUI.cxx +++ b/graf3d/gviz3d/src/TStructViewerGUI.cxx @@ -208,7 +208,7 @@ TStructViewerGUI::TStructViewerGUI(TStructViewer* parent, TStructNode* nodePtr, gGeoManager->SetTopVolume(fTopVolume); gGeoManager->SetNsegments(40); - fCanvas = new TCanvas("", "", 0, 0); + fCanvas = new TCanvas("c", "c", 0, 0); // drawing after creating canvas to avoid drawing in default canvas fGLViewer = new TGLEmbeddedViewer(this, fCanvas); AddFrame(fGLViewer->GetFrame(), new TGLayoutHints(kLHintsExpandX| kLHintsExpandY, 10,10,10,10)); diff --git a/gui/canvaspainter/v7/src/TCanvasPainter.cxx b/gui/canvaspainter/v7/src/TCanvasPainter.cxx index bf8423c2c103f..f3c1b528b6d16 100644 --- a/gui/canvaspainter/v7/src/TCanvasPainter.cxx +++ b/gui/canvaspainter/v7/src/TCanvasPainter.cxx @@ -13,12 +13,12 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TVirtualCanvasPainter.hxx" -#include "ROOT/TCanvas.hxx" +#include "ROOT/RVirtualCanvasPainter.hxx" +#include "ROOT/RCanvas.hxx" #include -#include -#include -#include +#include +#include +#include #include #include @@ -42,7 +42,7 @@ namespace ROOT { namespace Experimental { -class TCanvasPainter : public Internal::TVirtualCanvasPainter { +class TCanvasPainter : public Internal::RVirtualCanvasPainter { private: struct WebConn { unsigned fConnId{0}; /// WebUpdatesList; - typedef std::vector MenuItemsVector; + typedef std::vector MenuItemsVector; /// The canvas we are painting. It might go out of existence while painting. - const TCanvas &fCanvas; /// fWindow; ///!< configured display WebConnList fWebConn; /// FindDrawable(const ROOT::Experimental::TCanvas &can, const std::string &id); + std::shared_ptr FindDrawable(const ROOT::Experimental::RCanvas &can, const std::string &id); void SaveCreatedFile(std::string &reply); @@ -136,11 +136,11 @@ class TCanvasPainter : public Internal::TVirtualCanvasPainter { int CheckWaitingCmd(const std::string &cmdname, double); public: - TCanvasPainter(const TCanvas &canv) : fCanvas(canv) {} + TCanvasPainter(const RCanvas &canv) : fCanvas(canv) {} virtual ~TCanvasPainter(); - // virtual void AddDisplayItem(std::unique_ptr &&item) override + // virtual void AddDisplayItem(std::unique_ptr &&item) override // { // item->SetObjectID(fCurrentDrawableId); // fDisplayList.Add(std::move(item)); @@ -167,14 +167,14 @@ class TCanvasPainter : public Internal::TVirtualCanvasPainter { class GeneratorImpl : public Generator { public: - /// Create a new TCanvasPainter to paint the given TCanvas. - std::unique_ptr Create(const ROOT::Experimental::TCanvas &canv) const override + /// Create a new TCanvasPainter to paint the given RCanvas. + std::unique_ptr Create(const ROOT::Experimental::RCanvas &canv) const override { return std::make_unique(canv); } ~GeneratorImpl() = default; - /// Set TVirtualCanvasPainter::fgGenerator to a new GeneratorImpl object. + /// Set RVirtualCanvasPainter::fgGenerator to a new GeneratorImpl object. static void SetGlobalPainter() { if (GetGenerator()) { @@ -286,11 +286,11 @@ void ROOT::Experimental::TCanvasPainter::CheckDataToSend() if (drawable) { - ROOT::Experimental::TMenuItems items; + ROOT::Experimental::RMenuItems items; drawable->PopulateMenu(items); - // FIXME: got problem with std::list, can be generic TBufferJSON + // FIXME: got problem with std::list, can be generic TBufferJSON buf = "MENU:"; buf.Append(conn.fGetMenu); buf.Append(":"); @@ -611,7 +611,7 @@ bool ROOT::Experimental::TCanvasPainter::AddPanel(std::shared_ptr wi /// Here server-side painting is performed - each drawable adds own elements in /// so-called display list, which transferred to the clients -std::string ROOT::Experimental::TCanvasPainter::CreateSnapshot(const ROOT::Experimental::TCanvas &can) +std::string ROOT::Experimental::TCanvasPainter::CreateSnapshot(const ROOT::Experimental::RCanvas &can) { PaintDrawables(can); @@ -622,7 +622,7 @@ std::string ROOT::Experimental::TCanvasPainter::CreateSnapshot(const ROOT::Exper if (!fNextDumpName.empty()) { TBufferJSON::ExportToFile(fNextDumpName.c_str(), fPadDisplayItem.get(), - gROOT->GetClass("ROOT::Experimental::TPadDisplayItem")); + gROOT->GetClass("ROOT::Experimental::RPadDisplayItem")); fNextDumpName.clear(); } @@ -635,8 +635,8 @@ std::string ROOT::Experimental::TCanvasPainter::CreateSnapshot(const ROOT::Exper /// Find drawable in the canvas with specified id /// Used to communicate with the clients, which does not have any pointer -std::shared_ptr -ROOT::Experimental::TCanvasPainter::FindDrawable(const ROOT::Experimental::TCanvas &can, const std::string &id) +std::shared_ptr +ROOT::Experimental::TCanvasPainter::FindDrawable(const ROOT::Experimental::RCanvas &can, const std::string &id) { std::string search = id; size_t pos = search.find("#"); diff --git a/gui/fitpanelv7/inc/ROOT/TFitPanel.hxx b/gui/fitpanelv7/inc/ROOT/TFitPanel.hxx index 78f9e0687f112..81ee02d3d50ea 100644 --- a/gui/fitpanelv7/inc/ROOT/TFitPanel.hxx +++ b/gui/fitpanelv7/inc/ROOT/TFitPanel.hxx @@ -18,7 +18,7 @@ #include -#include +#include #include "ROOT/THist.hxx" @@ -59,7 +59,7 @@ class TFitPanel { std::shared_ptr fWindow; ///!< configured display - std::shared_ptr fCanvas; ///!< canvas used to display results + std::shared_ptr fCanvas; ///!< canvas used to display results std::shared_ptr fFitHist; ///!< histogram created when fit is performed @@ -79,7 +79,7 @@ public: /// destructor virtual ~TFitPanel() { printf("Fit panel destructor!!!\n"); } - // method required when any panel want to be inserted into the TCanvas + // method required when any panel want to be inserted into the RCanvas std::shared_ptr GetWindow(); /// show FitPanel in specified place @@ -89,7 +89,7 @@ public: void Hide(); /// let use canvas to display fit results - void UseCanvas(std::shared_ptr &canv); + void UseCanvas(std::shared_ptr &canv); /// Dummy function, called when "Fit" button pressed in UI void DoFit(const std::string &dname, const std::string &mname); diff --git a/gui/fitpanelv7/src/TFitPanel.cxx b/gui/fitpanelv7/src/TFitPanel.cxx index 85206272ded6f..96486dfa15548 100644 --- a/gui/fitpanelv7/src/TFitPanel.cxx +++ b/gui/fitpanelv7/src/TFitPanel.cxx @@ -113,7 +113,7 @@ void ROOT::Experimental::TFitPanel::ProcessData(unsigned connid, const std::stri /////////////////////////////////////////////////////////////////////////////////////////////////////// /// Let use canvas to display fit results -void ROOT::Experimental::TFitPanel::UseCanvas(std::shared_ptr &canv) +void ROOT::Experimental::TFitPanel::UseCanvas(std::shared_ptr &canv) { if (!fCanvas) { fCanvas = canv; @@ -132,7 +132,7 @@ void ROOT::Experimental::TFitPanel::DoFit(const std::string &dname, const std::s bool first_time = false; if (!fCanvas) { - fCanvas = Experimental::TCanvas::Create("FitPanel Canvas"); + fCanvas = Experimental::RCanvas::Create("FitPanel Canvas"); first_time = true; } @@ -149,7 +149,7 @@ void ROOT::Experimental::TFitPanel::DoFit(const std::string &dname, const std::s fFitHist->Fill(6); fFitHist->Fill(7); - fCanvas->Draw(fFitHist)->SetLineColor(Experimental::TColor::kBlue); + fCanvas->Draw(fFitHist)->SetLineColor(Experimental::RColor::kBlue); // workaround to keep histogram in the lists ROOT::Experimental::TDirectory::Heap().Add("fitaxis", xaxis); diff --git a/hist/hist/inc/TH1.h b/hist/hist/inc/TH1.h index 68bdc6d33c658..8acf0c3663f30 100644 --- a/hist/hist/inc/TH1.h +++ b/hist/hist/inc/TH1.h @@ -135,7 +135,7 @@ class TH1 : public TNamed, public TAttLine, public TAttFill, public TAttMarker { virtual void SavePrimitiveHelp(std::ostream &out, const char *hname, Option_t *option = ""); static Bool_t RecomputeAxisLimits(TAxis& destAxis, const TAxis& anAxis); static Bool_t SameLimitsAndNBins(const TAxis& axis1, const TAxis& axis2); - Bool_t IsEmpty() const { return fTsumw == 0 && GetEntries() == 0; } //need to use GetEntries() in case of buffer histograms + Bool_t IsEmpty() const; inline static Double_t AutoP2GetPower2(Double_t x, Bool_t next = kTRUE); inline static Int_t AutoP2GetBins(Int_t n); diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index d20ca3c05e1bc..b58c0c1f1276f 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -543,7 +543,7 @@ void TAxis::GetCenter(Double_t *center) const } //////////////////////////////////////////////////////////////////////////////// -/// Return an array with the lod edge of all bins +/// Return an array with the low edge of all bins void TAxis::GetLowEdge(Double_t *edge) const { diff --git a/hist/hist/src/TF1.cxx b/hist/hist/src/TF1.cxx index 8684a391176ba..0a192eaebeb78 100644 --- a/hist/hist/src/TF1.cxx +++ b/hist/hist/src/TF1.cxx @@ -2502,8 +2502,8 @@ Double_t TF1::IntegralOneDim(Double_t a, Double_t b, Double_t epsrel, Double_t TF1_EvalWrapper wf1(this, 0, fgAbsValue); Double_t result = 0; Int_t status = 0; - if (epsrel <= 0) epsrel = ROOT::Math::IntegratorOneDimOptions::DefaultRelTolerance(); - if (epsabs <= 0) epsabs = ROOT::Math::IntegratorOneDimOptions::DefaultAbsTolerance(); + if (epsrel <= 0) epsrel = ROOT::Math::IntegratorOneDimOptions::DefaultRelTolerance(); + if (epsabs <= 0) epsabs = ROOT::Math::IntegratorOneDimOptions::DefaultAbsTolerance(); if (ROOT::Math::IntegratorOneDimOptions::DefaultIntegratorType() == ROOT::Math::IntegrationOneDim::kGAUSS) { ROOT::Math::GaussIntegrator iod(epsabs, epsrel); iod.SetFunction(wf1); @@ -2864,9 +2864,9 @@ void TF1::Paint(Option_t *choptin) char *l3 = strstr(option,"PMC"); // Automatic Marker Color if (l1 || l2 || l3) { Int_t i = gPad->NextPaletteColor(); - if (l1) {strncpy(l1," ",3); fHistogram->SetFillColor(i);} - if (l2) {strncpy(l2," ",3); fHistogram->SetLineColor(i);} - if (l3) {strncpy(l3," ",3); fHistogram->SetMarkerColor(i);} + if (l1) {memcpy(l1," ",3); fHistogram->SetFillColor(i);} + if (l2) {memcpy(l2," ",3); fHistogram->SetLineColor(i);} + if (l3) {memcpy(l3," ",3); fHistogram->SetMarkerColor(i);} } // set the optimal minimum and maximum diff --git a/hist/hist/src/TH1.cxx b/hist/hist/src/TH1.cxx index aa2477b4d77aa..2d15e07d6abb8 100644 --- a/hist/hist/src/TH1.cxx +++ b/hist/hist/src/TH1.cxx @@ -1646,8 +1646,7 @@ bool TH1::CheckConsistency(const TH1* h1, const TH1* h2) if (dim > 2) ret &= CheckBinLimits(h1->GetZaxis(), h2->GetZaxis()); // check labels if histograms are both not empty - if ( (h1->fTsumw != 0 || h1->GetEntries() != 0) && - (h2->fTsumw != 0 || h2->GetEntries() != 0) ) { + if ( !h1->IsEmpty() && !h2->IsEmpty() ) { ret &= CheckBinLabels(h1->GetXaxis(), h2->GetXaxis()); if (dim > 1) ret &= CheckBinLabels(h1->GetYaxis(), h2->GetYaxis()); if (dim > 2) ret &= CheckBinLabels(h1->GetZaxis(), h2->GetZaxis()); @@ -4889,6 +4888,25 @@ Double_t TH1::Interpolate(Double_t, Double_t, Double_t) return 0; } +/////////////////////////////////////////////////////////////////////////////// +/// Check if an histogram is empty +/// (this a protected method used mainly by TH1Merger ) + +Bool_t TH1::IsEmpty() const +{ + // if fTsumw or fentries are not zero histogram is not empty + // need to use GetEntries() instead of fEntries in case of bugger histograms + // so we will flash the buffer + if (fTsumw != 0) return kFALSE; + if (GetEntries() != 0) return kFALSE; + // case fTSumw == 0 amd entries are also zero + // this should not really happening, but if one sets content by hand + // it can happen. a call to ResetStats() should be done in such cases + double sumw = 0; + for (int i = 0; i< GetNcells(); ++i) sumw += RetrieveBinContent(i); + return (sumw != 0) ? kFALSE : kTRUE; +} + //////////////////////////////////////////////////////////////////////////////// /// Return true if the bin is overflow. @@ -7202,15 +7220,11 @@ void TH1::GetStats(Double_t *stats) const Int_t bin, binx; Double_t w,err; Double_t x; - // case of labels with extension of axis range - // statistics in x does not make any sense - set to zero - if ((const_cast(fXaxis)).GetLabels() && CanExtendAllAxes() ) { - stats[0] = fTsumw; - stats[1] = fTsumw2; - stats[2] = 0; - stats[3] = 0; - } - else if ((fTsumw == 0 && fEntries > 0) || fXaxis.TestBit(TAxis::kAxisRange)) { + // identify the case of labels with extension of axis range + // in this case the statistics in x does not make any sense + Bool_t labelHist = ((const_cast(fXaxis)).GetLabels() && CanExtendAllAxes() ); + // fTsumw == 0 && fEntries > 0 is a special case when uses SetBinContent or calls ResetStats before + if ((fTsumw == 0 && fEntries > 0) || ( fXaxis.TestBit(TAxis::kAxisRange) && !labelHist) ) { for (bin=0;bin<4;bin++) stats[bin] = 0; Int_t firstBinX = fXaxis.GetFirst(); @@ -7228,8 +7242,11 @@ void TH1::GetStats(Double_t *stats) const err = TMath::Abs(GetBinError(binx)); stats[0] += w; stats[1] += err*err; - stats[2] += w*x; - stats[3] += w*x*x; + // statistics in x makes sense only for not labels histograms + if (!labelHist) { + stats[2] += w*x; + stats[3] += w*x*x; + } } // if (stats[0] < 0) { // // in case total is negative do something ?? diff --git a/hist/hist/src/THStack.cxx b/hist/hist/src/THStack.cxx index 2d9dfe4901a01..c59d6a1a18988 100644 --- a/hist/hist/src/THStack.cxx +++ b/hist/hist/src/THStack.cxx @@ -708,9 +708,9 @@ void THStack::Paint(Option_t *choptin) char *l3 = strstr(option,"pmc"); // Automatic Marker Color if (l1 || l2 || l3) { TString opt1 = option; - if (l1) strncpy(l1," ",3); - if (l2) strncpy(l2," ",3); - if (l3) strncpy(l3," ",3); + if (l1) memcpy(l1," ",3); + if (l2) memcpy(l2," ",3); + if (l3) memcpy(l3," ",3); TString ws = option; if (ws.IsWhitespace()) strncpy(option,"\0",1); TObjOptLink *lnk = (TObjOptLink*)fHists->FirstLink(); @@ -789,7 +789,7 @@ void THStack::Paint(Option_t *choptin) if (h->GetYaxis()->GetXmax() > ymax) ymax = h->GetYaxis()->GetXmax(); } - char loption[32]; + char loption[40]; snprintf(loption,31,"%s",opt.Data()); char *nostack = strstr(loption,"nostack"); char *nostackb = strstr(loption,"nostackb"); @@ -903,14 +903,14 @@ void THStack::Paint(Option_t *choptin) Double_t bw = (1.-(2*bo))/nhists; for (Int_t i=0;iGetOption(),"same")) { - if (nostackb) snprintf(loption,31,"%s%s b",noption,lnk->GetOption()); - else snprintf(loption,31,"%s%s",noption,lnk->GetOption()); + if (nostackb) snprintf(loption,34,"%s%s b",noption,lnk->GetOption()); + else snprintf(loption,32,"%s%s",noption,lnk->GetOption()); } else { TString indivOpt = lnk->GetOption(); indivOpt.ToLower(); - if (nostackb) snprintf(loption,31,"%ssame%s b",noption,lnk->GetOption()); + if (nostackb) snprintf(loption,38,"%ssame%s b",noption,lnk->GetOption()); else if (candle && (indivOpt.Contains("candle") || indivOpt.Contains("violin"))) snprintf(loption,31,"%ssame",lnk->GetOption()); - else snprintf(loption,31,"%ssame%s",noption,lnk->GetOption()); + else snprintf(loption,36,"%ssame%s",noption,lnk->GetOption()); } hAti = (TH1F*)(fHists->At(i)); if (nostackb) { @@ -934,9 +934,9 @@ void THStack::Paint(Option_t *choptin) Int_t h1col, h1fill; for (Int_t i=0;iGetOption(),"same")) { - snprintf(loption,31,"%s%s",noption,lnk->GetOption()); + snprintf(loption,32,"%s%s",noption,lnk->GetOption()); } else { - snprintf(loption,31,"%ssame%s",noption,lnk->GetOption()); + snprintf(loption,36,"%ssame%s",noption,lnk->GetOption()); } h1 = (TH1*)fStack->At(nhists-i-1); if (i>0 && lclear) { diff --git a/hist/hist/src/TMultiGraph.cxx b/hist/hist/src/TMultiGraph.cxx index 0c4921861c26b..759ed15c1581a 100644 --- a/hist/hist/src/TMultiGraph.cxx +++ b/hist/hist/src/TMultiGraph.cxx @@ -1079,9 +1079,9 @@ void TMultiGraph::Paint(Option_t *choptin) char *l3 = strstr(option,"PMC"); // Automatic Marker Color if (l1 || l2 || l3) { TString opt1 = option; opt1.ToLower(); - if (l1) strncpy(l1," ",3); - if (l2) strncpy(l2," ",3); - if (l3) strncpy(l3," ",3); + if (l1) memcpy(l1," ",3); + if (l2) memcpy(l2," ",3); + if (l3) memcpy(l3," ",3); TObjOptLink *lnk = (TObjOptLink*)fGraphs->FirstLink(); TGraph* gAti; Int_t ngraphs = fGraphs->GetSize(); diff --git a/hist/hist/v7/inc/ROOT/THist.hxx b/hist/hist/v7/inc/ROOT/THist.hxx index 365e08024328b..182e42c33b122 100644 --- a/hist/hist/v7/inc/ROOT/THist.hxx +++ b/hist/hist/v7/inc/ROOT/THist.hxx @@ -18,7 +18,7 @@ #include "ROOT/RSpan.hxx" #include "ROOT/TAxis.hxx" -#include "ROOT/TDrawable.hxx" +#include "ROOT/RDrawable.hxx" #include "ROOT/THistBinIter.hxx" #include "ROOT/THistDrawable.hxx" #include "ROOT/THistImpl.hxx" diff --git a/hist/histdraw/inc/LinkDef.h b/hist/histdraw/inc/LinkDef.h index a9b11e08b73c1..60eabb0be9d67 100644 --- a/hist/histdraw/inc/LinkDef.h +++ b/hist/histdraw/inc/LinkDef.h @@ -16,7 +16,7 @@ // need to correctly generate dictionary for display items, used in v7 histpainter, // but currently histpainter does not creates dictionary at all -#pragma extra_include "ROOT/TDisplayItem.hxx"; +#pragma extra_include "ROOT/RDisplayItem.hxx"; #pragma link C++ class ROOT::Experimental::THistDrawingOpts<1>+; #pragma link C++ class ROOT::Experimental::THistDrawingOpts<2>+; @@ -24,24 +24,24 @@ #pragma link C++ class ROOT::Experimental::THistDrawable<1>+; #pragma link C++ class ROOT::Experimental::THistDrawable<2>+; #pragma link C++ class ROOT::Experimental::THistDrawable<3>+; -#pragma link C++ class ROOT::Experimental::TDrawableBase>+; -#pragma link C++ class ROOT::Experimental::TDrawableBase>+; -#pragma link C++ class ROOT::Experimental::TDrawableBase>+; +#pragma link C++ class ROOT::Experimental::RDrawableBase>+; +#pragma link C++ class ROOT::Experimental::RDrawableBase>+; +#pragma link C++ class ROOT::Experimental::RDrawableBase>+; #pragma link C++ class ROOT::Experimental::THistDrawableBase>+; #pragma link C++ class ROOT::Experimental::THistDrawableBase>+; #pragma link C++ class ROOT::Experimental::THistDrawableBase>+; -#pragma link C++ class ROOT::Experimental::TOrdinaryDisplayItem>+; -#pragma link C++ class ROOT::Experimental::TOrdinaryDisplayItem>+; -#pragma link C++ class ROOT::Experimental::TOrdinaryDisplayItem>+; +#pragma link C++ class ROOT::Experimental::ROrdinaryDisplayItem>+; +#pragma link C++ class ROOT::Experimental::ROrdinaryDisplayItem>+; +#pragma link C++ class ROOT::Experimental::ROrdinaryDisplayItem>+; #pragma link C++ class ROOT::Experimental::Internal::TUniWeakPtr >+; #pragma link C++ class ROOT::Experimental::Internal::TUniWeakPtr>+; #pragma link C++ class ROOT::Experimental::Internal::TUniWeakPtr>+; -#pragma link C++ class ROOT::Experimental::TStringEnumAttr::EStyle>+; -#pragma link C++ class ROOT::Experimental::TStringEnumAttr::EStyle>+; -#pragma link C++ class ROOT::Experimental::TStringEnumAttr::EStyle>+; -#pragma link C++ class ROOT::Experimental::TDrawingAttr::EStyle>>+; -#pragma link C++ class ROOT::Experimental::TDrawingAttr::EStyle>>+; -#pragma link C++ class ROOT::Experimental::TDrawingAttr::EStyle>>+; +#pragma link C++ class ROOT::Experimental::RStringEnumAttr::EStyle>+; +#pragma link C++ class ROOT::Experimental::RStringEnumAttr::EStyle>+; +#pragma link C++ class ROOT::Experimental::RStringEnumAttr::EStyle>+; +#pragma link C++ class ROOT::Experimental::RDrawingAttr::EStyle>>+; +#pragma link C++ class ROOT::Experimental::RDrawingAttr::EStyle>>+; +#pragma link C++ class ROOT::Experimental::RDrawingAttr::EStyle>>+; #endif diff --git a/hist/histdraw/v7/inc/ROOT/THistDrawable.hxx b/hist/histdraw/v7/inc/ROOT/THistDrawable.hxx index 34abbad65acb8..db3585e5b9468 100644 --- a/hist/histdraw/v7/inc/ROOT/THistDrawable.hxx +++ b/hist/histdraw/v7/inc/ROOT/THistDrawable.hxx @@ -16,10 +16,10 @@ #ifndef ROOT7_THistDrawable #define ROOT7_THistDrawable -#include "ROOT/TDrawable.hxx" +#include "ROOT/RDrawable.hxx" #include "ROOT/THistDrawingOpts.hxx" #include "ROOT/THistImpl.hxx" -#include "ROOT/TMenuItem.hxx" +#include "ROOT/RMenuItem.hxx" #include @@ -51,7 +51,7 @@ public: static THistPainterBase *GetPainter(); /// Paint a THist. All we need is access to its GetBinContent() - virtual void Paint(TDrawable &obj, const THistDrawingOpts &opts, TPadPainter &pad) = 0; + virtual void Paint(RDrawable &obj, const THistDrawingOpts &opts, RPadPainter &pad) = 0; }; extern template class THistPainterBase<1>; @@ -61,11 +61,11 @@ extern template class THistPainterBase<3>; } // namespace Internal template -class THistDrawableBase: public TDrawableBase { +class THistDrawableBase: public RDrawableBase { public: virtual ~THistDrawableBase() = default; - void PopulateMenu(TMenuItems &) final; + void PopulateMenu(RMenuItems &) final; void Execute(const std::string &) final { @@ -96,7 +96,7 @@ public: {} /// Paint the histogram - void Paint(Internal::TPadPainter &pad) final; + void Paint(Internal::RPadPainter &pad) final; THistDrawingOpts &GetOptions() { return fOpts; } const THistDrawingOpts &GetOptions() const { return fOpts; } diff --git a/hist/histdraw/v7/inc/ROOT/THistDrawingOpts.hxx b/hist/histdraw/v7/inc/ROOT/THistDrawingOpts.hxx index d669b6a508e43..64c102e2483c0 100644 --- a/hist/histdraw/v7/inc/ROOT/THistDrawingOpts.hxx +++ b/hist/histdraw/v7/inc/ROOT/THistDrawingOpts.hxx @@ -16,9 +16,9 @@ #ifndef ROOT7_THistDrawingOpts #define ROOT7_THistDrawingOpts -#include -#include -#include +#include +#include +#include namespace ROOT { namespace Experimental { @@ -34,30 +34,30 @@ class THistDrawingOpts { Drawing options for a 1D histogram. */ template <> -class THistDrawingOpts<1>: public TDrawingOptsBase { +class THistDrawingOpts<1>: public RDrawingOptsBase { public: enum class EStyle { kBar, kText }; private: - static const TStringEnumAttrSet &Styles() { - static const TStringEnumAttrSet styles{"hist", "bar", "text"}; + static const RStringEnumAttrSet &Styles() { + static const RStringEnumAttrSet styles{"hist", "bar", "text"}; return styles; } - TDrawingAttr> fStyle{*this, "Hist.1D.Style", EStyle::kBar, Styles()}; - TDrawingAttr fLineColor{*this, "Hist.1D.Line.Color"}; - TDrawingAttr fLineWidth{*this, "Hist.1D.Line.Width"}; + RDrawingAttr> fStyle{*this, "Hist.1D.Style", EStyle::kBar, Styles()}; + RDrawingAttr fLineColor{*this, "Hist.1D.Line.Color"}; + RDrawingAttr fLineWidth{*this, "Hist.1D.Line.Width"}; public: EStyle GetStyle() const { return fStyle.Get().GetIndex(); } - TDrawingAttr> &GetStyle() { return fStyle; } + RDrawingAttr> &GetStyle() { return fStyle; } void SetStyle(EStyle style) { fStyle.Get().SetIndex(style); } - TColor GetLineColor() const { return fLineColor.Get(); } - TDrawingAttr &GetLineColor() { return fLineColor; } - void SetLineColor(const TColor& col) { fLineColor = col; } + RColor GetLineColor() const { return fLineColor.Get(); } + RDrawingAttr &GetLineColor() { return fLineColor; } + void SetLineColor(const RColor& col) { fLineColor = col; } int GetLineWidth() const { return fLineWidth.Get(); } - TDrawingAttr &GetLineWidth() { return fLineWidth; } + RDrawingAttr &GetLineWidth() { return fLineWidth; } void SetLineWidth(int width) { fLineWidth = width; } }; @@ -65,30 +65,30 @@ public: Drawing options for a 2D histogram. */ template <> -class THistDrawingOpts<2>: public TDrawingOptsBase { +class THistDrawingOpts<2>: public RDrawingOptsBase { public: enum class EStyle { kBox, kSurf, kText }; private: - static const TStringEnumAttrSet &Styles() { - static const TStringEnumAttrSet styles{"box", "surf", "text"}; + static const RStringEnumAttrSet &Styles() { + static const RStringEnumAttrSet styles{"box", "surf", "text"}; return styles; } - TDrawingAttr> fStyle{*this, "Hist.2D.Style", EStyle::kBox, Styles()}; - TDrawingAttr fLineColor{*this, "Hist.2D.Line.Color"}; - TDrawingAttr fLineWidth{*this, "Hist.2D.Line.Width"}; + RDrawingAttr> fStyle{*this, "Hist.2D.Style", EStyle::kBox, Styles()}; + RDrawingAttr fLineColor{*this, "Hist.2D.Line.Color"}; + RDrawingAttr fLineWidth{*this, "Hist.2D.Line.Width"}; public: EStyle GetStyle() const { return fStyle.Get().GetIndex(); } - TDrawingAttr> &GetStyle() { return fStyle; } + RDrawingAttr> &GetStyle() { return fStyle; } void SetStyle(EStyle style) { fStyle.Get().SetIndex(style); } - TColor GetLineColor() const { return fLineColor.Get(); } - TDrawingAttr &GetLineColor() { return fLineColor; } - void SetLineColor(const TColor& col) { fLineColor = col; } + RColor GetLineColor() const { return fLineColor.Get(); } + RDrawingAttr &GetLineColor() { return fLineColor; } + void SetLineColor(const RColor& col) { fLineColor = col; } int GetLineWidth() const { return fLineWidth.Get(); } - TDrawingAttr &GetLineWidth() { return fLineWidth; } + RDrawingAttr &GetLineWidth() { return fLineWidth; } void SetLineWidth(int width) { fLineWidth = width; } }; @@ -96,30 +96,30 @@ public: Drawing options for a 3D histogram. */ template <> -class THistDrawingOpts<3>: public TDrawingOptsBase { +class THistDrawingOpts<3>: public RDrawingOptsBase { public: enum class EStyle { kBox, kIso }; private: - static const TStringEnumAttrSet &Styles() { - static const TStringEnumAttrSet styles{"box", "iso"}; + static const RStringEnumAttrSet &Styles() { + static const RStringEnumAttrSet styles{"box", "iso"}; return styles; } - TDrawingAttr> fStyle{*this, "Hist.3D.Style", EStyle::kBox, Styles()}; - TDrawingAttr fLineColor{*this, "Hist.3D.Line.Color"}; - TDrawingAttr fLineWidth{*this, "Hist.3D.Line.Width"}; + RDrawingAttr> fStyle{*this, "Hist.3D.Style", EStyle::kBox, Styles()}; + RDrawingAttr fLineColor{*this, "Hist.3D.Line.Color"}; + RDrawingAttr fLineWidth{*this, "Hist.3D.Line.Width"}; public: EStyle GetStyle() const { return fStyle.Get().GetIndex(); } - TDrawingAttr> &GetStyle() { return fStyle; } + RDrawingAttr> &GetStyle() { return fStyle; } void SetStyle(EStyle style) { fStyle.Get().SetIndex(style); } - TColor GetLineColor() const { return fLineColor.Get(); } - TDrawingAttr &GetLineColor() { return fLineColor; } - void SetLineColor(const TColor& col) { fLineColor = col; } + RColor GetLineColor() const { return fLineColor.Get(); } + RDrawingAttr &GetLineColor() { return fLineColor; } + void SetLineColor(const RColor& col) { fLineColor = col; } int GetLineWidth() const { return fLineWidth.Get(); } - TDrawingAttr &GetLineWidth() { return fLineWidth; } + RDrawingAttr &GetLineWidth() { return fLineWidth; } void SetLineWidth(int width) { fLineWidth = width; } }; diff --git a/hist/histdraw/v7/src/THistDrawable.cxx b/hist/histdraw/v7/src/THistDrawable.cxx index 719b66586a6b8..039845b3309e3 100644 --- a/hist/histdraw/v7/src/THistDrawable.cxx +++ b/hist/histdraw/v7/src/THistDrawable.cxx @@ -61,7 +61,7 @@ THistPainterBase *THistPainterBase::GetPainter() } template -void THistDrawableBase::PopulateMenu(TMenuItems &) +void THistDrawableBase::PopulateMenu(RMenuItems &) { // here should be filling of context menu for the given object } @@ -72,7 +72,7 @@ THistDrawable::THistDrawable() = default; /// Paint the histogram template -void THistDrawable::Paint(Internal::TPadPainter &pad) +void THistDrawable::Paint(Internal::RPadPainter &pad) { Internal::THistPainterBase::GetPainter()->Paint(*this, fOpts, pad); } diff --git a/hist/histdraw/v7/test/draw.cxx b/hist/histdraw/v7/test/draw.cxx index 6119a7b98fde3..4891092e18d31 100644 --- a/hist/histdraw/v7/test/draw.cxx +++ b/hist/histdraw/v7/test/draw.cxx @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "ROOT/THist.hxx" -#include "ROOT/TCanvas.hxx" -#include "ROOT/TColor.hxx" +#include "ROOT/RCanvas.hxx" +#include "ROOT/RColor.hxx" using namespace ROOT::Experimental; @@ -10,7 +10,7 @@ TEST(DrawTest, OneD) { TAxisConfig xaxis{10, 0., 1.}; auto h = std::make_shared(xaxis); - TCanvas canv; + RCanvas canv; canv.Draw(h); EXPECT_EQ(canv.GetPrimitives().size(), 1u); } @@ -20,7 +20,7 @@ TEST(DrawTest, TwoD) TAxisConfig xaxis{10, 0., 1.}; TAxisConfig yaxis{{0., 1., 10., 100.}}; auto h = std::make_shared(xaxis, yaxis); - TCanvas canv; + RCanvas canv; canv.Draw(h); // No THist copt c'tor: // canv.Draw(TH2F(xaxis, yaxis)); @@ -34,7 +34,7 @@ TEST(DrawTest, ThreeD) TAxisConfig yaxis{10, 0., 1.}; TAxisConfig zaxis{{0., 1., 10., 100.}}; auto h = std::make_shared(xaxis, yaxis, zaxis); - TCanvas canv; + RCanvas canv; canv.Draw(h); EXPECT_EQ(canv.GetPrimitives().size(), 1u); } @@ -44,9 +44,9 @@ TEST(DrawOptTest, OneD) { TAxisConfig xaxis{10, 0., 1.}; auto h = std::make_shared(xaxis); - TCanvas canv; + RCanvas canv; auto optsPtr = canv.Draw(h); - optsPtr->SetLineColor(TColor::kRed); - TColor shouldBeRed = (TColor)optsPtr->GetLineColor(); - EXPECT_EQ(shouldBeRed, TColor::kRed); + optsPtr->SetLineColor(RColor::kRed); + RColor shouldBeRed = (RColor)optsPtr->GetLineColor(); + EXPECT_EQ(shouldBeRed, RColor::kRed); } diff --git a/hist/histdraw/v7/test/io.cxx b/hist/histdraw/v7/test/io.cxx index bb8fc4493e3fb..9dd4bc2191cab 100644 --- a/hist/histdraw/v7/test/io.cxx +++ b/hist/histdraw/v7/test/io.cxx @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "ROOT/THist.hxx" -#include "ROOT/TCanvas.hxx" -#include "ROOT/TColor.hxx" +#include "ROOT/RCanvas.hxx" +#include "ROOT/RColor.hxx" #include "ROOT/TFile.hxx" #include @@ -28,9 +28,9 @@ TEST(IOTest, OneDOpts) { TAxisConfig xaxis{10, 0., 1.}; auto h = std::make_unique(xaxis); - TCanvas canv; + RCanvas canv; auto optsPtr = canv.Draw(std::move(h)); - optsPtr->SetLineColor(TColor::kRed); + optsPtr->SetLineColor(RColor::kRed); auto file = TFile::Recreate("IOTestOneDOpts.root"); file->Write("canv", canv); diff --git a/hist/histpainter/inc/TPainter3dAlgorithms.h b/hist/histpainter/inc/TPainter3dAlgorithms.h index 873924eafc67d..5cc094c925ad7 100644 --- a/hist/histpainter/inc/TPainter3dAlgorithms.h +++ b/hist/histpainter/inc/TPainter3dAlgorithms.h @@ -31,7 +31,8 @@ class TPainter3dAlgorithms : public TObject, public TAttLine, public TAttFill { private: Double_t fRmin[3]; /// Lower limits of lego Double_t fRmax[3]; /// Upper limits of lego - Double_t fAphi[183]; /// + Double_t *fAphi; /// + Int_t fNaphi; /// Size of fAphi Int_t fSystem; /// Coordinate system Int_t *fColorMain; /// Int_t *fColorDark; /// diff --git a/hist/histpainter/src/TGraphPainter.cxx b/hist/histpainter/src/TGraphPainter.cxx index 428c584518f89..6b4d37387f39d 100644 --- a/hist/histpainter/src/TGraphPainter.cxx +++ b/hist/histpainter/src/TGraphPainter.cxx @@ -1148,9 +1148,9 @@ void TGraphPainter::PaintHelper(TGraph *theGraph, Option_t *option) char *l3 = strstr(chopt,"pmc"); // Automatic Marker Color if (l1 || l2 || l3) { Int_t i = gPad->NextPaletteColor(); - if (l1) {strncpy(l1," ",3); theGraph->SetFillColor(i);} - if (l2) {strncpy(l2," ",3); theGraph->SetLineColor(i);} - if (l3) {strncpy(l3," ",3); theGraph->SetMarkerColor(i);} + if (l1) {memcpy(l1," ",3); theGraph->SetFillColor(i);} + if (l2) {memcpy(l2," ",3); theGraph->SetLineColor(i);} + if (l3) {memcpy(l3," ",3); theGraph->SetMarkerColor(i);} } SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame)); @@ -1315,9 +1315,9 @@ void TGraphPainter::PaintGraph(TGraph *theGraph, Int_t npoints, const Double_t * // Create a temporary histogram and fill each bin with the // function value. char chopth[8] = " "; - if (strstr(chopt,"x+")) strncat(chopth, "x+",2); - if (strstr(chopt,"y+")) strncat(chopth, "y+",2); - if (optionIAxis) strncat(chopth, "A",1); + if (strstr(chopt,"x+")) strncat(chopth, "x+",3); + if (strstr(chopt,"y+")) strncat(chopth, "y+",3); + if (optionIAxis) strncat(chopth, "A",2); if (!theGraph->GetHistogram()) { // the graph is created with at least as many bins as there are // points to permit zooming on the full range. @@ -3207,7 +3207,7 @@ void TGraphPainter::PaintGraphPolar(TGraph *theGraph, Option_t* options) } if (theEX) { for (i=0; iTAttLine::Modify(); diff --git a/hist/histpainter/src/THistPainter.cxx b/hist/histpainter/src/THistPainter.cxx index 37696f6e8bd47..ff0a3a529b29c 100644 --- a/hist/histpainter/src/THistPainter.cxx +++ b/hist/histpainter/src/THistPainter.cxx @@ -3962,15 +3962,15 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) char *l3 = strstr(chopt,"PMC"); // Automatic Marker Color if (l1 || l2 || l3) { Int_t i = gPad->NextPaletteColor(); - if (l1) {strncpy(l1," ",3); fH->SetFillColor(i);} - if (l2) {strncpy(l2," ",3); fH->SetLineColor(i);} - if (l3) {strncpy(l3," ",3); fH->SetMarkerColor(i);} + if (l1) {memcpy(l1," ",3); fH->SetFillColor(i);} + if (l2) {memcpy(l2," ",3); fH->SetLineColor(i);} + if (l3) {memcpy(l3," ",3); fH->SetMarkerColor(i);} } l = strstr(chopt,"SPEC"); if (l) { Hoption.Scat = 0; - strncpy(l," ",4); + memcpy(l," ",4); Int_t bs=0; l = strstr(chopt,"BF("); if (l) { @@ -3989,17 +3989,17 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) l = strstr(chopt,"GL"); if (l) { - strncpy(l," ",2); + memcpy(l," ",2); } l = strstr(chopt,"X+"); if (l) { Hoption.AxisPos = 10; - strncpy(l," ",2); + memcpy(l," ",2); } l = strstr(chopt,"Y+"); if (l) { Hoption.AxisPos += 1; - strncpy(l," ",2); + memcpy(l," ",2); } if ((Hoption.AxisPos == 10 || Hoption.AxisPos == 1) && (nch == 2)) Hoption.Hist = 1; if (Hoption.AxisPos == 11 && nch == 4) Hoption.Hist = 1; @@ -4008,19 +4008,19 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) if (l) { if (nch == 5) Hoption.Hist = 1; Hoption.Same = 2; - strncpy(l," ",5); + memcpy(l," ",5); } l = strstr(chopt,"SAME"); if (l) { if (nch == 4) Hoption.Hist = 1; Hoption.Same = 1; - strncpy(l," ",4); + memcpy(l," ",4); } l = strstr(chopt,"PIE"); if (l) { Hoption.Pie = 1; - strncpy(l," ",3); + memcpy(l," ",3); } @@ -4041,21 +4041,21 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) l = strstr(chopt,"LEGO"); if (l) { Hoption.Scat = 0; - Hoption.Lego = 1; strncpy(l," ",4); + Hoption.Lego = 1; memcpy(l," ",4); if (l[4] == '1') { Hoption.Lego = 11; l[4] = ' '; } if (l[4] == '2') { Hoption.Lego = 12; l[4] = ' '; } if (l[4] == '3') { Hoption.Lego = 13; l[4] = ' '; } if (l[4] == '4') { Hoption.Lego = 14; l[4] = ' '; } if (l[4] == '9') { Hoption.Lego = 19; l[4] = ' '; } - l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; strncpy(l," ",2); } - l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; strncpy(l," ",2); } - l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; strncpy(l," ",1); } + l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); } + l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); } + l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; memcpy(l," ",1); } } l = strstr(chopt,"SURF"); if (l) { Hoption.Scat = 0; - Hoption.Surf = 1; strncpy(l," ",4); + Hoption.Surf = 1; memcpy(l," ",4); if (l[4] == '1') { Hoption.Surf = 11; l[4] = ' '; } if (l[4] == '2') { Hoption.Surf = 12; l[4] = ' '; } if (l[4] == '3') { Hoption.Surf = 13; l[4] = ' '; } @@ -4063,27 +4063,27 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) if (l[4] == '5') { Hoption.Surf = 15; l[4] = ' '; } if (l[4] == '6') { Hoption.Surf = 16; l[4] = ' '; } if (l[4] == '7') { Hoption.Surf = 17; l[4] = ' '; } - l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; strncpy(l," ",2); } - l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; strncpy(l," ",2); } + l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); } + l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); } } l = strstr(chopt,"TF3"); if (l) { - l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; strncpy(l," ",2); } - l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; strncpy(l," ",2); } + l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); } + l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); } } l = strstr(chopt,"ISO"); if (l) { - l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; strncpy(l," ",2); } - l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; strncpy(l," ",2); } + l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); } + l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); } } - l = strstr(chopt,"LIST"); if (l) { Hoption.List = 1; strncpy(l," ",4);} + l = strstr(chopt,"LIST"); if (l) { Hoption.List = 1; memcpy(l," ",4);} l = strstr(chopt,"CONT"); if (l) { - strncpy(l," ",4); + memcpy(l," ",4); if (hdim>1) { Hoption.Scat = 0; Hoption.Contour = 1; @@ -4099,7 +4099,7 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) l = strstr(chopt,"HBAR"); if (l) { Hoption.Hist = 0; - Hoption.Bar = 20; strncpy(l," ",4); + Hoption.Bar = 20; memcpy(l," ",4); if (l[4] == '1') { Hoption.Bar = 21; l[4] = ' '; } if (l[4] == '2') { Hoption.Bar = 22; l[4] = ' '; } if (l[4] == '3') { Hoption.Bar = 23; l[4] = ' '; } @@ -4108,7 +4108,7 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) l = strstr(chopt,"BAR"); if (l) { Hoption.Hist = 0; - Hoption.Bar = 10; strncpy(l," ",3); + Hoption.Bar = 10; memcpy(l," ",3); if (l[3] == '1') { Hoption.Bar = 11; l[3] = ' '; } if (l[3] == '2') { Hoption.Bar = 12; l[3] = ' '; } if (l[3] == '3') { Hoption.Bar = 13; l[3] = ' '; } @@ -4117,7 +4117,7 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) l = strstr(chopt,"ARR" ); if (l) { - strncpy(l," ", 3); + memcpy(l," ", 3); if (hdim>1) { Hoption.Arrow = 1; Hoption.Scat = 0; @@ -4127,7 +4127,7 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) } l = strstr(chopt,"BOX" ); if (l) { - strncpy(l," ", 3); + memcpy(l," ", 3); if (hdim>1) { Hoption.Scat = 0; Hoption.Box = 1; @@ -4140,37 +4140,37 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) } l = strstr(chopt,"COLZ"); if (l) { - strncpy(l," ",4); + memcpy(l," ",4); if (hdim>1) { Hoption.Color = 1; Hoption.Scat = 0; Hoption.Zscale = 1; if (l[4] == '2') { Hoption.Color = 3; l[4] = ' '; } - l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; strncpy(l," ",1); } - l = strstr(chopt,"1"); if (l) { Hoption.Color = 2; strncpy(l," ",1); } + l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; memcpy(l," ",1); } + l = strstr(chopt,"1"); if (l) { Hoption.Color = 2; memcpy(l," ",1); } } else { Hoption.Hist = 1; } } l = strstr(chopt,"COL" ); if (l) { - strncpy(l," ", 3); + memcpy(l," ", 3); if (hdim>1) { Hoption.Color = 1; Hoption.Scat = 0; if (l[3] == '2') { Hoption.Color = 3; l[3] = ' '; } - l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; strncpy(l," ",1); } - l = strstr(chopt,"1"); if (l) { Hoption.Color = 2; strncpy(l," ",1); } + l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; memcpy(l," ",1); } + l = strstr(chopt,"1"); if (l) { Hoption.Color = 2; memcpy(l," ",1); } } else { Hoption.Hist = 1; } } - l = strstr(chopt,"CHAR"); if (l) { Hoption.Char = 1; strncpy(l," ",4); Hoption.Scat = 0; } - l = strstr(chopt,"FUNC"); if (l) { Hoption.Func = 2; strncpy(l," ",4); Hoption.Hist = 0; } - l = strstr(chopt,"HIST"); if (l) { Hoption.Hist = 2; strncpy(l," ",4); Hoption.Func = 0; Hoption.Error = 0;} - l = strstr(chopt,"AXIS"); if (l) { Hoption.Axis = 1; strncpy(l," ",4); } - l = strstr(chopt,"AXIG"); if (l) { Hoption.Axis = 2; strncpy(l," ",4); } - l = strstr(chopt,"SCAT"); if (l) { Hoption.Scat = 1; strncpy(l," ",4); } + l = strstr(chopt,"CHAR"); if (l) { Hoption.Char = 1; memcpy(l," ",4); Hoption.Scat = 0; } + l = strstr(chopt,"FUNC"); if (l) { Hoption.Func = 2; memcpy(l," ",4); Hoption.Hist = 0; } + l = strstr(chopt,"HIST"); if (l) { Hoption.Hist = 2; memcpy(l," ",4); Hoption.Func = 0; Hoption.Error = 0;} + l = strstr(chopt,"AXIS"); if (l) { Hoption.Axis = 1; memcpy(l," ",4); } + l = strstr(chopt,"AXIG"); if (l) { Hoption.Axis = 2; memcpy(l," ",4); } + l = strstr(chopt,"SCAT"); if (l) { Hoption.Scat = 1; memcpy(l," ",4); } l = strstr(chopt,"TEXT"); if (l) { Int_t angle; @@ -4181,41 +4181,41 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) } else { Hoption.Text = 1; } - strncpy(l," ", 4); + memcpy(l," ", 4); l = strstr(chopt,"N"); if (l && fH->InheritsFrom(TH2Poly::Class())) Hoption.Text += 3000; Hoption.Scat = 0; } - l = strstr(chopt,"POL"); if (l) { Hoption.System = kPOLAR; strncpy(l," ",3); } - l = strstr(chopt,"CYL"); if (l) { Hoption.System = kCYLINDRICAL; strncpy(l," ",3); } - l = strstr(chopt,"SPH"); if (l) { Hoption.System = kSPHERICAL; strncpy(l," ",3); } - l = strstr(chopt,"PSR"); if (l) { Hoption.System = kRAPIDITY; strncpy(l," ",3); } + l = strstr(chopt,"POL"); if (l) { Hoption.System = kPOLAR; memcpy(l," ",3); } + l = strstr(chopt,"CYL"); if (l) { Hoption.System = kCYLINDRICAL; memcpy(l," ",3); } + l = strstr(chopt,"SPH"); if (l) { Hoption.System = kSPHERICAL; memcpy(l," ",3); } + l = strstr(chopt,"PSR"); if (l) { Hoption.System = kRAPIDITY; memcpy(l," ",3); } l = strstr(chopt,"TRI"); if (l) { Hoption.Scat = 0; Hoption.Color = 0; - Hoption.Tri = 1; strncpy(l," ",3); - l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; strncpy(l," ",2); } - l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; strncpy(l," ",2); } - l = strstr(chopt,"ERR"); if (l) strncpy(l," ",3); + Hoption.Tri = 1; memcpy(l," ",3); + l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); } + l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); } + l = strstr(chopt,"ERR"); if (l) memcpy(l," ",3); } l = strstr(chopt,"AITOFF"); if (l) { - Hoption.Proj = 1; strncpy(l," ",6); //Aitoff projection + Hoption.Proj = 1; memcpy(l," ",6); //Aitoff projection } l = strstr(chopt,"MERCATOR"); if (l) { - Hoption.Proj = 2; strncpy(l," ",8); //Mercator projection + Hoption.Proj = 2; memcpy(l," ",8); //Mercator projection } l = strstr(chopt,"SINUSOIDAL"); if (l) { - Hoption.Proj = 3; strncpy(l," ",10); //Sinusoidal projection + Hoption.Proj = 3; memcpy(l," ",10); //Sinusoidal projection } l = strstr(chopt,"PARABOLIC"); if (l) { - Hoption.Proj = 4; strncpy(l," ",9); //Parabolic projection + Hoption.Proj = 4; memcpy(l," ",9); //Parabolic projection } if (Hoption.Proj > 0) { Hoption.Scat = 0; @@ -10018,7 +10018,16 @@ void THistPainter::PaintTitle() } Double_t ht = gStyle->GetTitleH(); Double_t wt = gStyle->GetTitleW(); - if (ht <= 0) ht = 1.1*gStyle->GetTitleFontSize(); + + if (ht <= 0) { + if (gStyle->GetTitleFont("")%10 == 3) { + Double_t hw = TMath::Max((Double_t)gPad->XtoPixel(gPad->GetX2()), + (Double_t)gPad->YtoPixel(gPad->GetY1())); + ht = 1.1*(gStyle->GetTitleSize("")/hw); + } else { + ht = 1.1*gStyle->GetTitleFontSize(); + } + } if (ht <= 0) ht = 0.05; if (wt <= 0) { TLatex l; diff --git a/hist/histpainter/src/TPainter3dAlgorithms.cxx b/hist/histpainter/src/TPainter3dAlgorithms.cxx index dfe6a4e418f01..5353778683c6b 100644 --- a/hist/histpainter/src/TPainter3dAlgorithms.cxx +++ b/hist/histpainter/src/TPainter3dAlgorithms.cxx @@ -81,6 +81,8 @@ ClassImp(TPainter3dAlgorithms); TPainter3dAlgorithms::TPainter3dAlgorithms(): TObject(), TAttLine(1,1,1), TAttFill(1,0) { Int_t i; + fAphi = 0; + fNaphi = 0; fIfrast = 0; fMesh = 1; fRaster = 0; @@ -124,7 +126,6 @@ TPainter3dAlgorithms::TPainter3dAlgorithms(): TObject(), TAttLine(1,1,1), TAttFi for (i=0;i<2*NumOfSlices;i++) { fU[i] = 0.; fD[i] = 0.; } for (i=0;i<12;i++) { fVls[i] = 0.; } for (i=0;i<257;i++) { fFunLevel[i] = 0.; } - for (i=0;i<183;i++) { fAphi[i] = 0.; } for (i=0;i<8;i++) { fF8[i] = 0.; } fLoff = 0; @@ -163,6 +164,8 @@ TPainter3dAlgorithms::TPainter3dAlgorithms(Double_t *rmin, Double_t *rmax, Int_t Int_t i; Double_t psi; + fAphi = 0; + fNaphi = 0; fIfrast = 0; fMesh = 1; fRaster = 0; @@ -207,7 +210,6 @@ TPainter3dAlgorithms::TPainter3dAlgorithms(Double_t *rmin, Double_t *rmax, Int_t for (i=0;i<2*NumOfSlices;i++) { fU[i] = 0.; fD[i] = 0.; } for (i=0;i<12;i++) { fVls[i] = 0.; } for (i=0;i<257;i++) { fFunLevel[i] = 0.; } - for (i=0;i<183;i++) { fAphi[i] = 0.; } for (i=0;i<8;i++) { fF8[i] = 0.; } fLoff = 0; @@ -247,6 +249,7 @@ TPainter3dAlgorithms::TPainter3dAlgorithms(Double_t *rmin, Double_t *rmax, Int_t TPainter3dAlgorithms::~TPainter3dAlgorithms() { + if (fAphi) { delete [] fAphi; fAphi = 0; } if (fRaster) { delete [] fRaster; fRaster = 0; } if (fNStack > kVSizeMax) { delete [] fColorMain; @@ -2446,8 +2449,14 @@ void TPainter3dAlgorithms::LegoPolar(Int_t iordr, Int_t na, Int_t nb, const char nr = nb; nphi = na; } - if (nphi > 180) { - Error("LegoPolar", "too many PHI sectors (%d)", nphi); + if (fNaphi < nphi + 3) { + if (fAphi) { delete [] fAphi; fAphi = 0; } + fNaphi = nphi + 3; + fAphi = new Double_t[fNaphi]; + } + if (fAphi == 0) { + Error("LegoPolar", "failed to allocate array fAphi[%d]", fNaphi); + fNaphi = 0; return; } iopt = 2; @@ -2658,8 +2667,14 @@ void TPainter3dAlgorithms::LegoCylindrical(Int_t iordr, Int_t na, Int_t nb, cons nz = nb; nphi = na; } - if (nphi > 180) { - Error("LegoCylindrical", "too many PHI sectors (%d)", nphi); + if (fNaphi < nphi + 3) { + if (fAphi) { delete [] fAphi; fAphi = 0; } + fNaphi = nphi + 3; + fAphi = new Double_t[fNaphi]; + } + if (fAphi == 0) { + Error("LegoCylindrical", "failed to allocate array fAphi[%d]", fNaphi); + fNaphi = 0; return; } iopt = 2; @@ -2874,12 +2889,14 @@ void TPainter3dAlgorithms::LegoSpherical(Int_t ipsdr, Int_t iordr, Int_t na, Int nth = nb; nphi = na; } - if (nth > 180) { - Error("LegoSpherical", "too many THETA sectors (%d)", nth); - return; + if (fNaphi < nth + 3 || fNaphi < nphi + 3) { + if (fAphi) { delete [] fAphi; fAphi = 0; } + fNaphi = TMath::Max(nth, nphi) + 3; + fAphi = new Double_t[fNaphi]; } - if (nphi > 180) { - Error("LegoSpherical", "too many PHI sectors (%d)", nphi); + if (fAphi == 0) { + Error("LegoSpherical", "failed to allocate array fAphi[%d]", fNaphi); + fNaphi = 0; return; } iopt = 2; @@ -3725,8 +3742,14 @@ void TPainter3dAlgorithms::SurfacePolar(Int_t iordr, Int_t na, Int_t nb, const c nr = nb; nphi = na; } - if (nphi > 180) { - Error("SurfacePolar", "too many PHI sectors (%d)", nphi); + if (fNaphi < nphi + 3) { + if (fAphi) { delete [] fAphi; fAphi = 0; } + fNaphi =nphi + 3; + fAphi = new Double_t[fNaphi]; + } + if (fAphi == 0) { + Error("SurfacePolar", "failed to allocate array fAphi[%d]", fNaphi); + fNaphi = 0; return; } iopt = 2; @@ -3848,8 +3871,14 @@ void TPainter3dAlgorithms::SurfaceCylindrical(Int_t iordr, Int_t na, Int_t nb, c nz = nb; nphi = na; } - if (nphi > 180) { - Error("SurfaceCylindrical", "too many PHI sectors (%d)", nphi); + if (fNaphi < nphi + 3) { + if (fAphi) { delete [] fAphi; fAphi = 0; } + fNaphi =nphi + 3; + fAphi = new Double_t[fNaphi]; + } + if (fAphi == 0) { + Error("SurfaceCylindrical", "failed to allocate array fAphi[%d]", fNaphi); + fNaphi = 0; return; } iopt = 2; @@ -3963,12 +3992,14 @@ void TPainter3dAlgorithms::SurfaceSpherical(Int_t ipsdr, Int_t iordr, Int_t na, nth = nb; nphi = na; } - if (nth > 180) { - Error("SurfaceSpherical", "too many THETA sectors (%d)", nth); - return; + if (fNaphi < nth + 3 || fNaphi < nphi + 3) { + if (fAphi) { delete [] fAphi; fAphi = 0; } + fNaphi = TMath::Max(nth, nphi) + 3; + fAphi = new Double_t[fNaphi]; } - if (nphi > 180) { - Error("SurfaceSpherical", "too many PHI sectors (%d)", nphi); + if (fAphi == 0) { + Error("SurfaceSpherical", "failed to allocate array fAphi[%d]", fNaphi); + fNaphi = 0; return; } iopt = 2; diff --git a/hist/histpainter/src/TPaletteAxis.cxx b/hist/histpainter/src/TPaletteAxis.cxx index b3391329d528e..84b8d44fb290e 100644 --- a/hist/histpainter/src/TPaletteAxis.cxx +++ b/hist/histpainter/src/TPaletteAxis.cxx @@ -427,15 +427,15 @@ void TPaletteAxis::Paint(Option_t *) Int_t ndiv = fH->GetZaxis()->GetNdivisions() % 100; //take primary divisions only char chopt[6] = "S "; chopt[1] = 0; - strncat(chopt, "+L", 2); + strncat(chopt, "+L", 3); if (ndiv < 0) { ndiv = TMath::Abs(ndiv); - strncat(chopt, "N", 1); + strncat(chopt, "N", 2); } if (gPad->GetLogz()) { wmin = TMath::Power(10., wlmin); wmax = TMath::Power(10., wlmax); - strncat(chopt, "G", 1); + strncat(chopt, "G", 2); } fAxis.ImportAxisAttributes(fH->GetZaxis()); fAxis.PaintAxis(xmax, ymin, xmax, ymax, wmin, wmax, ndiv, chopt); diff --git a/hist/histpainter/v7/src/THistPainter.cxx b/hist/histpainter/v7/src/THistPainter.cxx index 30d298fa7bd57..148edb3d5f093 100644 --- a/hist/histpainter/v7/src/THistPainter.cxx +++ b/hist/histpainter/v7/src/THistPainter.cxx @@ -16,8 +16,8 @@ //#include "ROOT/THistPainter.hxx" see ROOT/THistDrawable.h #include "ROOT/THistDrawable.hxx" -#include "ROOT/TPadPainter.hxx" -#include "ROOT/TDisplayItem.hxx" +#include "ROOT/RPadPainter.hxx" +#include "ROOT/RDisplayItem.hxx" #include #include @@ -28,7 +28,7 @@ using namespace ROOT::Experimental::Internal; namespace { class THistPainter1D : public THistPainterBase<1> { public: - void Paint(TDrawable &drw, const THistDrawingOpts<1> & /*opts*/, TPadPainter &pad) final + void Paint(RDrawable &drw, const THistDrawingOpts<1> & /*opts*/, RPadPainter &pad) final { // TODO: paint! std::cout << "Painting 1D histogram @" << &drw << '\n'; @@ -37,28 +37,28 @@ class THistPainter1D : public THistPainterBase<1> { THistDrawable<1> &hd = static_cast &>(drw); pad.AddDisplayItem( - std::make_unique>>(&hd)); + std::make_unique>>(&hd)); } virtual ~THistPainter1D() final {} }; class THistPainter2D : public THistPainterBase<2> { public: - void Paint(TDrawable &drw, const THistDrawingOpts<2> & /*opts*/, TPadPainter &pad) final + void Paint(RDrawable &drw, const THistDrawingOpts<2> & /*opts*/, RPadPainter &pad) final { std::cout << "Painting 2D histogram @" << &drw << '\n'; assert(dynamic_cast *>(&drw) && "Wrong drawable type"); THistDrawable<2> &hd = static_cast &>(drw); pad.AddDisplayItem( - std::make_unique>>(&hd)); + std::make_unique>>(&hd)); } virtual ~THistPainter2D() final {} }; class THistPainter3D : public THistPainterBase<3> { public: - void Paint(TDrawable &hist, const THistDrawingOpts<3> & /*opts*/, TPadPainter & /*canv*/) final + void Paint(RDrawable &hist, const THistDrawingOpts<3> & /*opts*/, RPadPainter & /*canv*/) final { // TODO: paint! std::cout << "Painting 3D histogram (to be done) @" << &hist << '\n'; diff --git a/interpreter/cling/.travis.yml b/interpreter/cling/.travis.yml index f69b2a00c9897..7951d6e61e2e1 100644 --- a/interpreter/cling/.travis.yml +++ b/interpreter/cling/.travis.yml @@ -4,14 +4,7 @@ language: cpp addons: &addons apt: - packages: timeout - sources: &sources - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.5 - - llvm-toolchain-precise-3.6 - - llvm-toolchain-precise-3.7 - - llvm-toolchain-precise-3.8 - - llvm-toolchain-precise + packages: coreutils cache: apt: true @@ -49,166 +42,95 @@ matrix: include: # There seems to be a hard limit to how many machines a Travis build will - # across all platforms. By interleaving OS X, the hope is to get in the + # run across all platforms. By interleaving OS X, the hope is to get in the # queue faster while not blocking Linux builds from occuring. - os: linux - env: DIST=pangolin COMPILER=g++-4.8 CCOMPILER=gcc-4.8 NIGHTLY_CRON_SYNC=1 - addons: - apt: - sources: *sources - packages: g++-4.8 + env: COMPILER=g++-4.8 CCOMPILER=gcc-4.8 NIGHTLY_CRON_SYNC=1 compiler: gcc-4.8 - - os: linux - env: DIST=pangolin COMPILER=g++-4.9 CCOMPILER=gcc-4.9 - addons: - apt: - sources: *sources - packages: g++-4.9 - compiler: gcc-4.9 - - os: osx env: COMPILER=clang++ CCOMPILER=clang - osx_image: xcode6.4 + osx_image: xcode8.3 compiler: clang - os: linux - env: DIST=pangolin COMPILER=g++-5 CCOMPILER=gcc-5 + env: COMPILER=g++-5 CCOMPILER=gcc-5 addons: apt: - sources: *sources + sources: ubuntu-toolchain-r-test packages: g++-5 compiler: gcc-5 - os: linux - env: DIST=pangolin COMPILER=g++-6 CCOMPILER=gcc-6 - addons: - apt: - sources: *sources - packages: g++-6 - compiler: gcc-6 - - - os: osx - env: COMPILER=clang++ CCOMPILER=clang - osx_image: xcode7.3 - compiler: clang - - - os: linux - env: DIST=trusty COMPILER=g++-4.8 CCOMPILER=gcc-4.8 - sudo: required - dist: trusty - addons: - apt: - sources: *sources - packages: g++-4.8 - compiler: gcc-4.8 - - - os: linux - env: DIST=trusty COMPILER=g++-4.9 CCOMPILER=gcc-4.9 - sudo: required - dist: trusty - addons: - apt: - sources: *sources - packages: g++-4.9 - compiler: gcc-4.9 - - - os: osx env: COMPILER=g++-6 CCOMPILER=gcc-6 - osx_image: xcode7.3 - compiler: gcc-6 - - - os: linux - env: DIST=trusty COMPILER=g++-5 CCOMPILER=gcc-5 - sudo: required - dist: trusty - addons: - apt: - sources: *sources - packages: g++-5 - compiler: gcc-5 - - - os: linux - env: DIST=trusty COMPILER=g++-6 CCOMPILER=gcc-6 - sudo: required - dist: trusty addons: apt: - sources: *sources + sources: ubuntu-toolchain-r-test packages: g++-6 compiler: gcc-6 - os: osx - env: COMPILER=clang++ CCOMPILER=clang + env: COMPILER=g++-7 CCOMPILER=gcc-7 osx_image: xcode8.3 - compiler: clang + before_install: + - brew cask uninstall oclint + - brew install gcc@7 + compiler: gcc-7 - os: linux - env: DIST=trusty COMPILER=g++-7 CCOMPILER=gcc-7 - sudo: required - dist: trusty + env: COMPILER=g++-7 CCOMPILER=gcc-7 addons: apt: - sources: *sources + sources: ubuntu-toolchain-r-test packages: g++-7 compiler: gcc-7 - os: linux - env: CXXLIB=libstdc++ COMPILER=clang++-3.7 CCOMPILER=clang-3.7 + env: CXXLIB=libstdc++ COMPILER=clang++-3.9 CCOMPILER=clang-3.9 addons: apt: - sources: *sources - packages: ['clang-3.7', 'libstdc++-5-dev'] - compiler: clang-3.7 + sources: llvm-toolchain-trusty-3.9 + packages: clang-3.9 + compiler: clang-3.9 - os: osx - env: COMPILER=g++-7 CCOMPILER=gcc-7 - osx_image: xcode8.3 - compiler: gcc-7 + env: COMPILER=clang++ CCOMPILER=clang + osx_image: xcode9.3 + compiler: clang - os: linux - env: CXXLIB=libstdc++ COMPILER=clang++-3.8 CCOMPILER=clang-3.8 + env: CXXLIB=libstdc++ COMPILER=clang++-5.0 CCOMPILER=clang-5.0 addons: apt: - sources: *sources - packages: ['clang-3.8', 'libstdc++-6-dev'] - compiler: clang-3.8 + sources: llvm-toolchain-trusty-5.0 + packages: clang-5.0 + compiler: clang-5.0 - allow_failures: - # clang-3.5 crashes compiling clang-3.9 with libc++-3.9 - - env: CXXLIB=libc++ COMPILER=clang++-3.5 CCOMPILER=clang-3.5 +# allow_failures: +# # clang-3.5 crashes compiling clang-3.9 with libc++-3.9 +# - env: CXXLIB=libc++ COMPILER=clang++-3.5 CCOMPILER=clang-3.5 install: # If cmake is not in the cache, download it. - | + echo "travis_fold:""start:install" CLING_USER_ROOT=`dirname $TRAVIS_BUILD_DIR` export CLING_BUILD_DEPS="$CLING_USER_ROOT/deps" export CLING_LOCAL_BIN="$CLING_USER_ROOT/bin" if [ $TRAVIS_OS_NAME == 'osx' ]; then brew install ccache python coreutils - if [[ "$COMPILER" == g++-* ]]; then - brew install "gcc@${COMPILER##*++-}" - brew link --overwrite "gcc@${COMPILER##*++-}" - if [[ "$COMPILER" == "g++-6" ]]; then - export CXXFLAGS="-D__builtin_unreachable=__builtin_trap" - export CFLAGS="-D__builtin_unreachable=__builtin_trap" - fi - fi + PATH="/usr/local/opt/ccache/libexec:$PATH" - # This is where timeout is hiding now, is the above still neccessary? - PATH="$PATH:/usr/local/opt/coreutils/libexec/gnubin" fi - if [ "$COMPILER" == "g++-6" ]; then + if [ "$COMPILER" == "g++-7" ]; then export CLING_BUILD_FLAGS="-DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON" # On OS X force the test to reproduce __float128 issues with libstdc++. if [ $TRAVIS_OS_NAME != 'osx' ]; then export CLING_BUILD_FLAGS="$CLING_BUILD_FLAGS -DCXX_EXTENSIONS=OFF" fi - CMAKEREQ="3.8" - else - CMAKEREQ="3.6" fi + echo "travis_fold:""end:install" # Containers need to timeout before the buildscript exits TIMEOUT='37m' # Any more and Travis might cancel @@ -217,27 +139,8 @@ install: # Turn this on to get the mapping to the cache.o to delete # export CCACHE_LOGFILE="$CLING_USER_ROOT/ccache.log" - # Get installed CMake version and make sure its at least CMAKEREQ - CMKV=( `cmake --version` ) - CMKV=${CMKV[2]} - if [ "${CMKV:0:1}" -lt "${CMAKEREQ:0:1}" ] || [ "${CMKV:2:1}" -lt "${CMAKEREQ:2:1}" ]; then - if [ $TRAVIS_OS_NAME == 'linux' ]; then - CMAKE_URL="https://cmake.org/files/v${CMAKEREQ}/cmake-${CMAKEREQ}.0-Linux-x86_64.tar.gz" - export CMAKE=$CLING_BUILD_DEPS/cmake/bin/cmake - else - CMAKE_URL="https://cmake.org/files/v${CMAKEREQ}/cmake-${CMAKEREQ}.0-Darwin-x86_64.tar.gz" - export CMAKE=$CLING_BUILD_DEPS/cmake/CMake.app/Contents/bin/cmake - fi - if [ ! -f $CMAKE ]; then - mkdir -pv $CLING_BUILD_DEPS/cmake - travis_retry curl -k $CMAKE_URL | tar --strip-components=1 -xz -C $CLING_BUILD_DEPS/cmake - fi - else - export CMAKE="cmake" - fi - before_script: - - $CMAKE --version + - cmake --version - export CXX="ccache $COMPILER" - export CC="ccache $CCOMPILER" - | @@ -245,6 +148,7 @@ before_script: if [ -n "$NIGHTLY_CRON_SYNC" ] && [ "$TRAVIS_EVENT_TYPE" = "cron" ] \ && [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] \ && [ "$TRAVIS_REPO_SLUG" == "vgvassilev/cling" ] ; then + echo "travis_fold:""start:sync-vgvassilev" # Override the default travis clone command to enable sync. cd ../../ && rm -fr ${TRAVIS_REPO_SLUG} git clone https://$OAUTH_TOKEN@github.com/${TRAVIS_REPO_SLUG} ${TRAVIS_REPO_SLUG} @@ -263,12 +167,15 @@ before_script: # Some debug output. git remote -v && git branch -a + echo "travis_fold:""end:sync-vgvassilev" fi script: - | if [ -z $TRAVIS_TAG ]; then - timeout -s SIGTERM $TIMEOUT tools/packaging/cpt.py \ + TIMEOUTEXE=`which timeout`; + if [ "x" = "x$TIMEOUTEXE" ] ; then TIMEOUTEXE=gtimeout; fi + $TIMEOUTEXE -s SIGTERM $TIMEOUT tools/packaging/cpt.py \ --current-dev=tar \ --with-cling-url=https://github.com/$TRAVIS_REPO_SLUG \ --with-clang-url=http://root.cern.ch/git/clang.git \ @@ -286,7 +193,9 @@ script: RESULT="$?" echo "Build Result: $RESULT" + echo "travis_fold:""start:ccache-s" ccache -s + echo "travis_fold:""end:ccache-s" if [ $RESULT -ne 124 ]; then return $RESULT fi @@ -310,6 +219,7 @@ notifications: before_deploy: - | + echo "travis_fold:""start:before_deploy" export RELEASE_TARBALL=$(ls $HOME/ci/build/cling*.tar.bz2) if [[ $TRAVIS_TAG -eq "cling-nightlies" ]]; then NIGHTLY="`dirname $RELEASE_TARBALL`/`date "+%Y-%b-%d-"``basename $RELEASE_TARBALL`" @@ -318,6 +228,7 @@ before_deploy: export RELEASE_TARBALL=$NIGHTLY fi echo "Deploying $RELEASE_TARBALL to GitHub releases" + echo "travis_fold:""end:before_deploy" deploy: @@ -333,31 +244,40 @@ deploy: after_failure: - | if [ -n "$CCACHE_LOGFILE" ]; then + echo "travis_fold:""start:ccache_log" echo "ccache log stored to:" cat "$CCACHE_LOGFILE" | curl -sT - chunk.io + echo "travis_fold:""end:ccache_log" fi - | if [ "$CLING_BUILD_TIMEOUT" != "1" ]; then + echo "travis_fold:""start:env_dump" echo "Dumping env." find $CLING_LOCAL_BIN -type f -print0 -exec cat {} \; - $CMAKE --version + cmake --version $CC --version $CXX --version ls -al `which ld` && ld -v export + echo "travis_fold:""end:env_dump" fi - | if [ "$CLING_BUILD_TIMEOUT" != "1" ]; then + echo "travis_fold:""start:cmakeoutputlog_dump" echo "Dumping CMakeOutput.log" cat /home/travis/ci/build/builddir/CMakeFiles/CMakeOutput.log + echo "travis_fold:""end:cmakeoutputlog_dump" fi - | if [ "$CLING_BUILD_TIMEOUT" != "1" ]; then + echo "travis_fold:""start:cmakeerrorlog_dump" echo "Dumping CMakeError.log" cat /home/travis/ci/build/builddir/CMakeFiles/CMakeError.log + echo "travis_fold:""end:cmakeerrorlog_dump" fi - | if [ "$CLING_BUILD_TIMEOUT" != "1" ]; then + echo "travis_fold:""start:clingcompiledata_dump" echo "Dumping cling-compiledata.h..." COMPILE_DATA_H=$HOME/ci/build/builddir/tools/cling/lib/Interpreter/cling-compiledata.h cat $COMPILE_DATA_H @@ -365,10 +285,13 @@ after_failure: echo "Running cling-compiledata compiler..." COMPDATA_CXX=$(cat $COMPILE_DATA_H | cut -c 18- | sed "s,\",,g") eval echo | LC_ALL=C $COMPDATA_CXX -xc++ -E -v - + echo "travis_fold:""end:clingcompiledata_dump" fi - | - if [ "$CLING_BUILD_TIMEOUT" != "1" ]; then + if [ "$CLING_BUILD_TIMEOUT" != "1" ]; then + echo "travis_fold:""start:ccache_stats" echo "Dumping `which ccache`" ccache -s ls -la /usr/lib/ccache/ || ls -la /usr/local/opt/ccache/libexec + echo "travis_fold:""end:ccache_stats" fi diff --git a/interpreter/cling/CREDITS.txt b/interpreter/cling/CREDITS.txt index dfa7d9a75a29b..c167dc9ffea89 100644 --- a/interpreter/cling/CREDITS.txt +++ b/interpreter/cling/CREDITS.txt @@ -57,3 +57,7 @@ D: Function call interfaces. N: Vassil Vassilev E: vvasilev@cern.ch D: Main developer of cling. + +N: Simeon Ehrig +E: s.ehrig@hzdr.de +D: cling CUDA runtime support diff --git a/interpreter/cling/README.md b/interpreter/cling/README.md index 78fa27caa11ed..394609b5b1bb3 100644 --- a/interpreter/cling/README.md +++ b/interpreter/cling/README.md @@ -80,10 +80,8 @@ or type Jupyter ------- Cling comes with a [Jupyter](http://jupyter.org) kernel. After building cling, -install Jupyter and run `jupyter kernelspec install cling`. It requires a fairly -new Jupyter. Make sure cling is in your PATH when you start jupyter! - -See also the [tools/Jupyter](tools/Jupyter) subdirectory for more information. +install Jupyter and cling's kernel by following the README.md in +[tools/Jupyter](tools/Jupyter). Make sure cling is in your PATH when you start jupyter! Developers' Corner diff --git a/interpreter/cling/include/cling/Interpreter/InterpreterCallbacks.h b/interpreter/cling/include/cling/Interpreter/InterpreterCallbacks.h index 2103d5a335b88..5100fc7398ab8 100644 --- a/interpreter/cling/include/cling/Interpreter/InterpreterCallbacks.h +++ b/interpreter/cling/include/cling/Interpreter/InterpreterCallbacks.h @@ -125,6 +125,12 @@ namespace cling { virtual bool LookupObject(const clang::DeclContext*, clang::DeclarationName); virtual bool LookupObject(clang::TagDecl*); + /// \brief This callback is invoked whenever the interpreter failed to load a library. + /// + /// \param[in] - Error message and parameters passed to loadLibrary + /// \returns true if the error was handled. + virtual bool LibraryLoadingFailed(const std::string&, const std::string&, bool, bool) { return 0; } + ///\brief This callback is invoked whenever interpreter has committed new /// portion of declarations. /// @@ -132,13 +138,6 @@ namespace cling { /// virtual void TransactionCommitted(const Transaction&) {} - ///\brief This callback is invoked before a transaction is executed. - /// This event happens after a transaction was committed and LLVM IR was produced. - /// - ///\param[in] - The transaction to be executed. - /// - virtual void beforeExecuteTransaction(const Transaction&) {} - ///\brief This callback is invoked whenever interpreter has reverted a /// transaction that has been fully committed. /// diff --git a/interpreter/cling/include/cling/Interpreter/InvocationOptions.h b/interpreter/cling/include/cling/Interpreter/InvocationOptions.h index 833d139284e9f..55827bf1a562b 100644 --- a/interpreter/cling/include/cling/Interpreter/InvocationOptions.h +++ b/interpreter/cling/include/cling/Interpreter/InvocationOptions.h @@ -64,6 +64,14 @@ namespace cling { std::string CachePath; // If not empty, the name of the module we're currently compiling. std::string ModuleName; + /// \brief Custom path of the CUDA toolkit + std::string CUDAPath; + /// \brief Architecture level of the CUDA gpu. Necessary for the + /// NVIDIA fatbinary tool. + std::string CUDAGpuArch; + /// \brief Contains arguments, which will passed to the nvidia tool + /// fatbinary. + std::vector CUDAFatbinaryArgs; ///\brief The remaining arguments to pass to clang. /// diff --git a/interpreter/cling/include/cling/Interpreter/Transaction.h b/interpreter/cling/include/cling/Interpreter/Transaction.h index 680543d021991..454ec7986e6e8 100644 --- a/interpreter/cling/include/cling/Interpreter/Transaction.h +++ b/interpreter/cling/include/cling/Interpreter/Transaction.h @@ -31,7 +31,6 @@ namespace clang { class Preprocessor; struct PrintingPolicy; class Sema; - class Module; } namespace llvm { @@ -116,11 +115,6 @@ namespace cling { typedef llvm::SmallVector DeclQueue; typedef llvm::SmallVector NestedTransactions; - ///\brief The list of cxxmodules, which is collected by DeserializationListener - /// and will be used to load corresponding libraries. - /// - std::vector m_CxxModules; - ///\brief All seen declarations, except the deserialized ones. /// If we collect the declarations by walking the clang::DeclContext we /// will miss the injected onces (eg. template instantiations). @@ -274,17 +268,6 @@ namespace cling { return const_reverse_nested_iterator(0); } - void addClangModule(clang::Module* M) { - assert(M && "addClangModules: passed clang::Module pointer is null"); - - if (std::find(m_CxxModules.rbegin(), m_CxxModules.rend(), M) == m_CxxModules.rend()) - m_CxxModules.push_back(M); - } - - const std::vector &getClangModules() const { - return m_CxxModules; - } - /// Macro iteration typedef MacroDirectiveInfoQueue::iterator macros_iterator; typedef MacroDirectiveInfoQueue::const_iterator const_macros_iterator; diff --git a/interpreter/cling/lib/Interpreter/CMakeLists.txt b/interpreter/cling/lib/Interpreter/CMakeLists.txt index af86e0ac82b3f..82356472a09e7 100644 --- a/interpreter/cling/lib/Interpreter/CMakeLists.txt +++ b/interpreter/cling/lib/Interpreter/CMakeLists.txt @@ -75,6 +75,7 @@ add_cling_library(clingInterpreter OBJECT Exception.cpp ExternalInterpreterSource.cpp ForwardDeclPrinter.cpp + IncrementalCUDADeviceCompiler.cpp IncrementalExecutor.cpp IncrementalJIT.cpp IncrementalParser.cpp diff --git a/interpreter/cling/lib/Interpreter/DeclCollector.cpp b/interpreter/cling/lib/Interpreter/DeclCollector.cpp index 5275feb5ce8ab..24f43aa372c42 100644 --- a/interpreter/cling/lib/Interpreter/DeclCollector.cpp +++ b/interpreter/cling/lib/Interpreter/DeclCollector.cpp @@ -321,17 +321,4 @@ namespace cling { m_Consumer->HandleCXXStaticMemberVarInstantiation(D); } - void DeclCollector::DeclRead(clang::serialization::DeclID, const clang::Decl *D) { - assertHasTransaction(m_CurTransaction); - - assert(D && "Decl doesn't exist!"); - if (!D->hasOwningModule()) return; - - clang::Module *M = D->getOwningModule(); - M = M->getTopLevelModule(); - - // Add interesting module to Transaction's m_cxxmodules; Corresponding library will be loaded. - m_CurTransaction->addClangModule(M); - } - } // namespace cling diff --git a/interpreter/cling/lib/Interpreter/DeclCollector.h b/interpreter/cling/lib/Interpreter/DeclCollector.h index c60c11d039b1e..476f49d5fea54 100644 --- a/interpreter/cling/lib/Interpreter/DeclCollector.h +++ b/interpreter/cling/lib/Interpreter/DeclCollector.h @@ -11,7 +11,6 @@ #define CLING_DECL_COLLECTOR_H #include "clang/AST/ASTConsumer.h" -#include "clang/Serialization/ASTDeserializationListener.h" #include "ASTTransformer.h" @@ -25,7 +24,6 @@ namespace clang { class DeclGroupRef; class Preprocessor; class Token; - class Module; } namespace cling { @@ -42,7 +40,7 @@ namespace cling { /// cling::DeclCollector is responsible for appending all the declarations /// seen by clang. /// - class DeclCollector : public clang::ASTConsumer , public clang::ASTDeserializationListener { + class DeclCollector : public clang::ASTConsumer { /// \brief PPCallbacks overrides/ Macro support class PPAdapter; @@ -118,11 +116,6 @@ namespace cling { // dyn_cast/isa support static bool classof(const clang::ASTConsumer*) { return true; } - static bool classof(const clang::ASTDeserializationListener*) { return true; } - - ///\brief ASTDeserializationListener function which gets callback when a decl is deserialized - void DeclRead(clang::serialization::DeclID, const clang::Decl *D) final; - }; } // namespace cling diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp index 1ac25789366e0..a4ce7998b46d8 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp @@ -206,6 +206,12 @@ namespace cling { std::string errMsg; DyLibHandle dyLibHandle = platform::DLOpen(canonicalLoadedLib, &errMsg); if (!dyLibHandle) { + // We emit callback to LibraryLoadingFailed when we get error with error message. + if (InterpreterCallbacks* C = getCallbacks()) { + if (C->LibraryLoadingFailed(errMsg, libStem, permanent, resolved)) + return kLoadLibSuccess; + } + cling::errs() << "cling::DynamicLibraryManager::loadLibrary(): " << errMsg << '\n'; return kLoadLibLoadError; diff --git a/interpreter/cling/lib/Interpreter/IncrementalCUDADeviceCompiler.cpp b/interpreter/cling/lib/Interpreter/IncrementalCUDADeviceCompiler.cpp new file mode 100644 index 0000000000000..c88d6ae29f67a --- /dev/null +++ b/interpreter/cling/lib/Interpreter/IncrementalCUDADeviceCompiler.cpp @@ -0,0 +1,538 @@ +//--------------------------------------------------------------------*- C++ -*- +// CLING - the C++ LLVM-based InterpreterG :) +// author: Simeon Ehrig +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +#include "IncrementalCUDADeviceCompiler.h" + +#include "cling/Interpreter/InvocationOptions.h" +#include "cling/Interpreter/Transaction.h" +#include "cling/Utils/Paths.h" + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclGroup.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/HeaderSearchOptions.h" + +#include "llvm/ADT/Triple.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +// The clang nvptx jit has an growing AST-Tree. At runtime, continuously new +// statements will append to the AST. To improve the compiletime, the existing +// AST will save as PCH-file. The new statements will append via source code +// files. A bug in clang avoids, that more than 4 statements can append to the +// PCH. If the flag is true, it improves the compiletime but it crash after the +// fifth iteration. https://bugs.llvm.org/show_bug.cgi?id=37167 +#define PCHMODE 0 + +namespace cling { + + IncrementalCUDADeviceCompiler::IncrementalCUDADeviceCompiler( + const std::string& filePath, const int optLevel, + const cling::InvocationOptions& invocationOptions, + const clang::CompilerInstance& CI) + : m_FilePath(filePath), + m_FatbinFilePath(CI.getCodeGenOpts().CudaGpuBinaryFileNames.empty() + ? "" + : CI.getCodeGenOpts().CudaGpuBinaryFileNames[0]), + m_DummyCUPath(m_FilePath + "dummy.cu"), + m_PTXFilePath(m_FilePath + "cling.ptx"), + m_GenericFileName(m_FilePath + "cling") { + if (m_FatbinFilePath.empty()) { + llvm::errs() << "Error: CudaGpuBinaryFileNames can't be empty\n"; + return; + } + + if (!generateHelperFiles()) return; + if (!findToolchain(invocationOptions)) return; + setCuArgs(CI.getLangOpts(), invocationOptions, optLevel, + CI.getCodeGenOpts().getDebugInfo()); + + m_HeaderSearchOptions = CI.getHeaderSearchOptsPtr(); + + // This code will write to the first .cu-file. It is necessary that some + // cling generated code can be handled. + const std::string initialCUDADeviceCode = + "extern void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, char " + "vpOn, float value);\n" + "extern void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, char " + "vpOn, double value);\n" + "extern void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, char " + "vpOn, long double value);\n" + "extern void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, char " + "vpOn, unsigned long long value);\n" + "extern void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, char " + "vpOn, const void* value);\n"; + + std::error_code EC; + llvm::raw_fd_ostream cuFile(m_FilePath + "cling0.cu", EC, + llvm::sys::fs::F_Text); + if (EC) { + llvm::errs() << "Could not open " << m_FilePath << "cling0.cu" + << EC.message() << "\n"; + return; + } + + cuFile << initialCUDADeviceCode; + cuFile.close(); + + m_Init = true; + } + + void IncrementalCUDADeviceCompiler::setCuArgs( + const clang::LangOptions& langOpts, + const cling::InvocationOptions& invocationOptions, + const int intprOptLevel, + const clang::codegenoptions::DebugInfoKind debugInfo) { + + std::string cppStdVersion; + // Set the c++ standard. Just one condition is possible. + if (langOpts.CPlusPlus11) cppStdVersion = "-std=c++11"; + if (langOpts.CPlusPlus14) cppStdVersion = "-std=c++14"; + if (langOpts.CPlusPlus1z) cppStdVersion = "-std=c++1z"; + if (langOpts.CPlusPlus2a) cppStdVersion = "-std=c++2a"; + + if (cppStdVersion.empty()) + llvm::errs() + << "IncrementalCUDADeviceCompiler: No valid c++ standard is set.\n"; + + const std::string optLevel = "-O" + std::to_string(intprOptLevel); + + std::string ptxSmVersion = "--cuda-gpu-arch=sm_20"; + std::string fatbinSmVersion = "--image=profile=compute_20"; + if (!invocationOptions.CompilerOpts.CUDAGpuArch.empty()) { + ptxSmVersion = + "--cuda-gpu-arch=" + invocationOptions.CompilerOpts.CUDAGpuArch; + fatbinSmVersion = "--image=profile=compute_" + + invocationOptions.CompilerOpts.CUDAGpuArch.substr(3); + } + + // The generating of the fatbin file is depend of the architecture of the + // host. + llvm::Triple hostTarget(llvm::sys::getDefaultTargetTriple()); + const std::string fatbinArch = hostTarget.isArch64Bit() ? "-64" : "-32"; + + // FIXME : Should not reduce the fine granulated debug options to a simple. + // -g + bool debug = false; + if (debugInfo == clang::codegenoptions::DebugLineTablesOnly || + debugInfo == clang::codegenoptions::LimitedDebugInfo || + debugInfo == clang::codegenoptions::FullDebugInfo) + debug = true; + + // FIXME : Cling has problems to detect these arguments. + /* + if(langOpts.CUDADeviceFlushDenormalsToZero) + m_CuArgs.additionalPtxOpt.push_back("-fcuda-flush-denormals-to-zero"); + if(langOpts.CUDADeviceApproxTranscendentals) + m_CuArgs.additionalPtxOpt.push_back("-fcuda-approx-transcendentals"); + if(langOpts.CUDAAllowVariadicFunctions) + m_CuArgs.additionalPtxOpt.push_back("-fcuda-allow-variadic-functions"); + */ + std::vector additionalPtxOpt; + + m_CuArgs.reset(new IncrementalCUDADeviceCompiler::CUDACompilerArgs( + cppStdVersion, optLevel, ptxSmVersion, fatbinSmVersion, fatbinArch, + invocationOptions.Verbose(), debug, additionalPtxOpt, + invocationOptions.CompilerOpts.CUDAFatbinaryArgs)); + } + + bool IncrementalCUDADeviceCompiler::generateHelperFiles() { + // Generate an empty dummy.cu file. + std::error_code EC; + llvm::raw_fd_ostream dummyCU(m_DummyCUPath, EC, llvm::sys::fs::F_Text); + if (EC) { + llvm::errs() << "Could not open " << m_DummyCUPath << ": " << EC.message() + << "\n"; + return false; + } + dummyCU.close(); + + return true; + } + + bool IncrementalCUDADeviceCompiler::findToolchain( + const cling::InvocationOptions& invocationOptions) { + // Search after clang in the folder of cling. + llvm::SmallString<128> cwd; + // get folder of the cling executable to find the clang which is contained + // in cling + // nullptr is ok, if we are the main and not a shared library + cwd.append(llvm::sys::path::parent_path(llvm::sys::fs::getMainExecutable( + invocationOptions.CompilerOpts.Remaining[0], (void*)&cwd))); + cwd.append(llvm::sys::path::get_separator()); + cwd.append("clang++"); + m_ClangPath = cwd.c_str(); + // Check, if clang is existing and executable. + if (!llvm::sys::fs::can_execute(m_ClangPath)) { + llvm::errs() << "Error: " << m_ClangPath + << " not existing or executable!\n"; + return false; + } + + // Use the custom CUDA toolkit path, if it set via cling argument. + if (!invocationOptions.CompilerOpts.CUDAPath.empty()) { + m_FatbinaryPath = + invocationOptions.CompilerOpts.CUDAPath + "/bin/fatbinary"; + if (!llvm::sys::fs::can_execute(m_FatbinaryPath)) { + llvm::errs() << "Error: " << m_FatbinaryPath + << " not existing or executable!\n"; + return false; + } + } else { + // Search after fatbinary on the system. + if (llvm::ErrorOr fatbinary = + llvm::sys::findProgramByName("fatbinary")) { + llvm::SmallString<256> fatbinaryAbsolutePath; + llvm::sys::fs::real_path(*fatbinary, fatbinaryAbsolutePath); + m_FatbinaryPath = fatbinaryAbsolutePath.c_str(); + } else { + llvm::errs() << "Error: nvidia tool fatbinary not found!\n" + << "Please add the cuda /bin path to PATH or set the " + "toolkit path via --cuda-path argument.\n"; + return false; + } + } + + return true; + } + + void IncrementalCUDADeviceCompiler::addHeaderSearchPathFlags( + llvm::SmallVectorImpl& argv) { + for (clang::HeaderSearchOptions::Entry e : + m_HeaderSearchOptions->UserEntries) { + if (e.Group == clang::frontend::IncludeDirGroup::Quoted) { + argv.push_back("-iquote"); + argv.push_back(e.Path); + } + + if (e.Group == clang::frontend::IncludeDirGroup::Angled) + argv.push_back("-I" + e.Path); + } + } + + bool IncrementalCUDADeviceCompiler::compileDeviceCode( + const llvm::StringRef input, const cling::Transaction* const T) { + if (!m_Init) { + llvm::errs() + << "Error: Initializiation of CUDA Device Code Compiler failed\n"; + return false; + } + + const unsigned int counter = getCounterCopy(); + + // Write the (CUDA) C++ source code to a file. + std::error_code EC; + llvm::raw_fd_ostream cuFile(m_GenericFileName + std::to_string(counter) + + ".cu", + EC, llvm::sys::fs::F_Text); + if (EC) { + llvm::errs() << "Could not open " + << m_GenericFileName + std::to_string(counter) + << ".cu: " << EC.message() << "\n"; + return false; + } + // This variable prevent, that the input and the code from the transaction + // will be written to the .cu-file. + bool foundUnwrappedDecl = false; + + assert(T != nullptr && "transaction can't be missing"); + + // Search after statements, which are unwrapped. The conditions are, that + // the source code comes from the prompt (getWrapperFD()) and has the type + // kCCIHandleTopLevelDecl. + if (T->getWrapperFD()) { + // Template specialization declaration will be save two times at a + // transaction. Once with the type + // kCCIHandleCXXImplicitFunctionInstantiation and once with the type + // kCCIHandleTopLevelDecl. To avoid sending a template specialization to + // the clang nvptx and causing a + // explicit-specialization-after-instantiation-error it have to check, + // which kCCIHandleTopLevelDecl declaration is also a + // kCCIHandleCXXImplicitFunctionInstantiation declaration. + std::vector implFunc; + for (auto iDCI = T->decls_begin(), eDCI = T->decls_end(); iDCI != eDCI; + ++iDCI) + if (iDCI->m_Call == Transaction::ConsumerCallInfo:: + kCCIHandleCXXImplicitFunctionInstantiation) + for (clang::Decl* decl : iDCI->m_DGR) + implFunc.push_back(decl); + + for (auto iDCI = T->decls_begin(), eDCI = T->decls_end(); iDCI != eDCI; + ++iDCI) { + if (iDCI->m_Call == + Transaction::ConsumerCallInfo::kCCIHandleTopLevelDecl) { + for (clang::Decl* decl : iDCI->m_DGR) { + if (std::find(implFunc.begin(), implFunc.end(), decl) == + implFunc.end()) { + foundUnwrappedDecl = true; + decl->print(cuFile); + // The c++ code has no whitespace and semicolon at the end. + cuFile << ";\n"; + } + } + } + } + } + + if (!foundUnwrappedDecl) { + cuFile << input; + } + + cuFile.close(); + + if (!generatePCH() || !generatePTX() || !generateFatbinary()) { + saveFaultyCUfile(); + return false; + } + +#if PCHMODE == 0 + llvm::sys::fs::remove(m_GenericFileName + std::to_string(counter) + + ".cu.pch"); +#endif + + ++m_Counter; + return true; + } + + bool IncrementalCUDADeviceCompiler::generatePCH() { + const unsigned int counter = getCounterCopy(); + + // clang++ -std=c++xx -Ox -S -Xclang -emit-pch ${clingHeaders} cling[0-9].cu + // -D__CLING__ -o cling[0-9].cu.pch [-include-pch cling[0-9].cu.pch] + // --cuda-gpu-arch=sm_[1-7][0-9] -pthread --cuda-device-only [-v] [-g] + // ${m_CuArgs->additionalPtxOpt} + llvm::SmallVector argv; + + // First argument have to be the program name. + argv.push_back(m_ClangPath); + + argv.push_back(m_CuArgs->cppStdVersion); + argv.push_back(m_CuArgs->optLevel); + argv.push_back("-S"); + argv.push_back("-Xclang"); + argv.push_back("-emit-pch"); + addHeaderSearchPathFlags(argv); + // Is necessary for the cling runtime header. + argv.push_back("-D__CLING__"); + argv.push_back(m_GenericFileName + std::to_string(counter) + ".cu"); + argv.push_back("-o"); + argv.push_back(m_GenericFileName + std::to_string(counter) + ".cu.pch"); + // If a previos file exist, include it. +#if PCHMODE == 1 + if (counter) { + argv.push_back("-include-pch"); + argv.push_back(m_GenericFileName + std::to_string(counter - 1) + + ".cu.pch"); + } +#else + if (counter) { + for (unsigned int i = 0; i <= counter - 1; ++i) { + argv.push_back("-include"); + argv.push_back(m_GenericFileName + std::to_string(i) + ".cu"); + } + } +#endif + argv.push_back(m_CuArgs->ptxSmVersion); + argv.push_back("-pthread"); + argv.push_back("--cuda-device-only"); + if (m_CuArgs->verbose) argv.push_back("-v"); + if (m_CuArgs->debug) argv.push_back("-g"); + for (const std::string& s : m_CuArgs->additionalPtxOpt) { + argv.push_back(s.c_str()); + } + + argv.push_back("-Wno-unused-value"); + + std::vector argvChar; + argvChar.resize(argv.size() + 1); + + std::transform(argv.begin(), argv.end(), argvChar.begin(), + [&](const std::string& s) { return s.c_str(); }); + + // Argv list have to finish with a nullptr. + argvChar.push_back(nullptr); + + std::string executionError; + int res = llvm::sys::ExecuteAndWait(m_ClangPath.c_str(), argvChar.data(), + nullptr, {}, 0, 0, &executionError); + + if (res) { + llvm::errs() << "cling::IncrementalCUDADeviceCompiler::generatePCH(): " + "error compiling PCH file:\n" + << m_ClangPath; + for (const char* c : argvChar) + llvm::errs() << " " << c; + llvm::errs() << '\n' << executionError << "\n"; + return false; + } + + return true; + } + + bool cling::IncrementalCUDADeviceCompiler::generatePTX() { + const unsigned int counter = getCounterCopy(); + + // clang++ -std=c++xx -Ox -S dummy.cu -o cling.ptx -include-pch + // cling[0-9].cu.pch --cuda-gpu-arch=sm_xx -pthread --cuda-device-only [-v] + // [-g] ${m_CuArgs->additionalPtxOpt} + llvm::SmallVector argv; + + // First argument have to be the program name. + argv.push_back(m_ClangPath); + + argv.push_back(m_CuArgs->cppStdVersion); + argv.push_back(m_CuArgs->optLevel); + argv.push_back("-S"); + argv.push_back(m_DummyCUPath); + argv.push_back("-o"); + argv.push_back(m_PTXFilePath); + argv.push_back("-include-pch"); + argv.push_back(m_GenericFileName + std::to_string(counter) + ".cu.pch"); + argv.push_back(m_CuArgs->ptxSmVersion); + argv.push_back("-pthread"); + argv.push_back("--cuda-device-only"); + if (m_CuArgs->verbose) argv.push_back("-v"); + if (m_CuArgs->debug) argv.push_back("-g"); + for (const std::string& s : m_CuArgs->additionalPtxOpt) { + argv.push_back(s.c_str()); + } + + std::vector argvChar; + argvChar.resize(argv.size() + 1); + + std::transform(argv.begin(), argv.end(), argvChar.begin(), + [&](const std::string& s) { return s.c_str(); }); + + // Argv list have to finish with a nullptr. + argvChar.push_back(nullptr); + + std::string executionError; + int res = llvm::sys::ExecuteAndWait(m_ClangPath.c_str(), argvChar.data(), + nullptr, {}, 0, 0, &executionError); + + if (res) { + llvm::errs() << "cling::IncrementalCUDADeviceCompiler::generatePTX(): " + "error compiling PCH file:\n" + << m_ClangPath; + for (const char* c : argvChar) + llvm::errs() << " " << c; + llvm::errs() << '\n' << executionError << "\n"; + return false; + } + + return true; + } + + bool IncrementalCUDADeviceCompiler::generateFatbinary() { + // fatbinary --cuda [-32 | -64] --create cling.fatbin + // --image=profile=compute_xx,file=cling.ptx [-g] ${m_CuArgs->fatbinaryOpt} + llvm::SmallVector argv; + + // First argument have to be the program name. + argv.push_back(m_FatbinaryPath); + + argv.push_back("--cuda"); + argv.push_back(m_CuArgs->fatbinArch); + argv.push_back("--create"); + argv.push_back(m_FatbinFilePath); + argv.push_back(m_CuArgs->fatbinSmVersion + ",file=" + m_PTXFilePath); + if (m_CuArgs->debug) argv.push_back("-g"); + for (const std::string& s : m_CuArgs->fatbinaryOpt) { + argv.push_back(s.c_str()); + } + + std::vector argvChar; + argvChar.resize(argv.size() + 1); + + std::transform(argv.begin(), argv.end(), argvChar.begin(), + [&](const std::string& s) { return s.c_str(); }); + + // Argv list have to finish with a nullptr. + argvChar.push_back(nullptr); + + std::string executionError; + int res = + llvm::sys::ExecuteAndWait(m_FatbinaryPath.c_str(), argvChar.data(), + nullptr, {}, 0, 0, &executionError); + + if (res) { + llvm::errs() << "cling::IncrementalCUDADeviceCompiler::generateFatbinary(" + "): error compiling PCH file:\n" + << m_ClangPath; + for (const char* c : argvChar) + llvm::errs() << " " << c; + llvm::errs() << '\n' << executionError << "\n"; + return false; + } + + return true; + } + + void IncrementalCUDADeviceCompiler::dump() { + llvm::outs() << "current counter: " << getCounterCopy() << "\n" + << "CUDA device compiler is valid: " << m_Init << "\n" + << "file path: " << m_FilePath << "\n" + << "fatbin file path: " << m_FatbinFilePath << "\n" + << "dummy.cu file path: " << m_DummyCUPath << "\n" + << "cling.ptx file path: " << m_PTXFilePath << "\n" + << "generic file path: " << m_GenericFileName + << "[0-9]*.cu{.pch}\n" + << "clang++ path: " << m_ClangPath << "\n" + << "nvidia fatbinary path: " << m_FatbinaryPath << "\n" + << "m_CuArgs c++ standard: " << m_CuArgs->cppStdVersion << "\n" + << "m_CuArgs opt level: " << m_CuArgs->optLevel << "\n" + << "m_CuArgs SM level for clang nvptx: " + << m_CuArgs->ptxSmVersion << "\n" + << "m_CuArgs SM level for fatbinary: " + << m_CuArgs->fatbinSmVersion << "\n" + << "m_CuArgs fatbinary architectur: " << m_CuArgs->fatbinArch + << "\n" + << "m_CuArgs verbose: " << m_CuArgs->verbose << "\n" + << "m_CuArgs debug: " << m_CuArgs->debug << "\n"; + llvm::outs() << "m_CuArgs additional clang nvptx options: "; + for (const std::string& s : m_CuArgs->additionalPtxOpt) { + llvm::outs() << s << " "; + } + llvm::outs() << "\n"; + llvm::outs() << "m_CuArgs additional fatbinary options: "; + for (const std::string& s : m_CuArgs->fatbinaryOpt) { + llvm::outs() << s << " "; + } + llvm::outs() << "\n"; + } + + std::error_code IncrementalCUDADeviceCompiler::saveFaultyCUfile() { + const unsigned int counter = getCounterCopy(); + unsigned int faultFileCounter = 0; + + // Construct the file path of the current .cu file without extension. + std::string originalCU = m_GenericFileName + std::to_string(counter); + + // counter (= m_Counter) will just increased, if the compiling get right. So + // we need a second counter, if two or more following files fails. + std::string faultyCU; + do { + faultFileCounter += 1; + faultyCU = + originalCU + "_fault" + std::to_string(faultFileCounter) + ".cu"; + } while (llvm::sys::fs::exists(faultyCU)); + + // orginial: cling[counter].cu + // faulty file: cling[counter]_fault[faultFileCounter].cu + return llvm::sys::fs::rename(originalCU + ".cu", faultyCU); + } + +} // end namespace cling diff --git a/interpreter/cling/lib/Interpreter/IncrementalCUDADeviceCompiler.h b/interpreter/cling/lib/Interpreter/IncrementalCUDADeviceCompiler.h new file mode 100644 index 0000000000000..48c461633641d --- /dev/null +++ b/interpreter/cling/lib/Interpreter/IncrementalCUDADeviceCompiler.h @@ -0,0 +1,208 @@ +//--------------------------------------------------------------------*- C++ -*- +// CLING - the C++ LLVM-based InterpreterG :) +// author: Simeon Ehrig +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +#ifndef CLING_INCREMENTAL_CUDA_DEVICE_JIT_H +#define CLING_INCREMENTAL_CUDA_DEVICE_JIT_H + +#include "clang/Frontend/CodeGenOptions.h" +#include "llvm/ADT/SmallVector.h" + +#include +#include +#include + +namespace cling { + class InvocationOptions; + class Transaction; +} // namespace cling + +namespace clang { + class CompilerInstance; + class HeaderSearchOptions; + class LangOptions; +} // namespace clang + +namespace llvm { + class StringRef; +} + +namespace cling { + + ///\brief The class is responsible for generating CUDA device code in + /// cuda fatbinary form during the runtime. It works with + /// llvm::sys::ExecuteAndWait. + /// + class IncrementalCUDADeviceCompiler { + + ///\brief Contains the arguments for the cling nvptx and the nvidia + /// fatbinary tool. + struct CUDACompilerArgs { + const std::string cppStdVersion; + const std::string optLevel; + const std::string ptxSmVersion; + const std::string fatbinSmVersion; + ///\brief Argument for the fatbinary tool, which is depend, if the OS is + /// 32 bit or 64 bit. + const std::string fatbinArch; + ///\brief True, if the flag -v is set. + const bool verbose; + ///\brief True, if the flag -g is set. + const bool debug; + ///\brief A list Arguments, which will passed to the clang nvptx. + const std::vector additionalPtxOpt; + ///\brief A list Arguments, which will passed to the fatbinary tool. + const std::vector fatbinaryOpt; + + CUDACompilerArgs(std::string cppStdVersion, std::string optLevel, + std::string ptxSmVersion, std::string fatbinSmVersion, + std::string fatbinArch, bool verbose, bool debug, + std::vector additionalPtxOpt, + std::vector fatbinaryOpt) + : cppStdVersion(cppStdVersion), optLevel(optLevel), + ptxSmVersion(ptxSmVersion), fatbinSmVersion(fatbinSmVersion), + fatbinArch(fatbinArch), verbose(verbose), debug(debug), + additionalPtxOpt(additionalPtxOpt), fatbinaryOpt(fatbinaryOpt) {} + }; + + std::unique_ptr m_CuArgs; + + ///\brief The counter responsible to generate a chain of .cu source files + /// and .cu.pch files. Starts with 1 because the cling0.cu file is reserved + /// for internal code. + unsigned int m_Counter = 1; + + ///\brief Is true if all necessary files have been generated and clang and + /// cuda NVIDIA fatbinary are found. + bool m_Init = false; + + ///\brief Path to the folder, where all files will put in. Ordinary the tmp + /// folder. Have to end with a separator. Can be empty. + const std::string m_FilePath; + ///\brief Path to the fatbin file, which will used by the CUDACodeGen. + const std::string m_FatbinFilePath; + ///\brief Path to a empty dummy.cu file. The file is necessary to generate + /// PTX code from the pch files. + const std::string m_DummyCUPath; + ///\brief Path to the PTX file. Will be reused for every PTX generation. + const std::string m_PTXFilePath; + ///\brief Will be used to generate .cu and .cu.pch files. + const std::string m_GenericFileName; + + ///\brief Path to the clang++ compiler, which will used to compile the pch + /// files and the PTX code. Should be in same folder, as the cling. + std::string m_ClangPath; + ///\brief Path to the NIVDIA tool fatbinary. + std::string m_FatbinaryPath; + + ///\brief Contains information about all include paths. + /// + std::shared_ptr m_HeaderSearchOptions; + + ///\brief get copy of m_Counter + /// + ///\returns copy of m_Counter + unsigned int getCounterCopy() { return m_Counter; } + + ///\brief Generate the dummy.cu file and set the paths of m_PTXFilePath and + /// m_GenericFileName. + /// + ///\returns True, if it created a dummy.cu file. + bool generateHelperFiles(); + + ///\brief Find the path of the clang and the NIVDIA tool fatbinary. Clang + /// have to be in the same folder as cling. + /// + ///\param [in] invocationOptions - Can contains a custom path to the cuda + /// toolkit + /// + ///\returns True, whether clang and fatbinary was found. + bool findToolchain(const cling::InvocationOptions& invocationOptions); + + ///\brief Add the include paths from the interpreter runtime to a argument + /// list. + /// + ///\param [in,out] argv - The include commands will append to the argv + /// vector. + void addHeaderSearchPathFlags(llvm::SmallVectorImpl& argv); + + ///\brief Start an clang compiler with nvptx backend. Read the content of + /// cling.cu and compile it to a new PCH file. If predecessor PCH file is + /// existing, it will included. + /// + ///\returns True, if the clang returns 0. + bool generatePCH(); + + ///\brief Start an clang compiler with nvptx backend. Generate a PTX file + /// from the latest PCH file. The PTX code will write to cling.ptx. + /// + ///\returns True, if the clang returns 0. + bool generatePTX(); + + ///\brief Start the NVIDIA tool fatbinary. Generate a fatbin file + /// from the cling.ptx. The fatbin code will write to the path of + /// m_FatbinFilePath. + /// + ///\returns True, if the fatbinary tool returns 0. + bool generateFatbinary(); + + ///\brief The function set the values of m_CuArgs. + /// + ///\param [in] langOpts - The LangOptions of the CompilerInstance. + ///\param [in] invocationOptions - The invocationOptions of the interpreter. + ///\param [in] intprOptLevel - The optimization level of the interpreter. + ///\param [in] debugInfo - The debugInfo of the CompilerInstance. + void setCuArgs(const clang::LangOptions& langOpts, + const cling::InvocationOptions& invocationOptions, + const int intprOptLevel, + const clang::codegenoptions::DebugInfoKind debugInfo); + + ///\brief Save .cu file, if cuda device code compiler failed at translation. + /// + ///\returns The error code of the rename operation + std::error_code saveFaultyCUfile(); + + public: + ///\brief Constructor for IncrementalCUDADeviceCompiler + /// + ///\param [in] filePath - All files will generated in the folder of the + /// filePath, except the fatbin file, if it have another path. Have + /// to end with a separator. Can be empty. + ///\param [in] optLevel - The optimization level of the interpreter + /// instance. + /// The value will be copied, because a change of it is not allowed. + ///\param [in] invocationOptions - Contains values for the arguments of + /// clang and the NVIDIA tool fatbinary. + ///\param [in] CI - Will be used for m_CuArgs and the include path handling. + IncrementalCUDADeviceCompiler( + const std::string& filePath, const int optLevel, + const cling::InvocationOptions& invocationOptions, + const clang::CompilerInstance& CI); + + ///\brief Generate an new fatbin file with the path in + /// CudaGpuBinaryFileNames. + /// It will add the content of input, to the existing source code, which was + /// passed to compileDeviceCode, before. + /// + ///\param [in] input - New source code. The function can select, if code + /// is relevant for the device side. Have to be valid CUDA C++ code. + ///\param [in] T - Source of c++ code for variable declaration. + /// + ///\returns True, if all stages of generating fatbin runs right and a new + /// fatbin file is written. + bool compileDeviceCode(const llvm::StringRef input, + const cling::Transaction* const T); + + ///\brief Print some information of the IncrementalCUDADeviceCompiler to + /// llvm::outs(). For Example the paths of the files and tools. + void dump(); + }; + +} // namespace cling + +#endif // CLING_INCREMENTAL_CUDA_DEVICE_JIT_H diff --git a/interpreter/cling/lib/Interpreter/IncrementalParser.cpp b/interpreter/cling/lib/Interpreter/IncrementalParser.cpp index ce322cc2de22f..56692341b5a70 100644 --- a/interpreter/cling/lib/Interpreter/IncrementalParser.cpp +++ b/interpreter/cling/lib/Interpreter/IncrementalParser.cpp @@ -17,6 +17,7 @@ #include "DeclCollector.h" #include "DeclExtractor.h" #include "DynamicLookup.h" +#include "IncrementalCUDADeviceCompiler.h" #include "IncrementalExecutor.h" #include "NullDerefProtectionTransformer.h" #include "TransactionPool.h" @@ -45,6 +46,7 @@ #include "clang/Sema/SemaDiagnostic.h" #include "clang/Serialization/ASTWriter.h" #include "clang/Serialization/ASTReader.h" +#include "llvm/Support/Path.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -118,7 +120,7 @@ namespace { m_PrevClient.EndSourceFile(); SyncDiagCountWithTarget(); } - + void finish() override { m_PrevClient.finish(); SyncDiagCountWithTarget(); @@ -213,6 +215,34 @@ namespace cling { m_DiagConsumer.reset(new FilteringDiagConsumer(Diag, false)); initializeVirtualFile(); + + if(m_CI->getFrontendOpts().ProgramAction != frontend::ParseSyntaxOnly && + m_Interpreter->getOptions().CompilerOpts.CUDA){ + // Create temporary folder for all files, which the CUDA device compiler + // will generate. + llvm::SmallString<256> TmpPath; + llvm::StringRef sep = llvm::sys::path::get_separator().data(); + llvm::sys::path::system_temp_directory(false, TmpPath); + TmpPath.append(sep.data()); + TmpPath.append("cling-%%%%"); + TmpPath.append(sep.data()); + + llvm::SmallString<256> TmpFolder; + llvm::sys::fs::createUniqueFile(TmpPath.c_str(), TmpFolder); + llvm::sys::fs::create_directory(TmpFolder); + + // The CUDA fatbin file is the connection beetween the CUDA device + // compiler and the CodeGen of cling. The file will every time reused. + if(getCI()->getCodeGenOpts().CudaGpuBinaryFileNames.empty()) + getCI()->getCodeGenOpts().CudaGpuBinaryFileNames.push_back( + std::string(TmpFolder.c_str()) + "cling.fatbin"); + + m_CUDACompiler.reset( + new IncrementalCUDADeviceCompiler(TmpFolder.c_str(), + m_CI->getCodeGenOpts().OptimizationLevel, + m_Interpreter->getOptions(), + *m_CI)); + } } bool @@ -227,13 +257,6 @@ namespace cling { Preprocessor& PP = m_CI->getPreprocessor(); DiagnosticsEngine& Diags = m_CI->getSema().getDiagnostics(); - ASTReader* Reader = m_CI->getModuleManager().get(); - assert(isa(m_Consumer)); - ASTDeserializationListener* Listener = cast(m_Consumer); - // FIXME: We should create a multiplexing deserialization listener if there is one already attached. - if (Reader && Listener && !Reader->getDeserializationListener()) - Reader->setDeserializationListener(Listener); - // Pull in PCH. const std::string& PCHFileName = m_CI->getInvocation().getPreprocessorOpts().ImplicitPCHInclude; @@ -800,6 +823,9 @@ namespace cling { else if (Diags.getNumWarnings()) return kSuccessWithWarnings; + if(!m_Interpreter->isInSyntaxOnlyMode() && m_CI->getLangOpts().CUDA ) + m_CUDACompiler->compileDeviceCode(input, m_Consumer->getTransaction()); + return kSuccess; } diff --git a/interpreter/cling/lib/Interpreter/IncrementalParser.h b/interpreter/cling/lib/Interpreter/IncrementalParser.h index 0d76c32a2961c..903c8b6a24a8f 100644 --- a/interpreter/cling/lib/Interpreter/IncrementalParser.h +++ b/interpreter/cling/lib/Interpreter/IncrementalParser.h @@ -43,6 +43,7 @@ namespace cling { class Transaction; class TransactionPool; class ASTTransformer; + class IncrementalCUDADeviceCompiler; ///\brief Responsible for the incremental parsing and compilation of input. /// @@ -94,6 +95,10 @@ namespace cling { /// std::unique_ptr m_DiagConsumer; + ///\brief Cling's worker class implementing the compilation of CUDA device code + /// + std::unique_ptr m_CUDACompiler; + public: enum EParseResult { kSuccess, diff --git a/interpreter/cling/lib/Interpreter/Interpreter.cpp b/interpreter/cling/lib/Interpreter/Interpreter.cpp index 56c5c3ecf2d1d..192fd92188029 100644 --- a/interpreter/cling/lib/Interpreter/Interpreter.cpp +++ b/interpreter/cling/lib/Interpreter/Interpreter.cpp @@ -165,7 +165,7 @@ namespace cling { m_DyLibManager && m_LookupHelper && (isInSyntaxOnlyMode() || m_Executor); } - + namespace internal { void symbol_requester(); } const char* Interpreter::getVersion() { @@ -673,7 +673,7 @@ namespace cling { } return Value; } - + ///\brief Maybe transform the input line to implement cint command line /// semantics (declarations are global) and compile to produce a module. /// @@ -869,11 +869,11 @@ namespace cling { // Ignore diagnostics when we tab complete. // This is because we get redefinition errors due to the import of the decls. clang::IgnoringDiagConsumer* ignoringDiagConsumer = - new clang::IgnoringDiagConsumer(); + new clang::IgnoringDiagConsumer(); childSemaRef.getDiagnostics().setClient(ignoringDiagConsumer, true); DiagnosticsEngine& parentDiagnostics = this->getCI()->getSema().getDiagnostics(); - std::unique_ptr ownerDiagConsumer = + std::unique_ptr ownerDiagConsumer = parentDiagnostics.takeClient(); auto clientDiagConsumer = parentDiagnostics.getClient(); parentDiagnostics.setClient(ignoringDiagConsumer, /*owns*/ false); @@ -1529,9 +1529,6 @@ namespace cling { assert(!isInSyntaxOnlyMode() && "Running on what?"); assert(T.getState() == Transaction::kCommitted && "Must be committed"); - if (InterpreterCallbacks* callbacks = getCallbacks()) - callbacks->beforeExecuteTransaction(T); - const std::shared_ptr& M = T.getModule(); if (!M) return Interpreter::kExeNoModule; diff --git a/interpreter/cling/lib/Interpreter/InvocationOptions.cpp b/interpreter/cling/lib/Interpreter/InvocationOptions.cpp index 77dd965a42b98..6ee95b329aadc 100644 --- a/interpreter/cling/lib/Interpreter/InvocationOptions.cpp +++ b/interpreter/cling/lib/Interpreter/InvocationOptions.cpp @@ -142,6 +142,10 @@ void CompilerOptions::Parse(int argc, const char* const argv[], case options::OPT_fmodule_name_EQ: LLVM_FALLTHROUGH; case options::OPT_fmodule_name: ModuleName = arg->getValue(); break; case options::OPT_fmodules_cache_path: CachePath = arg->getValue(); break; + case options::OPT_cuda_path_EQ: CUDAPath = arg->getValue(); break; + case options::OPT_cuda_gpu_arch_EQ: CUDAGpuArch = arg->getValue(); break; + case options::OPT_Xcuda_fatbinary: CUDAFatbinaryArgs.push_back(arg->getValue()); + break; default: if (Inputs && arg->getOption().getKind() == Option::InputClass) @@ -184,6 +188,7 @@ InvocationOptions::InvocationOptions(int argc, const char* const* argv) : // pass -v to clang as well if (arg->getOption().getID() != OPT_v) break; + /* Falls through. */ case Option::UnknownClass: case Option::InputClass: // prune "-" we need to control where it appears when invoking clang diff --git a/interpreter/cling/lib/Interpreter/LookupHelper.cpp b/interpreter/cling/lib/Interpreter/LookupHelper.cpp index b8fc0cd3eb3ca..4df32ba572a0f 100644 --- a/interpreter/cling/lib/Interpreter/LookupHelper.cpp +++ b/interpreter/cling/lib/Interpreter/LookupHelper.cpp @@ -1452,9 +1452,9 @@ namespace cling { DigestArgsInput inputEval; llvm::SmallVector GivenArgs; - Interpreter::PushTransactionRAII pushedT(Interp); if (!inputEval(GivenArgs,funcArgs,diagOnOff,P,Interp)) return 0; + Interpreter::PushTransactionRAII pushedT(Interp); return findFunction(foundDC, funcName, GivenArgs, objectIsConst, Context, Interp, functionSelector, diff --git a/interpreter/cling/lib/Interpreter/MultiplexInterpreterCallbacks.h b/interpreter/cling/lib/Interpreter/MultiplexInterpreterCallbacks.h index 3d98ae0418985..7d2bfe0ea3203 100644 --- a/interpreter/cling/lib/Interpreter/MultiplexInterpreterCallbacks.h +++ b/interpreter/cling/lib/Interpreter/MultiplexInterpreterCallbacks.h @@ -77,10 +77,13 @@ namespace cling { } } - void beforeExecuteTransaction(const Transaction& T) override { + bool LibraryLoadingFailed(const std::string& errmessage, const std::string& libStem, bool permanent, + bool resolved) override { for (auto&& cb : m_Callbacks) { - cb->beforeExecuteTransaction(T); + if (bool res = cb->LibraryLoadingFailed(errmessage, libStem, permanent, resolved)) + return res; } + return 0; } void TransactionUnloaded(const Transaction& T) override { diff --git a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp index 2bc3b9360f343..dc1621b860a9a 100644 --- a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp +++ b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp @@ -18,23 +18,18 @@ #include "clang/AST/Expr.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Sema/Lookup.h" #include -#include using namespace clang; -namespace cling { - NullDerefProtectionTransformer::NullDerefProtectionTransformer(Interpreter* I) - : ASTTransformer(&I->getCI()->getSema()), m_Interp(I) { - } +namespace { +using namespace cling; - NullDerefProtectionTransformer::~NullDerefProtectionTransformer() - { } - - class PointerCheckInjector : public RecursiveASTVisitor { +class PointerCheckInjector : public RecursiveASTVisitor { private: Interpreter& m_Interp; Sema& m_Sema; @@ -223,10 +218,59 @@ namespace cling { "Lookup of cling_runtime_internal_throwIfInvalidPointer failed!"); } }; +} + +namespace cling { + NullDerefProtectionTransformer::NullDerefProtectionTransformer(Interpreter* I) + : ASTTransformer(&I->getCI()->getSema()), m_Interp(I) { + } + + NullDerefProtectionTransformer::~NullDerefProtectionTransformer() + { } + + bool NullDerefProtectionTransformer::shouldTransform(const clang::Decl* D) { + if (D->isFromASTFile()) + return false; + if (D->isTemplateDecl()) + return false; + + auto Loc = D->getLocation(); + if (Loc.isInvalid()) + return false; + + SourceManager& SM = m_Interp->getSema().getSourceManager(); + auto Characteristic = SM.getFileCharacteristic(Loc); + if (Characteristic != clang::SrcMgr::C_User) + return false; + + auto FID = SM.getFileID(Loc); + if (FID.isInvalid()) + return false; + + auto FE = SM.getFileEntryForID(FID); + if (!FE) + return false; + + auto Dir = FE->getDir(); + if (!Dir) + return false; + + auto IterAndInserted = m_ShouldVisitDir.try_emplace(Dir, true); + if (IterAndInserted.second == false) + return IterAndInserted.first->second; + + if (llvm::sys::fs::can_write(Dir->getName())) + return true; // `true` is already emplaced above. + + // Remember that this dir is not writable and should not be visited. + IterAndInserted.first->second = false; + return false; + } + ASTTransformer::Result NullDerefProtectionTransformer::Transform(clang::Decl* D) { - if (getCompilationOpts().CheckPointerValidity) { + if (getCompilationOpts().CheckPointerValidity && shouldTransform(D)) { PointerCheckInjector injector(*m_Interp); injector.TraverseDecl(D); } diff --git a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h index a7b679fe9fcd9..72fd608869e97 100644 --- a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h +++ b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h @@ -13,8 +13,11 @@ #include "ASTTransformer.h" +#include "llvm/ADT/DenseMap.h" + namespace clang { class Decl; + class DirectoryEntry; } namespace cling { class Interpreter; @@ -24,6 +27,13 @@ namespace cling { class NullDerefProtectionTransformer : public ASTTransformer { cling::Interpreter* m_Interp; + + /// Whether to visit a Decl coming from a file in a given directory. + llvm::DenseMap m_ShouldVisitDir; + + /// Whether the declaration should be visited and possibly transformed. + bool shouldTransform(const clang::Decl* D); + public: ///\ brief Constructs the NullDeref AST Transformer. /// diff --git a/interpreter/cling/lib/Interpreter/Value.cpp b/interpreter/cling/lib/Interpreter/Value.cpp index e019a332f57e9..ce99884178139 100644 --- a/interpreter/cling/lib/Interpreter/Value.cpp +++ b/interpreter/cling/lib/Interpreter/Value.cpp @@ -243,7 +243,8 @@ namespace cling { const std::string Type = valuePrinterInternal::printTypeInternal(*this); // Get the value string representation, by printValue() method overloading - const std::string Val = cling::valuePrinterInternal::printValueInternal(*this); + const std::string Val + = cling::valuePrinterInternal::printValueInternal(*this); if (Escape) { const char* Data = Val.data(); const size_t N = Val.size(); @@ -251,9 +252,10 @@ namespace cling { case 'u': case 'U': case 'L': if (N < 3 || Data[1] != '\"') break; + /* Falls through. */ - // Unicode string, encoded as Utf-8 case '\"': + // Unicode string, encoded as Utf-8 if (N > 2 && Data[N-1] == '\"') { // Drop the terminating " so Utf-8 errors can be detected ("\xeA") Out << Type << ' '; diff --git a/interpreter/cling/lib/Utils/SourceNormalization.cpp b/interpreter/cling/lib/Utils/SourceNormalization.cpp index ea73d42c49197..da2deb481f452 100644 --- a/interpreter/cling/lib/Utils/SourceNormalization.cpp +++ b/interpreter/cling/lib/Utils/SourceNormalization.cpp @@ -375,12 +375,32 @@ size_t cling::utils::getWrapPoint(std::string& source, return std::string::npos; } - const tok::TokenKind kind = Tok.getKind(); // Prior behavior was to return getFileOffset, which was only used as an // in a test against std::string::npos. By returning 0 we preserve prior // behavior to pass the test against std::string::npos and wrap everything const size_t offset = 0; + // Check, if a function with c++ attributes should be defined. + while (Tok.getKind() == tok::l_square) { + Lex.Lex(Tok); + // Check, if attribute starts with '[[' + if (Tok.getKind() != tok::l_square) { + return offset; + } + // Check, if the second '[' is closing. + if (!Lex.CheckBalance(Tok)) { + return offset; + } + Lex.Lex(Tok); + // Check, if the first '[' is closing. + if (Tok.getKind() != tok::r_square) { + return offset; + } + Lex.Lex(Tok); + } + + const tok::TokenKind kind = Tok.getKind(); + if (kind == tok::raw_identifier && !Tok.needsCleaning()) { StringRef keyword(Tok.getRawIdentifier()); if (keyword.equals("using")) { diff --git a/interpreter/cling/test/CUDADeviceCode/CUDAHostPrefix.C b/interpreter/cling/test/CUDADeviceCode/CUDAHostPrefix.C new file mode 100644 index 0000000000000..f67c63e484190 --- /dev/null +++ b/interpreter/cling/test/CUDADeviceCode/CUDAHostPrefix.C @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +// The Test checks if a function with __host__ and __device__ prefix available +// on host and device side. +// RUN: cat %s | %cling -x cuda -Xclang -verify 2>&1 | FileCheck %s +// REQUIRES: cuda-runtime + +.rawInput 1 +__host__ __device__ int sum(int a, int b){ + return a + b; +} + +__global__ void gKernel1(int * output){ + *output = sum(40,2); +} +.rawInput 0 + +sum(41,1) +// CHECK: (int) 42 + +int hostOutput = 0; +int * deviceOutput; +cudaMalloc( (void **) &deviceOutput, sizeof(int)) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +gKernel1<<<1,1>>>(deviceOutput); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpy(&hostOutput, deviceOutput, sizeof(int), cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +hostOutput +// CHECK: (int) 42 + + +// expected-no-diagnostics +.q diff --git a/interpreter/cling/test/CUDADeviceCode/CUDAKernelArgument.C b/interpreter/cling/test/CUDADeviceCode/CUDAKernelArgument.C new file mode 100644 index 0000000000000..4ac6a2d9e41c8 --- /dev/null +++ b/interpreter/cling/test/CUDADeviceCode/CUDAKernelArgument.C @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +// The Test checks if a CUDA kernel works with a arguments and built-in +// functions. +// RUN: cat %s | %cling -x cuda -Xclang -verify 2>&1 | FileCheck %s +// REQUIRES: cuda-runtime + +// Test, if a simple kernel with arguments works. +.rawInput 1 +__global__ void gKernel1(int * out){ + *out = 42; +} +.rawInput 0 + +int * deviceOutput; +int hostOutput = 0; +cudaMalloc( (void **) &deviceOutput, sizeof(int)) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +gKernel1<<<1,1>>>(deviceOutput); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpy(&hostOutput, deviceOutput, sizeof(int), cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +hostOutput +// CHECK: (int) 42 + + +// Test, if a parallel kernel with built-in functions. +const unsigned int numberOfThreads = 4; + +.rawInput 1 +__device__ int mul7(int in){ + return 7*in; +} + +__global__ void gKernel2(int * out){ + int i = threadIdx.x; + out[i] = mul7(i); +} +.rawInput 0 + +int * deviceOutput2; +int hostOutput2[numberOfThreads]; +for(unsigned int i = 0; i < numberOfThreads; ++i){ + hostOutput2[i] = 0; +} +cudaMalloc( (void **) &deviceOutput2, sizeof(int)*numberOfThreads) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +gKernel2<<<1,numberOfThreads>>>(deviceOutput2); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpy(hostOutput2, deviceOutput2, sizeof(int)*numberOfThreads, cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +unsigned int expectedSum = 0; +unsigned int cudaSum = 0; + +for(unsigned int i = 0; i < numberOfThreads; ++i){ + expectedSum += 7*i; + cudaSum += hostOutput2[i]; +} + +expectedSum == cudaSum // expected-note {{use '=' to turn this equality comparison into an assignment}} +// CHECK: (bool) true + +.q diff --git a/interpreter/cling/test/CUDADeviceCode/CUDAKernelTemplateComplex.C b/interpreter/cling/test/CUDADeviceCode/CUDAKernelTemplateComplex.C new file mode 100644 index 0000000000000..c935d4102bca9 --- /dev/null +++ b/interpreter/cling/test/CUDADeviceCode/CUDAKernelTemplateComplex.C @@ -0,0 +1,186 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +// The Test checks if templated CUDA kernel in some special cases works. +// RUN: cat %s | %cling -x cuda -Xclang -verify 2>&1 | FileCheck %s +// REQUIRES: cuda-runtime + +// Check if templated CUDA kernel works, without explicit template type declaration. +.rawInput 1 + +template +__global__ void gKernel1(T * value){ + *value = (T)42.0; +} +.rawInput 0 + +int * deviceOutput1; +int hostOutput1 = 1; +cudaMalloc( (void **) &deviceOutput1, sizeof(int)) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +gKernel1<<<1,1>>>(deviceOutput1); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpy(&hostOutput1, deviceOutput1, sizeof(int), cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +hostOutput1 +// CHECK: (int) 42 + + + +// Check if specialization of templated CUDA kernel works. + +.rawInput 1 + +template +__global__ void gKernel2(T * value){ + *value = (T)1.0; +} + +template <> +__global__ void gKernel2(float * value){ + *value = 2.0; +} +.rawInput 0 + +int * deviceOutput2; +int hostOutput2 = 10; +cudaMalloc( (void **) &deviceOutput2, sizeof(int)) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +float * deviceOutput3; +float hostOutput3= 10.0; +cudaMalloc( (void **) &deviceOutput3, sizeof(float)) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +gKernel2<<<1,1>>>(deviceOutput2); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +gKernel2<<<1,1>>>(deviceOutput3); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +cudaMemcpy(&hostOutput2, deviceOutput2, sizeof(int), cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpy(&hostOutput3, deviceOutput3, sizeof(float), cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +hostOutput2 +// CHECK: (int) 1 +hostOutput3 +// CHECK: (float) 2.00000f + + + +// Check if function as parameter works on a templated CUDA kernel. +.rawInput 1 + +template +__global__ void gKernel3(T * out, int value){ + *out = value; +} + +__global__ void gKernel4(int * out){ + *out = 5; +} + +int func1(int * input){ + int result = 1; + gKernel4<<<1,1>>>(input); + cudaMemcpy(&result, input, sizeof(int), cudaMemcpyDeviceToHost); + return result; +} +.rawInput 0 + +int * deviceOutput4; +int hostOutput4 = 10; +cudaMalloc( (void **) &deviceOutput4, sizeof(int)) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +int * deviceOutput5; +cudaMalloc( (void **) &deviceOutput5, sizeof(int)) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +gKernel3<<<1,1>>>(deviceOutput4, func1(deviceOutput5)); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +cudaMemcpy(&hostOutput4, deviceOutput4, sizeof(int), cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +hostOutput4 +// CHECK: (int) 5 + +// Check if specialization of struct __device__ functors works. + +template +struct Struct1 +{ + __device__ T operator()(T* dummy) const + { + return (T)1; + } +}; + +template<> +struct Struct1 +{ + __device__ double operator()(double * dummy) const + { + return 2.0; + } +}; + +.rawInput 1 + +template +__global__ void gKernel5(T * x, Functor const functor){ + *x = functor(x); +} +.rawInput 0 + +int * deviceOutput6; +int hostOutput6 = 10; +cudaMalloc( (void **) &deviceOutput6, sizeof(int)) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +double * deviceOutput7; +double hostOutput7 = 10.0; +cudaMalloc( (void **) &deviceOutput7, sizeof(double)) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +gKernel5<<<1,1>>>(deviceOutput6, Struct1{}); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +gKernel5<<<1,1>>>(deviceOutput7, Struct1{}); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +cudaMemcpy(&hostOutput6, deviceOutput6, sizeof(int), cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpy(&hostOutput7, deviceOutput7, sizeof(double), cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +hostOutput6 +// CHECK: (int) 1 + +hostOutput7 +// CHECK: (double) 2.0000000 + +// expected-no-diagnostics +.q \ No newline at end of file diff --git a/interpreter/cling/test/CUDADeviceCode/CUDAKernelTemplateSimple.C b/interpreter/cling/test/CUDADeviceCode/CUDAKernelTemplateSimple.C new file mode 100644 index 0000000000000..b1f3c975250b8 --- /dev/null +++ b/interpreter/cling/test/CUDADeviceCode/CUDAKernelTemplateSimple.C @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +// The Test checks if templated CUDA kernel works. +// RUN: cat %s | %cling -x cuda -Xclang -verify 2>&1 | FileCheck %s +// REQUIRES: cuda-runtime + +// Check if template device side resoultion works. +.rawInput 1 +template +__device__ int dKernel1(){ + return T; +} + +__global__ void gKernel1(int * out){ + *out = dKernel1<42>(); +} +.rawInput 0 + +int * deviceOutput; +int hostOutput = 0; +cudaMalloc( (void **) &deviceOutput, sizeof(int)) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +gKernel1<<<1,1>>>(deviceOutput); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpy(&hostOutput, deviceOutput, sizeof(int), cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +hostOutput +// CHECK: (int) 42 + + +// Check if template host-device side resoultion works. +.rawInput 1 +template +__global__ void gKernel2(int * out){ + *out = dKernel1(); +} +.rawInput 0 + +hostOutput = 0; +gKernel2<43><<<1,1>>>(deviceOutput); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpy(&hostOutput, deviceOutput, sizeof(int), cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +hostOutput +// CHECK: (int) 43 + + +// expected-no-diagnostics +.q diff --git a/interpreter/cling/test/CUDADeviceCode/CUDASharedMemory.C b/interpreter/cling/test/CUDADeviceCode/CUDASharedMemory.C new file mode 100644 index 0000000000000..19bcf18202ce0 --- /dev/null +++ b/interpreter/cling/test/CUDADeviceCode/CUDASharedMemory.C @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +// The Test checks if runtime shared memory works. +// RUN: cat %s | %cling -x cuda -Xclang -verify 2>&1 | FileCheck %s +// REQUIRES: cuda-runtime + +const unsigned int numberOfThreads = 4; + +.rawInput 1 +__global__ void gKernel1(int * input, int * output){ + extern __shared__ int s[]; + int i = threadIdx.x; + s[(i+1)%blockDim.x] = input[i]; + __syncthreads(); + output[i] = s[i]; +} +.rawInput 0 + +int hostInput[numberOfThreads]; +int hostOutput[numberOfThreads]; +for(unsigned int i = 0; i < numberOfThreads; ++i){ + hostInput[i] = i+1; + hostOutput[i] = 0; +} +int * deviceInput; +int * deviceOutput; +cudaMalloc( (void **) &deviceInput, sizeof(int)*numberOfThreads) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMalloc( (void **) &deviceOutput, sizeof(int)*numberOfThreads) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +cudaMemcpy(deviceInput, hostInput, sizeof(int)*numberOfThreads, cudaMemcpyHostToDevice) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +gKernel1<<<1,numberOfThreads, sizeof(int)*numberOfThreads>>>(deviceInput, deviceOutput); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpy(hostOutput, deviceOutput, sizeof(int)*numberOfThreads, cudaMemcpyDeviceToHost) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +int expectedSum = (numberOfThreads*(numberOfThreads+1))/2; +int cudaSum = 0; + +for(unsigned int i = 0; i < numberOfThreads; ++i){ + cudaSum += hostOutput[i]; +} + +//check, if elements was shifted +hostOutput[0] == numberOfThreads // expected-note {{use '=' to turn this equality comparison into an assignment}} +// CHECK: (bool) true +hostOutput[numberOfThreads-1] == numberOfThreads-1 // expected-note {{use '=' to turn this equality comparison into an assignment}} +// CHECK: (bool) true +expectedSum == cudaSum // expected-note {{use '=' to turn this equality comparison into an assignment}} +// CHECK: (bool) true + +.q diff --git a/interpreter/cling/test/CUDADeviceCode/CUDASimpleKernel.C b/interpreter/cling/test/CUDADeviceCode/CUDASimpleKernel.C new file mode 100644 index 0000000000000..3370d4d89d978 --- /dev/null +++ b/interpreter/cling/test/CUDADeviceCode/CUDASimpleKernel.C @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +// The Test checks if a CUDA compatible device is available and checks, if simple +// __global__ and __device__ kernels are running. +// RUN: cat %s | %cling -x cuda -Xclang -verify 2>&1 | FileCheck %s +// REQUIRES: cuda-runtime + +// Check if cuda driver is available +int version; +cudaDriverGetVersion(&version) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +// Check if a CUDA compatible device (GPU) is available. +int device_count = 0; +cudaGetDeviceCount(&device_count) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +device_count > 0 +// CHECK: (bool) true + +// Check, if the smallest __global__ kernel is callable. +.rawInput 1 +__global__ void gKernel1(){} +.rawInput 0 +gKernel1<<<1,1>>>(); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +// Check, if a simple __device__ kernel is useable. +.rawInput 1 +__device__ int dKernel1(){return 42;} +__global__ void gKernel2(){int i = dKernel1();} +.rawInput 0 +gKernel2<<<1,1>>>(); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + + +// expected-no-diagnostics +.q diff --git a/interpreter/cling/test/CUDADeviceCode/CUDAStreams.C b/interpreter/cling/test/CUDADeviceCode/CUDAStreams.C new file mode 100644 index 0000000000000..1b9cd46667999 --- /dev/null +++ b/interpreter/cling/test/CUDADeviceCode/CUDAStreams.C @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +// The Test checks if cuda streams works. +// RUN: cat %s | %cling -x cuda -Xclang -verify 2>&1 | FileCheck %s +// REQUIRES: cuda-runtime + +const unsigned int numberOfThreads = 4; + +.rawInput 1 +__global__ void gKernel1(int * a, int b){ + int i = threadIdx.x; + a[i] += b; +} +.rawInput 0 + +cudaStream_t stream1, stream2; +cudaStreamCreate(&stream1) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaStreamCreate(&stream2) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +int hostInput1[numberOfThreads]; +int hostInput2[numberOfThreads]; +int hostOutput1[numberOfThreads]; +int hostOutput2[numberOfThreads]; +for(unsigned int i = 0; i < numberOfThreads; ++i){ + hostInput1[i] = i; + hostInput2[i] = i+10; +} +int * device1; +int * device2; +cudaMalloc( (void **) &device1, sizeof(int)*numberOfThreads) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMalloc( (void **) &device2, sizeof(int)*numberOfThreads) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +cudaMemcpyAsync(device1, hostInput1, sizeof(int)*numberOfThreads, cudaMemcpyHostToDevice, stream1) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpyAsync(device2, hostInput2, sizeof(int)*numberOfThreads, cudaMemcpyHostToDevice, stream2) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +gKernel1<<<1,numberOfThreads,0,stream2>>>(device2, 2); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +gKernel1<<<1,numberOfThreads,0,stream1>>>(device1, 1); +cudaGetLastError() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaDeviceSynchronize() +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +cudaMemcpyAsync(hostOutput2, device2, sizeof(int)*numberOfThreads, cudaMemcpyDeviceToHost, stream2) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 +cudaMemcpyAsync(hostOutput1, device1, sizeof(int)*numberOfThreads, cudaMemcpyDeviceToHost, stream1) +// CHECK: (cudaError_t) (cudaError::cudaSuccess) : (unsigned int) 0 + +unsigned int expectedSum1 = 0; +unsigned int cudaSum1 = 0; +unsigned int expectedSum2 = 0; +unsigned int cudaSum2 = 0; + +for(unsigned int i = 0; i < numberOfThreads; ++i){ + expectedSum1 += i+1; + cudaSum1 += hostOutput1[i]; + expectedSum2 += i+12; + cudaSum2 += hostOutput2[i]; +} + +expectedSum1 == cudaSum1 // expected-note {{use '=' to turn this equality comparison into an assignment}} +// CHECK: (bool) true +expectedSum2 == cudaSum2 // expected-note {{use '=' to turn this equality comparison into an assignment}} +// CHECK: (bool) true + +.q diff --git a/interpreter/cling/test/Prompt/ValuePrinter/Regression.C b/interpreter/cling/test/Prompt/ValuePrinter/Regression.C index 2017c2b42b3c4..23543fc6adc8c 100644 --- a/interpreter/cling/test/Prompt/ValuePrinter/Regression.C +++ b/interpreter/cling/test/Prompt/ValuePrinter/Regression.C @@ -112,6 +112,16 @@ struct OverloadedAddrOf { OverloadedAddrOf overloadedAddrOf // CHECK: (OverloadedAddrOf &) @0x{{[0-9a-f]+}} +// Much more important than what cling prints: cling survives this! +.rawInput +auto func() { class X {} x; return x; }; +namespace WithUnnamed { namespace { struct Y {} y; } Y z; } +.rawInput +//func +func() +WithUnnamed::y +WithUnnamed::z // CHECK: (WithUnnamed:: + namespace PR180 { class base {}; diff --git a/interpreter/cling/tools/packaging/cpt.py b/interpreter/cling/tools/packaging/cpt.py index 6f202d3743fa6..ede9ecb8f7794 100755 --- a/interpreter/cling/tools/packaging/cpt.py +++ b/interpreter/cling/tools/packaging/cpt.py @@ -90,6 +90,13 @@ def exec_subprocess_check_output(cmd, cwd): finally: return out +def travis_fold_start(tag): + if os.environ.get('TRAVIS_BUILD_DIR', None): + print('travis_fold:start:cpt-%s:' % (tag)) + +def travis_fold_end(tag): + if os.environ.get('TRAVIS_BUILD_DIR', None): + print('travis_fold:end:cpt-%s:' % (tag)) def box_draw_header(): msg = 'cling (' + platform.machine() + ')' + formatdate(time.time(), tzinfo()) @@ -461,6 +468,7 @@ def make(self, targets, flags=''): LLVM_OBJ_ROOT) def compile(arg, build_libcpp): + travis_fold_start("compile") global prefix, EXTRA_CMAKE_FLAGS prefix = arg PYTHON = sys.executable @@ -553,8 +561,10 @@ def compile(arg, build_libcpp): + ' -v ".I"', shell=True) except Exception as e: print(e) + travis_fold_end("compile") def install_prefix(): + travis_fold_start("install") global prefix set_vars() @@ -579,6 +589,7 @@ def install_prefix(): os.makedirs(os.path.join(prefix, os.path.dirname(f))) shutil.copy(os.path.join(TMP_PREFIX, f), os.path.join(prefix, f)) break + travis_fold_end("install") def runSingleTest(test, Idx = 2, Recurse = True): @@ -1939,6 +1950,7 @@ def make_dmg(): continue if args['current_dev']: + travis_fold_start("git-clone") llvm_revision = urlopen( "https://raw.githubusercontent.com/root-project/cling/master/LastKnownGoodLLVMSVNRevision.txt").readline().strip().decode( 'utf-8') @@ -1968,6 +1980,7 @@ def make_dmg(): print('\n') else: fetch_cling(CLING_BRANCH if CLING_BRANCH else 'master') + travis_fold_end("git-clone") set_version() if args['current_dev'] == 'tar': diff --git a/interpreter/llvm/src/tools/clang/include/clang/Serialization/ASTReader.h b/interpreter/llvm/src/tools/clang/include/clang/Serialization/ASTReader.h index f515756bf2901..ab6f4f00436c2 100644 --- a/interpreter/llvm/src/tools/clang/include/clang/Serialization/ASTReader.h +++ b/interpreter/llvm/src/tools/clang/include/clang/Serialization/ASTReader.h @@ -1555,10 +1555,6 @@ class ASTReader void setDeserializationListener(ASTDeserializationListener *Listener, bool TakeOwnership = false); - ASTDeserializationListener *getDeserializationListener() { - return DeserializationListener; - }; - /// \brief Determine whether this AST reader has a global index. bool hasGlobalIndex() const { return (bool)GlobalIndex; } diff --git a/io/chirp/doc/index.txt b/io/chirp/doc/index.txt deleted file mode 100644 index 401dfb45b69a1..0000000000000 --- a/io/chirp/doc/index.txt +++ /dev/null @@ -1,10 +0,0 @@ -BEGIN_HTML -This directory contains the I/O interface classes for the Chirp filesystem. Briefly, Chirp is a lightweight user-level distributed filesystem designed for sharing code and data across wide area computing grids. It provides extensive support for multiple authentication methods, allowing you to mix users employing Globus, Kerberos, hostname, and ticket authentication. Ordinary POSIX applications can be transparently attached to a Chirp filesystem using either Parrot or FUSE. -

-To build ROOT with Chirp support, you must have the Notre Dame CCTools package version 3.2.2 or greater installed. -

-For more information about the Chirp filesystem, see: -

-END_HTML diff --git a/io/chirp/inc/LinkDef.h b/io/chirp/inc/LinkDef.h deleted file mode 100644 index 51be5a2436ecb..0000000000000 --- a/io/chirp/inc/LinkDef.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifdef __CINT__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class TChirpFile; -#pragma link C++ class TChirpSystem; - -#endif diff --git a/io/chirp/inc/TChirpFile.h b/io/chirp/inc/TChirpFile.h deleted file mode 100644 index 74dfdfcdce76c..0000000000000 --- a/io/chirp/inc/TChirpFile.h +++ /dev/null @@ -1,66 +0,0 @@ -// @(#)root/chirp:$Id$ -// Author: Dan Bradley, Michael Albrecht, Douglas Thain - -/************************************************************************* - * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_TChirpFile -#define ROOT_TChirpFile - -#include "TFile.h" - -#include "TSystem.h" - -class TChirpFile:public TFile { -private: - TChirpFile(); - struct chirp_file *chirp_file_ptr; - - Int_t SysOpen(const char *pathname, Int_t flags, UInt_t mode); - Int_t SysClose(Int_t fd); - Int_t SysRead(Int_t fd, void *buf, Int_t len); - Int_t SysWrite(Int_t fd, const void *buf, Int_t len); - Long64_t SysSeek(Int_t fd, Long64_t offset, Int_t whence); - Int_t SysStat(Int_t fd, Long_t * id, Long64_t * size, Long_t * flags, Long_t * modtime); - Int_t SysSync(Int_t fd); - -public: - TChirpFile(const char *path, Option_t * option = "", const char *ftitle = "", Int_t compress = 1); - - ~TChirpFile(); - - Bool_t ReadBuffers(char *buf, Long64_t * pos, Int_t * len, Int_t nbuf); - - ClassDef(TChirpFile, 0) -}; - - -class TChirpSystem:public TSystem { -public: - TChirpSystem(); - virtual ~ TChirpSystem(); - - Int_t MakeDirectory(const char *name); - void *OpenDirectory(const char *name); - void FreeDirectory(void *dirp); - const char *GetDirEntry(void *dirp); - Int_t GetPathInfo(const char *path, FileStat_t & buf); - Bool_t AccessPathName(const char *path, EAccessMode mode); - Int_t Unlink(const char *path); - - int Rename(const char *from, const char *to); - int Link(const char *from, const char *to); - int Symlink(const char *from, const char *to); - int GetFsInfo(const char *path, Long_t * id, Long_t * bsize, Long_t * blocks, Long_t * bfree); - int Chmod(const char *file, UInt_t mode); - int Utime(const char *file, Long_t modtime, Long_t actime); - - ClassDef(TChirpSystem, 0) -}; - -#endif diff --git a/io/chirp/src/TChirpFile.cxx b/io/chirp/src/TChirpFile.cxx deleted file mode 100644 index 665ae22d8c0bc..0000000000000 --- a/io/chirp/src/TChirpFile.cxx +++ /dev/null @@ -1,464 +0,0 @@ -// @(#)root/chirp:$Id$ -// Authors: Dan Bradley, Michael Albrecht, Douglas Thain - -/************************************************************************* - * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -/** -\class TChirpFile -\ingroup IO - -Read and write data via a Chirp server. - -A TChirpFile is like a normal TFile except that it may read and -write its data via a Chirp server. The primary API for accessing -Chirp is through the chirp_reli interface, which corresponds closely -to Unix. Most operations return an integer where >=0 indicates -success and <0 indicates failure, setting the global errno. -This allows most TFile methods to be implemented with a single -line or two of Chirp (for more on the Chirp filesystem. -Note that this class overrides ReadBuffers so as to take advantage -of the Chirp "bulk I/O" feature which does multiple remote ops -in a single call. -Most users of Chirp will access a named remote server url: - chirp://host.somewhere.edu/path -The special host CONDOR is used to indicate a connection to the -Chirp I/O proxy service when running inside of Condor: - chirp://CONDOR/path - -This module recognizes the following environment variables: - - \b CHIRP_DEBUG_FILE: Send debugging output to this file. - - \b CHIRP_DEBUG_FLAGS: Turn on select debugging flags (e.g. 'all'). - - \b CHIRP_AUTH: Select a specific auth type (e.g. 'globus'). - - \b CHIRP_TIMEOUT: Specify how long to attempt each op, in secs. - -For more information about the Chirp fileystem and protocol: - http://www.cse.nd.edu/~ccl/software/chirp -*/ - -#include "TChirpFile.h" -#include "TError.h" -#include "TSystem.h" -#include "TROOT.h" - -#include -#include -#include -#include -#include - -extern "C" { -#include "chirp_reli.h" -#include "auth_all.h" -#include "debug.h" -} - -// If the path component of a url is a blank string, -// then convert it to the root directory of that server. -#define FIXPATH(x) ( x[0]==0 ? "/" : x ) - -static int chirp_root_timeout = 3600; - -static void chirp_root_global_setup() -{ - static int did_setup = 0; - if (did_setup) return; - - debug_config("chirp_root"); - - const char *debug_file = getenv("CHIRP_DEBUG_FILE"); - if (debug_file) debug_config_file(debug_file); - - const char *debug_flags = getenv("CHIRP_DEBUG_FLAGS"); - if (debug_flags) debug_flags_set(debug_flags); - - const char *auth_flags = getenv("CHIRP_AUTH"); - if (auth_flags) { - auth_register_byname(auth_flags); - } else { - auth_register_all(); - } - - const char *timeout_string = getenv("CHIRP_TIMEOUT"); - if (timeout_string) chirp_root_timeout = atoi(timeout_string); - - did_setup = 1; -} - -ClassImp(TChirpFile); - -//////////////////////////////////////////////////////////////////////////////// -/// Constructor. - -TChirpFile::TChirpFile(const char *path, Option_t * option, const char *ftitle, Int_t compress):TFile(path, "NET", ftitle, compress) -{ - chirp_root_global_setup(); - - chirp_file_ptr = 0; - - fOption = option; - fOption.ToUpper(); - - if (fOption == "NEW") - fOption = "CREATE"; - - Bool_t create = (fOption == "CREATE") ? kTRUE : kFALSE; - Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE; - Bool_t update = (fOption == "UPDATE") ? kTRUE : kFALSE; - Bool_t read = (fOption == "READ") ? kTRUE : kFALSE; - - if (!create && !recreate && !update && !read) { - read = kTRUE; - fOption = "READ"; - } - - fRealName = path; - - if (create || update || recreate) { - Int_t mode = O_RDWR | O_CREAT; - if (recreate) - mode |= O_TRUNC; - -#ifndef WIN32 - fD = SysOpen(path, mode, 0644); -#else - fD = SysOpen(path, mode | O_BINARY, S_IREAD | S_IWRITE); -#endif - if (fD == -1) { - SysError("TChirpFile", "file %s can not be created", path); - goto zombie; - } - fWritable = kTRUE; - } else { -#ifndef WIN32 - fD = SysOpen(path, O_RDONLY, 0644); -#else - fD = SysOpen(path, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE); -#endif - if (fD == -1) { - SysError("TChirpFile", "file %s can not be opened for reading", path); - goto zombie; - } - fWritable = kFALSE; - } - - Init(create || recreate); - - return; - -zombie: - MakeZombie(); - gDirectory = gROOT; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Destructor. - -TChirpFile::~TChirpFile() -{ - Close(); -} - -//////////////////////////////////////////////////////////////////////////////// - -Bool_t TChirpFile::ReadBuffers(char *buf, Long64_t * pos, Int_t * len, Int_t nbuf) -{ - struct chirp_bulkio bulkio[nbuf]; - int i; - - char *nextbuf = buf; - - for (i = 0; i < nbuf; i++) { - bulkio[i].type = CHIRP_BULKIO_PREAD; - bulkio[i].file = chirp_file_ptr; - bulkio[i].offset = pos[i]; - bulkio[i].length = len[i]; - bulkio[i].buffer = nextbuf; - nextbuf += len[i]; - } - - INT64_T result = chirp_reli_bulkio(bulkio, nbuf, time(0) + chirp_root_timeout); - - if (result >= 0) { - return kFALSE; - } else { - return kTRUE; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t TChirpFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode) -{ - TUrl url(pathname); - chirp_file_ptr = chirp_reli_open(url.GetHost(), FIXPATH(url.GetFile()), flags, (Int_t) mode, time(0) + chirp_root_timeout); - if (chirp_file_ptr) { - return 1; - } else { - return -1; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t TChirpFile::SysClose(Int_t) -{ - return chirp_reli_close(chirp_file_ptr, time(0) + chirp_root_timeout); -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t TChirpFile::SysRead(Int_t, void *buf, Int_t len) -{ - Int_t rc = chirp_reli_pread(chirp_file_ptr, buf, len, fOffset, time(0) + chirp_root_timeout); - if (rc > 0) fOffset += rc; - return rc; -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t TChirpFile::SysWrite(Int_t, const void *buf, Int_t len) -{ - Int_t rc = chirp_reli_pwrite(chirp_file_ptr, buf, len, fOffset, time(0) + chirp_root_timeout); - if (rc > 0) fOffset += rc; - return rc; -} - -//////////////////////////////////////////////////////////////////////////////// - -Long64_t TChirpFile::SysSeek(Int_t, Long64_t offset, Int_t whence) -{ - if (whence == SEEK_SET) { - fOffset = offset; - } else if(whence == SEEK_CUR) { - fOffset += offset; - } else if(whence == SEEK_END) { - struct chirp_stat info; - - Int_t rc = chirp_reli_fstat(chirp_file_ptr, &info, time(0) + chirp_root_timeout); - if (rc < 0) { - SysError("TChirpFile", "Unable to seek from end of file"); - return -1; - } - - fOffset = info.cst_size + offset; - - } else { - SysError("TChirpFile", "Unknown whence!"); - return -1; - } - - return fOffset; -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t TChirpFile::SysSync(Int_t /*fd*/) -{ - return chirp_reli_fsync(chirp_file_ptr, time(0) + chirp_root_timeout); -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t TChirpFile::SysStat(Int_t, Long_t * id, Long64_t * size, Long_t * flags, Long_t * modtime) -{ - struct chirp_stat cst; - - int rc = chirp_reli_fstat(chirp_file_ptr, &cst, time(0) + chirp_root_timeout); - - if (rc < 0) return rc; - - *id =::Hash(fRealName); - *size = cst.cst_size; - *flags = cst.cst_mode; - *modtime = cst.cst_mtime; - - return 0; -} - -ClassImp(TChirpSystem); - -//////////////////////////////////////////////////////////////////////////////// - -TChirpSystem::TChirpSystem():TSystem("-chirp", "Chirp Helper System") -{ - SetName("chirp"); - chirp_root_global_setup(); -} - -//////////////////////////////////////////////////////////////////////////////// - -TChirpSystem::~TChirpSystem() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t TChirpSystem::MakeDirectory(const char *path) -{ - TUrl url(path); - return chirp_reli_mkdir(url.GetHost(), FIXPATH(url.GetFile()), 0777, time(0) + chirp_root_timeout); -} - -//////////////////////////////////////////////////////////////////////////////// - -void *TChirpSystem::OpenDirectory(const char *path) -{ - TUrl url(path); - return chirp_reli_opendir(url.GetHost(), FIXPATH(url.GetFile()), time(0) + chirp_root_timeout); -} - -//////////////////////////////////////////////////////////////////////////////// - -void TChirpSystem::FreeDirectory(void *dirp) -{ - return chirp_reli_closedir((struct chirp_dir *) dirp); -} - -//////////////////////////////////////////////////////////////////////////////// - -const char *TChirpSystem::GetDirEntry(void *dirp) -{ - struct chirp_dirent *d = chirp_reli_readdir((struct chirp_dir *) dirp); - if (d) { - return d->name; - } else { - return 0; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t TChirpSystem::GetPathInfo(const char *path, FileStat_t & buf) -{ - TUrl url(path); - struct chirp_stat info; - Int_t rc = chirp_reli_stat(url.GetHost(), FIXPATH(url.GetFile()), &info, time(0) + chirp_root_timeout); - if (rc >= 0) { - buf.fDev = info.cst_dev; - buf.fIno = info.cst_ino; - buf.fMode = info.cst_mode; - buf.fUid = info.cst_uid; - buf.fGid = info.cst_gid; - buf.fSize = info.cst_size; - buf.fMtime = info.cst_mtime; - buf.fIsLink = S_ISLNK(info.cst_mode); - buf.fUrl = TString(path); - } - return rc; -} - -//////////////////////////////////////////////////////////////////////////////// - -Bool_t TChirpSystem::AccessPathName(const char *path, EAccessMode mode) -{ - TUrl url(path); - - int cmode = F_OK; - - if (mode & kExecutePermission) cmode |= X_OK; - if (mode & kWritePermission) cmode |= W_OK; - if (mode & kReadPermission) cmode |= R_OK; - - if (chirp_reli_access(url.GetHost(), FIXPATH(url.GetFile()), cmode, time(0) + chirp_root_timeout) == 0) { - return kFALSE; - } else { - return kTRUE; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -Int_t TChirpSystem::Unlink(const char *path) -{ - TUrl url(path); - Int_t rc = chirp_reli_unlink(url.GetHost(), FIXPATH(url.GetFile()), time(0) + chirp_root_timeout); - if (rc < 0 && errno == EISDIR) { - rc = chirp_reli_rmdir(url.GetHost(), FIXPATH(url.GetFile()), time(0) + chirp_root_timeout); - } - return rc; -} - -//////////////////////////////////////////////////////////////////////////////// - -int TChirpSystem::Rename(const char *from, const char *to) -{ - TUrl fromurl(from); - TUrl tourl(to); - - if (strcmp(fromurl.GetHost(), tourl.GetHost())) { - errno = EXDEV; - return -1; - } - - return chirp_reli_rename(fromurl.GetHost(), FIXPATH(fromurl.GetFile()), FIXPATH(tourl.GetFile()), time(0) + chirp_root_timeout); -} - -//////////////////////////////////////////////////////////////////////////////// - -int TChirpSystem::Link(const char *from, const char *to) -{ - TUrl fromurl(from); - TUrl tourl(to); - - if (strcmp(fromurl.GetHost(), tourl.GetHost())) { - errno = EXDEV; - return -1; - } - - return chirp_reli_link(fromurl.GetHost(), FIXPATH(fromurl.GetFile()), FIXPATH(tourl.GetFile()), time(0) + chirp_root_timeout); -} - -//////////////////////////////////////////////////////////////////////////////// - -int TChirpSystem::Symlink(const char *from, const char *to) -{ - TUrl fromurl(from); - TUrl tourl(to); - - if (strcmp(fromurl.GetHost(), tourl.GetHost())) { - errno = EXDEV; - return -1; - } - - return chirp_reli_symlink(fromurl.GetHost(), FIXPATH(fromurl.GetFile()), FIXPATH(tourl.GetFile()), time(0) + chirp_root_timeout); -} - -//////////////////////////////////////////////////////////////////////////////// - -int TChirpSystem::GetFsInfo(const char *path, Long_t * id, Long_t * bsize, Long_t * blocks, Long_t * bfree) -{ - TUrl url(path); - - struct chirp_statfs info; - - int rc = chirp_reli_statfs(url.GetHost(), FIXPATH(url.GetFile()), &info, time(0) + chirp_root_timeout); - if (rc >= 0) { - *id = info.f_type; - *bsize = info.f_bsize; - *blocks = info.f_blocks; - *bfree = info.f_bfree; - } - return rc; -} - -//////////////////////////////////////////////////////////////////////////////// - -int TChirpSystem::Chmod(const char *path, UInt_t mode) -{ - TUrl url(path); - return chirp_reli_chmod(url.GetHost(), FIXPATH(url.GetFile()), mode, time(0) + chirp_root_timeout); -} - -//////////////////////////////////////////////////////////////////////////////// - -int TChirpSystem::Utime(const char *path, Long_t modtime, Long_t actime) -{ - TUrl url(path); - return chirp_reli_utime(url.GetHost(), FIXPATH(url.GetFile()), modtime, actime, time(0) + chirp_root_timeout); -} diff --git a/io/io/inc/ROOT/TBufferMerger.hxx b/io/io/inc/ROOT/TBufferMerger.hxx index a5360991c35bc..0a5d28f45e87b 100644 --- a/io/io/inc/ROOT/TBufferMerger.hxx +++ b/io/io/inc/ROOT/TBufferMerger.hxx @@ -15,12 +15,10 @@ #include "TFileMerger.h" #include "TMemFile.h" -#include #include #include #include #include -#include namespace ROOT { namespace Experimental { @@ -72,13 +70,6 @@ public: /** Returns the number of buffers currently in the queue. */ size_t GetQueueSize() const; - /** Register a user callback function to be called after a buffer has been - * removed from the merging queue and finished being processed. This - * function can be useful to allow asynchronous launching of new tasks to - * push more data into the queue once its size satisfies user requirements. - */ - void RegisterCallback(const std::function &f); - /** Returns the current value of the auto save setting in bytes (default = 0). */ size_t GetAutoSave() const; @@ -108,17 +99,14 @@ private: void Merge(); void Push(TBufferFile *buffer); - void WriteOutputFile(); size_t fAutoSave{0}; //< AutoSave only every fAutoSave bytes size_t fBuffered{0}; //< Number of bytes currently buffered TFileMerger fMerger{false, false}; //< TFileMerger used to merge all buffers + std::mutex fMergeMutex; //< Mutex used to lock fMerger std::mutex fQueueMutex; //< Mutex used to lock fQueue - std::condition_variable fDataAvailable; //< Condition variable used to wait for data std::queue fQueue; //< Queue to which data is pushed and merged - std::unique_ptr fMergingThread; //< Worker thread that writes to disk std::vector> fAttachedFiles; //< Attached files - std::function fCallback; //< Callback for when data is removed from queue }; /** diff --git a/io/io/inc/TFile.h b/io/io/inc/TFile.h index 19f2c8adddc51..37ef71cddd053 100644 --- a/io/io/inc/TFile.h +++ b/io/io/inc/TFile.h @@ -29,6 +29,7 @@ #ifdef R__USE_IMT #include "ROOT/TRWSpinLock.hxx" +#include "ROOT/RConcurrentHashColl.hxx" #include #endif @@ -106,8 +107,9 @@ class TFile : public TDirectoryFile { TList *fOpenPhases; /// GetStreamerInfoListImpl(bool readSI); // Creating projects Int_t MakeProjectParMake(const char *packname, const char *filename); diff --git a/io/io/inc/TStreamerInfoActions.h b/io/io/inc/TStreamerInfoActions.h index 68b7ead967171..9de6aa8b67f6f 100644 --- a/io/io/inc/TStreamerInfoActions.h +++ b/io/io/inc/TStreamerInfoActions.h @@ -13,6 +13,7 @@ #define ROOT_TStreamerInfoActions #include +#include #include "TStreamerInfo.h" #include @@ -50,12 +51,17 @@ namespace TStreamerInfoActions { /// Base class of the Configurations for the member wise looping routines. class TLoopConfiguration { public: - TLoopConfiguration() {}; + TVirtualCollectionProxy *fProxy = nullptr; + public: + TLoopConfiguration() = default; + TLoopConfiguration(TVirtualCollectionProxy *proxy) : fProxy(proxy) {} + // virtual void PrintDebug(TBuffer &buffer, void *object) const; virtual ~TLoopConfiguration() {}; virtual void Print() const; virtual void *GetFirstAddress(void *start, const void *end) const = 0; - virtual TLoopConfiguration* Copy() = 0; // { return new TLoopConfiguration(*this); } + virtual TLoopConfiguration* Copy() const = 0; // { return new TLoopConfiguration(*this); } + virtual TVirtualCollectionProxy* GetCollectionProxy() const { return fProxy; } }; typedef TVirtualCollectionProxy::Next_t Next_t; @@ -127,10 +133,43 @@ namespace TStreamerInfoActions { ClassDef(TConfiguredAction,0); // A configured action }; + struct TIDNode; + using TIDs = std::vector; + + // Hold information about unfolded/extracted StreamerElement for + // a sub-object + struct TNestedIDs { + TNestedIDs() = default; + TNestedIDs(TStreamerInfo *info, Int_t offset) : fInfo(info), fOffset(offset) {} + + TStreamerInfo *fInfo = nullptr; ///< Not owned. + TVirtualArray *fOnfileObject = nullptr; ///< Not owned. + Int_t fOffset; + TIDs fIDs; + }; + + // A 'node' in the list of StreamerElement ID, either + // the index of the element in the current streamerInfo + // or a set of unfolded/extracted StreamerElement for a sub-object. + struct TIDNode { + TIDNode() = default; + TIDNode(Int_t id) : fElemID(id), fElement(nullptr), fInfo(nullptr) {} + TIDNode(TStreamerInfo *info, Int_t offset) : fElemID(-1), fElement(nullptr), fInfo(nullptr) { + fNestedIDs = std::make_unique(info, offset); + } + Int_t fElemID = -1; + TStreamerElement *fElement = nullptr; + TStreamerInfo *fInfo = nullptr; + std::unique_ptr fNestedIDs; + }; + typedef std::vector ActionContainer_t; class TActionSequence : public TObject { TActionSequence() {}; public: + struct SequencePtr; + using SequenceGetter_t = SequencePtr(*)(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *originalClass); + TActionSequence(TVirtualStreamerInfo *info, UInt_t maxdata) : fStreamerInfo(info), fLoopConfig(0) { fActions.reserve(maxdata); }; ~TActionSequence() { delete fLoopConfig; @@ -155,8 +194,80 @@ namespace TStreamerInfoActions { static TActionSequence *CreateWriteMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy); TActionSequence *CreateSubSequence(const std::vector &element_ids, size_t offset); + TActionSequence *CreateSubSequence(const TIDs &element_ids, size_t offset, SequenceGetter_t create); + void AddToSubSequence(TActionSequence *sequence, const TIDs &element_ids, Int_t offset, SequenceGetter_t create); + void Print(Option_t * = "") const; + // Maybe owner unique_ptr + struct SequencePtr { + TStreamerInfoActions::TActionSequence *fSequence = nullptr; + Bool_t fOwner = kFALSE; + + SequencePtr() = default; + SequencePtr(TStreamerInfoActions::TActionSequence *sequence, Bool_t owner) : fSequence(sequence), fOwner(owner) {} + + ~SequencePtr() { + if (fOwner) delete fSequence; + } + + // Accessor to the pointee. + TStreamerInfoActions::TActionSequence &operator*() const { + return *fSequence; + } + + // Accessor to the pointee + TStreamerInfoActions::TActionSequence *operator->() const { + return fSequence; + } + + // Return true is the pointee is not nullptr. + operator bool() { + return fSequence != nullptr; + } + }; + + // SequenceGetter_t implementations + + static SequencePtr ReadMemberWiseActionsCollectionGetter(TStreamerInfo *info, TVirtualCollectionProxy * /* collectionProxy */, TClass * /* originalClass */) { + auto seq = info->GetReadMemberWiseActions(kTRUE); + return {seq, kFALSE}; + } + static SequencePtr ConversionReadMemberWiseActionsViaProxyGetter(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *originalClass) { + auto seq = collectionProxy->GetConversionReadMemberWiseActions(originalClass, info->GetClassVersion()); + return {seq, kFALSE}; + } + static SequencePtr ReadMemberWiseActionsViaProxyGetter(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass * /* originalClass */) { + auto seq = collectionProxy->GetReadMemberWiseActions(info->GetClassVersion()); + return {seq, kFALSE}; + } + static SequencePtr ReadMemberWiseActionsCollectionCreator(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass * /* originalClass */) { + auto seq = TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(info,*collectionProxy); + return {seq, kTRUE}; + } + // Creator5() = Creator1; + static SequencePtr ReadMemberWiseActionsGetter(TStreamerInfo *info, TVirtualCollectionProxy * /* collectionProxy */, TClass * /* originalClass */) { + auto seq = info->GetReadMemberWiseActions(kFALSE); + return {seq, kFALSE}; + } + + static SequencePtr WriteMemberWiseActionsCollectionGetter(TStreamerInfo *info, TVirtualCollectionProxy * /* collectionProxy */, TClass * /* originalClass */) { + auto seq = info->GetWriteMemberWiseActions(kTRUE); + return {seq, kFALSE}; + } + static SequencePtr WriteMemberWiseActionsViaProxyGetter(TStreamerInfo *, TVirtualCollectionProxy *collectionProxy, TClass * /* originalClass */) { + auto seq = collectionProxy->GetWriteMemberWiseActions(); + return {seq, kFALSE}; + } + static SequencePtr WriteMemberWiseActionsCollectionCreator(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass * /* originalClass */) { + auto seq = TStreamerInfoActions::TActionSequence::CreateWriteMemberWiseActions(info,*collectionProxy); + return {seq, kTRUE}; + } + // Creator5() = Creator1; + static SequencePtr WriteMemberWiseActionsGetter(TStreamerInfo *info, TVirtualCollectionProxy * /* collectionProxy */, TClass * /* originalClass */) { + auto seq = info->GetWriteMemberWiseActions(kFALSE); + return {seq, kFALSE}; + } ClassDef(TActionSequence,0); }; diff --git a/io/io/src/TBufferMerger.cxx b/io/io/src/TBufferMerger.cxx index db9f87fd8c037..e48ed3d098df5 100644 --- a/io/io/src/TBufferMerger.cxx +++ b/io/io/src/TBufferMerger.cxx @@ -40,7 +40,6 @@ void TBufferMerger::Init(std::unique_ptr output) Error("TBufferMerger", "cannot write to output file"); fMerger.OutputFile(std::move(output)); - fMergingThread.reset(new std::thread([&]() { this->WriteOutputFile(); })); } TBufferMerger::~TBufferMerger() @@ -48,8 +47,8 @@ TBufferMerger::~TBufferMerger() for (const auto &f : fAttachedFiles) if (!f.expired()) Fatal("TBufferMerger", " TBufferMergerFiles must be destroyed before the server"); - this->Push(nullptr); - fMergingThread->join(); + if (!fQueue.empty()) + Merge(); } std::shared_ptr TBufferMerger::GetFile() @@ -66,18 +65,16 @@ size_t TBufferMerger::GetQueueSize() const return fQueue.size(); } -void TBufferMerger::RegisterCallback(const std::function &f) -{ - fCallback = f; -} - void TBufferMerger::Push(TBufferFile *buffer) { { std::lock_guard lock(fQueueMutex); + fBuffered += buffer->BufferSize(); fQueue.push(buffer); } - fDataAvailable.notify_one(); + + if (fBuffered > fAutoSave) + Merge(); } size_t TBufferMerger::GetAutoSave() const @@ -92,37 +89,25 @@ void TBufferMerger::SetAutoSave(size_t size) void TBufferMerger::Merge() { - fBuffered = 0; - fMerger.PartialMerge(); - fMerger.Reset(); - - if (fCallback) - fCallback(); -} - -void TBufferMerger::WriteOutputFile() -{ - std::unique_ptr buffer; - - while (true) { - std::unique_lock lock(fQueueMutex); - fDataAvailable.wait(lock, [this]() { return !this->fQueue.empty(); }); - - buffer.reset(fQueue.front()); - fQueue.pop(); - lock.unlock(); - - if (!buffer) - break; - - fBuffered += buffer->BufferSize(); - fMerger.AddAdoptFile(new TMemFile(fMerger.GetOutputFileName(), buffer->Buffer(), buffer->BufferSize(), "read")); - - if (fBuffered > fAutoSave) - Merge(); + if (fMergeMutex.try_lock()) { + std::queue queue; + { + std::lock_guard q(fQueueMutex); + std::swap(queue, fQueue); + fBuffered = 0; + } + + while (!queue.empty()) { + std::unique_ptr buffer{queue.front()}; + fMerger.AddAdoptFile( + new TMemFile(fMerger.GetOutputFileName(), buffer->Buffer(), buffer->BufferSize(), "READ")); + queue.pop(); + } + + fMerger.PartialMerge(); + fMerger.Reset(); + fMergeMutex.unlock(); } - - Merge(); } } // namespace Experimental diff --git a/io/io/src/TFile.cxx b/io/io/src/TFile.cxx index 4f86182b869dc..2fec4948cbca9 100644 --- a/io/io/src/TFile.cxx +++ b/io/io/src/TFile.cxx @@ -150,6 +150,7 @@ UInt_t TFile::fgOpenTimeout = TFile::kEternalTimeout; Bool_t TFile::fgOnlyStaged = 0; #ifdef R__USE_IMT ROOT::TRWSpinLock TFile::fgRwLock; +ROOT::Internal::RConcurrentHashColl TFile::fgTsSIHashes; #endif const Int_t kBEGIN = 100; @@ -1318,28 +1319,13 @@ const TList *TFile::GetStreamerInfoCache() } //////////////////////////////////////////////////////////////////////////////// -/// Read the list of TStreamerInfo objects written to this file. -/// -/// The function returns a TList. It is the user's responsibility -/// to delete the list created by this function. -/// -/// Note the list, in addition to TStreamerInfo object, contains sometimes -/// a TList named 'listOfRules' and containing the schema evolution rules -/// related to the file's content. -/// -/// Using the list, one can access additional information, e.g.: -/// ~~~{.cpp} -/// TFile f("myfile.root"); -/// auto list = f.GetStreamerInfoList(); -/// auto info = dynamic_cast(list->FindObject("MyClass")); -/// if (info) auto classversionid = info->GetClassVersion(); -/// delete list; -/// ~~~ -/// +/// See documentation of GetStreamerInfoList for more details. +/// This is an internal method which returns the list of streamer infos and also +/// information about the success of the operation. -TList *TFile::GetStreamerInfoList() +std::pair TFile::GetStreamerInfoListImpl(bool lookupSICache) { - if (fIsPcmFile) return 0; // No schema evolution for ROOT PCM files. + if (fIsPcmFile) return {nullptr, 1}; // No schema evolution for ROOT PCM files. TList *list = 0; if (fSeekInfo) { @@ -1352,8 +1338,19 @@ TList *TFile::GetStreamerInfoList() // ReadBuffer returns kTRUE in case of failure. Warning("GetRecordHeader","%s: failed to read the StreamerInfo data from disk.", GetName()); - return 0; + return {nullptr, 1}; } + +#ifdef R__USE_IMT + if (lookupSICache) { + if (!fgTsSIHashes.Insert(buf,fNbytesInfo)) { + if (gDebug > 0) Info("GetStreamerInfo", "The streamer info record for file %s has already been treated, skipping it.", GetName()); + return {nullptr, 0}; + } + } +#else + (void) lookupSICache; +#endif key->ReadKeyBuffer(buf); list = dynamic_cast(key->ReadObjWithBuffer(buffer)); if (list) list->SetOwner(); @@ -1363,13 +1360,44 @@ TList *TFile::GetStreamerInfoList() list = (TList*)Get("StreamerInfo"); //for versions 2.26 (never released) } + // Before giving up, try to invoke GetStreamerInfoList, in case we are + // in a call stack which started from an inherited class such as TXMLFile or + // TSQLFile + + if (!list) list = GetStreamerInfoList(); + if (list == 0) { Info("GetStreamerInfoList", "cannot find the StreamerInfo record in file %s", GetName()); - return 0; + return {nullptr, 1}; } - return list; + return {list, 0}; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Read the list of TStreamerInfo objects written to this file. +/// +/// The function returns a TList. It is the user's responsibility +/// to delete the list created by this function. +/// +/// Note the list, in addition to TStreamerInfo object, contains sometimes +/// a TList named 'listOfRules' and containing the schema evolution rules +/// related to the file's content. +/// +/// Using the list, one can access additional information, e.g.: +/// ~~~{.cpp} +/// TFile f("myfile.root"); +/// auto list = f.GetStreamerInfoList(); +/// auto info = dynamic_cast(list->FindObject("MyClass")); +/// if (info) auto classversionid = info->GetClassVersion(); +/// delete list; +/// ~~~ +/// + +TList *TFile::GetStreamerInfoList() +{ + return GetStreamerInfoListImpl(/*lookupSICache*/ false).first; } //////////////////////////////////////////////////////////////////////////////// @@ -3474,9 +3502,11 @@ Int_t TFile::MakeProjectParProofInf(const char *pack, const char *proofinf) void TFile::ReadStreamerInfo() { - TList *list = GetStreamerInfoList(); + auto listRetcode = GetStreamerInfoListImpl(/*lookupSICache*/ true); + TList *list = listRetcode.first; + auto retcode = listRetcode.second; if (!list) { - MakeZombie(); + if (retcode) MakeZombie(); return; } @@ -3710,10 +3740,6 @@ void TFile::WriteStreamerInfo() list.Add(&listOfRules); } - // always write with compression on - Int_t compress = fCompress; - fCompress = 1; - //free previous StreamerInfo record if (fSeekInfo) MakeFree(fSeekInfo,fSeekInfo+fNbytesInfo-1); //Create new key @@ -3725,7 +3751,6 @@ void TFile::WriteStreamerInfo() key.WriteFile(0); fClassIndex->fArray[0] = 0; - fCompress = compress; list.RemoveLast(); // remove the listOfRules. } diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 4f20da44d70ec..7d45f5a5b468a 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -998,7 +998,7 @@ namespace TStreamerInfoActions public: Long_t fIncrement; // Either a value to increase the cursor by and public: - TVectorLoopConfig(Long_t increment, Bool_t /* read */) : fIncrement(increment) {}; + TVectorLoopConfig(TVirtualCollectionProxy *proxy, Long_t increment, Bool_t /* read */) : TLoopConfiguration(proxy), fIncrement(increment) {}; //virtual void PrintDebug(TBuffer &buffer, void *); virtual ~TVectorLoopConfig() {}; void Print() const @@ -1013,23 +1013,20 @@ namespace TStreamerInfoActions return start; } - virtual TLoopConfiguration* Copy() { return new TVectorLoopConfig(*this); } + virtual TLoopConfiguration* Copy() const { return new TVectorLoopConfig(*this); } }; class TAssocLoopConfig : public TLoopConfiguration { // Base class of the Configurations used in member wise streaming. - protected: - public: - TVirtualCollectionProxy *fProxy; public: - TAssocLoopConfig(TVirtualCollectionProxy *proxy, Bool_t /* read */) : fProxy(proxy) {}; + TAssocLoopConfig(TVirtualCollectionProxy *proxy, Bool_t /* read */) : TLoopConfiguration(proxy) {}; //virtual void PrintDebug(TBuffer &buffer, void *); virtual ~TAssocLoopConfig() {}; void Print() const { printf("TAssocLoopConfig: proxy=%s\n",fProxy->GetCollectionClass()->GetName()); } - virtual TLoopConfiguration* Copy() { return new TAssocLoopConfig(*this); } + virtual TLoopConfiguration* Copy() const { return new TAssocLoopConfig(*this); } void* GetFirstAddress(void *start, const void * /* end */) const { @@ -1063,12 +1060,11 @@ namespace TStreamerInfoActions } } public: - TVirtualCollectionProxy *fProxy; TVirtualCollectionProxy::Next_t fNext; TVirtualCollectionProxy::CopyIterator_t fCopyIterator; TVirtualCollectionProxy::DeleteIterator_t fDeleteIterator; - TGenericLoopConfig(TVirtualCollectionProxy *proxy, Bool_t read) : fProxy(proxy), fNext(0), fCopyIterator(0), fDeleteIterator(0) + TGenericLoopConfig(TVirtualCollectionProxy *proxy, Bool_t read) : TLoopConfiguration(proxy), fNext(0), fCopyIterator(0), fDeleteIterator(0) { Init(read); } @@ -1077,7 +1073,7 @@ namespace TStreamerInfoActions { printf("TGenericLoopConfig: proxy=%s\n",fProxy->GetCollectionClass()->GetName()); } - virtual TLoopConfiguration* Copy() { return new TGenericLoopConfig(*this); } + virtual TLoopConfiguration* Copy() const { return new TGenericLoopConfig(*this); } void* GetFirstAddress(void *start_collection, const void *end_collection) const { @@ -1440,6 +1436,71 @@ namespace TStreamerInfoActions } }; + class TConfigurationPushDataCache : public TConfiguration { + // Configuration object for the PushDataCache case. + public: + TVirtualArray *fOnfileObject; + + TConfigurationPushDataCache(TVirtualStreamerInfo *info, TVirtualArray *onfileObject, Int_t offset) : + TConfiguration(info, -1, nullptr, offset), fOnfileObject(onfileObject) + {} + + virtual void Print() const { + TStreamerInfo *info = (TStreamerInfo*)fInfo; + if (fOnfileObject) + printf("StreamerInfoAction, class:%s, PushDataCache offset=%d\n", + info->GetClass()->GetName(), fOffset); + else + printf("StreamerInfoAction, class:%s, PopDataCache offset=%d\n", + info->GetClass()->GetName(), fOffset); + } + virtual void PrintDebug(TBuffer &buffer, void *object) const { + if (gDebug > 1) { + TStreamerInfo *info = (TStreamerInfo*)fInfo; + printf("StreamerInfoAction, class:%s, %sDataCache, bufpos=%d, arr=%p, offset=%d, onfileObject=%p\n", + info->GetClass()->GetName(), fOnfileObject ? "Push" : "Pop", buffer.Length(), object, fOffset, fOnfileObject); + + } + } + }; + + Int_t PushDataCache(TBuffer &b, void *, const TConfiguration *conf) + { + TConfigurationPushDataCache *config = (TConfigurationPushDataCache*)conf; + auto onfileObject = config->fOnfileObject; + + // onfileObject->SetSize(1); + b.PushDataCache( onfileObject ); + + return 0; + } + + Int_t PushDataCacheGenericCollection(TBuffer &b, void *, const void *, const TLoopConfiguration *loopconfig, const TConfiguration *conf) + { + TConfigurationPushDataCache *config = (TConfigurationPushDataCache*)conf; + auto onfileObject = config->fOnfileObject; + + TVirtualCollectionProxy *proxy = ((TGenericLoopConfig*)loopconfig)->fProxy; + UInt_t n = proxy->Size(); + + onfileObject->SetSize(n); + b.PushDataCache( onfileObject ); + + return 0; + } + + Int_t PopDataCache(TBuffer &b, void *, const TConfiguration *) + { + b.PopDataCache(); + return 0; + } + + Int_t PopDataCacheGenericCollection(TBuffer &b, void *, const void *, const TLoopConfiguration *, const TConfiguration *) + { + b.PopDataCache(); + return 0; + } + class TConfigurationUseCache : public TConfiguration { // Configuration object for the UseCache case. public: @@ -1469,7 +1530,6 @@ namespace TStreamerInfoActions } }; - INLINE_TEMPLATE_ARGS Int_t UseCache(TBuffer &b, void *addr, const TConfiguration *conf) { TConfigurationUseCache *config = (TConfigurationUseCache*)conf; @@ -1506,7 +1566,7 @@ namespace TStreamerInfoActions UInt_t n = (((void**)end)-((void**)start)); info->ReadBufferSkip(b,&ptr,config->fCompInfo,conf->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0); } else { - TVectorLoopConfig cached_config( cached->fClass->Size(), /* read */ kTRUE ); + TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE ); void *cached_start = (*cached)[0]; void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement; config->fAction(b,cached_start,cached_end,&cached_config); @@ -1532,7 +1592,7 @@ namespace TStreamerInfoActions UInt_t n = (((char*)end)-((char*)start))/((TVectorLoopConfig*)loopconf)->fIncrement; info->ReadBufferSkip(b,&ptr,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0); } else { - TVectorLoopConfig cached_config( cached->fClass->Size(), /* read */ kTRUE ); + TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE ); void *cached_start = (*cached)[0]; void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement; config->fAction(b,cached_start,cached_end,&cached_config); @@ -1559,7 +1619,7 @@ namespace TStreamerInfoActions UInt_t n = proxy->Size(); info->ReadBufferSkip(b, *proxy,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0); } else { - TVectorLoopConfig cached_config( cached->fClass->Size(), /* read */ kTRUE ); + TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE ); void *cached_start = (*cached)[0]; void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement; config->fAction(b,cached_start,cached_end,&cached_config); @@ -3821,14 +3881,14 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector. Long_t increment = proxy.GetIncrement(); - sequence->fLoopConfig = new TVectorLoopConfig(increment, /* read */ kTRUE); + sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE); } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLunorderedset || proxy.GetCollectionType() == ROOT::kSTLmultiset || proxy.GetCollectionType() == ROOT::kSTLunorderedmultiset || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap || proxy.GetCollectionType() == ROOT::kSTLunorderedmap || proxy.GetCollectionType() == ROOT::kSTLunorderedmultimap) { Long_t increment = proxy.GetIncrement(); - sequence->fLoopConfig = new TVectorLoopConfig(increment, /* read */ kTRUE); + sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE); // sequence->fLoopConfig = new TAssocLoopConfig(proxy); } else { sequence->fLoopConfig = new TGenericLoopConfig(&proxy, /* read */ kTRUE); @@ -3852,13 +3912,14 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr } TStreamerBase *baseEl = dynamic_cast(element); if (baseEl) { - if (baseEl->GetErrorMessage()[0]) { + if (!baseEl->TestBit(TStreamerElement::kWarned) && baseEl->GetErrorMessage()[0]) { // There was a problem with the checksum, the user likely did not // increment the version number of the derived class when the // base class changed. Since we will be member wise streaming // this class, let's warn the user that something is wrong. ::Warning("CreateReadMemberWiseActions","%s", baseEl->GetErrorMessage()); + baseEl->SetBit(TStreamerElement::kWarned); } } @@ -3937,7 +3998,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector. Long_t increment = proxy.GetIncrement(); - sequence->fLoopConfig = new TVectorLoopConfig(increment, /* read */ kFALSE); + sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kFALSE); /*} else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) { @@ -4110,6 +4171,83 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr return sequence; } +void TStreamerInfoActions::TActionSequence::AddToSubSequence(TStreamerInfoActions::TActionSequence *sequence, + const TStreamerInfoActions::TIDs &element_ids, + Int_t offset, + TStreamerInfoActions::TActionSequence::SequenceGetter_t create) +{ + for(UInt_t id = 0; id < element_ids.size(); ++id) { + if ( element_ids[id].fElemID < 0 ) { + if (element_ids[id].fNestedIDs) { + auto original = create(element_ids[id].fNestedIDs->fInfo, + sequence->fLoopConfig ? sequence->fLoopConfig->GetCollectionProxy() : nullptr, + nullptr); + if (element_ids[id].fNestedIDs->fOnfileObject) { + auto conf = new TConfigurationPushDataCache(element_ids[id].fNestedIDs->fInfo, element_ids[id].fNestedIDs->fOnfileObject, offset); + if ( sequence->fLoopConfig ) + sequence->AddAction( PushDataCacheGenericCollection, conf ); + else + sequence->AddAction( PushDataCache, conf ); + } + + original->AddToSubSequence(sequence, element_ids[id].fNestedIDs->fIDs, element_ids[id].fNestedIDs->fOffset, create); + + if (element_ids[id].fNestedIDs->fOnfileObject) + sequence->AddAction( PopDataCache, + new TConfigurationPushDataCache(element_ids[id].fNestedIDs->fInfo, nullptr, element_ids[id].fNestedIDs->fOffset) ); + } else { + TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end(); + for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin(); + iter != end; + ++iter) + { + TConfiguration *conf = iter->fConfiguration->Copy(); + if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache)) + conf->AddToOffset(offset); + sequence->AddAction( iter->fAction, conf ); + } + } + } else { + int localIndex = 0; + TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end(); + for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin(); + iter != end; + ++iter) { + // fprintf(stderr, "With element_ids[%d] For %s comparing act[%d/%zu] %d to %d for %p vs %p %s\n", + // id, + // iter->fConfiguration->fInfo->GetName(), + // localIndex, fActions.size(), + // iter->fConfiguration->fElemId, + // (UInt_t)element_ids[id].fElemID, iter->fConfiguration->fInfo, + // element_ids[id].fInfo, + // element_ids[id].fInfo ? element_ids[id].fInfo->GetName() : "nullptr" ); + ++localIndex; + if ( iter->fConfiguration->fElemId == (UInt_t)element_ids[id].fElemID ) { + TConfiguration *conf = iter->fConfiguration->Copy(); + if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache)) + conf->AddToOffset(offset); + sequence->AddAction( iter->fAction, conf ); + } + } + } + } +} + +TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateSubSequence(const TIDs &element_ids, size_t offset, + TStreamerInfoActions::TActionSequence::SequenceGetter_t create) +{ + // Create a sequence containing the subset of the action corresponding to the SteamerElement whose ids is contained in the vector. + // 'offset' is the location of this 'class' within the object (address) that will be passed to ReadBuffer when using this sequence. + + TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(fStreamerInfo,element_ids.size()); + + sequence->fLoopConfig = fLoopConfig ? fLoopConfig->Copy() : 0; + + AddToSubSequence(sequence, element_ids, offset, create); + + return sequence; +} + TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateSubSequence(const std::vector &element_ids, size_t offset) { // Create a sequence containing the subset of the action corresponding to the SteamerElement whose ids is contained in the vector. diff --git a/io/io/src/TStreamerInfoReadBuffer.cxx b/io/io/src/TStreamerInfoReadBuffer.cxx index 17a9a0eaa5b04..68ce0948f4064 100644 --- a/io/io/src/TStreamerInfoReadBuffer.cxx +++ b/io/io/src/TStreamerInfoReadBuffer.cxx @@ -543,6 +543,7 @@ Int_t TStreamerInfo::ReadBufferArtificial(TBuffer &b, const T &arr, TVirtualArray *objarr = ((TBufferFile&)b).PeekDataCache(); if (objarr) { obj.fClass = objarr->fClass; + for(Int_t k=0; kGetObjectAt(k); readfunc(arr[k]+eoffset, &obj); diff --git a/io/io/src/TStreamerInfoWriteBuffer.cxx b/io/io/src/TStreamerInfoWriteBuffer.cxx index 04c3d34063ff8..9b6b406990c4e 100644 --- a/io/io/src/TStreamerInfoWriteBuffer.cxx +++ b/io/io/src/TStreamerInfoWriteBuffer.cxx @@ -169,10 +169,10 @@ Int_t TStreamerInfo::WriteBufferAux(TBuffer &b, const T &arr, // next element (the one for the rule itself). if (aElement->TestBit(TStreamerElement::kRepeat)) continue; ioffset = eoffset+compinfo[i]->fOffset; + continue; } } - if (gDebug > 1) { printf("WriteBuffer, class:%s, name=%s, fType[%d]=%d, %s, " "bufpos=%d, arr=%p, offset=%d\n", diff --git a/io/io/test/TBufferMerger.cxx b/io/io/test/TBufferMerger.cxx index 4707fa987f7dd..ec6839fb188c0 100644 --- a/io/io/test/TBufferMerger.cxx +++ b/io/io/test/TBufferMerger.cxx @@ -219,171 +219,3 @@ TEST(TBufferMerger, CheckTreeFillResults) remove("tbuffermerger_sequential.root"); remove("tbuffermerger_parallel.root"); } - -TEST(TBufferMerger, RegisterCallbackThreads) -{ - const char *testfile = "tbuffermerger_threads.root"; - int events = 1000; - int events_per_task = 50; - int tasks = events / events_per_task; - std::atomic launched(0); - std::atomic processed(0); - - { - ROOT::EnableThreadSafety(); - TBufferMerger merger(testfile); - - /* define a task: create and push some events */ - auto task = [&]() { - auto myfile = merger.GetFile(); - auto mytree = new TTree("mytree", "mytree"); - - mytree->ResetBit(kMustCleanup); - - int n = 1; - mytree->Branch("n", &n, "n/I"); - - for (int i = 0; i < events_per_task; ++i) - mytree->Fill(); - - myfile->Write(); - - processed += events_per_task; - }; - - std::vector workers; - - /* callback: launches new tasks when called */ - merger.RegisterCallback([&]() { - int i = 0; - while (launched < tasks && ++i <= 2) { - workers.emplace_back(task); - ++launched; - } - }); - - launched = 1; - workers.emplace_back(task); - - /* wait until all tasks have been launched */ - while (launched != tasks) - ; - - /* wait until all tasks have finished running */ - for (auto &w : workers) - w.join(); - - ASSERT_EQ(processed, events); - } - - ASSERT_TRUE(FileExists(testfile)); - - /* open file and check data integrity */ - { - TFile f(testfile); - auto t = (TTree *)f.Get("mytree"); - - int n, sum = 0; - int nentries = (int)t->GetEntries(); - - EXPECT_EQ(nentries, events); - - t->SetBranchAddress("n", &n); - - for (int i = 0; i < nentries; ++i) { - t->GetEntry(i); - sum += n; - } - - EXPECT_EQ(sum, events); - } - - remove(testfile); -} - -TEST(TBufferMerger, RegisterCallbackTasks) -{ - using namespace ROOT::Experimental; - - const char *testfile = "tbuffermerger_tasks.root"; - - std::mutex m; - int events = 1000; - int events_per_task = 50; - int tasks = events / events_per_task; - volatile int launched = 0; - volatile int processed = 0; - - { -#ifdef R__USE_IMT - ROOT::EnableImplicitMT(); -#endif - TBufferMerger merger(testfile); - - /* define a task: create and push some events */ - auto task = [&]() { - auto myfile = merger.GetFile(); - auto mytree = new TTree("mytree", "mytree"); - - mytree->ResetBit(kMustCleanup); - - int n = 1; - mytree->Branch("n", &n, "n/I"); - - for (int i = 0; i < events_per_task; ++i) - mytree->Fill(); - - myfile->Write(); - - std::lock_guard lk(m); - processed += events_per_task; - }; - - TTaskGroup tg; - - /* callback: launches new tasks when called */ - merger.RegisterCallback([&]() { - int i = 0; - while (launched < tasks && ++i <= 2) { - tg.Run(task); - ++launched; - } - }); - - launched = 1; - tg.Run(task); - - /* wait until all tasks have been launched */ - while (launched != tasks) - ; - - /* wait until all tasks have finished running */ - tg.Wait(); - - ASSERT_EQ(processed, events); - } - - ASSERT_TRUE(FileExists(testfile)); - - /* open file and check data integrity */ - { - TFile f(testfile); - auto t = (TTree *)f.Get("mytree"); - - int n, sum = 0; - int nentries = (int)t->GetEntries(); - - EXPECT_EQ(nentries, events); - - t->SetBranchAddress("n", &n); - - for (int i = 0; i < nentries; ++i) { - t->GetEntry(i); - sum += n; - } - - EXPECT_EQ(sum, events); - } - - remove(testfile); -} diff --git a/io/xml/src/TXMLEngine.cxx b/io/xml/src/TXMLEngine.cxx index f0a5a82e946b0..3f5150393dd5b 100644 --- a/io/xml/src/TXMLEngine.cxx +++ b/io/xml/src/TXMLEngine.cxx @@ -286,19 +286,20 @@ class TXMLInputStream { //////////////////////////////////////////////////////////////////////////// /// Allocate more data for the buffer, preserving content - Bool_t ExpandStream() + Bool_t ExpandStream(char *&curr) { if (EndOfFile()) return kFALSE; fBufSize *= 2; int curlength = fMaxAddr - fBuf; char *newbuf = (char *)realloc(fBuf, fBufSize); - if (newbuf == 0) + if (!newbuf) return kFALSE; fMaxAddr = newbuf + (fMaxAddr - fBuf); fCurrent = newbuf + (fCurrent - fBuf); fLimitAddr = newbuf + (fLimitAddr - fBuf); + curr = newbuf + (curr - fBuf); fBuf = newbuf; int len = DoRead(fMaxAddr, fBufSize - curlength); @@ -382,10 +383,11 @@ class TXMLInputStream { Bool_t CheckFor(const char *str) { int len = strlen(str); - while (fCurrent + len > fMaxAddr) - if (!ExpandStream()) - return kFALSE; char *curr = fCurrent; + while (curr + len > fMaxAddr) { + if (!ExpandStream(curr)) + return kFALSE; + } while (*str != 0) if (*str++ != *curr++) return kFALSE; @@ -405,7 +407,7 @@ class TXMLInputStream { do { curr++; while (curr + len > fMaxAddr) - if (!ExpandStream()) + if (!ExpandStream(curr)) return -1; char *chk0 = curr; const char *chk = str; @@ -447,7 +449,7 @@ class TXMLInputStream { do { curr++; if (curr >= fMaxAddr) - if (!ExpandStream()) + if (!ExpandStream(curr)) return 0; symb = (unsigned char)*curr; ok = GoodStartSymbol(symb) || ((symb >= '0') && (symb <= '9')) || (symb == ':') || (symb == '-') || @@ -470,7 +472,7 @@ class TXMLInputStream { return curr - fCurrent; curr++; if (curr >= fMaxAddr) - if (!ExpandStream()) + if (!ExpandStream(curr)) return -1; } return -1; @@ -479,18 +481,18 @@ class TXMLInputStream { //////////////////////////////////////////////////////////////////////////// /// locate attribute value, returns length (or 0 if fails) - Int_t LocateValue(char *start, bool withequalsign = true) + Int_t LocateValue(unsigned curr_offset, bool withequalsign = true) { - char *curr = start; + char *curr = fCurrent + curr_offset; if (curr >= fMaxAddr) - if (!ExpandStream()) + if (!ExpandStream(curr)) return 0; if (withequalsign) { if (*curr != '=') return 0; curr++; if (curr >= fMaxAddr) - if (!ExpandStream()) + if (!ExpandStream(curr)) return 0; } if ((*curr != '\"') && (*curr != '\'')) @@ -499,10 +501,10 @@ class TXMLInputStream { do { curr++; if (curr >= fMaxAddr) - if (!ExpandStream()) + if (!ExpandStream(curr)) return 0; if (*curr == quote) - return curr - start + 1; + return curr - (fCurrent + curr_offset) + 1; } while (curr < fMaxAddr); return 0; } @@ -1998,14 +2000,13 @@ XMLNodePointer_t TXMLEngine::ReadNode(XMLNodePointer_t xmlparent, TXMLInputStrea is_system = kTRUE; } - char *valuestart = inp->fCurrent; - Int_t valuelen = inp->LocateValue(valuestart, false); + Int_t valuelen = inp->LocateValue(0, false); if (valuelen < 2) { resvalue = -13; return 0; } - TString entity_value(valuestart + 1, valuelen - 2); + TString entity_value(inp->fCurrent + 1, valuelen - 2); if (!inp->ShiftCurrent(valuelen)) { resvalue = -13; @@ -2170,9 +2171,7 @@ XMLNodePointer_t TXMLEngine::ReadNode(XMLNodePointer_t xmlparent, TXMLInputStrea return 0; } - char *valuestart = inp->fCurrent + attrlen; - - int valuelen = inp->LocateValue(valuestart, true); + int valuelen = inp->LocateValue(attrlen, true); if (valuelen < 3) { resvalue = -7; return 0; @@ -2185,7 +2184,7 @@ XMLNodePointer_t TXMLEngine::ReadNode(XMLNodePointer_t xmlparent, TXMLInputStrea attrname += attrlen; *attrname = 0; attrname++; - UnpackSpecialCharacters(attrname, valuestart + 2, valuelen - 3); + UnpackSpecialCharacters(attrname, inp->fCurrent + attrlen + 2, valuelen - 3); if (!inp->ShiftCurrent(attrlen + valuelen)) return 0; diff --git a/main/src/hadd.cxx b/main/src/hadd.cxx index d1477e3cbb7a5..1921baafe88fb 100644 --- a/main/src/hadd.cxx +++ b/main/src/hadd.cxx @@ -504,8 +504,8 @@ int main( int argc, char **argv ) std::cerr << "hadd skipping file with error: " << argv[i] << std::endl; } else { std::cerr << "hadd exiting due to error in " << argv[i] << std::endl; + return kFALSE; } - return kFALSE; } } return mergeFiles(merger); diff --git a/math/mathcore/test/stress/testSMatrix.cxx b/math/mathcore/test/stress/testSMatrix.cxx index 2f1af1f7b1418..68304fecdaeac 100644 --- a/math/mathcore/test/stress/testSMatrix.cxx +++ b/math/mathcore/test/stress/testSMatrix.cxx @@ -104,7 +104,7 @@ TYPED_TEST_P(SMatrixTest, TestSMatrix) name = name0 + "," + this->GetRepSName() + ">"; typeName = "ROOT::Math::" + name0 + "," + this->GetRepName32() + ">"; - estSize = this->fNGen * 4 * this->fDim + 10000; + estSize = this->fNGen * 4 * this->fDim + 60158; scale = 0.1 / std::numeric_limits::epsilon(); fsize32 = this->fVectorTest.TestWrite(this->v1, typeName); EXPECT_TRUE(IsNear(name + " write", fsize32, estSize, scale)); diff --git a/math/vecops/inc/ROOT/RVec.hxx b/math/vecops/inc/ROOT/RVec.hxx index 06edf7f2d73aa..239904b5fd771 100644 --- a/math/vecops/inc/ROOT/RVec.hxx +++ b/math/vecops/inc/ROOT/RVec.hxx @@ -58,7 +58,7 @@ the manipulation and analysis of the data in the RVec. ## Table of Contents - [Example](#example) - [Owning and adopting memory](#owningandadoptingmemory) -- [Usage in combination with TDataFrame](#usagetdataframe) +- [Usage in combination with RDataFrame](#usagetdataframe) ## Example Suppose to have an event featuring a collection of muons with a certain pseudorapidity, @@ -85,18 +85,14 @@ for (size_t i=0; i < size; ++i) { These operations become straightforward with RVec - we just need to *write what we mean*: ~~~{.cpp} -RVec mu_charge {1, 1, -1, -1, -1, 1, 1, -1}; -RVec mu_pt {56, 45, 32, 24, 12, 8, 7, 6.2}; -RVec mu_eta {3.1, -.2, -1.1, 1, 4.1, 1.6, 2.4, -.5}; - -auto goodMuons_pt = mu_pt[ (mu_pt > 10.f && abs(mu_eta) <= 2.f && mu_charge == -1) +auto goodMuons_pt = mu_pt[ (mu_pt > 10.f && abs(mu_eta) <= 2.f && mu_charge == -1) ] ~~~ Now the clean collection of transverse momenta can be used within the rest of the data analysis, for example to fill a histogram. ## Owning and adopting memory RVec has contiguous memory associated to it. It can own it or simply adopt it. In the latter case, -it can be constructed with the address of the memory associated to it and its lenght. For example: +it can be constructed with the address of the memory associated to it and its length. For example: ~~~{.cpp} std::vector myStlVec {1,2,3}; RVec myRVec(myStlVec.data(), myStlVec.size()); @@ -106,8 +102,8 @@ If any method which implies a re-allocation is called, e.g. *emplace_back* or *r memory is released and new one is allocated. The previous content is copied in the new memory and preserved. -## Usage in combination with TDataFrame -TDataFrame leverages internally RVecs. Suppose to have a dataset stored in a +## Usage in combination with RDataFrame +RDataFrame leverages internally RVecs. Suppose to have a dataset stored in a TTree which holds these columns (here we choose C arrays to represent the collections, they could be as well std::vector instances): ~~~{.bash} @@ -120,7 +116,7 @@ Suppose you'd like to plot in a histogram the transverse momenta of all particle for which the energy is greater than 200 MeV. The code required would just be: ~~~{.cpp} -TDataFrame d("mytree", "myfile.root"); +RDataFrame d("mytree", "myfile.root"); using doubles = RVec; auto cutPt = [](doubles &pxs, doubles &pys, doubles &Es) { auto all_pts = sqrt(pxs * pxs + pys * pys); @@ -134,7 +130,7 @@ hpt->Draw(); ~~~ And if you'd like to express your selection as a string: ~~~{.cpp} -TDataFrame d("mytree", "myfile.root"); +RDataFrame d("mytree", "myfile.root"); auto hpt = d.Define("pt", "sqrt(pxs * pxs + pys * pys)[E>200]") .Histo1D("pt"); hpt->Draw(); diff --git a/net/http/CMakeLists.txt b/net/http/CMakeLists.txt index dda8f91179169..40f095b7e01a3 100644 --- a/net/http/CMakeLists.txt +++ b/net/http/CMakeLists.txt @@ -38,12 +38,6 @@ endif() if(ssl) include_directories(${OPENSSL_INCLUDE_DIR}) - if(OPENSSL_VERSION AND (${OPENSSL_VERSION} VERSION_EQUAL "1.1")) - MESSAGE( STATUS "Use SSL API VERSION 1.1 for civetweb" ) - set(_ssl11 "ON") - endif() -else() - set(OPENSSL_LIBRARIES) endif() # look for the realtime extensions library and use it if it exists @@ -55,17 +49,18 @@ endif() ROOT_STANDARD_LIBRARY_PACKAGE(RHTTP HEADERS ${headers} SOURCES ${sources} - LIBRARIES ${SYSLIBS} ZLIB::ZLIB ${RT_LIBRARIES} ${FASTCGI_LIBRARY} - ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} + LIBRARIES ZLIB::ZLIB ${RT_LIBRARIES} ${FASTCGI_LIBRARY} ${CMAKE_DL_LIBS} DEPENDENCIES Thread RIO) target_compile_definitions(RHTTP PUBLIC -DUSE_WEBSOCKET) if(ssl) - target_compile_definitions(RHTTP PUBLIC -DNO_SSL_DL) - if (_ssl11) - target_compile_definitions(RHTTP PUBLIC -DOPENSSL_API_1_1) - endif() + target_compile_definitions(RHTTP PUBLIC -DNO_SSL_DL) + target_link_libraries(RHTTP ${OPENSSL_LIBRARIES}) + if(OPENSSL_VERSION AND (${OPENSSL_VERSION} VERSION_EQUAL "1.1")) + MESSAGE(STATUS "Use SSL API VERSION 1.1 for civetweb") + target_compile_definitions(RHTTP PUBLIC -DOPENSSL_API_1_1) + endif() endif() if(_nofcgi) diff --git a/net/net/CMakeLists.txt b/net/net/CMakeLists.txt index 333255d8a07f7..1cbe26faa6555 100644 --- a/net/net/CMakeLists.txt +++ b/net/net/CMakeLists.txt @@ -5,14 +5,12 @@ ROOT_GLOB_HEADERS(headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/inc inc/*.h) ROOT_GLOB_SOURCES(sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/src src/*.cxx) -if(NOT ssl) - list(REMOVE_ITEM headers TSSLSocket.h) - list(REMOVE_ITEM sources TSSLSocket.cxx) - set(ssllib) -else() - set(ssllib ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS}) +if(ssl) add_definitions(-DR__SSL) include_directories(${OPENSSL_INCLUDE_DIR}) +else() + list(REMOVE_ITEM headers TSSLSocket.h) + list(REMOVE_ITEM sources TSSLSocket.cxx) endif() if(NOT ssl OR NOT CRYPTLIBS) @@ -31,6 +29,8 @@ ROOT_STANDARD_LIBRARY_PACKAGE(Net HEADERS ${headers} SOURCES ${sources} DICTIONARY_OPTIONS "-writeEmptyRootPCM" - LIBRARIES ${ssllib} ${CRYPTLIBS} - DEPENDENCIES RIO BUILTINS OPENSSL) + DEPENDENCIES RIO) +if(ssl) + target_link_libraries(Net ${OPENSSL_LIBRARIES} ${CRYPTLIBS}) +endif() diff --git a/net/netxng/src/TNetXNGFile.cxx b/net/netxng/src/TNetXNGFile.cxx index 59655d7a35c0b..36829575ebfb2 100644 --- a/net/netxng/src/TNetXNGFile.cxx +++ b/net/netxng/src/TNetXNGFile.cxx @@ -132,6 +132,11 @@ TNetXNGFile::TNetXNGFile(const char *url, { using namespace XrdCl; + // Set the log level + TString val = gSystem->Getenv("XRD_LOGLEVEL"); + if (val.IsNull()) val = gEnv->GetValue("NetXNG.Debug", ""); + if (!val.IsNull()) XrdCl::DefaultEnv::SetLogLevel(val.Data()); + // Remove any anchor from the url. It may have been used by the base TFile // constructor to setup a TArchiveFile but we should not pass it to the xroot // client as a part of the filename diff --git a/net/rootd/CMakeLists.txt b/net/rootd/CMakeLists.txt index 45887dff1de18..67d1cd05f1ba6 100644 --- a/net/rootd/CMakeLists.txt +++ b/net/rootd/CMakeLists.txt @@ -4,7 +4,6 @@ ############################################################################ ROOT_EXECUTABLE(rootd *.cxx ${CMAKE_SOURCE_DIR}/core/clib/src/strlcpy.c - LIBRARIES rpdutil rsa ${GLOBUS_LIBRARIES} ${OPENSSL_LIBRARIES} ${CRYPTLIBS} - BUILTINS OPENSSL) + LIBRARIES rpdutil rsa ${GLOBUS_LIBRARIES} ${OPENSSL_LIBRARIES}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../rpdutils/res) diff --git a/net/rpdutils/CMakeLists.txt b/net/rpdutils/CMakeLists.txt index 1c2143651c297..6a66e4aee7f36 100644 --- a/net/rpdutils/CMakeLists.txt +++ b/net/rpdutils/CMakeLists.txt @@ -35,8 +35,10 @@ endif() #---static library needed for rootd and proofd -------------------------------------------- add_library(rpdutil STATIC ${rpdutilsrcs}) +target_link_libraries(rpdutil INTERFACE ${CRYPTLIBS}) set_property(TARGET rpdutil PROPERTY POSITION_INDEPENDENT_CODE ON) add_dependencies(rpdutil move_headers) -ROOT_LINKER_LIBRARY(SrvAuth rpdutils.cxx ssh.cxx LIBRARIES rpdutil rsa ${CRYPTLIBS} ${GLOBUS_LIBRARIES} ${OPENSSL_LIBRARIES} DEPENDENCIES Net BUILTINS OPENSSL) +ROOT_LINKER_LIBRARY(SrvAuth rpdutils.cxx ssh.cxx + LIBRARIES rpdutil rsa ${GLOBUS_LIBRARIES} DEPENDENCIES Net) diff --git a/test/ios/RootBrowser/AxisFontInspector.h b/test/ios/RootBrowser/AxisFontInspector.h deleted file mode 100644 index 0d36edc185eb5..0000000000000 --- a/test/ios/RootBrowser/AxisFontInspector.h +++ /dev/null @@ -1,25 +0,0 @@ -#import "ObjectInspectorComponent.h" - -namespace ROOT_IOSObjectInspector { - -enum AxisFontInspectorMode{ -afimTitleFont, -afimLabelFont -}; - -} - -@interface AxisFontInspector : UIViewController { -@private - __weak IBOutlet UILabel *titleLabel; - __weak IBOutlet UIPickerView *fontPicker; -} - -- (id)initWithNibName : (NSString *)nibName mode : (ROOT_IOSObjectInspector::AxisFontInspectorMode)m; - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; - -- (IBAction) back; - -@end diff --git a/test/ios/RootBrowser/AxisFontInspector.mm b/test/ios/RootBrowser/AxisFontInspector.mm deleted file mode 100644 index 52334e98c4d87..0000000000000 --- a/test/ios/RootBrowser/AxisFontInspector.mm +++ /dev/null @@ -1,202 +0,0 @@ -#import - -#import "ROOTObjectController.h" -#import "AxisFontInspector.h" - -//C++ (ROOT) imports. -#import "TObject.h" -#import "TAxis.h" - -namespace { - -const CGFloat defaultCellW = 180.f; -const CGFloat defaultCellH = 44.f; - -NSString *fixedFonts[] = //These are the strings with font names to use with UILabel. - { - @"TimesNewRomanPS-ItalicMT", - @"TimesNewRomanPS-BoldMT", - @"TimesNewRomanPS-BoldItalicMT", - @"Helvetica", - @"Helvetica-Oblique", - @"Helvetica-Bold", - @"Helvetica-BoldOblique", - @"Courier", - @"Courier-Oblique", - @"Courier-Bold", - @"Courier-BoldOblique", - @"symbol",//No custom fonts yet. - @"TimesNewRomanPSMT" - }; - -NSString *fixedFontNames[] = //these are the strings to show in a picker view. - { - @"Times New Roman", - @"Times New Roman", - @"Times New Roman", - @"Helvetica", - @"Helvetica", - @"Helvetica", - @"Helvetica", - @"Courier", - @"Courier", - @"Courier", - @"Courier", - @"Symbol",//No custom fonts yet. - @"Times New Roman" - }; - -const unsigned nFixedFonts = sizeof fixedFonts / sizeof fixedFonts[0]; - -} - -@implementation AxisFontInspector { - ROOT_IOSObjectInspector::AxisFontInspectorMode mode; - __weak ROOTObjectController *controller; - TAxis *object; -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibName mode : (ROOT_IOSObjectInspector::AxisFontInspectorMode)m -{ - using namespace ROOT_IOSObjectInspector; - - self = [super initWithNibName : nibName bundle : nil]; - - [self view]; - - if (self) { - // Custom initialization - mode = m; - if (mode == afimTitleFont) - titleLabel.text = @"Title font:"; - else if (mode == afimLabelFont) - titleLabel.text = @"Label font:"; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - using namespace ROOT_IOSObjectInspector; - - object = dynamic_cast(o); - Font_t fontIndex = 0; - - if (mode == afimTitleFont) - fontIndex = object->GetTitleFont() / 10 - 1; - else if (mode == afimLabelFont) - fontIndex = object->GetLabelFont() / 10 - 1; - - if (fontIndex < 0 || fontIndex > nFixedFonts) - fontIndex = 0; - - [fontPicker selectRow : fontIndex inComponent : 0 animated : NO]; -} - -#pragma mark - color/pattern picker's dataSource. -//____________________________________________________________________________________________________ -- (CGFloat)pickerView : (UIPickerView *)pickerView widthForComponent : (NSInteger)component -{ - return defaultCellW; -} - -//____________________________________________________________________________________________________ -- (CGFloat)pickerView : (UIPickerView *)pickerView rowHeightForComponent : (NSInteger)component -{ - return defaultCellH; -} - -//____________________________________________________________________________________________________ -- (NSInteger)pickerView : (UIPickerView *)pickerView numberOfRowsInComponent : (NSInteger)component -{ - return nFixedFonts; -} - -//____________________________________________________________________________________________________ -- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView -{ - return 1; -} - -#pragma mark color/pattern picker's delegate. - -//____________________________________________________________________________________________________ -- (UIView *) pickerView : (UIPickerView *)pickerView viewForRow : (NSInteger)row forComponent : (NSInteger)component reusingView : (UIView *)view -{ - UILabel *label = [[UILabel alloc] initWithFrame : CGRectMake(0.f, 0.f, defaultCellW, defaultCellH)]; - label.text = fixedFontNames[row]; - label.font = [UIFont fontWithName : fixedFonts[row] size : 14.f]; - -#ifdef __IPHONE_6_0 - label.textAlignment = NSTextAlignmentCenter; -#else - label.textAlignment = UITextAlignmentCenter; -#endif - - label.backgroundColor = [UIColor colorWithPatternImage : [UIImage imageNamed : @"text_cell_bkn.png"]]; - - return label; -} - -//____________________________________________________________________________________________________ -- (void) pickerView : (UIPickerView *)thePickerView didSelectRow : (NSInteger)row inComponent : (NSInteger)component -{ - using namespace ROOT_IOSObjectInspector; - - const Font_t fontIndex = (row + 1) * 10; - if (mode == afimTitleFont) - object->SetTitleFont(fontIndex); - else if (mode == afimLabelFont) - object->SetLabelFont(fontIndex); - - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (void) back -{ - [self.navigationController popViewControllerAnimated : YES]; -} - -@end diff --git a/test/ios/RootBrowser/AxisFontInspector.xib b/test/ios/RootBrowser/AxisFontInspector.xib deleted file mode 100644 index e21afd32d2490..0000000000000 --- a/test/ios/RootBrowser/AxisFontInspector.xib +++ /dev/null @@ -1,338 +0,0 @@ - - - - 1056 - 11B26 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBUIPickerView - IBUIButton - IBUIView - IBUILabel - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 292 - {{20, 26}, {211, 21}} - - - - _NS:327 - - 3 - MCAwAA - - NO - YES - 7 - NO - IBIPadFramework - - - 1 - MCAwIDAAA - - - 1 - 10 - 1 - - - - 290 - {{25, 61}, {200, 216}} - - - - _NS:191 - IBIPadFramework - YES - - - - 292 - {{35, 285}, {180, 50}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - Helvetica-Bold - 15 - 16 - - 1 - Back - - 3 - MQA - - - - 3 - MC41AA - - - NSImage - back_btn.png - - - - {250, 351} - - - - _NS:195 - - IBIPadFramework - - - - - YES - - - dataSource - - - - 8 - - - - delegate - - - - 9 - - - - back - - - 7 - - 10 - - - - view - - - - 11 - - - - titleLabel - - - - 12 - - - - fontPicker - - - - 13 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - - 5 - - - - - 6 - - - - - 7 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 4.IBPluginDependency - 5.IBPluginDependency - 6.IBPluginDependency - 7.IBPluginDependency - - - YES - AxisFontInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 13 - - - - YES - - AxisFontInspector - UIViewController - - back - id - - - back - - back - id - - - - YES - - YES - fontPicker - titleLabel - - - YES - UIPickerView - UILabel - - - - YES - - YES - fontPicker - titleLabel - - - YES - - fontPicker - UIPickerView - - - titleLabel - UILabel - - - - - IBProjectSource - ./Classes/AxisFontInspector.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - back_btn.png - {180, 50} - - 534 - - diff --git a/test/ios/RootBrowser/AxisInspector.h b/test/ios/RootBrowser/AxisInspector.h deleted file mode 100644 index 463030d16a61c..0000000000000 --- a/test/ios/RootBrowser/AxisInspector.h +++ /dev/null @@ -1,19 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" - -@interface AxisInspector : UIViewController { -@private - __weak IBOutlet UITabBar *tabBar; -} - -+ (CGRect) inspectorFrame; - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; -- (NSString *) getComponentName; -- (void) resetInspector; - - - -@end diff --git a/test/ios/RootBrowser/AxisInspector.mm b/test/ios/RootBrowser/AxisInspector.mm deleted file mode 100644 index 1cf22da182d68..0000000000000 --- a/test/ios/RootBrowser/AxisInspector.mm +++ /dev/null @@ -1,167 +0,0 @@ -#import "InspectorWithNavigation.h" -#import "AxisLabelsInspector.h" -#import "AxisTitleInspector.h" -#import "AxisTicksInspector.h" -#import "AxisInspector.h" - -@interface AxisInspector () { - AxisTicksInspector *ticksInspector; - - InspectorWithNavigation *titleInspector; - InspectorWithNavigation *labelInspector; - - __weak ROOTObjectController *controller; - TObject *object; -} - -- (void) showTicksInspector; -- (void) showAxisTitleInspector; -- (void) showAxisLabelsInspector; - -@end - - -@implementation AxisInspector - -//____________________________________________________________________________________________________ -+ (CGRect) inspectorFrame -{ - return CGRectMake(0.f, 0.f, 250.f, 400.f); -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName : nibNameOrNil bundle:nibBundleOrNil]; - - if (self) { - [self view]; - - ticksInspector = [[AxisTicksInspector alloc] initWithNibName : @"AxisTicksInspector" bundle : nil]; - [self.view addSubview : ticksInspector.view]; - - // - AxisTitleInspector *titleInspectorCompositor = [[AxisTitleInspector alloc] initWithNibName : @"AxisTitleInspector" bundle : nil]; - titleInspector = [[InspectorWithNavigation alloc] initWithRootViewController : titleInspectorCompositor]; - titleInspector.view.frame = [AxisTitleInspector inspectorFrame]; - [self.view addSubview : titleInspector.view]; - titleInspector.view.hidden = YES; - // - - AxisLabelsInspector *labelInspectorCompositor = [[AxisLabelsInspector alloc] initWithNibName : @"AxisLabelsInspector" bundle : nil]; - labelInspector = [[InspectorWithNavigation alloc] initWithRootViewController : labelInspectorCompositor]; - labelInspector.view.frame = [AxisLabelsInspector inspectorFrame]; - [self.view addSubview : labelInspector.view]; - labelInspector.view.hidden = YES; - - tabBar.selectedItem = [[tabBar items] objectAtIndex : 0]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -#pragma mark - ObjectInspectorComponent's protocol. -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; - [ticksInspector setROOTObjectController : c]; - [titleInspector setROOTObjectController : c]; - [labelInspector setROOTObjectController : c]; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - object = o; - [ticksInspector setROOTObject : o]; - [titleInspector setROOTObject : o]; - [labelInspector setROOTObject : o]; -} - -//____________________________________________________________________________________________________ -- (NSString *) getComponentName -{ - return @"Axis attributes"; -} - -//____________________________________________________________________________________________________ -- (void) resetInspector -{ - tabBar.selectedItem = [[tabBar items] objectAtIndex : 0]; - [titleInspector resetInspector]; - [labelInspector resetInspector]; - - [self showTicksInspector]; -} - -//____________________________________________________________________________________________________ -- (void) showTicksInspector -{ - ticksInspector.view.hidden = NO; - titleInspector.view.hidden = YES; - labelInspector.view.hidden = YES; -} - -//____________________________________________________________________________________________________ -- (void) showAxisTitleInspector -{ - ticksInspector.view.hidden = YES; - titleInspector.view.hidden = NO; - labelInspector.view.hidden = YES; -} - -//____________________________________________________________________________________________________ -- (void) showAxisLabelsInspector -{ - ticksInspector.view.hidden = YES; - titleInspector.view.hidden = YES; - labelInspector.view.hidden = NO; -} - -#pragma mark - Tabbar delegate. - -//____________________________________________________________________________________________________ -- (void) tabBar : (UITabBar *) tb didSelectItem : (UITabBarItem *)item -{ - if (item.tag == 1) - [self showTicksInspector]; - else if (item.tag == 2) - [self showAxisTitleInspector]; - else if (item.tag == 3) - [self showAxisLabelsInspector]; -} - -@end diff --git a/test/ios/RootBrowser/AxisInspector.xib b/test/ios/RootBrowser/AxisInspector.xib deleted file mode 100644 index e4754913a9ed1..0000000000000 --- a/test/ios/RootBrowser/AxisInspector.xib +++ /dev/null @@ -1,4646 +0,0 @@ - - - - 1056 - 11B26 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBUITabBar - IBUIView - IBUITabBarItem - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 266 - {250, 49} - - - _NS:518 - - 10 - - 549453824 - {256, 256} - - YES - - YES - - - - TU0AKgAEAAh1eIH/cHJ5/3Bzff9vcXX/bnB3/3Byef9vcXX/bG51/2xudf9ucHf/cHN9/2dqdP9ucXv/ -cHJ5/3Bzff9qbHP/b3F1/3N1fP9sbnX/am13/2ptd/9sbnX/am13/3l7gf91d33/bG95/2xudf9sb3n/ -bG95/2dqdP9qbXf/c3V8/3Bzff93eoP/bG51/3Bzff9sbnX/dXd9/2dqdP9qbHP/bG51/2psc/9sb3n/ -am13/2ptd/9sb3n/bG51/3V3ff97fYP/YmVu/25xe/9sb3n/c3Z//2psc/9zdXz/cHN9/2dqcf9qbHP/ -YmVu/2dqdP9nanH/am13/2xvef91eIH/Z2p0/25xe/91d33/bG51/25wd/92eHz/dXd9/29xdf9ucHf/ -eHl9/2xudf9ucHf/bG95/3Bzff9sb3n/bnF7/3l7gf9zdn//c3Z//3N2f/91eIH/c3V8/3Byef9nanT/ -bnB3/3Byef91d33/dHZ8/2psc/9sbnX/Z2p0/3N1fP9qbXf/cXN6/2psdf9wcnv/dnd9/25xe/9ucHf/ -bnB3/2ptd/92eH//a254/3Fzev9sb3n/cHJ5/25wd/9ucHf/cHN9/25wd/9wcnn/dnh8/2xudf93eX// -dXd9/2dqdP9ucXv/dXd9/3N2f/9zdXz/Z2px/2xudf9ucXv/am13/3Bzff9zdXz/cHN9/2psc/9qbXf/ -bG51/2Jlbv9qbXf/aGp0/2hqcP9rbnX/cnV//29yfP9ucXv/bnF7/25xe/9zdn//bXB1/2xvef9qbXb/ -Zmly/2Jlbv9kZ3H/Zmhu/2Rncf9kZ3H/Zmlz/2Zpc/9kZ3H/bnB3/2Jlbv9nanT/ZGdx/2Zobv9zdXz/ -ZGdx/2xvef9maXP/foCG/2xvef9ucXv/bG95/25wd/9wc33/b3F1/3l8hv91eIH/cHN9/3N1fP9sb3n/ -d3qD/25wd/9zdn//cHJ5/3Bzff9wcnn/cHN9/3Bzff9ucXv/d3l//2ptd/9ucXv/c3Z//3N2f/9wcnn/ -bnF7/3N2f/9ucHf/cHJ5/3Bzff9sb3n/cHJ5/25xe/9wc33/bnF7/3Byef9zdXz/bnB3/25xe/9zdXz/ -d3l//3N2f/9sb3n/bnB3/3Bzff9sb3n/bnF7/25wd/9wcnn/cHJ5/3Byef9sbnX/c3V8/2psc/9zdXz/ -dnh8/3Byef9kZ3H/am13/25xe/9sb3n/bnF7/25xe/9zdn//Z2p0/2xudf95e4H/Z2p0/2xvef9ucXv/ -bG51/2psc/9ucXv/cHJ5/2psc/9qbXf/Z2px/2ptd/9qbHP/cHN9/2ptd/9sbnX/bG51/3V3ff9wcnn/ -c3V8/3Byef9wc33/d3l//29xdf9zdXz/bnB3/2ptd/9qbXf/Z2px/2Zpc/9kZ3H/am13/2xvef9nanH/ -cHJ5/29xdf9wcnn/Z2px/2xudf9zdXz/b3F1/25wd/9ucHf/bnB3/25wd/9+gIb/eHl9/3N1fP9wcnn/ -cHJ5/3Byef9qbHP/bG51/3Z4fP9wcnn/dXiB/2xudf9ucXv/bG51/3Byef9nanH/ZGdx/2Zpc/9nanH/ -Z2px/2Zobv9iZW7/Zmhu/2Zobv9qbXf/c3Z//1lcZf9maXP/Z2p0/3Byef9kZ3H/bG95/2xvef9qbHP/ -am13/2Zpc/9qbXf/bG51/2xvef9wc33/dXd9/2dqdP9sb3n/dXd9/2dqdP9ucHf/c3V8/3V3ff9qbXf/ -bnF7/3d5f/9ucHf/bG51/2xudf9wc33/bG51/2xudf91d33/bnB3/3Byef9wcnn/cHJ5/29xdf9ucHf/ -Z2p0/3Byef9wc33/eXuB/3d5f/9sb3n/bnF7/2psc/9zdXz/b3F5/29yev9qbHX/bnB4/3d5f/9wcnn/ -bnB3/2xudf9ucHf/dHZ7/25wd/9ucXn/bW92/3Byef9ucHf/bG51/3N1fP9ucXv/cHN9/3V3ff9qbHP/ -dnh8/3V3ff9nanH/bnB3/3V3ff9ucHf/cHJ5/2Zpc/9qbXf/bG95/2xudf9sb3n/dXd9/3Z4fP9vcXX/ -bnF7/25wd/9nanH/c3Z//3Bzff9wcnn/bnB3/3R2ff9ucXr/bnF7/3Bzff9sb3n/dXd9/25xev90dnz/ -dXiA/3V4gP9wcnn/c3Z//3Bzff9ucXv/cHN9/3N2f/9zdn//bG95/3d6g/9sb3n/c3Z//3Bzff9ucHf/ -d3l//2dqcf9qbXf/Z2p0/3d6g/9sbnX/am13/2Zpc/9nanT/am13/2Zobv9zdXz/bnB3/2dqdP9kZ3H/ -ZGZs/3Byef9gY2z/Z2px/2Rncf9maG7/YGNs/2Zobv9kZ3H/Zmhu/2ptd/9gY2z/ZGdx/2Rncf9nanT/ -ZGdx/2psc/9maXP/ZGdx/2Zobv9maG7/YmVu/2Zpc/9qbHP/am13/2psc/9ucXv/cHN9/2xudf9nanT/ -bnF7/3V3ff9wcnn/bnB3/29xdf9zdXz/bG95/3Bzff9sb3n/c3Z//3N2f/91eIH/bnF7/3V4gf9ucXv/ -dXiB/3l7gf9zdn//am13/3Byef9zdn//cHN9/3N2f/91eIH/e36H/3Bzff9wc33/foCG/3V4gf93eoP/ -eXuB/3N2f/9ucXv/dXiB/3V3ff9vcXX/c3V8/25wd/91d33/c3V8/3d5f/9wc33/cHJ5/25wd/93eX// -c3Z//3Bzff9ucXv/cHN9/3V3ff9vcXX/c3V8/25wd/9vcXX/bnB3/2xvef9nanT/Zmhu/2ptd/9sb3n/ -Zmlz/3Byef9tb3P/bnF7/2xudf9ucHf/dXd9/2xvef9sb3n/bG95/25xe/9ucXv/e36H/3l7gf9zdn// -c3Z//3V4gf93eoP/c3Z//3N2f/9+gYr/eXyG/4GDiv9wc33/d3qD/3N1fP93eX//cHJ5/3Bzff9wc33/ -bnF7/25xe/9ucHf/b3F1/3Byef9ucXv/eXuB/36Ahv9nanT/c3Z//3Byef93eX//bW9z/3Z4fP91d33/ -bnB3/25xe/9nanT/bG95/25wd/9ucXv/dXiB/3l8hv9ucHf/c3Z//3V4gf9ucHf/dXiB/3N2f/91d33/ -am13/29xdf91d33/bnB3/2xvef9ucXv/d3qD/25xe/9wcnn/c3Z//25wd/9ucHf/cHJ5/3V3ff9vcXX/ -cHJ5/2xudf9vcXX/bG51/3Byef9ucXj/aGty/21vc/9nanT/cHN9/25wd/9vcnr/a212/21wev91d33/ -am13/2xudf9maXP/am13/3R2e/9tb3b/bnF6/2xudf9wcnn/am13/2xudf9ucXv/bG95/25xe/9wc33/ -ZGdx/3Byef9ucHf/YmVu/2psc/9wc33/bnF7/2ptd/9maG7/bW9z/25wd/9sbnX/c3V8/3d5f/91d33/ -b3F1/25xe/9ucXv/Z2p0/3V3ff9wc33/bnF7/21vdv9zdnz/cHJ5/25weP9zdXz/bnF7/3l7gf9xc3r/ -d3mA/3d5f/9zdX3/b3F1/3N1fP9sbnX/bG51/25wd/9sbnX/cHJ5/2psc/92eHz/amxz/3Bzff9ucHf/ -bW9z/3h5ff9nanH/bG51/2Jlbv91eIH/amxz/2Zpc/9iZW7/YmVu/2dqdP9maG7/c3Z//3N1fP9qbXf/ -Z2p0/2dqdP91eIH/ZGdx/2xudf9nanT/am13/2ptd/9ucXv/bnF7/21vc/91eIH/Zmlz/25wd/9wcnn/ -bnB3/25wd/9vcXX/cHJ5/21vc/9sbnX/bG95/2dqdP9sbnX/bG51/2xvef9sbnX/bnF7/25xe/9nanT/ -bnF7/3Bzff91d33/cHN9/2ptd/9qbHP/bnF7/2Zpc/9qbXf/YmVu/2ptd/9qbHP/bG95/2Rncf9ucXv/ -ZGdx/25xe/9zdXz/bG95/2Rncf9tb3P/bG95/25wd/91d33/dXiB/3t9g/9ucHf/c3V8/3t9g/9ucXv/ -dXiB/3d5f/9wcnn/bnF7/3N2f/95e4H/cHN9/3V4gf9ucXv/d3qD/3V4gf93eX//c3Z//3N1fP9zdXz/ -d3l//3Bzff9ucXv/bnF7/3N1fP9zdXz/bG51/2xvef9nanH/Z2px/2dqdP9qbHP/YmVu/2BjbP9sbnX/ -bG51/2Rncf9sb3n/bG51/2ptd/9maXP/Z2px/25xe/9qbHP/Zmlz/2Zpc/9qbHP/Z2p0/3V4gf91d33/ -cHN9/25wd/9sb3n/am13/2Zpc/9sb3n/dXd9/3Bzff91eIH/bW9z/25xe/9sbnX/c3V8/21vc/9sbnX/ -cHN9/2ptd/9qbXf/bnF7/2ptd/9sbnX/bG51/3Byef93eX//ZGdx/2xvef9ucXv/dXd9/2xudf92eHz/ -dXd9/25wd/9sbnX/amxz/2xvef9vcXX/bnB3/3Bzff93eoP/bG95/3Bzff9zdn//bG95/3N2f/9wc33/ -dXiB/25xe/9zdXz/e32D/3Bzff9ucHf/bnF7/3V3ff9vcXX/b3F1/3N1fP9tb3P/bG51/3Byef9zdXz/ -bW9z/3Byef9nanH/amxz/2psc/9ucHf/bnB3/2psc/9sbnX/amxz/3V3fP9ucHj/bW93/2psdf9vcnr/ -dXd8/25wd/9qbXf/Z2p0/25xe/9zdoD/bXB6/3J0fP9wcnf/c3V8/29xdf9ucHf/bnF7/3Byef9zdXz/ -cHN9/2ptd/91d33/eHl9/2psc/9zdXz/dnh8/3N1fP9ucXv/Zmhu/29xdf9ucHf/bnB3/25wd/92eHz/ -cHJ5/2xudf9wcnn/bG95/2Rncf9wc33/bnF7/2ttdP9maXP/bnF5/2lsdf9laHL/am13/2ptd/9zdXz/ -bm92/3R3fv91d33/bnB3/21vc/9zdXz/bW9z/3Byef9ucHf/bnB3/3N1fP9nanH/d3l//25wd/97fYP/ -c3Z//3Bzff97fYP/bnF7/21vc/9maG7/eXuB/2ptd/9qbXf/ZGdx/2Zobv9nanT/Z2px/3N2f/9wcnn/ -am13/2ptd/9qbXf/d3qD/2Rncf9qbXf/Z2p0/2xvef9qbXf/Z2p0/2ptd/9maXP/d3l//2Rncf9qbXf/ -bnB3/2ptd/9qbXf/bG51/25xe/9tb3P/bnB3/25wd/9qbHP/bG51/2xudf9qbXf/bG51/3N1fP9zdXz/ -bG51/3N1fP91d33/dXd9/25xe/9sbnX/bW9z/3Bzff9maXP/bG51/2Rncf9nanT/Z2px/2ptd/9nanT/ -bnF7/2dqdP9wc33/cHJ5/2psc/9dYGr/bG51/2ptd/9sb3n/c3V8/2ptd/91eIH/bG51/2ptd/9zdn// -am13/25xe/9sb3n/Z2p0/2psc/9nanT/bG95/2xudf9ucXv/amxz/2xvef9sb3n/cHN9/2dqcf9maXP/ -Zmlz/25xe/9sb3n/am13/2ptd/9nanT/d3l//25xe/9zdn//bnB3/25xe/9wc33/cHN9/25xe/9qbXf/ -cHJ5/3Bzff9sb3n/cHN9/25wd/9wcnn/bnB3/29xdf94eX3/cHN9/25wd/9wc33/bnB3/25xe/97fYP/ -dXiB/3V3ff9sb3n/c3V8/3Byef9sbnX/c3V8/3V3ff9ucXv/c3V8/2psc/9ucXv/am13/3N1fP9sbnX/ -bG51/3V3ff9ucHf/cHJ5/3Byef9sb3n/bnB3/25wd/92eHz/gIKG/25wd/91d33/c3V8/3d5f/9ucHf/ -dnh8/3Z4fP9ucHf/bG51/2xudf9sbnX/bG51/2ptd/9sb3n/dXiB/2Zpc/9sb3n/Zmlz/2Jlbv9qbXf/ -Z2p0/2dqdP9iZW7/YGNs/2xvef9kZ3H/YGNs/2Zpc/9kZ3H/Zmhu/2Jlbv9qbXf/ZGdx/2Zpc/9qbXf/ -bnF7/2xudf9sb3n/Zmlz/2ptd/9sbnX/am13/21wef9laHH/am13/2dqdP9zdXz/bW92/25weP9rbnj/ -b3F6/3N2fv9ucXX/bG51/2dqcf9sb3n/b3J8/2xud/9ucXr/bW9z/25xe/9ucHf/bnB3/3Byef9ucHf/ -dXd9/3N1fP9sbnX/cHJ5/3V3ff9kZ3H/am13/3N1fP9wcnn/bG95/2Jlbv9nanT/am13/2ptd/9qbXf/ -d3l//25xe/9qbXf/bnF7/2ptd/9iZW7/am13/2ptd/9nanL/Z2ly/29xef9ucHf/amxz/3N1fP9wcnn/ -cHN9/3Byef9ydX7/dXd9/29xdv9rbnj/cHJ5/25wd/9wc33/bnB3/25wd/9zdXz/amxz/3d5f/9wcnn/ -d3l//29xdf9wcnn/eXuB/2xvef9vcXX/Z2px/3t9g/9sb3n/cHN9/2xvef9ucHf/cHJ5/25xe/9+f4P/ -dXd9/3Byef9qbXf/bG51/35/g/9qbHP/cHJ5/2xvef91d33/bnB3/25xe/9zdn//bG95/3l7gf9maG7/ -bnB3/2xvef9qbXf/am13/2psc/9qbXf/bG51/2psc/9sbnX/Zmlz/2Zpc/9nanH/Z2px/2Rncf9qbXf/ -Zmlz/2Jlbv9nanT/bG95/2xvef9kZ3H/Zmhu/2Jlbv9nanT/YGNs/2Rncf9dYGr/ZGdx/2Rncf9qbXf/ -ZGdx/2xvef9iZW7/Z2p0/2ptd/9maG7/XWBq/2psc/9nanT/am13/3N1fP9ucXv/eXyG/2ptd/9nanT/ -dXd9/25wd/9zdXz/cHJ5/3Byef9vcXX/bnF7/3Bzff9wcnn/eXuB/3N1fP91eIH/dXiB/3l8hv9zdXz/ -cHJ5/25xe/95e4H/d3qD/3N2f/9zdn//cHN9/3l7gf9zdXz/bnF7/25wd/9wc33/cHN9/3N2f/9sb3n/ -bG95/3Byef9wc33/bG95/25xe/9ucXv/cHJ5/25wd/9ucHf/eXuB/3N2f/9ucHf/bG95/25wd/9wc33/ -d3qD/3d5f/91d33/bG51/3Byef9sbnX/amxz/3N1fP94eX3/dXd9/3V4gf9ucHf/cHJ5/3Byef92eHz/ -bG95/3Bzff93eoP/c3Z//3N2f/9zdXz/bnB3/25wd/9zdXz/eHl9/3+Bh/9ucHf/dnh8/3Byef93eX// -bnB3/3d6g/95e4H/bnB3/3Byef9sbnX/bnB3/2psc/9qbXf/am13/3l8hv9maXP/bnF7/2psc/9kZ3H/ -bnF7/2xvef9ucXv/amxz/2ptd/91d33/bG51/2psc/9wc33/cHN9/2xudf9maXP/cHN9/2dqcf9nanT/ -amxz/2dqdP9sbnX/am13/2Zpc/9sb3n/bG51/2xvef9sbnj/ZWhy/2dqdP9nanH/bnF7/2ttdf9rbnb/ -a252/29xeP90dnz/am13/2ptd/9nanH/cHJ5/3N1fP9tcHj/bnF6/2dqdP9qbHP/Zmhu/2psc/9nanT/ -amxz/2dqdP9qbXf/YGNs/2dqdP91d33/YmVu/2xudf9sb3n/am13/2xudf9iZW7/am13/2xvef9ucXv/ -bG51/3d5f/9ucXv/am13/3Byef9ucHf/ZGdx/25xe/9sb3n/am13/2lsdP9wcnv/b3J7/21vd/9zdXz/ -bnB3/3Bzff9rbXT/a254/25xe/9rbXX/bW9z/25wd/9tb3P/b3F1/2xvef9wcnn/c3V8/2ptd/93eX// -bnB3/3V4gf9ucXv/cHJ5/3d6g/9qbXf/bG51/2Jlbv91eIH/am13/25xe/9maXP/amxz/2ptd/9qbXf/ -e32D/3N1fP9qbXf/bG51/2psc/91eIH/YGNs/2Zpc/9kZ3H/Z2p0/2Zpc/9nanH/bG95/2Rncf9zdXz/ -YGNs/2Zpc/9nanT/amxz/2Zpc/9qbHP/bG95/2xudf9qbHP/bG51/2Zpc/9nanT/amxz/2ptd/9maXP/ -cHN9/25xe/9maXP/am13/3Bzff91d33/bG95/2xvef9tb3P/dXd9/25wd/9ucHf/Zmlz/25wd/9tb3P/ -c3V8/21vc/92eHz/bnB3/3h5ff94eX3/bG51/2dqcf9sb3n/bnF7/25xe/9zdXz/cHJ5/36Ahv9wc33/ -c3V8/3l7gf9zdXz/bnF7/25xe/9sbnX/bG51/3N1fP9zdXz/b3F1/3N1fP9ucHf/c3V8/3Byef91d33/ -b3F1/2xudf9sb3n/dnh8/3Z4fP9zdXz/cHN9/3Bzff94eX3/b3F1/3Bzff9qbHP/bnB3/2xvef9wc33/ -ZGdx/2dqdP9nanT/am13/2ptd/9ucHf/cHJ5/3Byef9sbnX/bG51/3V3ff92eHz/amxz/25xe/9ucHf/ -cHN9/3d5f/93eX//c3V8/21vc/9zdXz/bW9z/2xudf9zdn//d3qD/3V4gf95e4H/bnF7/3N2f/91eIH/ -e32D/3Byef91eIH/eXuB/3d6g/93eoP/d3qD/3Bzff9wc33/bnF7/3V4gf+Bg4r/bG95/3V3ff9wc33/ -eXuB/25xe/97fof/eXuB/3N1fP9zdn//bG95/3V4gf9wcnn/d3qD/3V4gf9/gYf/cHJ5/3d6g/9wc33/ -bG95/3V4gf9zdn//dXiB/3N1fP9zdXz/eXyG/3V4gf9zdn//e32D/3l7gf9zdn//c3V8/3d6g/9ucHf/ -bnF7/2xvef9wc33/bG95/25xe/9qbXf/cHJ5/25wd/9wcnn/cnR6/21vdv9sb3n/bnB3/3Bzff9tcHr/ -cXN7/25wd/9vcXr/bnB6/2xudf9sbnX/Z2px/3V3ff9ydX7/b3J8/2tueP9rbXT/am13/2xudf9sbnX/ -bG51/3Byef9zdXz/cHJ5/2RmbP9ucHf/dXd9/2Rncf9qbXf/bG95/2dqdP9sbnX/YmVu/2ptd/9qbXf/ -bG95/2xudf91d33/bG95/2xudf9zdXz/bG51/2Zobv9wcnn/cHJ5/2xvef9rbnf/c3V+/3F0fv9sb3n/ -c3V8/3N1fP9zdXz/bnB0/29xeP90dnz/bW94/3Byef9wc33/b3F1/25wd/9tb3P/cHJ5/3Byef9qbHP/ -dXd9/2ptd/91d33/amxz/2xudf9zdXz/YmVu/25wd/9nanH/eXuB/25wd/9ucHf/bnB3/25wd/9wcnn/ -b3F1/36Ahv91d33/bnB3/2xudf9tb3P/fn+D/2psc/9sbnX/bnB3/25xe/9sbnX/amxz/25xe/9nanT/ -d3l//2Rncf9sbnX/bnB3/21vc/9nanH/b3F1/3Bzff9ucHf/bnB3/25xe/9sb3n/c3V8/3Byef91d33/ -b3F1/3h5ff9zdXz/bG51/3Byef91d33/dXiB/3V4gf9wc33/cHN9/3N2f/9sb3n/bnF7/2dqdP9wcnn/ -bW9z/3N1fP9sbnX/cHN9/2ptd/91d33/dXd9/2xudf9iZW7/am13/2ptd/9qbXf/bnF7/3Byef9zdn// -bnF7/25xe/9zdn//cHN9/25xe/9ucXv/bG51/2ptd/9sb3n/bnF7/2ptd/9sb3n/bnB3/25wd/9wcnn/ -dXd9/2xudf9maXP/Z2p0/3Z4fP9zdXz/dXd9/3N1fP9ucHf/dnh8/2ptd/9ucXv/ZGdx/2psc/9maXP/ -am13/2Jlbv9kZ3H/ZGdx/2Rncf9iZW7/Zmlz/2Zpc/9qbXf/ZGdx/2dqcf9sb3n/bnF7/2Rncf9qbXf/ -amxz/25xe/9zdXz/dXd9/2xvef9sbnX/cHN9/21vc/9qbHP/dXd9/3V3ff91d33/eHl9/25wd/9vcXX/ -bnB3/3Z4fP9ucHf/c3Z//3Z4fP91d33/cHJ5/3N1fP9ucHf/bnB3/25wd/91d33/f4KM/3Byef9zdn// -bnF7/3d5f/9sb3n/e32D/3h5ff9ucHf/cHN9/2ptd/9zdn//bG95/3Bzff9wcnn/e36H/25wd/9wc33/ -bG95/2ptd/9zdn//dXiB/3V3ff9sb3n/bnB3/3d6g/9ucXv/bnB3/3N2f/9zdn//bnB3/2xudf9wcnn/ -bW9z/29xdf9ucHf/bnB3/2xvef9wcnn/cHN9/3Bzff9wcnn/c3Z//3N2f/9xc3r/cHJ5/3N2f/93eoP/ -cHN9/3h6gP9zdXr/d3l//3h7hP9zdn//cHN9/2dqdP93eoL/dnmB/3N2fv9wcnr/bnB3/25wd/9vcXX/ -cHJ5/25wd/91d33/dXd9/3N1fP9maG7/bnB3/3l7gf9maG7/bG51/2ptd/9sbnX/amxz/2Jlbv9sbnX/ -cHN9/2ptd/9nanH/c3V8/2dqdP9nanH/Zmlz/2Zobv9ZXGX/ZGdx/2Zpc/9iZW7/YmVt/2xud/9sb3f/ -a210/29yef9wcnn/dnh8/29xdf9tcHr/bnF7/2Zpcv9naXD/Z2pz/2Jlbv9kZmz/Zmhu/2dqdP9nanT/ -ZGdx/25wd/9maXP/c3V8/2psc/9maXP/cHJ5/2Jlbv9wcnn/bnF7/3+Bh/9zdn//dXiB/3N1fP9wc33/ -cHN9/2xvef97fYP/cHN9/2xvef9sb3n/cHJ5/3+Bh/9sb3n/cHN9/3Byef9zdn//c3V8/3Byef9zdn// -bG95/3t+h/9sb3n/dXiB/3d6g/9wcnn/am13/3Byef9wc33/cHJ5/25xe/9zdn//cHJ5/3l7gf91eIH/ -eXyG/3d6g/95fIb/d3qD/3Bzff91eIH/d3l//3l8hv91d33/cHN9/2xvef9wc33/am13/3Byef9sbnX/ -cHJ5/29xdf91d33/bG95/3Bzff9ucHf/d3qD/3h5ff9sbnX/Zmlz/2xvef9wcnn/cHJ5/3Byef91d33/ -dXiB/3d5f/9wc33/e36H/3l7gf9wc33/c3Z//25wd/9wc33/d3qD/3Bzff9wcnn/cHN9/25xe/9wc33/ -c3V8/3h5ff9vcXX/amxz/2psc/92eHz/cHJ5/3Bzff9ucXv/bG51/3V4gf9ucXv/c3V8/2dqcf9sbnX/ -cHJ5/3N1fP9qbHP/bG51/29xdf9zdXz/bW9z/2xudf9wcnn/cHJ5/2xudf9sb3n/c3V8/3Z4fP9sb3n/ -cHN9/25xe/9zdn//dXd9/3d5f/9wc33/bG95/3N2f/9ucXv/bnB3/3d5f/95e4H/d3l//3d5f/9sb3n/ -cHJ5/29xdf92eHz/bnB3/3N1fP92eHz/dXd9/3N1fP9wcnn/b3F1/2xudf9wc33/dXd9/4CChv9tb3P/ -bnF7/2xudf91d33/bW9z/3d5f/92eHz/bW9z/2xudf9nanH/cHN9/2xvef9wcnn/bnB3/3d5f/9ucHf/ -cHN9/2xvef9sb3n/dXd9/3N2f/91d33/bnB3/25wd/95e4H/bG95/25wd/9wc33/dnh8/2xudf9qbHP/ -bnB3/21vc/9sbnX/bG95/2ptd/9ucHf/bnB3/25wd/9wcnn/bW9z/3N1fP9xc3r/a253/2psc/9nanT/ -bnF7/2dqdP9vcnz/aWx2/29xev9sb3n/amxz/2xudf9iZW7/cHN9/3R2fP9xdH3/bW93/2hrcv9sb3n/ -bG51/2xvef9sbnX/dXd9/3V3ff9wcnn/amxz/2xudf93eX//Z2px/2ptd/9qbXf/am13/2xvef9maG7/ -bW9z/25wd/9wcnn/b3F1/3N1fP9sbnX/bG51/2xvef9wcnn/Zmhu/2xvef9qbXf/Zmlz/2Vocv9sb3n/ -cXR7/2xvef9zdXz/c3V8/3V3ff9ucHT/bnB1/3R2fP9sb3j/b3F2/21vdf9tb3P/bG51/25wd/9zdXz/ -c3V8/2psc/93eX//am13/3d5f/9sbnX/am13/3d5f/9sbnX/bG51/2ptd/97fYP/dXd9/3Byef9vcXX/ -cHJ5/2xvef9ucHf/eXuB/2xvef9qbXf/am13/2xudf9+gIb/amxz/3Byef9ucHf/cHJ5/25wd/9ucHf/ -bnB3/2Zpc/91d33/Z2px/3N2f/9wcnn/bnB3/2psc/9sb3n/cHN9/3N1fP9zdn//dXiB/3Byef95fIb/ -dXiB/3d6g/93eoP/e36H/3l8hv9wc33/dXiB/3l7gf9+gYr/foCG/3d6g/93eoP/d3qD/3V3ff93eoP/ -cHN9/3d6g/91eIH/e32D/3Bzff9zdn//bnB3/3l7gf94eX3/c3Z//2dqdP9zdn//c3Z//3N2f/9ucHf/ -d3l//3l7gf97fYP/d3qD/3+CjP97fof/eXuB/3l7gf91d33/dXiB/3l7gf93eoP/cHJ5/3Bzff9ucXv/ -c3Z//25xe/97fYP/c3V8/2xvef9sb3n/d3l//3N2f/9wc33/cHJ5/2xvef9ucXv/am13/3Byef9sbnX/ -bW9z/25xe/9ucXv/ZGdx/2dqdP9qbHP/cHJ5/2dqcf9maG7/bG95/2dqdP9kZ3H/ZGdx/2ptd/9wc33/ -Z2p0/2ptd/9nanH/bG95/3N1fP9wc33/bG95/2xudf9zdXz/am13/2dqdP9ucXv/c3V8/3V3ff91d33/ -bG51/25xe/9sbnX/bG95/2ptd/9ucXv/bnF7/3V3ff92eHz/cHJ5/2xudf9tb3P/c3V8/3d5f/+Agob/ -bW9z/2xvef9sb3n/eHl9/2xudf93eoP/dXd9/2ptd/9qbXf/Zmlz/3N1fP9wcnn/c3Z//3Bzff97fof/ -cHJ5/3N2f/9sb3n/bG51/3V3ff9zdXz/c3V8/25wd/9ucHf/dXiB/25xe/9sb3n/cHN9/3N2f/9tb3P/ -bG51/3N1fP9sb3n/cHN9/3Bzff9sb3n/bnB3/25xe/9ucHf/cHJ5/21vc/91d33/c3V6/21wef9ucHf/ -bnB3/3N1fP9ucHf/cXN7/2xud/9wcnn/dHZ9/25wd/9ucHf/Z2px/3V3ff90dnv/cXR7/25wd/9lZ3D/ -amxz/2xudf9qbXf/am13/3Bzff9ucXv/bnF7/2Zpc/9sbnX/c3V8/2Rncf9maXP/Zmlz/2dqcf9maXP/ -XWBq/2dqcf9nanT/Z2p0/2Zpc/9sb3n/Z2px/2dqcf9qbXf/am13/2Jlbv9qbXf/bG51/2Vocf9oa3T/ -b3J5/3J1f/9tcHr/dHeA/3V4gf97fYP/dXd9/3Z4f/95e4H/bG93/21vdv9tb3b/bG51/2ptd/9tb3P/ -dXd9/3Byef9sbnX/d3l//2xudf92eHz/bG51/2xudf93eX//bG51/2xvef9sb3n/d3qD/3N2f/9ucXv/ -bG95/3Byef9ucHf/bnB3/3d5f/9ucHf/bG51/2ptd/9ucHf/gYOK/2ptd/9zdn//cHJ5/3N2f/9wcnn/ -bnB3/2xvef9qbXf/eXuB/2dqcf95e4H/dXiB/3N2f/9wc33/dXd9/3l7gf91d33/dXd9/3d6g/91d33/ -fX6B/3t9g/9/gYf/foCG/36Ahv97fYP/eHl9/3l7gf9+f4P/gYOK/36Ahv95e4H/d3qD/3N2f/91d33/ -d3qD/3Bzff9wc33/cHN9/3l7gf9zdn//dXiB/3N1fP9/gYf/e36H/3V4gf9sb3n/c3Z//3Bzff9wc33/ -bnF7/3Z4fP9zdXz/dXd9/25xe/93eX//dnh8/3V3ff94eX3/bnB3/25wd/91d33/cHJ5/25wd/9ucHf/ -bnB3/3N1fP9wcnn/dnh8/29xdf9qbHP/bG51/3Z4fP9wcnn/c3V8/25wd/9qbXf/bnF7/25wd/9zdn// -am13/25wd/9zdXz/dXd9/2ptd/9vcXX/bG51/3N1fP9sbnX/am13/3N1fP9ucXv/bG51/2xudf9wcnn/ -eHl9/2ptd/9zdXz/c3V8/3V4gf93eoP/eXuB/3l7gf9zdXz/e32D/3V4gf9zdXz/d3qD/3t9g/9+gIb/ -foGK/3N2f/97fYP/dXiB/3d6g/9wc33/dXiB/3N2f/91eIH/c3Z//3Bzff9ucHf/bnB3/3N1fP92eHz/ -gIKG/2xvef9ucHf/bnB3/3Z4fP9qbXf/c3Z//3N1fP9qbHP/am13/2BjbP9ucXv/Z2p0/25xe/9wc33/ -dXiB/2xudf9sb3n/bG95/2ptd/9wc33/cHN9/3N1fP9tb3P/am13/3V3ff9qbXf/Z2px/2xvef9ucXv/ -amxz/2Zpc/9sb3n/bG95/25xe/9sb3n/bG51/2xudf9qbXf/Zmlz/2Zpc/9maG7/am13/2tueP9nanT/ -Zmlz/2Zpc/9nanT/Z2lv/2ptd/9maXL/a252/2xvef9qbHP/am13/2Rncf9sb3n/b3J8/3Bze/9sbnT/ -Z2lw/2xudf9wcnn/bnB3/3N1fP92eHz/cHJ5/3Byef9qbHP/bG95/3l7gf9qbXf/cHJ5/3d6g/9zdn// -c3Z//2ptd/9wc33/dXiB/3d6g/9wcnn/d3qD/3Bzff9wcnn/c3Z//3Bzff9maXP/bnF7/25xe/9sb3n/ -bG95/3N2f/9xdH7/am12/25wd/9ucXv/dXd9/2xudf9tb3b/cnV8/21veP9vcXj/bnB3/25wd/9wcnn/ -bW9z/3N1fP9zdXz/bG51/3d5f/9tb3P/dXd9/21vc/9sbnX/dXd9/2dqdP9maXP/Z2p0/3d5f/9zdXz/ -bnB3/2xudf91d33/bG95/2ptd/93eoP/c3Z//25xe/9sb3n/bnB3/4GDiv9qbXf/bG95/25wd/9ucXv/ -cHJ5/25xe/9ucHf/Z2px/3Z4fP9lZmr/c3V8/25wd/9tb3P/Z2p0/2dqcf9sb3n/amxz/2psc/9maXP/ -YmVu/2xvef9qbXf/bG95/2xvef91d33/bnF7/2xudf9sbnX/c3V8/3V3ff91d33/bG95/2xvef9qbXf/ -am13/2xvef9qbHP/cHJ5/2xudf91d33/bG51/3N1fP9vcXX/e32D/3d6g/9wc33/Z2p0/3Bzff91d33/ -c3V8/25wd/9zdn//d3l//3d5f/91d33/dXiB/3d5f/93eX//eXuB/25xe/9wc33/dXiB/3V4gf9zdn// -d3qD/35/g/97fYP/dXiB/3t+h/9zdn//bnF7/3Byef93eX//cHN9/3N2f/9wc33/bnB3/3Bzff9qbXf/ -c3V8/2dqcf9ucHf/c3V8/3N1fP9sbnX/bG51/2xudf9wc33/bG95/2ptd/9zdXz/c3V8/2psc/9sbnX/ -bnF7/3Z4fP9sbnX/bG51/2psc/9ucXv/c3V8/3N1fP9wcnn/bG51/3V3ff9sbnX/Z2p0/3Byef9wc33/ -dnh8/3d5f/9ucHf/c3Z//2xvef9zdXz/bG95/25xe/9ucHf/c3Z//3N2f/9wc33/bnB3/25wd/9zdn// -eXuB/4GDiv9ucHf/bnF7/3Bzff95e4H/cHN9/3d6g/93eoP/cHJ5/3N2f/9maXP/dXd9/3Bzff91d33/ -c3Z//3l8hv9ucHf/cHJ5/25xe/9ucHf/dXd9/3V3ff92eHz/b3F1/25wd/91d33/bG95/2xvef91eIH/ -dXiB/25xe/9sb3n/c3Z//3Bzff9wc33/cHN9/2xvef9zdXz/cHJ5/25wd/9wcnn/b3F1/3N1fP9zdXr/ -bW92/2xudf9tb3P/cHJ5/2xudv9tb3f/aWx1/25xef9ucXv/Zmhu/2dqdP9kZ3H/bG95/2xvef9vcXr/ -a252/2Vobv9sbnX/cHJ5/2xudf9zdXz/dXd9/2xvef9sb3n/Zmlz/2ptd/9zdXz/YmVu/2psc/91d33/ -cHN9/25wd/9nanH/bnB3/25xe/91eIH/bG95/3V3ff9sb3n/bnB3/3V4gf9ucXv/am13/25wd/9ucHf/ -bG95/29xeP9zdn7/dHd//21vdv9wcnn/cHJ5/3V3ff9qbXf/cHJ6/3d6g/9wc33/bnF6/3F0fv9ucXv/ -bnF7/2xudf9zdXz/cHJ5/2ptd/9zdXz/bG51/3V3ff9sbnX/b3F1/3d5f/9sbnX/amxz/29xdf92eHz/ -cHJ5/3Byef9ucHf/dXd9/2ptd/9maXP/c3Z//25xe/9sb3n/Zmlz/2psc/9/gYf/am13/2ptd/9qbHP/ -am13/21vc/9sbnX/bG51/2psc/93eX//Zmlz/3Bzff9ucXv/bnB3/2xudf9sbnX/bnB3/2xudf9sb3n/ -bnB3/2psc/9zdXz/bnB3/3N1fP9ucHf/eHl9/3Bzff9wcnn/cHN9/3d6g/95fIb/e32D/3V4gf93eoP/ -cHN9/2xvef9wc33/bG95/3V3ff9ucHf/dXd9/25wd/91eIH/bnB3/3l8hv93eX//c3V8/2psc/9zdXz/ -cHJ5/3N1fP9ucHf/c3V8/3N1fP92eHz/cHN9/3V3ff91d33/dXd9/3d5f/9qbHP/bnB3/3V3ff9zdXz/ -b3F1/25wd/91d33/cHJ5/25xe/93eX//bG51/2psc/9sbnX/eHl9/3Byef91d33/bnF7/2xudf91eIH/ -cHN9/3V4gf9kZ3H/bnB3/25xe/93eoP/c3V8/3N1fP9zdXz/eXuB/3N2f/9wcnn/eXuB/3t9g/9ucXv/ -cHJ5/3V4gf93eX//bnB3/3Byef9wcnn/d3l//3Bzff9zdn//c3V8/3Byef91d33/cHJ5/25wd/9zdXz/ -cHN9/3N1fP91d33/bG95/3N1fP9ucHf/c3V8/25wd/9wcnn/bnB3/3N2f/91eIH/c3Z//2xvef9ucXv/ -c3Z//3V4gf+DhYz/dXd9/3V3ff97fYP/f4GH/3t9g/9/gYf/hYeN/3t9g/95fIb/c3Z//36Biv9+gIb/ -foCG/31+gf+Bg4r/dnh8/3l7gf97fYP/dnh8/3t9g/97fYP/eXuB/3Bzff9ucXv/d3l//25wd/9qbHP/ -cHN9/3Bzff9qbHP/ZGdx/2ptd/9qbXf/Z2p0/2dqdP9nanH/Z2p0/2Zpc/9kZ3H/Z2p0/2psc/9nanT/ -bG95/2Nmbv9gY2z/Zmhu/2ptd/9oa3P/bG52/2lsdv9sb3j/bnF7/21vc/9tb3P/Z2px/3Byef9xdHv/ -b3F4/3Byef9oanD/b3F1/3N1fP9ucHf/dXd9/3V3ff9ucHf/bnB3/2psc/9wcnn/dnh8/2Zobv9sbnX/ -dXd9/3N1fP9wcnn/Zmhu/2xudf9sb3n/dXd9/2ptd/9wcnn/b3F1/21vc/9wc33/bG51/2Rncf9qbHP/ -Z2p0/2BjbP9kZ3H/aGt1/2tud/9nanP/bnB4/21vdv91d33/bG51/21vc/9zdn3/a254/21vd/9tcHr/ -am13/2ptd/9sbnX/cHJ5/2xvef9nanT/c3V8/2psc/91d33/bG51/2xvef93eX//Z2p0/25xe/9wc33/ -e32D/3d6g/9zdn//cHN9/3d6g/9zdXz/bnF7/3l8hv9zdn//cHN9/2ptd/9ucHf/f4KM/2xvef9zdn// -cHN9/3Bzff9zdXz/c3Z//25xe/9nanT/eHl9/2dqcf9zdXz/cHJ5/25wd/9sbnX/bG51/29xdf9vcXX/ -cHJ5/3Byef9sbnX/c3V8/3Byef9sb3n/cHN9/3V3ff9wc33/bW9z/2ptd/9ucXv/dXd9/3Z4fP9wcnn/ -cHN9/2ptd/9nanT/cHN9/2psc/9wc33/am13/3Bzff9qbXf/bG95/2xudf93eoP/dXd9/2xvef9qbHP/ -bG95/2xvef9wc33/bG51/2ptd/9ucXv/bnF7/3Bzff9zdXz/dXd9/2xvef93eX//Zmlz/2ptd/9wc33/ -bG95/2ptd/9sbnX/cHN9/3Byef9zdXz/eXuB/3N2f/9qbXf/bnB3/3l7gf9wc33/dnh8/3N1fP9ucHf/ -bnF7/25wd/9zdXz/ZGdx/25wd/9zdXz/c3Z//25xe/9ucXv/cHN9/3d6g/95fIb/c3Z//36Ahv97fof/ -cHN9/3V4gf95e4H/e36H/3V3ff93eX//c3Z//3l8hv9zdn//d3qD/3d6g/9zdn//d3qD/3N2f/9sb3n/ -c3Z//3N2f/91eIH/d3qD/3Bzff9wc33/cHN9/25xe/9ucXv/cHN9/3Bzff91eIH/c3Z//3N2f/9ucHf/ -bW9z/3N1fP91d33/fn+D/25wd/9sb3n/dXiB/3d5f/9ucXv/d3l//3d6g/9zdn//bnF7/2psc/9wc33/ -cHJ5/3V3ff9zdXz/eXuB/2xudf9wcnn/bG95/2xudf91d33/dXd9/25xe/9ucHf/bG95/3V3ff9ucHf/ -Z2p0/3Bzff91d33/bW9z/2dqcf9wcnn/bG95/2ptd/9sbnX/bG51/25xe/9sbnX/am13/2xvef9qbHP/ -bG95/21veP9pa3L/YmVu/2Zobv9sb3n/bG51/2lsdP9oa3X/am12/2hrdf9maG7/Zmhu/1lcZf9maXP/ -bXB6/21wef9tb3f/Z2p0/25xdf9ucXv/bnB3/3N2f/93eX//bnF7/3Bzff9qbXf/c3Z//3d5f/9nanT/ -cHJ5/3N2f/93eX//cHJ5/2psc/9sbnX/bG95/3V3ff9sbnX/bG95/2ptd/9nanT/cHN9/2xvef9maXP/ -bG51/25xe/9kZmz/bG51/2xudv9ucHj/aWx0/25xe/9sb3n/cHN9/2dqdP9qbXf/cHJ4/25wdf9sbnb/ -c3V9/25wd/9wcnn/bG51/3Byef9ucHf/bG51/3V3ff9sbnX/dXd9/2xudf9sbnX/d3l//2dqdP9qbHP/ -b3F1/3Z4fP9zdn//bG95/25wd/91d33/bG95/2xvef97fof/dXiB/3N2f/9ucHf/cHJ5/3+CjP9qbXf/ -bnF7/25wd/9ucXv/cHN9/3N2f/9wc33/am13/3d5f/9nanH/cHJ5/3Byef9sbnX/Z2p0/2dqdP9sbnX/ -amxz/2xudf9nanT/Zmlz/2xvef9qbXf/am13/2xvef9zdXz/cHJ5/21vc/9wcnn/cHJ5/3Z4fP91d33/ -am13/3N1fP9ucXv/bG51/3V3ff9qbHP/cHN9/2ptd/9zdXz/bnB3/3Bzff9sb3n/foCG/3d5f/9ucXv/ -bW9z/3N1fP9zdXz/dnh8/3Byef9sbnX/bG95/3Bzff9wc33/cHN9/3V3ff9wcnn/dXiB/2Rncf9nanT/ -cHN9/2ptd/9qbXf/am13/2dqdP9qbXf/bG95/3N2f/9qbHP/Zmlz/2psc/91d33/bnF7/3Bzff9qbXf/ -Zmlz/2dqdP9sbnX/bnF7/2Zpc/9sbnX/bW9z/3N1fP9wcnn/bnB3/3Byef93eX//c3Z//25wd/91d33/ -eXuB/3Byef9wcnn/dXiB/3t9g/9ucHf/cHJ5/3Byef9zdn//cHN9/3d6g/97fYP/dXiB/3t+h/9zdn// -c3Z//3t9g/95e4H/d3qD/3t9g/9wc33/dXiB/3l7gf9wc33/dXiB/3V4gf9zdXz/d3qD/3l7gf91eIH/ -bnB3/3Byef9wc33/cHN9/3t9g/9vcXX/bnB3/3d5f/9zdn//bnF7/3d5f/91eIH/bnF7/25xe/9qbXf/ -cHN9/25xe/91eIH/cHN9/3l8hv9wcnn/cHN9/3N2f/9ucHf/dXiB/3d5f/9zdn//c3Z//3V4gf95e4H/ -cHN9/3Byef93eX//dXd9/2xvef9qbXf/cHN9/25xe/9wcnn/bnF7/25wd/91d33/bnB3/3Byef9zdn// -bnB3/3Bzff9vcnv/b3F1/2dqdP9ucHf/cHN9/25xe/9vcnv/bXB6/29xev9ydX7/bnB3/25wd/9maG7/ -b3F1/3J0ev9tcHr/bW93/2Zpc/9sbnX/am13/2dqdP9ucXv/c3V8/2psc/9sb3n/amxz/2xvef9ucXv/ -ZGdx/2dqdP9ucXv/cHN9/2ptd/9iZW7/Zmlz/2xudf9ucXv/Z2p0/25xe/9sbnX/bG51/3N1fP9wcnn/ -Z2px/2xudf9ucXv/ZGZs/25wd/9vcXj/b3F4/25wd/9wcnn/cHJ5/3h5ff9nanT/bG51/29xeP9sbnX/ -bnB3/3F0fv9sb3n/bG51/2ptd/9ucHf/cHJ5/29xdf9zdXz/bG51/3l7gf9ucHf/bnB3/3d6g/9ucHf/ -bG51/2ptd/9zdn//c3Z//3Bzff9sb3n/c3Z//2dqdP9nanT/eXuB/3N2f/9wc33/am13/29xdf+Agob/ -bG51/25wd/9sbnX/cHJ5/2xvef9ucXv/b3F1/2xudf92eHz/Zmhu/3N1fP9sbnX/Z2p0/2Zpc/9nanT/ -bG51/2psc/9nanH/bG51/2Zpc/9wc33/am13/2ptd/9ucXv/cHN9/2xvef9tb3P/bnF7/25xe/9zdXz/ -dXd9/3Bzff9wc33/bnF7/2Zpc/93eX//bnB3/3V3ff9ucHf/bnF7/2xvef9zdn//cHN9/3+Bh/95e4H/ -c3Z//3Byef9zdn//dXiB/3d5f/9zdn//cHN9/25wd/9zdn//dXd9/3N1fP93eX//cHJ5/3d5f/9maXP/ -am13/3N1fP9sb3n/Z2px/2psc/9qbXf/Zmlz/2dqdP9wcnn/Zmlz/2BjbP9nanH/bG95/2ptd/9sb3n/ -bG95/2Jlbv9qbXf/amxz/2ptd/9iZW7/Zmlz/2Zobv9sb3n/am13/2ptd/9tb3P/dXd9/3N1fP9ucHf/ -dXd9/3Z4fP9tb3P/bW9z/3N1fP91d33/am13/2xudf9sbnX/bnF7/2ptd/9wc33/dXd9/3Byef93eX// -c3V8/2psc/94eX3/dnh8/3Z4fP91d33/bG51/25xe/9wc33/bG51/25xe/9sb3n/bG51/25xe/91d33/ -bG51/25wd/9vcXX/c3V8/3Byef97fYP/bnB3/21vc/9zdXz/c3V8/25wd/91d33/dXd9/3Byef9wcnn/ -amxz/2xudf9sb3n/cHN9/3Bzff91d33/bG51/2xvef9sbnX/bnB3/3N1fP9zdn//c3V8/25wd/9zdXz/ -dXd9/25xe/9sb3n/dXiB/3N2f/9sb3n/bG95/25xe/9wcnn/c3V8/2xudf9sbnX/dnh8/29xdf9ucHf/ -cHN9/3Byef9zdn//c3Z//3F0fv9sb3n/bG95/3V3ff9ucHj/b3F4/2ptdf9rbnf/cXR+/2ptd/9qbXf/ -YmVu/2xvef9wcnn/b3F6/3Bye/91eID/Z2px/3N1fP9vcXX/Z2px/2psc/97fYP/cHJ5/2psc/9zdXz/ -bG95/25xe/9wc33/c3V8/25xe/9ucXv/c3V8/25xe/9nanT/cHN9/2xudf9qbXf/bG51/2xvef9gY2z/ -c3V8/2xvef9qbHP/dXd9/2Zpc/9nanH/Zmly/2dqdP9pbHT/bG95/3J1fv93eX//bG95/3Byef9ucXv/ -bG50/21wev9kZ3D/Z2lz/2dqdP9gY2z/ZGdx/2Zobv9iZW7/Zmhu/2Jlbv9maXP/Zmhu/2Rncf9sbnX/ -bG95/2Zobv9qbXf/bnF7/2xvef9ucXv/amxz/25xe/9kZ3H/ZGdx/3V3ff9sb3n/bnF7/2Zpc/9tb3P/ -foCG/2psc/9sbnX/bG51/3Bzff9qbXf/bG95/2xudf9maXP/bG95/11gav9sb3n/amxz/2Rncf9kZ3H/ -Z2p0/2xudf9sbnX/bG51/2ptd/9maXP/c3V8/2ptd/9sb3n/bnF7/25xe/9sb3n/bG51/2xvef9ucXv/ -dnh8/3h5ff9zdn//dnh8/3V3ff9qbXf/eXuB/3Byef93eX//bG95/2xvef9ucHf/c3Z//25xe/9+gIb/ -eHl9/3N1fP9wcnn/c3Z//3V4gf93eX//cHN9/25xe/9sb3n/dXiB/3l7gf9ucXv/dXiB/25wd/93eoP/ -Zmlz/25wd/93eX//bnF7/2ptd/9sbnX/cHJ5/3Byef9ucXv/dXd9/3N1fP9nanH/bW9z/3N1fP9wc33/ -c3V8/25xe/9nanT/bnB3/25xe/9zdn//bG95/25wd/9sb3n/cHN9/25wd/9ucHf/am13/3h5ff9zdn// -bnF7/3l8hv95e4H/bnB3/25wd/93eX//eXuB/3Byef9ucHf/c3V8/3V4gf93eoP/d3qD/3V4gf91eIH/ -d3qD/3V4gf9wc33/e36H/3t9g/97fof/eXyG/3Bzff95e4H/d3qD/25wd/9wc33/bnF7/3Byef91eIH/ -d3qD/3Bzff9ucHf/bnB3/3Bzff9wc33/e32D/2xvef9tb3P/dXd9/3V3ff9wcnn/eXuB/3h5ff9wcnn/ -bnF7/2ptd/9ucHf/bnB3/3V4gf93eoP/e32D/3N1fP9zdn//c3Z//2ptd/9wc33/cHN9/3N2f/9ucXv/ -c3Z//3V3ff9sb3n/bnB3/3N2f/91d33/bnB3/2psc/9sbnX/cHJ5/2ptd/9sbnX/Zmlz/3Bzff9qbHP/ -Z2px/2dqcf9maXP/am13/2lrdP9oa3L/Z2p0/2psc/9wc33/bW9z/21vdv9sbnT/aWxz/3N1fv9ucXv/ -bG95/2dqdP9ydX//dHd//3Byef9wc3r/dnh+/2Zobv9wc33/cHJ5/2dqdP9nanT/d3qD/2xvef9qbXf/ -dnh8/25xe/9zdn//cHN9/3V3ff9wcnn/cHJ5/3N1fP9wcnn/amxz/3Bzff9qbXf/bnB3/25wd/91d33/ -Zmhu/3N1fP9zdXz/am13/3d6g/9nanT/Z2p0/2hrdP9oa3L/a212/2tueP9tcHn/dXd9/2xudf9vcXX/ -bnB3/25wdv90dn3/am12/2ptd/9wc33/bG51/2xudf9sbnX/bG51/2ptd/9qbHP/cHJ5/25wd/9ucHf/ -bG95/3Bzff9gY2z/bG51/25wd/9ucXv/bnF7/2ptd/9ucXv/am13/2Rncf91d33/c3V8/3N1fP9nanH/ -b3F1/36Ahv9ucHf/bG95/29xdf9zdXz/bnB3/2xudf9ucHf/bW9z/3N1fP9maG7/bnF7/25xe/9maXP/ -ZGdx/2xudf9sbnX/b3F1/3Byef9ucXv/bG51/3N1fP9wc33/cHN9/3Bzff9wc33/bnB3/2ptd/9ucXv/ -c3Z//3l7gf93eX//d3l//3V3ff91eIH/bG95/3l7gf9zdXz/d3qD/2ptd/9wc33/c3V8/3V4gf9wc33/ -f4GH/3d5f/9wc33/cHJ5/3Bzff9zdn//dXd9/25wd/9tb3P/am13/25xe/9zdXz/am13/3V3ff9ucHf/ -d3qD/2psc/9sb3n/eHl9/3Byef9ucHf/bnB3/3V3ff9wcnn/c3V8/3V3ff9wcnn/amxz/25wd/9wcnn/ -c3V8/3N1fP91d33/bG51/3Bzff9zdn//dXiB/2ptd/9zdXz/cHN9/3V4gf9zdn//c3Z//3Bzff97fYP/ -c3Z//2xvef95fIb/d3l//2xvef9wcnn/d3l//3d6g/9zdXz/c3V8/3N1fP9zdn//cHN9/3Bzff93eoP/ -dXiB/3t+h/95e4H/bnF7/3l8hv93eX//eXuB/3l7gf9ucHf/d3l//3d6g/9zdXz/eXuB/3d6g/9zdn// -eXyG/3d6g/91eIH/c3V8/3N1fP9zdn//dXiB/3l8hv9wc33/bG95/3V3ff91d33/cHJ5/3d5f/94eX3/ -cHJ5/25wd/9nanT/bG95/25xe/91d33/dnh8/3V3ff9sbnX/am13/25wd/9nanH/cHJ5/3Byef9wc33/ -bnF7/3Bzff91eIH/cHN9/2xvef9zdn//dXd9/25xe/9qbXf/bnF7/3N2f/9sb3n/bnB3/2dqdP91d33/ -b3F1/25wd/9ucHf/amxz/25wd/9ucHj/a254/2ptd/9tb3P/cHJ5/2ptd/9qbXf/Z2pz/2Vocf9sb3n/ -Zmhu/2dqdP9gY2z/Z2p0/2hrdf9oanD/aWx2/3BzfP9iZW7/bnF7/2ptd/9maXP/Zmlz/3V4gf9qbXf/ -Z2p0/25xe/9qbXf/bnF7/25xe/9ucXv/bnF7/25xe/91d33/cHJ5/2psc/9ucXv/Z2p0/2dqdP9sbnX/ -bnF7/2Jlbv9ucXv/am13/2psc/9zdXz/Zmlz/2Rncf9nanT/aGty/2xvd/9sbnb/c3V8/3V3ff9sbnX/ -bnB3/2tud/9tb3b/cXN6/21vdv9wcnn/dXd9/2xvef9sb3n/bG95/2xvef9sb3n/bG95/3N2f/9wcnn/ -cHJ5/3Bzff91eIH/Zmhu/25wd/9vcXX/c3V8/3N1fP9wcnn/c3V8/2psc/9qbHP/d3l//3V4gf9wc33/ -cHJ5/3Byef9/gYf/bG95/25wd/9vcXX/c3V8/2xudf9tb3P/am13/2ptd/9wc33/ZGdx/2xvef9ucXv/ -YmVu/2Zpc/9sbnX/Z2p0/21vc/9sbnX/am13/2dqdP9ucXv/bnF7/3Bzff9sb3n/bG95/2ptd/9nanT/ -bG95/2ptd/9zdXz/dnh8/3Z4fP9zdXz/cHJ5/2psc/93eX//am13/3N1fP9sbnX/b3F1/29xdf9wcnn/ -dXd9/36Ahv91d33/c3V8/21vc/9ucXv/cHN9/3N1fP9sb3n/Z2p0/2ptd/9sb3n/dnh8/29xdf94eX3/ -bnB3/3V3ff9nanH/bnB3/3h5ff9wcnn/bnB3/2xvef9zdXz/c3V8/3Byef92eHz/cHJ5/2psc/9sbnX/ -cHN9/3V4gf91eIH/dXiB/2ptd/9ucXv/bG95/3Bzff9qbXf/cHJ5/2xvef9zdXz/bG95/3Byef9ucHf/ -eHl9/3V3ff9qbXf/foCG/3V4gf9tb3P/bW9z/3V3ff91eIH/bW9z/2xudf9nanT/bnB3/2ptd/9sbnX/ -cHJ5/2xudf92eHz/dXd9/2dqdP91d33/bnF7/3N1fP9ucXv/Z2p0/3Bzff9wc33/bG51/2xvef9qbHP/ -Z2px/2dqdP9nanT/am13/2psc/9nanH/bG95/2dqdP9zdn//Zmlz/2Rncf9nanT/bG95/2psc/9wcnn/ -cHJ5/2Zpc/9sbnX/Z2p0/2psc/9qbXf/cHN9/3Bzff93eX//bG51/2ptd/9sbnX/amxz/3N1fP9ucHf/ -cHJ5/3Byef91eIH/dXiB/3V4gf9ucXv/eXuB/3V4gf9ucHf/ZGdx/2xvef9wc33/bnB3/21vc/9nanH/ -dXd9/21vc/9qbXf/am13/2dqdP9sb3n/bW94/2xudv9maXP/amxz/2ptd/9kZ3H/Zmlz/2Nmbv9jZm// -bG94/2dqcf9nanT/YGNs/2xvef9sb3n/amx0/2hrdf9oa3T/Wl1m/2dqdP9nanH/XWBq/2Rncf93eX// -am13/2ptd/9zdXz/bnB3/3Byef9zdXz/c3V8/3Byef9wcnn/dXd9/3Byef9ucHX/c3V8/25wd/9wc33/ -b3F7/3V3ff9naXP/d3l//3N2f/9sb3n/dnh//25wd/9vcXX/bW92/2xudf9sbnX/bnB3/29ye/9wc33/ -Z2px/2psc/9sbnX/amxz/29xev9sbnX/bW92/3V3ff9qbXf/am13/21vef9nanT/bW9z/2Rncf9ucHj/ -bG51/2tud/9rbnf/c3V7/2Zpc/9qbXf/bnB3/3V3ff9ucXv/c3Z//3N1fP9qbHP/Z2p0/3V3ff92eHz/ -cHJ5/25wd/9vcXX/fX6B/2ptd/9qbXf/bG95/3Bzff9sbnX/bG51/2dqdP9qbXf/bnF7/2Jlbv9sb3n/ -bG95/2Rncf9iZW7/amxz/2dqcf9qbXf/amxz/2ptd/9maXP/bnF7/2xvef9sb3n/bG95/3Bzff9sb3n/ -bG51/25wd/9sb3n/dXiB/3l7gf95e4H/c3Z//3V4gf9zdXz/eXyG/3V4gf97fYP/c3Z//3V4gf9wc33/ -e32D/3t9g/+Bg4r/fn+D/35/g/9zdn//e32D/3t9g/97fYP/c3Z//3Byef9wc33/dXiB/3N2f/9ucHf/ -d3l//3Bzff93eoP/am13/25wd/93eX//bG95/3Byef9wcnn/dXiB/3V4gf9ucXv/d3l//3N1fP9qbHP/ -bG51/3N1fP9zdXz/dXd9/3V3ff9qbXf/am13/2ptd/91d33/amxz/29xdf9ucHf/c3V8/2xudf9wcnn/ -bW9z/3V3ff91d33/bG51/3t9g/93eX//bG51/2xudf9zdXz/d3l//3Byef9sbnX/bG51/25wd/9wcnn/ -bnB3/3N1fP9vcXX/dXd9/3V3ff9nanH/d3l//25xe/92eHz/cHJ5/25wd/92eHz/c3V8/2xvef9ucXv/ -bG95/2psc/9ucXv/bnF7/2xudf9vcXX/bnB3/3N2f/9ucHf/e32D/3N1fP9ucHf/dXd9/3N2f/9ucXv/ -dXiB/3V3ff9wc33/bnB3/25wd/9vcXX/bG51/3Byef91d33/eHl9/25wd/9wc33/bnF7/2xvef91eIH/ -cHN9/3V4gf9ucHf/cHJ5/3Byef9wcnn/bG51/3N1fP9ucXv/am13/2Rncf9sb3n/cHN9/21vc/9tb3P/ -amxz/3Z4fP9ucHf/bG95/3Bzff9sb3n/bnF7/25weP9wc33/bG51/2xudf9wcnn/am13/2ttdf9ucHX/ -bG52/3J0e/9sb3n/cHJ5/2Zpc/91eID/bnF7/3BzfP9vcnv/dXd9/2dqcf9zdXz/b3F4/2ttdP9sbnX/ -dXd9/21wd/9rbXX/c3V8/2ptd/9vcnz/bXB6/21wev9tcHr/aWx2/21wev9wcnr/a21y/3Fzev9tb3T/ -cHJ5/3Byef91d33/a210/3d5gv9wc3z/bnF6/3V3ff9ucHf/bW92/25wd/9tb3T/bnB1/21wef9vcnv/ -bnF7/2dqdP9sbnX/amx0/2ttdP9wcnv/cHJ7/29xev96fIL/cHJ6/29xeP93eoL/b3J8/29xef9pbHb/ -b3J8/2ptdv9tcHr/bXB6/29ye/9iZW7/Z2p0/2xudf9sb3n/bG95/2xvef9sb3n/Zmlz/2ptd/9wc33/ -dXd9/2xvef9qbXf/Zmlz/3d6g/9sb3n/Z2p0/2ptd/91d33/bG51/2xvef9nanH/bnB3/3N2f/9qbHP/ -c3V8/3Bzff9qbXf/bnB3/25xe/9sb3n/bnF7/3Bzff9ucHf/bnB3/3Bzff91d33/c3V8/3V4gf9zdn// -cHN9/3Byef9ucXv/bnF7/3N2f/91eIH/e32D/3Bzff9zdn//bnB3/3d5f/9ucXv/dXd9/2ptd/9qbXf/ -bG51/3Byef91d33/d3l//3Bzff9ucHf/bnB3/3N1fP9wcnn/cHJ5/2xvef9qbXf/bG51/2xvef9sb3n/ -Zmlz/3Bzff9qbXf/dXd9/2Jlbv9nanT/d3l//2ptd/9tb3P/bG51/3Byef9zdXz/bG51/3Z4fP9wcnn/ -bG51/2psc/9sb3n/bG95/3V3ff91d33/am13/2ptd/9qbHP/am13/2Zpc/9sbnX/am13/2xvef9qbHP/ -cHJ5/29xdf95e4H/dnh8/2xudf95fIb/e32D/29xdf9sbnX/c3V8/3d5f/9wcnn/bnB3/25wd/9vcXX/ -c3V8/2psc/9ucHf/bW9z/3V3ff91d33/Z2p0/3V4gf9ucXv/c3V8/2dqdP9maXP/bnB3/2ptd/9nanT/ -Z2p0/2Zpc/9kZmz/Zmhu/2dqdP9maG7/ZGdx/2Zobv9maXP/ZGdx/3Bzff9maXP/ZGdx/2xvef9sb3n/ -amxz/3V3ff9wc33/bnF7/2ptd/9qbXf/amxz/2xudf9sb3n/dXd9/3N1fP9tb3P/b3F1/3Byef9qbXf/ -cHN9/25wd/91d33/bW9z/25wd/9sb3n/am13/2xudf92eHz/cHJ5/25wd/9qbHP/bnB3/3N1fP9tb3P/ -bG95/25wd/97fYP/cHN9/3d6g/9ucXv/bG95/3Byef9vcXj/cHJ5/2dqcf9sbnX/bnB3/25wd/9vcXj/ -bnB1/2xvdv9ydHv/bW9z/3Byef9nanH/cHJ5/21vdv9ydHv/b3F6/3V3ff9jZnD/a254/2ptd/9maXL/ -Z2ly/3F0e/9oa3X/Zmlz/25xev9pbHT/bG95/25xe/9pbHX/amx1/2hrc/9sb3f/am13/2Zobv9pbHb/ -Z2pz/2hrdf9tcHj/am12/2Nlbv9wc3r/aGt0/2xudP9sb3n/aGtz/2ZocP9sb3f/amxy/2tud/9ucHb/ -c3V8/3N1fP9qbXf/bnB3/3Byef9ucHf/cHJ5/3J0ev9vcXj/dnh+/3Bze/9rbXb/cXR+/25wd/9ucHf/ -am12/3BzfP9sb3f/cXN6/3Fzev9wcnn/Zmlz/2ptd/9qbXf/bG95/2Zpc/9maXP/Z2p0/2Rncf9iZW7/ -ZGdx/25wd/9kZ3H/Z2px/2Jlbv9zdXz/Zmhu/11gav9kZmz/bG95/2Rncf9maXP/XWBq/2Zobv9qbXf/ -XWBq/2dqdP9kZ3H/XWBq/2Jlbv9kZ3H/Z2px/2dqdP9sb3n/Z2p0/2psc/9ucXv/cHN9/25xe/9sb3n/ -bG95/25wd/9sbnX/bnB3/29xdf92eHz/cHN9/3d5f/9zdn//eXuB/25xe/95fIb/c3Z//3V4gf9ucXv/ -c3V8/3N1fP91eIH/eXuB/3l8hv9zdn//bnF7/25xe/91eIH/cHN9/3N2f/9wc33/bnB3/3N2f/91eIH/ -c3Z//3Byef95e4H/c3Z//3l8hv9ucHf/b3F1/3d5f/9vcXX/bnB3/3Byef9zdn//cHN9/25xe/93eX// -c3Z//2xvef9ucHf/bnF7/3Byef92eHz/eHl9/25wd/93eoP/c3Z//3l7gf9ucXv/cHJ5/3Byef9wc33/ -bG95/3Bzff9sb3n/d3qD/3V3ff9ucHf/fn+D/3l7gf9vcXX/bG95/3V3ff91eIH/cHN9/29xdf9qbHP/ -bG95/25xe/9qbHP/bnB3/25wd/91d33/dXd9/2xvef93eoP/dXiB/3t9g/9zdn//bG95/3V4gf9zdn// -c3Z//3N2f/91eIH/bG95/3Bzff91d33/bnB3/29xdf9wcnn/c3V8/2xudf97fYP/bnB3/2ptd/91d33/ -dXd9/21vc/91d33/bnF7/2xvef9maXP/ZGdx/2Zobv9qbHP/Z2p0/25wd/9qbXf/ZGZs/2Zobv9maXP/ -YmVu/2dqdP9nanH/Z2p0/2psc/9nanT/am13/2ptd/9nanT/dXd9/2xvef9nanT/Zmlz/25xe/9wcnn/ -bW9z/25wd/9sbnX/d3l//25wd/9wcnn/bnB3/2xudf9vcXX/cHJ5/3Bzff9qbHP/b3F1/3N1fP9ucHf/ -cHJ5/25wd/9tb3b/b3F4/25wd/9ucXv/Z2p0/3Bzff9vcXj/cnV+/29xef95e4H/Zmlz/3J1fv9qbXf/ -b3J8/25wd/9xdH7/cnR9/25xef93eYD/cHJ6/3R2fv90dn7/bG95/3F0ff9ucXr/bnB5/29yfP9nanL/ -bXB6/21wdv9tb3f/dnh9/3J1fv9tb3b/d3l+/29yfP9xdHv/cHN7/2ptd/9maXP/dHZ8/2xudP9ucHf/ -bnB0/3N1fP9zdXz/Z2p0/2xudf9sb3n/Zmlz/2tud/9xc3r/aGt1/3V3ff9ucHf/ZWhy/3Fze/9qbXf/ -bG94/21wd/9zdX3/amx0/21wev9ydHr/a254/2Zpc/9ucXv/bG95/3Byef9ucHf/bnB3/25wd/9sbnX/ -am13/2xvef92eHz/bnB3/25wd/9ucHf/e32D/3V3ff9sbnX/bG95/3V3ff9sbnX/bG95/2Zpc/9qbXf/ -cHN9/2Rncf9qbHP/bnF7/2psc/9ucHf/c3V8/25wd/9sbnX/c3V8/25wd/9ucHf/cHN9/3d5f/9ucXv/ -dXd9/3V3ff9wcnn/bG51/25wd/9tb3P/dXd9/3Bzff95e4H/c3Z//3N2f/9sb3n/eXyG/3l7gf9zdn// -bnB3/3N1fP9zdXz/c3Z//3t9g/9+gYr/dXiB/3N2f/9ucXv/bnF7/25xe/9ucXv/bG95/2xvef91eIH/ -c3Z//3N2f/9wcnn/eXyG/3d6g/9+gIb/c3V8/3N1fP95fIb/cHN9/3Bzff9zdXz/dXiB/3N2f/9ucXv/ -eXuB/3V4gf9ucHf/cHN9/3V4gf91eIH/e32D/36Ahv91d33/c3V8/25wd/91d33/bnB3/25wd/9ucHf/ -bnB3/2xudf9wc33/am13/3V3ff9wc33/Z2px/3d6g/9zdn//amxz/2xudf9zdXz/dXd9/3Bzff9qbXf/ -Z2p0/2xudf9wc33/Z2p0/2xudf9sbnX/c3V8/3Bzff9maXP/dXd9/2dqdP9wc33/bnF7/2dqdP9zdXz/ -bnF7/2xvef9ucXv/bnF7/2ptd/9sbnX/bnF7/2dqcf9maG7/Z2px/2dqdP9kZ3H/dXd9/2psc/9nanH/ -bnB3/2xvef9maG7/bnF7/2ptd/9ucXv/Zmlz/2psc/9qbHP/bG95/2xvef9wcnn/cHJ5/2dqdP9qbHP/ -Z2p0/2Zpc/9wc33/bG51/2ptd/9qbXf/am13/2xudf9sb3n/bG51/3Z4fP91d33/bnB3/2Zpc/9wcnn/ -cHJ5/21vc/9sbnX/b3F1/3h5ff9ucHf/cHJ5/2xudf9sbnX/bG95/25xe/9ucXv/Zmhu/21vc/9zdXz/ -bnB3/3N1fP9ucHf/b3F2/2ptd/9sbnX/bnB3/2Zobv9zdXz/bnB3/3N1fP9xc3r/eXuC/2hrcv9ydXz/ -a211/3R2ff9ucHf/cnV//3V3ff9vcXj/dnh9/3Bzff9xdH7/eHqD/3F0fv9wc3z/cHN8/3Byef90d4D/ -aWxz/3N2f/9ucXv/bXB6/3d5f/90d3//bG95/3V3ff9sb3n/c3Z//29yfP9wcnn/Z2pz/3h6gP9vcXX/ -cHJ5/25wd/92eHz/c3V8/21vc/9sbnX/bnF7/2psc/9sbnX/cnR8/2Zpc/9wcnn/Zmlz/2Nmb/90dn3/ -am13/25xev9vcnz/dnh+/21vc/90dnz/dHZ8/25wd/9maXP/bnF7/2ptd/9ucXv/bnF7/2xvef9ucHf/ -bG51/2psc/9sbnX/dnh8/25wd/9wcnn/bG51/3l8hv9zdn//Z2p0/2xvef9zdn//bnB3/3Byef9sb3n/ -bG95/25xe/9qbHP/bG95/3Bzff9sb3n/bnB3/3N2f/93eoP/dXiB/3d6g/9wc33/dXd9/3t9g/9+gIb/ -dXiB/3d6g/97fYP/c3V8/3Bzff9wc33/bnB3/3N2f/9zdn//eXuB/3Bzff9wcnn/am13/3V4gf91d33/ -cHJ5/25wd/9sb3n/cHJ5/2xvef91d33/d3l//2xvef9sb3n/am13/2xvef9sbnX/bnB3/25wd/9sb3n/ -d3qD/3d6g/9zdn//bnF7/3t+h/95e4H/foGK/3N2f/9wc33/eXyG/3N1fP91eIH/d3l//3d6g/97fYP/ -eXyG/3t9g/95e4H/c3V8/3Bzff91eIH/bnF7/3Bzff93eX//bnB3/3N1fP9wcnn/dXd9/2xudf9tb3P/ -bG51/2ptd/9nanT/cHN9/2ptd/93eX//d3l//2dqcf95e4H/dXd9/2Zpc/9maG7/bG95/2ptd/9nanT/ -Zmhu/2Jlbv9nanH/am13/2Jlbv9kZ3H/Zmhu/2ptd/9nanT/ZGdx/25wd/9maXP/Z2p0/2dqdP9kZ3H/ -bnB3/2Rncf9maG7/Z2p0/2ptd/9kZ3H/ZGdx/2dqdP9nanT/Z2px/2dqcf9nanT/YmVu/3Byef9qbHP/ -amxz/3N1fP9ucXv/bG51/3Z4fP9ucXv/bG95/2Zpc/9qbHP/amxz/25xe/9sb3n/dnh8/3V3ff9sb3n/ -am13/2xudf9nanT/bnF7/2psc/9wc33/bG95/2xvef9qbXf/am13/2dqdP91d33/bnF7/2xudf9sbnX/ -cHJ5/3Byef9sbnX/b3F1/29xdf94eX3/bnB3/3Byef9ucHf/amxz/2ptd/9wc33/c3Z//2ptd/9zdXz/ -dXiB/3N1fP93eoP/c3V8/3Bzff9zdn//cHN9/3V4gf9ucXv/dXiB/2xvef9wc33/cHN9/3d6g/9nanT/ -c3Z+/2xvef94eoD/cHN9/3N2f/94eoD/cHJ5/3V3ff9wc33/bnF7/3d5f/9ucXv/bG95/3N1fP9sbnX/ -dXd9/2RmbP9ucHf/am13/2psc/94eX3/dXd9/29xdf94eX3/b3F1/3N1fP9sb3n/bW9z/2Zobv94eX3/ -b3F1/3Byef9wcnn/eHl9/3V3ff9tb3P/bnB3/3N1fP9sbnX/bG95/3N1fP9sbnX/dXd9/3Byef9qbHP/ -d3l//2ptd/9ucXv/cHN9/3V3ff9nanH/c3V8/25wd/9nanH/YGNs/2dqdP9maXP/am13/25xe/9sb3n/ -bG51/2psc/9nanT/amxz/3N1fP9qbXf/bG51/2psc/93eoP/bnF7/2Rncf9sbnX/cHN9/2xvef9sb3n/ -am13/2dqdP9qbXf/Z2p0/2ptd/9sb3n/bG51/25wd/9ucHf/dXd9/2xudf9zdXz/b3F1/2xudf9ucHf/ -dXd9/2ptd/9zdXz/dXd9/2xudf9qbXf/bG95/2xudf9wc33/cHJ5/3l7gf9sb3n/cHN9/25wd/95e4H/ -dXiB/25xe/9vcXX/b3F1/25wd/9sbnX/c3Z//3t+h/9ucXv/bnF7/3Bzff9sb3n/bG95/2xudf9wcnn/ -bnB3/3N2f/9zdn//bnF7/2ptd/91eIH/cHN9/3l7gf9wcnn/bW9z/3V3ff9tb3P/bG95/25wd/9vcXX/ -dXd9/3N1fP9zdXz/c3V8/25wd/9ucHf/c3V8/29xdf9zdXz/d3l//25wd/9wcnn/cHJ5/3Byef9qbXf/ -bG51/2xudf9sb3n/am13/3N1fP9qbXf/eHl9/3d5f/9vcXX/f4GH/3d5f/9wcnn/b3F1/3Z4fP92eHz/ -c3V8/2xudf9nanT/bG51/3N1fP9nanT/am13/2xvef9zdXz/cHJ5/29xdf93eX//dXd9/3N1fP9wcnn/ -b3F1/3Z4fP9wcnn/bnB3/3Byef9wc33/bnB3/25wd/9zdXz/c3V8/21vc/9sbnX/bG95/2dqdP9zdXz/ -bG51/2xvef91d33/cHJ5/25wd/93eX//cHJ5/3N1fP9qbHP/bnB3/2xvef91d33/c3Z//3d5f/91d33/ -c3Z//2xvef9ucHf/bG51/3N1fP9tb3P/dXd9/25wd/9sb3n/cHN9/3Bzff9ucHf/eXuB/3N2f/9zdXz/ -bnB3/3N1fP9ucHf/bG51/2xudf9sbnX/d3l//2ptd/9sb3n/bG95/2dqdP9sbnX/bnB3/3Byef9nanH/ -b3F1/3N2f/9wcnn/cHN9/2xvef9vcXX/bnF7/29xdf9wcnn/Zmhu/3N1fP9ucHf/dXd9/3V3ff93eX// -Z2p0/3N1fP9qbXf/dXiB/2xvef9sb3n/dnh8/21vc/91d33/bG95/2xvef9wc33/bG51/2psc/9ucXv/ -Zmlz/25xe/9dYGr/Zmlz/3Byef9qbXf/d3l//3Bzff9ucHf/d3l//25wd/9ucXv/bG95/2xvef9nanT/ -eHl9/25wd/9ucHf/cHJ5/3Z4fP91d33/bnB3/29xdf9zdXz/am13/2xudf9wc33/amxz/3V3ff9sbnX/ -amxz/3N1fP9qbXf/bG95/3N1fP93eoP/bG51/3V3ff92eHz/bG51/2Zpc/9wc33/cHN9/2xvef9sb3n/ -bnF7/2ptd/9qbHP/Zmlz/2dqcf91d33/Z2p0/2xvef9maXP/dXiB/25xe/9maXP/bG95/3N1fP9sb3n/ -bnF7/2psc/9maXP/am13/2psc/9nanT/cHJ5/2dqdP9qbXf/cHJ5/3Z4fP9wc33/dXd9/29xdf9sb3n/ -cHN9/3l7gf9wc33/c3Z//3V3ff9sb3n/bG95/25xe/9sb3n/dXd9/3N1fP97fof/bnF7/3Bzff9sb3n/ -eXuB/3N2f/9ucXv/bnB3/3N1fP9ucXv/bnF7/3N1fP93eoP/bG95/25wd/9ucXv/am13/2ptd/9ucHf/ -bnB3/2xudf9wc33/cHJ5/25wd/9qbHP/dXd9/3Byef91eIH/am13/2psc/9ucXv/bG51/2psc/9qbHP/ -Zmlz/25xe/9maXP/bnF7/3N1fP9qbXf/bG51/3Byef9tb3P/c3V8/3l7gf9ucHf/c3Z//3N2f/9wc33/ -bnB3/3Byef9wcnn/c3Z//3Byef93eX//bG95/3Z4fP95e4H/bG51/3+Bh/91d33/bG51/2ptd/91d33/ -cHN9/3Bzff9sb3n/Z2p0/2xudf9wc33/bG51/3Byef9qbXf/cHJ5/3Byef9qbXf/dXiB/3Bzff9zdXz/ -bG95/2xudf9zdXz/cHJ5/3Byef9wcnn/dXd9/3Byef9ucHf/bnB3/2xvef9sb3n/am13/2dqdP9nanT/ -cHN9/2xudf9qbHP/c3Z//2xvef9nanT/bnF7/2ptd/9ucXv/Z2px/21vc/9sbnX/eHl9/3Bzff9zdn// -d3l//3Bzff9ucHf/bG95/25wd/9wc33/bG95/3Bzff9ucHf/cHN9/3N2f/9ucXv/bG51/3d5f/9wcnn/ -bW9z/21vc/9zdXz/bnB3/2xvef9sbnX/bG51/3V3ff9maXP/Zmlz/2Zpc/9dYGr/amxz/2ptd/9sb3n/ -Zmlz/2xudf9wcnn/bG51/25wd/9tb3P/am13/2xvef9qbXf/bnF7/2Rncf9wc33/bG51/3N1fP9zdXz/ -dnh8/2dqcf9zdXz/b3F1/3V3ff9sb3n/bG95/3V3ff9ucHf/dXiB/3Byef9wcnn/c3Z//25xe/9ucHf/ -c3V8/2ptd/9wc33/Z2p0/3V4gf9zdXz/am13/3t9g/91eIH/dXiB/3t9g/9zdXz/dXiB/3Byef9ucXv/ -c3V8/36Bif9zdn//dXiB/3N2f/95fIb/eXuB/3N1fP9ucHf/dXd9/2xvef9zdn//d3qD/3Bzff95e4H/ -bnF7/2xudf93eX//bG95/3N1fP93eX//e32D/29xdf92eHz/dnh8/3Byef9sbnX/dnh8/3N2f/9ucXv/ -c3V8/3V3ff9wc33/c3Z//3Byef9wcnn/eXyG/3Bzff9wc33/am13/3t9g/9wc33/Z2p0/25xe/91d33/ -bnF7/3N2f/9ucHf/bG51/25wd/9vcXX/bG51/3N1fP9nanT/Zmlz/2xvef9wc33/bG95/2ptd/9kZ3H/ -amxz/2psc/9ucHf/Z2px/25xe/9wc33/amxz/21vc/9ucHf/cHJ5/25wd/9zdn//d3qD/2xvef9wc33/ -bG95/3l7gf91eIH/c3Z//3Byef9wc33/d3qD/3V4gf95fIb/foGK/3V4gf9zdn//dXiB/3V4gf91eIH/ -c3Z//3V4gf9zdXz/eXuB/3N2f/9ucHf/bG51/3V3ff9zdXz/eXuB/2xudf9vcXX/dXd9/2xvef9sb3n/ -bG95/2xvef92eHz/bnF7/3d5f/97fYP/bnF7/2xvef9wc33/b3F1/25xe/93eoP/bG95/3Byef9wcnn/ -cHJ5/2xudf9ucHf/bW9z/3Byef9ucHf/dnh8/3Byef93eX//e36H/25xe/+Bg4r/d3l//25wd/9wcnn/ -c3V8/3Z4fP91d33/c3Z//2xvef9wcnn/c3Z//2xvef9zdn//bnF7/3V4gf9zdn//cHJ5/3+Bh/93eoP/ -eXuB/3N2f/9wc33/dXiB/3N2f/9zdn//e32D/3d6g/95e4H/dXiB/3N2f/91eIH/c3Z//2xvef9ucXv/ -bG95/3l7gf9wc33/c3Z//3l8hv9wc33/b3F1/3Bzff9sb3n/c3V8/2Zpc/9tb3P/cHJ5/3Z4fP92eHz/ -dXiB/3h5ff9zdXz/bG95/25wd/9vcXX/cHJ5/3Byef91eIH/c3V8/3Bzff9zdn//cHN9/2ptd/91eIH/ -c3Z//2xvef9wcnn/cHN9/2xvef9ucXv/bG95/2xvef93eX//bnB3/3Byef9zdXz/Zmhu/2psc/9qbXf/ -bnF7/2Zpc/9qbHP/am13/2Zobv9sbnX/Z2px/2Zpc/9nanT/bG51/2xudf9iZW7/dXd9/25wd/92eHz/ -c3V8/3V3ff9nanT/bnF7/3Byef90d4H/c3Z//3N2f/94eoD/cnR7/36Ahv90d4D/dHeA/3p8gv92eYL/ -c3Z+/3Z5gv9vcnz/eXuC/21wev91eIH/bG51/2Jlbv9vcnz/a211/2lrcv9xdHv/aWxz/29yfP9qbHP/ -aWx2/2Zpcv91d33/aWx2/2xveP9qbXf/d3l//3Byef9ucHf/b3F1/3V3ff9sbnX/bnF7/3N1fP9sbnX/ -dXd9/2xudf9sbnX/d3h9/3Byef9wcnj/dHd7/3h6gP9sbnX/cHN9/3N1fP9tb3b/bG51/3V3ff9zdXz/ -bnB3/3N1fP9sb3n/am13/2xudf9nanT/bG51/3Z4fP9sbnX/bnF7/2dqdP93eoP/bnF7/2Zpc/9sbnX/ -dnh8/2xudf91d33/b3F1/2xvef9ucXv/bnB3/29xdf9wcnn/bG51/2psc/9zdXz/dXd9/3Byef9zdXz/ -bG51/2xudf9qbXf/c3V8/2xvef9zdXz/dnh8/25wd/9ucHf/cHJ5/3Byef9ucXv/dXd9/3t+h/9sb3n/ -cHJ5/2ptd/93eX//c3Z//3Bzff9ucHf/bG95/25xe/9wc33/c3Z//3l8hv9zdn//cHN9/3Bzff9wc33/ -cHN9/3Byef9wcnn/bnB3/3N2f/9ucXv/cHN9/2dqdP91eIH/dXd9/3d5f/9sbnX/bG51/3Bzff9sb3n/ -am13/2xudf9ucHf/dXd9/3Byef9zdn//d3l//2xudf9vcXX/c3V8/29xdf9ucHf/eHl9/3Byef9ucXv/ -bnF7/2ptd/9nanT/bG95/2xudf9wcnn/bnB3/3V3ff9sbnX/dXd9/3l7gf9vcXX/gYSN/3d5f/9sb3n/ -cHJ5/3Z4fP91d33/dnh8/3Byef9maG7/bnB3/3Bzff9wcnn/dXiB/3Byef9wc33/c3Z//3N1fP9/gYf/ -bnF7/3l7gf9wc33/c3V8/3l8hv93eoP/cHN9/3d6g/9wc33/c3Z//25xe/9ucXv/cHN9/3Bzff9ucXv/ -cHN9/3Byef93eoP/cHN9/3Bzff93eoP/dXiB/3Bzff91eIH/dXiB/3V4gf9qbXf/cHN9/3Bzff95e4H/ -c3Z//3l7gf95e4H/d3qD/3Bzff9wc33/dXiB/3d6g/9zdn//d3qD/3N2f/91eIH/c3Z//3Byef9ucHf/ -d3l//3N2f/9sb3n/bG95/25xe/9sbnX/c3V8/2xudf9ucHf/d3l//2dqdP9zdn//c3Z//2Zpc/9vcXX/ -bnB3/2xvef9kZ3H/bG51/3N1fP9vcXX/bnB3/25wd/9zdn//cHN9/25xe/9wc33/Zmlz/3d5f/9sb3n/ -dHeA/3h6gf93eX//am13/3BzfP9sb3n/cnV+/3J0e/91d33/dXh9/29xdv94eoH/bXB3/25weP9xdH3/ -bnF7/25wd/9wcnr/aWx2/29ye/9laG//aWx1/3J0ff9rbnj/cnV+/21weP9sb3n/dnh//2xvef9ydHv/ -cXN6/2psdP9naXD/cXN5/2psdP9sbnX/bG95/3d6hP9tcHr/cHN9/2xvef9wc33/bG95/25xe/9ydX7/ -bXB6/3h6gP9vcXj/bG51/3Z3ff9ydHv/b3F4/3N1e/90dn3/bnB0/3N1e/90dn3/bnF6/25wd/92eHz/ -c3Z//3Byef9wcnn/c3V8/2xudf9zdXz/bnB3/2xudf94eX3/am13/3Bzff9maXP/c3Z//3Bzff9maXP/ -bG51/3N1fP9sbnX/dXd9/2xudf9ucHf/bnF7/25wd/9ucHf/cHN9/2xvef9sbnX/c3V8/3h5ff9wcnn/ -c3V8/21vc/9vcXX/bG51/3l7gf9wc33/d3l//3V4gf9wcnn/bnF7/3Bzff9ucXv/bG95/3h5ff93eX// -bW9z/2xudf9nanT/d3l//25xe/9sb3n/amxz/2psc/9qbXf/bG95/2xvef9zdXz/cHJ5/2xudf9sb3n/ -am13/2xudf9sbnX/am13/2dqdP9ucXv/bG95/2xudf9maXP/dXd9/25xe/95e4H/bG51/25wd/9zdXz/ -cHJ5/2xvef9qbXf/bG51/3Z4fP9ucHf/dXd9/3d5f/9sbnX/b3F1/3Bzff9tb3P/bnB3/3V3ff9ucXv/ -cHJ5/25xe/9sbnX/bW9z/2xvef9qbXf/amxz/2ptd/9zdXz/am13/3Z4fP91eIH/bG51/3+Bh/91d33/ -bW9z/2xudf9wc33/bnF7/3N1fP9wcnn/ZGdx/21vc/9zdXz/bW9z/3Z4fP9sbnX/cHJ5/25wd/9sbnX/ -eXuB/2ptd/91d33/bG51/2dqcf93eX//am13/2xvef9ucXv/am13/25xe/9qbHP/bG51/2ptd/9sb3n/ -cHJ5/25wd/9sbnX/dXd9/2xvef9ucHf/d3qD/3Bzff9ucXv/c3Z//25xe/9ucXv/Z2p0/2xvef9ucXv/ -eXuB/3V4gf93eoP/dnh8/3N1fP9sbnX/bW9z/2xudf9ucHf/bW9z/2xvef9sbnX/bG95/2xudf9maXP/ -YmVu/2xvef9nanT/Zmlz/2xudf9sb3n/am13/25xe/9qbHP/bG51/3V3ff9qbHP/bG95/3Bzff9maXP/ -am13/21vef9tcHr/amxz/2psc/9zdXz/bG51/2xudf9vcXX/c3V8/3V3ff9sb3n/bnF7/2dqdP91eIH/ -bG95/3R2e/92eHz/dHZ9/2ptdv9ucHn/bG93/3Bze/9ucXn/c3Z+/3Fzev9sbnb/dnmC/3Byev9ydX7/ -dnh+/3N1fv91d33/d3l//25wef91eID/a212/3Bzff9vcnz/bW94/3V3f/9xdHz/bnF7/3V3gP9wcnv/ -cXN6/3R2fP9tcHr/bnB5/3N1fv9tb3j/bnB5/3J0ef93eoH/bW94/3V3ff9sbnX/cHJ5/25wd/9wcnn/ -dHZ8/21wef93eX7/bnF5/2tueP9xdHz/b3J6/21vdv9ucXn/c3V9/2xvdv9tcHj/bnF7/29yev9sb3n/ -dXd9/3V3ff9ucXv/dXiB/3V4gf9sb3n/cHN9/2xvef9qbXf/dXd9/3N1fP91d33/Zmhu/3V3ff9ucXv/ -ZGdx/2psc/9wc33/bG51/25wd/9nanH/Z2p0/2psc/9maG7/Zmhu/2xvef9nanT/Zmlz/3Byef92eHz/ -c3V8/3Byef9sb3n/bnB3/25wd/95fIb/cHN9/3l7gf91eIH/cHJ5/3N2f/91eIH/eXyG/3V4gf9+gIb/ -foGK/3N1fP9wc33/cHN9/36Biv97fYP/c3Z//3Bzff9zdn//c3Z//3N2f/9zdXz/dnh8/25wd/9ucHf/ -cHJ5/21vc/9vcXX/b3F1/2xvef9sb3n/cHN9/3Bzff9ucHf/Z2p0/3d6g/91eIH/foGK/2ptd/9ucXv/ -dnh8/3V3ff9sb3n/bG95/3Byef91eIH/bnF7/3V4gf93eoP/bG95/3Bzff91eIH/bnF7/25xe/94eX3/ -cHJ5/3N2f/9wc33/cHJ5/3Byef9wc33/bnB3/3Byef9ucXv/eXuB/25wd/91eIH/dXiB/2xvef9/gYf/ -eHl9/29xdf9sbnX/cHN9/25xe/91d33/bnF7/2BjbP9qbHP/am13/2Zobv9qbXf/Zmhu/2Zpc/9nanH/ -Z2px/3V3ff9qbHP/bG95/2xudf9nanH/cHJ5/2xvef9sb3n/bG95/2xudf9ucHf/b3F1/29xdf9ucXv/ -bnF7/3V4gf9ucXv/bnB3/25xe/9wc33/cHJ5/3l7gf9wc33/c3Z//3V4gf9zdn//bnF7/2xvef9zdn// -d3qD/3t9g/93eoP/eXyG/3l7gf93eoP/dXiB/3N1fP9wcnn/c3Z//3Bzff91eIH/cHN9/3l7gf9wc33/ -c3V8/25xe/97fYP/eXuB/3Bzff9wc33/cHN9/25xe/9sb3n/am13/29xdf92eHz/am13/25xe/9zdn// -Zmlz/2xvef9vcnz/b3J7/2dqdP9qbXf/c3Z//25xe/9sb3n/bnF7/3V4gf91eIH/cHN9/3N2f/9sb3n/ -eXuB/29ye/93eYD/eXuB/3l7gf9wc3v/dHd+/3V3fv92eH//c3aA/3t9hP90dn3/bnF6/3V3gP9vcnz/ -dnmD/3d6hP90d3z/d3mA/3x9gv91eH//e3yA/25xe/91d4D/dHd//29yfP92eYL/cnV+/29yef93eoL/ -dXiB/3F0ff93eX//bG94/2xueP9vcXj/bG94/21wef9ydHv/dnh8/29xef9wcnn/bG51/3N1fP9qbHP/ -b3F3/3J0e/9rbnj/eHp//3Byef9sb3n/dXiB/3V4gf9ydHv/b3F5/29yfP9ucHj/cXN6/29yef9ydX3/ -bnB3/3d5f/91eIH/bnF7/3V3ff91d33/bnB3/3N1fP9ucHf/bG51/3V3ff9zdXz/dnh8/2dqcf92eHz/ -dXd9/2dqdP9sb3n/dXd9/21vc/91d33/am13/2xudf9tb3P/bW9z/2xudf9wcnn/bG51/2psc/9zdXz/ -c3V8/3N1fP9wcnn/bG51/2xudf9vcXX/eXyG/25xe/91eIH/bnF7/2xvef9ucXv/bnF7/25xe/9wcnn/ -dXd9/3V4gf9sb3n/cHJ5/2psc/91d33/c3V8/2xudf9ucHf/bG95/2ptd/94eX3/bnB3/3V3ff9ucHf/ -cHJ5/3Byef9qbXf/am13/2xudf9qbHP/bG51/2xvef9ucXv/bG51/2dqdP91d33/bG95/3V4gf9maXP/ -bG95/3V3ff9zdXz/bG51/2psc/9sbnX/bnF7/2ptd/9wc33/d3l//2xudf9wcnn/dXd9/25wd/9ucXv/ -dXd9/3V4gf91eIH/c3Z//3Byef9sb3n/bnB3/25wd/9sbnX/bG51/3V3ff9ucHf/d3qD/3V4gf9ucHf/ -f4GH/3V4gf9tb3P/b3F1/3V3ff9ucXv/dXiB/3Bzff9nanT/bG95/25xe/9ucHf/dXd9/21vc/91d33/ -bnB3/25wd/93eoP/bnB3/3N1fP9ucHf/bW9z/3Z4fP9ucHf/cHJ5/3Byef9ucHf/c3V8/25wd/9ucHf/ -bnB3/29xdf91d33/bnB3/21vc/9sbnX/am13/2psc/9wc33/bG95/2ptd/9ucXv/Z2p0/2psc/9iZW7/ -Zmlz/2ptd/9nanT/Zmhu/2ptd/9maXP/Zmlz/2dqcf9maG7/ZGdx/2Rncf9kZ3H/Zmlz/2Jlbv9nanT/ -YmVu/2BjbP9kZ3H/bG95/2xvef9gY2z/Zmhu/2RmbP9nanT/ZGdx/11gav9kZ3H/Z2p0/2Zpc/9nanT/ -am13/11gav9maXP/bG95/2xveP9oa3T/Zmlz/2ptd/9qbXf/bG51/21vdv9wc3z/bG95/2ptd/9qbXf/ -Zmlz/3N1fP9sbnb/cXN5/3F0ff90d3//bnB1/25wd/9vcXn/bXB6/25weP9wc33/bW92/2psc/9vcnv/ -am13/29yfP9ucXv/bG51/25wd/9ydHv/bnF6/3d6gv9ydHv/c3Z//3V4gf91eIH/e32D/3V4gf90dn3/ -e32D/3d6g/9xdH7/e32G/3d5ff91eIH/dnh9/3V4gf90dn3/eXuA/3x/h/94eoH/enyC/3l7gf99foH/ -c3Z//3N2f/94eoD/cXN5/3p7gP9xc3f/bG95/3V3ff91d33/bW92/21vdv9tb3f/aGt1/2ttdP9oa3X/ -bG95/2xvef91d33/c3Z//3Byef9wc33/dXd9/2ptd/9wc33/bG51/2xudf91d33/cHJ5/3Z4fP9nanH/ -dnh8/3N2f/9sbnX/bW9z/3N1fP9ucHf/d3l//25wd/9ucHf/b3F1/21vc/9sbnX/c3V8/21vc/9qbXf/ -cHN9/3V3ff9zdXz/c3V8/21vc/9sbnX/bG51/3N2f/9qbXf/bnF7/2dqdP9maXP/Z2px/2dqcf9maXP/ -ZGdx/2xvef9wcnn/amxz/2psc/9maXP/c3V8/25xe/9sbnX/am13/2psc/9sbnX/c3V8/2xudf9sb3n/ -bG51/2ptd/9qbXf/am13/2xvef9sbnX/bG51/2xudf9ucXv/cHN9/2ptd/9ucHf/d3l//25wd/93eX// -amxz/25wd/92eHz/dXd9/2xudf9qbXf/bG51/3V3ff9sb3n/bG95/3d5f/9qbXf/bG95/3Bzff9sbnX/ -cHJ5/3V3ff9zdn//c3Z//3Bzff9ucHf/bG95/25wd/9sb3n/bnB3/2xvef91d33/bnB3/3l8hv93eX// -bW9z/35/g/93eX//bnB3/2xudf9zdXz/bnB3/3V3ff9wcnn/Zmlz/29xdf9zdXz/bnB3/3Z4fP9tb3P/ -c3V8/3N1fP9vcXX/e32D/25wd/9wcnn/bnF7/2xudf9zdXz/am13/2xvef9qbXf/am13/2ptd/9tb3P/ -bG51/2xudf9vcXX/c3Z//25xe/9ucHf/bG95/2xvef9ucHf/dnh8/3Byef9ucHf/cHJ5/25wd/9ucHf/ -amxz/3Byef9zdn//dXiB/3Bzff97fYP/c3Z//3V4gf9sb3n/bnB3/29xdf9ucHf/bG51/3Byef9qbXf/ -c3V8/2dqdP9nanT/Z2p0/3Bzff9sb3n/ZGdx/2ptd/9sbnX/c3V8/2xudf9kZ3H/bG51/25xe/9nanT/ -bG95/2xvef9iZW7/am13/25xef9vcnr/am13/2dqdP9ucHf/bG51/21vc/9tb3T/cnV8/25xev9qbXf/ -bnB3/25wd/93eH3/bW92/3Byef9vcXr/bG95/2dqc/9naXP/Zmlz/2Nmb/9nanH/aGp0/2Vocf9maXP/ -bG95/2psc/9ucXv/bG95/2Rncf9qbXf/bG95/2ptd/9wc33/bW9z/2ptd/9ucXv/am13/25xe/9sb3n/ -bG51/3V3ff9sb3n/bG95/3N1fP9nanT/bG95/2ptd/9ucHf/bnB3/29xef91d33/bG50/2xveP9qbXf/ -cHN9/2psc/9sbnb/bG95/2xud/92eH7/bG95/2xudf9zdXz/bnF7/2ptd/9tb3P/bnB3/2xvef9sb3n/ -bnB3/3d5f/9sbnX/dXd9/3Byef9ucHf/c3V8/3V3ff9ucHf/dXd9/2xvef9qbXf/c3Z//25xe/91d33/ -am13/3l7gf93eX//cHJ5/3N1fP91eIH/cHJ5/3t+h/9wcnn/bG95/29xdf9ucHf/bG51/3V3ff9tb3P/ -bG51/3V3ff92eHz/c3V8/3Byef9sbnX/amxz/2xudf95e4H/bG51/3Z4fP9ucHf/bG51/3Byef9ucHf/ -cHJ5/25wd/91d33/eHl9/29xdf9sb3n/bG95/3V4gf93eX//bnF7/3d6g/9zdn//c3Z//3l7gf9zdn// -dXiB/3V3ff95e4H/e32D/3Z4fP95e4H/dXd9/3N2f/91eIH/dXiB/3d6g/9zdXz/bnF7/36Ahv93eoP/ -foGK/3V3ff9zdn//d3qD/3t9g/9wc33/bnB3/2xvef9zdXz/cHN9/3Bzff91eIH/bnB3/25wd/9zdXz/ -bG51/2xudf9zdXz/dXd9/3Bzff91eIH/cHJ5/25xe/9wcnn/bnB3/2xvef9ucHf/dnh8/25wd/95e4H/ -d3l//3Byef9+f4P/dXd9/25wd/9sbnX/c3V8/2xudf91d33/bG95/2Rncf9qbHP/am13/2dqcf9ucXv/ -am13/2ptd/9qbXf/Z2px/3N2f/9sbnX/bnF7/25xe/9sbnX/c3V8/2xvef9sb3n/bG51/29xdf9sb3n/ -bnB3/2xvef9ucXv/bnB3/3N2f/9sb3n/bnB3/25wd/9wcnn/b3F1/3Z4fP9ucXv/bG95/25xe/9wc33/ -bnF7/2xvef9zdn//c3Z//3V4gf9wc33/eXuB/3N2f/9zdn//bnB3/25wd/9tb3P/bnB3/25wd/9zdXz/ -bG51/3N1fP9qbXf/Z2px/25wd/92eHz/bnF7/2dqdP9sbnX/bnB3/3Bzff9ucHf/Z2px/21vc/9sb3n/ -Z2p0/2ptd/9sb3n/ZGZs/2xudf9ucXv/b3J6/2ptd/9qbXf/bG95/2xvef9qbHP/bW9z/3J1fP9wcnz/ -am13/25wd/9ucHf/dXd8/2xudf9vcnj/bnF7/29yfP9nanT/ZGdx/2ptd/9kZ3H/amxz/2ptd/9sbnX/ -am13/2xvef9sbnX/cHJ5/3N1fP9qbHP/bG51/25wd/9ucHf/dXd9/2xudf9sb3n/cHN9/2ptd/9wc33/ -bG95/2xudf9wc33/bnB3/3Byef91d33/bG51/3N1fP9ucHf/bnB3/2xudf9ydHv/dnh+/25wd/9vcXn/ -bnB3/3Z4fP9sbnX/bnB3/29xef9tb3X/dnh9/3Byef9vcXX/dnh8/3N1fP9ucHf/b3F1/2xudf9tb3P/ -bG51/2xudf9wc33/b3F1/3Z4fP91d33/bG51/25xe/9wc33/bG51/3V3ff9sbnX/amxz/3N1fP9ucHf/ -c3V8/2Zobv9wc33/cHN9/2ptd/9vcXX/c3V8/29xdf92eHz/bW9z/2ptd/9sbnX/bG95/2dqdP9wc33/ -bG51/2xudf9zdXz/dXd9/3Bzff9wcnn/bG51/21vc/9qbHP/c3Z//2xudf9zdXz/bnB3/2xudf9zdXz/ -bW9z/2ptd/9tb3P/bnF7/3Z4fP9ucHf/bnB3/2xvef91eIH/dXd9/2xvef9zdn//bnB3/2xvef91d33/ -bG95/25wd/9ucHf/c3Z//3N2f/9ucXv/cHJ5/25xe/9ucHf/bnF7/3N2f/9zdn//bnB3/2dqdP91eIH/ -bnF7/3d5f/9sb3n/b3F1/3Bzff93eX//b3F1/25wd/9qbXf/c3V8/3Byef9ucHf/eHl9/25wd/9wcnn/ -cHJ5/2xvef9wcnn/c3Z//3d5f/9qbHP/Z2p0/2dqcf9sbnX/Z2px/2dqdP9nanT/bG51/3N1fP9qbXf/ -dXiB/3V3ff9sb3n/e32D/3V3ff9qbXf/am13/3Bzff9qbXf/dnh8/2ptd/9kZ3H/bG51/3Z4fP9ucHf/ -dnh8/3Byef9wc33/dXiB/25xe/97fof/bnF7/3Bzff9wc33/bnF7/3d5f/9ucXv/cHJ5/25wd/9wcnn/ -bnF7/25wd/9ucHf/cHN9/25xe/9zdn//cHN9/3N1fP9ucXv/bG95/25wd/93eX//bG95/3Byef9qbXf/ -bG51/25xe/9tb3P/dXd9/25wd/9ucXv/bnB3/3h5ff9wcnn/dXd9/2xudf9qbXf/bG51/2ptd/9qbHP/ -bG95/2Rncf9ucXv/ZGdx/2Jlbv9kZ3H/c3V8/25xe/9qbXf/bG51/25wd/9zdXz/c3V8/2Zobv9tb3P/ -bnB3/2xudf9ucHf/bG95/2RmbP9qbXf/bW93/25xef9rbnf/am13/25wd/9zdXz/bnB3/25wd/91d3z/ -dXd7/25wd/9tb3P/bW9z/3N1e/9sb3n/cnR6/3J0e/9xc3r/bG51/2psc/9ucHf/bG95/3Bzff91d33/ -bnB3/25wd/9wcnn/bG51/3Byef9ucHf/bnB3/2xvef9zdn//bnF7/3V4gf9ucXv/cHN9/3V4gf9zdXz/ -dXiB/3Bzff9zdXz/dXiB/3Bzff93eoP/dXiB/25xe/9wc33/bnB3/2xvef9tb3n/dHZ8/3h6g/9tb3j/ -cHN8/25wd/94eX3/Z2px/25weP9sbnb/cHJ5/3h6gf91eIH/cHN9/3t9g/91eIH/c3V8/3Byef9ucXv/ -cHJ5/25xe/9ucHf/d3qD/3Byef91d33/cHN9/3Byef9wc33/dXd9/2xvef91d33/cHJ5/2dqdP93eX// -bnF7/3h5ff9nanH/dXd9/3V3ff9wcnn/b3F1/3N1fP9ucHf/d3l//21vc/9sbnX/bG51/25wd/9nanT/ -bnF7/2xudf9qbHP/dXd9/3V3ff9wc33/bnF7/2xudf9qbXf/am13/3V3ff9wcnn/dXd9/25wd/9qbXf/ -cHN9/25wd/9ucHf/bW9z/25xe/95e4H/bnB3/25xe/9ucHf/eXuB/3V4gf9ucXv/dXd9/25wd/9ucHf/ -c3Z//25wd/9ucHf/bG95/3Byef9ucXv/Z2px/25wd/9vcXX/b3F1/29xdf91d33/bnF7/2ptd/9kZmz/ -bnF7/2xudf91d33/Z2p0/2psc/9ucXv/c3V8/2dqdP9nanT/Z2p0/3Bzff9sb3n/bG51/3N1fP9maXP/ -bnF7/3Bzff9sbnX/amxz/2xvef9wc33/bnB3/3Byef9sb3n/c3Z//2xvef9sb3n/bG95/2xvef9zdn// -b3F1/3l7gf93eX//c3V8/36Ahv93eX//bG95/2xvef95e4H/bnF7/3V4gf9ucHf/Z2px/25xe/93eX// -bnF7/3d5f/9ucXv/c3V8/3Byef9tb3P/eXuB/2xudf9ucHf/cHJ5/25wd/9zdXz/bnB3/25wd/9sbnX/ -am13/2psc/9nanT/amxz/2ptd/9sbnX/c3V8/21vc/9qbHP/am13/2xvef9qbXf/d3l//2xudf9sb3n/ -am13/2ptd/9wc33/am13/3N1fP9wcnn/bnB3/25wd/9zdXz/bG95/3V3ff9vcXX/b3F1/21vc/9tb3P/ -am13/25xe/9maXP/bG95/2Zpc/9kZ3H/Z2p0/3N1fP9sb3n/Zmlz/2xvef9qbXf/c3V8/2xvef9maXP/ -bG51/25xe/9vcXX/bnB3/29xdf9nanH/bW9z/2ttdP9sb3n/bG92/2xudf9tb3P/c3V8/2xudf9ucHf/ -dHZ9/29xef9tb3P/bG51/2psc/9zdXz/a254/29xev9ydHv/b3J7/21vc/9nanH/bG51/2dqdP9qbXf/ -bnF7/2psc/9nanT/bG95/2psc/9qbXf/bG95/2Jlbv9qbHP/am13/2psc/9sb3n/bG51/2xvef9wc33/ -am13/3Z4fP9vcXX/bG51/3Byef9ucHf/c3V8/3Byef9sbnX/c3Z//25wd/9qbXf/Z2p0/29yfP94eoP/ -b3F4/3V3ff9ucHf/dXd9/2Zpc/9sb3n/am13/2xud/90dn3/cHJ6/2xudf94eX3/cHJ5/2xudf9qbXf/ -am13/2xudf9sbnX/am13/3N1fP9sbnX/dXd9/25wd/9tb3P/cHJ5/25xe/9qbHP/c3V8/21vc/9qbHP/ -dnh8/3Bzff91eIH/Z2px/25xe/9zdn//bnB3/25wd/9wc33/bG95/3d5f/9vcXX/bnF7/3N1fP9zdn// -am13/3N2f/9zdn//bnB3/3d5f/93eoP/dXiB/3Bzff9wc33/bG95/2xvef91eIH/cHJ5/3N2f/9ucXv/ -b3F1/3V3ff9sb3n/cHJ5/29xdf9wcnn/d3l//25wd/9vcXX/bG51/3V4gf91eIH/cHJ5/3V4gf9wcnn/ -cHN9/3d5f/9ucHf/cHJ5/25wd/9sb3n/cHJ5/2psc/9ucHf/cHJ5/29xdf9sbnX/dnh8/25wd/9sbnX/ -Zmhu/25wd/9tb3P/dXd9/2ptd/9sbnX/bnF7/2xvef9kZ3H/Z2p0/2Zpc/9sb3n/Z2p0/2dqdP9wc33/ -Z2p0/3Bzff9wc33/am13/2xudf9ucXv/c3V8/25xe/9zdXz/bG51/3Byef9ucHf/bnB3/25wd/9vcXX/ -dXd9/2xudf94eX3/dXd9/3Byef93eoP/c3V8/2xudf9sbnX/eHl9/3Byef91d33/amxz/2Jkav9sbnX/ -bnF7/2psc/9wcnn/Z2px/2Zpc/9maXP/ZGdx/3Bzff9qbHP/amxz/2xvef9qbXf/am13/2ptd/9qbXf/ -bG51/2psc/9sbnX/bG51/2dqdP9qbXf/am13/25xe/9qbHP/bG51/2ptd/9wc33/am13/3N2f/9qbXf/ -cHN9/2ptd/9ucHf/dXd9/25wd/91d33/bnB3/3Byef9wcnn/cHJ5/21vc/9ucXv/bG51/25wd/9qbXf/ -am13/2ptd/9wc33/Z2p0/25xe/9qbHP/Z2px/2xvef93eX//c3Z//2xvef9ucXv/bnB3/3Z4fP9wcnn/ -amxz/2xudf9zdn//bnB3/2xvef9ucXv/Zmlz/25xe/9rbXT/b3J6/29xdv9ucHf/bnB3/3Bzff9sb3n/ -bnB3/3Z4fv9ucXr/b3F1/25wd/9tb3P/dnh+/2xvdv9tcHr/c3V7/29yfP9qbHP/YmVu/2xudf9qbXf/ -bG95/3N1fP9sbnX/bG51/25xe/9ucXv/bnF7/3N1fP9qbHP/cHJ5/25xe/9wcnn/d3l//29xdf91eIH/ -dXiB/3V4gf95e4H/c3V8/25wd/91eIH/bnF7/3N2f/93eoP/cHN9/3V4gf9ucXv/bG95/2ptd/9wc3z/ -dnh//3Byef91eIH/c3Z//3t+h/9wc33/d3mC/3Z4f/9ydHn/dHZ+/3BzfP9sbnb/cHN9/3Byef9tb3P/ -bG95/2xudf9vcXX/bnB3/2xvef9zdn//d3l//3l7gf93eoP/cHN9/3d6g/93eoP/bnB3/3d5f/9zdXz/ -cHN9/3t9g/9zdn//dXiB/2Zobv9ucHf/dXd9/2xvef9ucHf/c3Z//2xvef93eX//b3F1/25wd/9tb3P/ -cHJ5/2dqcf9ucXv/c3V8/2xvef91d33/eXyG/3d6g/91eIH/c3Z//25wd/9qbXf/eXuB/3Bzff9zdn// -dXiB/3Bzff95fIb/dXd9/3l7gf91d33/eXuB/3+Bh/9zdn//dXiB/3Z4fP+Bg4r/f4GH/3d5f/99foH/ -dXd9/3d5f/9+f4P/eHl9/3h5ff93eX//d3l//3l8hv9ucXv/dXiB/3d6g/9zdXz/c3V8/3t9g/93eoP/ -c3Z//2xvef9zdn//dXiB/3l8hv9wc33/cHN9/25xe/93eX//bnB3/25wd/9sbnX/cHN9/25wd/9sb3n/ -cHN9/2xudf91d33/dXd9/3N1fP9vcXX/cHJ5/3h5ff9wcnn/dXd9/25xe/9zdn//cHN9/25wd/9wcnn/ -c3V8/3V4gf9zdn//e36H/3t+h/95fIb/f4GH/3t+h/9wc33/dXd9/3+Bh/97fYP/foGK/3d6g/9ucXv/ -dXiB/3l8hv9zdXz/eXuB/3Bzff9ucXv/bG95/25wd/95fIb/bnF7/25xe/9wc33/bnF7/3Bzff9wcnn/ -bnF7/3N1fP9wcnn/bnF7/2xvef9ucHf/bW9z/25wd/9zdXz/bnB3/2xvef9ucXv/d3l//25xe/93eoP/ -bnF7/3N2f/9wc33/bG95/3V3ff9sb3n/dnh8/25wd/9zdXz/bnB3/25xe/9ucHf/cHN9/2xudf9sbnX/ -bW9z/2ptd/9tb3P/cHN9/2ptd/9ucHf/Z2p0/2Zpc/9nanH/dXd9/3Byef9nanH/bG95/2xudf9wc33/ -am13/2dqdP9sbnX/bnF7/2ptd/9sb3n/bG95/2BjbP9nanT/amxz/2xvef9rbXX/bG51/2dqcf9nanT/ -ZGdx/2Zobv9qbXf/Zmlz/2Jlbv9nanH/ZGdx/25wd/9sb3j/bW92/3N1ef9tb3b/bnB3/2dqdP9ucHf/ -bnB3/25xe/9zdn//bnB3/2xvef9ucXv/bnF7/25xe/9zdn//am13/3Bzff9zdXz/cHN9/3l7gf9wcnn/ -c3Z//3Z4fP9zdXz/eHl9/2xudf9sbnX/cHJ5/25wd/9wcnn/c3V8/2psc/9wcnn/am13/2dqdP9qbHP/ -bnB3/3R3fv9rbnX/bnB3/21vdf91eIH/Z2p0/2xvef9sb3n/bG92/3R2ff9wc33/bG95/3Bzff9zdn// -cHJ5/3N2f/9wc33/cHN9/3V4gf9zdXz/eXuB/2xudf9zdn//c3Z//2xvef9zdXz/dXd9/2xvef95e4H/ -cHJ5/25wd/91eIH/bnF7/3d6g/9maG7/bG95/3V3ff9sb3n/bnF7/3d6g/9wc33/eXuB/25wd/9ucHf/ -bW9z/3N1fP9qbHP/bnF7/2xvef9nanT/c3V8/3V3ff9qbXf/bG51/2xvef9qbHP/ZGdx/3N1fP9qbXf/ -cHJ5/25wd/9tb3P/cHJ5/2xudf9qbXf/amxz/2xvef93eX//Z2px/21vc/9sbnX/d3l//3N1fP9ucHf/ -dnh8/2xvef9ucHf/eHl9/29xdf9qbXf/amxz/25wd/9wcnn/bnB3/29xdf9tb3P/am13/2xudf9zdXz/ -bnF7/2ptd/9nanH/cHN9/2psc/9wc33/bG51/2xudf9sb3n/c3V8/2Rncf9nanH/YmVu/25xe/9nanT/ -bG51/3Bzff9qbXf/bG95/3Bzff9sb3n/bG51/25xe/93eX//cHN9/3d5f/9ucXv/c3Z//3Bzff9ucHf/ -bnB3/2xvef91d33/b3F1/3Z4fP94eX3/c3V8/3l7gf91d33/bG51/2dqdP93eX//bnB3/3l7gf9wcnn/ -Z2px/29xdf94eX3/bnB3/3l7gf9ucHf/bG95/3Bzff9ucXv/d3qD/3N2f/93eoP/e32D/3d5f/9+f4P/ -d3l//3d5f/97fYP/ent//3t+h/95e4H/eXuB/3l7gf97fYP/e32D/3V4gf93eX//fX6B/3+Bh/93eX// -f4KM/3d6g/93eoP/cHN9/2xvef91d33/bnB3/3V3ff9qbXf/bG95/2ptd/9ucXv/amxz/2xvef9qbHP/ -amxz/2dqcf9nanH/Zmhu/2dqdP9nanH/bG51/2Rncf9dYGr/XWBq/2xvef9nanT/YGNs/2Zpc/9sb3n/ -bnF7/25xe/9qbXf/bG51/2xudf9ucHf/dXd9/3V3ff9maG7/bG51/3N1fP90dn7/cXN5/25wd/9vcXX/ -bnF7/2xvef9vcXX/dXd9/25xe/9qbXf/bG95/25wd/93eH3/c3V8/3N1e/93eX//c3Z//25xe/9nanT/ -bnB3/2xudf9ucHf/dnh8/25wd/9qbXf/bnF7/25xe/9wc33/bnF7/2xvef9ucXv/c3V8/25wd/9zdXz/ -bnB3/3V3ff92eHz/cHJ5/3V3ff9qbXf/bnB3/2xvef9ucHf/cHJ5/3Byef9nanT/cHJ5/25xe/9qbXf/ -bG51/25xe/90d37/cHN6/3V3gP9wc33/foGK/3N1fP91eIH/cXR9/21wev9ydX3/cHN8/2ptd/9sb3n/ -bG95/2xudf9nanT/Z2px/2Zpc/9maXP/Z2p0/25xe/9zdn//dXiB/3l7gf9wc33/c3Z//3d5f/9qbHP/ -d3l//29xdf9qbHP/c3V8/29xdf93eX//Z2px/25wd/94eX3/bnB3/3Byef91d33/cHJ5/3d5f/9sb3n/ -bG95/25wd/9ucHf/Z2p0/3Bzff9sb3n/bW9z/3N1fP91d33/bG95/2ptd/9ucXv/bW9z/2Zpc/91d33/ -bG95/3Bzff9qbXf/bG51/2xvef9qbHP/bG51/2psc/9qbXf/dXd9/2Rncf9qbHP/Zmlz/3Bzff9zdXz/ -Zmlz/3V3ff9qbHP/amxz/3V3ff9sbnX/am13/2dqdP9sb3n/bG95/2ptd/9qbXf/bW9z/29xdf9ucHf/ -eXuB/3Bzff9sb3n/am13/3Bzff9ucHf/eHl9/25xe/9wc33/d3qD/3t9g/9ucHf/bnB3/2ptd/93eoP/ -c3Z//3N1fP95e4H/c3V8/3N2f/91eIH/eXuB/3N1fP9zdn//d3qD/2ptd/9wc33/bG51/2ptd/9nanT/ -Zmlz/2Zpc/9iZW7/bG95/2psc/9wc33/dXd9/2xvef93eoP/bnF7/2ptd/9sbnX/dXd9/2ptd/95e4H/ -bnF7/2dqdP9sb3n/eHl9/29xdf93eX//bnB3/25xe/9ucXv/bnB3/3l7gf9ucXv/c3Z//3V4gf9zdXz/ -dXiB/3Bzff9wcnn/bnB3/3Byef91eIH/cHJ5/25wd/9sb3n/bG95/3Bzff9ucHf/bW9z/3V3ff94eX3/ -cHJ5/3l7gf9wcnn/bG95/25xe/9qbHP/c3V8/2ptd/9wc33/bW9z/3Byef9ucHf/c3V8/29xdf91d33/ -bG95/25xe/9ucHf/bG95/3Byef9wc33/bnB3/25xe/9zdXz/bG95/3N2f/97fof/e32D/25xe/93eoP/ -eXyG/3V4gf93eoP/cHJ5/25xe/9zdXz/c3V8/3Bzff9zdn//ZGdx/25wd/9tb3T/cXN6/3Fzev9ucXr/ -bnB3/2xvef9sb3n/b3F1/3d5f/9ucHf/bW9z/25wd/9ucHf/d3l//3J0ff9xdHv/cnR7/29xeP9ucHf/ -Z2px/25wd/9sbnX/bnB3/3N1fP9tb3P/Zmlz/2xvef9qbXf/cHJ5/3Byef9ucHf/bG51/21vc/9sbnX/ -bnF7/2xudf9wc33/c3V8/2xvef92eHz/bG51/2ptd/9sbnX/bnB3/3N1fP9ucHf/Z2p0/2xvef9ucHf/ -bG51/2psc/9vcXn/c3V7/25wdf9xc3r/bW9z/3d5f/9qbXf/am13/2ttdP9oa3X/c3Z9/3V3ff9sb3n/ -bnF7/3N1fP9sb3n/bnF7/2xvef9wcnn/c3V8/25wd/91eIH/am13/2xvef9sb3n/Z2px/2Zpc/9qbXf/ -XWBq/3Byef9maXP/XWBq/2xvef9maG7/c3V8/2Jlbv9qbXf/dXd9/2dqdP9ucXv/c3V8/2xudf9zdXz/ -bG51/2xudf9vcXX/cHJ5/29xdf9zdn//c3Z//3Bzff91eIH/eXyG/3V4gf9wc33/cHN9/25wd/9qbXf/ -d3l//25xe/9wcnn/bnB3/21vc/9zdXz/bG51/2ptd/9qbHP/bG95/3V3ff9iZW7/bG51/2Rncf9sb3n/ -cHJ5/2Jlbv9qbXf/Z2px/2Zobv9ucHf/Zmlz/2Rncf9kZ3H/Z2p0/2xudf9qbHP/bG51/2dqdP9sbnX/ -am13/3V3ff9ucXv/bnB3/2xvef9zdn//bG95/3h5ff9ucHf/cHJ5/3V3ff94eX3/bG51/2xudf9nanT/ -cHN9/25wd/9tb3P/bnF7/2ptd/9sb3n/bnF7/3Bzff9qbXf/bnF7/3d5f/9ucHf/c3Z//25wd/9ucXv/ -bnB3/2xvef9ucHf/am13/3d6g/9zdXz/eXuB/3t9g/91eIH/eXyG/3N2f/9ucHf/bG95/3l7gf9wcnn/ -d3qD/25xe/9nanT/bnB3/3l7gf9wcnn/eXyG/3Byef9ucXv/cHN9/25wd/93eoP/bnB3/25wd/9wc33/ -bnB3/3Z4fP9vcXX/bnB3/2xvef9ucHf/cHN9/2xvef9sb3n/bnB3/25wd/9zdXz/b3F1/29xdf91d33/ -dXd9/25wd/95e4H/cHJ5/2xvef9ucXv/Z2p0/3N1fP9qbXf/bG95/2psc/9sb3n/bG51/3Bzff9qbHP/ -cHN9/2ptd/9sb3n/amxz/2dqcf9qbHP/Z2p0/2Zobv9nanH/Z2px/2Rncf9maXP/c3V8/25xe/9maG7/ -c3V8/25wd/9sbnX/dnh8/2ptd/9sb3n/bnB3/25wd/9zdXz/dXd9/2dqcf9wcnn/bW9z/29xeP9sb3n/ -bXB6/2xvef9sb3n/bnB3/3Byef93eX//cHJ5/2xudf9ucHf/am13/3N1fP9sb3n/cXN6/3N1ff9vcXv/ -c3V8/2ptd/9ucHf/bnB3/25xe/9zdn//bnB3/2xudf9wcnn/cHN9/3N2f/9wc33/bnB3/25xe/9ucXv/ -cHJ5/3N2f/9wcnn/d3l//3V4gf9wc33/d3l//2ptd/9ucXv/bnB3/3Bzff9wc33/cHJ5/25wd/9wc33/ -cHJ5/2xudf9ucHf/b3F4/3N1ev9pbHP/a253/2Vocv9wcnn/ZGdx/2Vocv9laHL/YmVv/3J0fP9zdoD/ -am13/3Bzff9zdn//bnB3/25wd/9ucHf/cHJ5/3N1fP9ucHf/c3V8/2xvef9wc33/c3V8/21vc/91d33/ -dXd9/2psc/91eIH/bnB3/2Zobv91d33/bnB3/3d5f/9maXP/cHJ5/3h5ff9sbnX/c3V8/3Z4fP9sb3n/ -eHl9/25wd/9tb3P/bW9z/3Byef9qbHP/cHJ5/25wd/9sbnX/bG95/3N1fP9ucXv/bG95/2ptd/9sbnX/ -Z2p0/3d5f/9qbXf/cHJ5/3Byef9ucHf/c3V8/2ptd/9wcnn/b3F1/25wd/92eHz/Z2px/29xdf9sbnX/ -cHJ5/3Z4fP9sbnX/dXiB/25xe/9zdn//e36H/3Byef9wc33/c3V8/25xe/9ucXv/cHJ5/25xe/9sb3n/ -bnB3/2xvef93eX//c3V8/25xe/9wcnn/dXiB/2xvef93eX//bnB3/25xe/9ucXv/d3qD/25wd/9qbXf/ -am13/3N2f/9ucHf/bnB3/3Bzff9sb3n/c3Z//3N2f/93eX//bG95/3N1fP91eIH/bnF7/3V4gf9ucXv/ -cHN9/25xe/9wcnn/cHJ5/2ptd/9zdn//bnB3/3N2f/92eHz/cHN9/3t9g/9wcnn/bnB3/25wd/94eX3/ -bnB3/3d5f/9wcnn/Zmhu/25wd/92eHz/bnB3/3l8hv9wcnn/cHN9/3Bzff9zdXz/d3qD/3N2f/91eIH/ -dXiB/25wd/94eX3/bnB3/29xdf9sbnX/bnB3/3Byef9vcXX/bG51/21vc/9sbnX/cHJ5/2xudf9tb3P/ -cHN9/3Bzff9sbnX/bnB3/2ptd/9qbXf/bG95/2Rncf9qbXf/ZGdx/2xvef9qbXf/cHN9/2ptd/91d33/ -am13/3N1fP9ucXv/cHJ5/25wd/9ucHf/cHJ5/25xe/9qbXf/bnB3/25wd/9sb3n/bnB3/3V3ff91d33/ -Z2px/3N1fP9ucXv/bG95/3V4gf9wcnn/bnF7/2ptd/9ucXv/cHN9/3N2f/9nanT/cHN9/2hrcv9qbXf/ -bG52/3Fzev9sbnX/bnB3/21vc/9tb3P/eHqA/2xudf9sbnX/bnB3/25wd/92eHz/bXB6/3Byef9ydHr/ -cXN5/3N1fP9sb3n/cHJ5/25xe/9zdn//bnF7/2xvef9sb3n/cHN9/3Byef9wc33/c3Z//25xe/9ucHf/ -bnF7/3Bzff93eoP/c3V8/3t9g/97fYP/dXiB/3l7gf9zdn//d3qD/3V4gf93eoP/c3Z//3Bzff9wcnn/ -d3qD/3d6g/9wc33/c3V8/3N1fP93eoP/b3J6/3J0fP9rbnj/d3l//25wd/9wcnn/bW90/2xudf90dn3/ -dHd//2dqdP9sb3n/c3Z//2xvef9sb3n/bG95/25xe/9wc33/cHJ5/25xe/9ucXv/c3Z//3h5ff9ucHf/ -c3V8/3N1fP9qbXf/dXiB/3Byef9nanH/cHJ5/21vc/94eX3/Zmhu/25wd/94eX3/bG51/3N1fP91d33/ -am13/3d5f/9sbnX/bG51/2xudf9wcnn/bG51/3N1fP9wcnn/cHJ5/3Byef94eX3/c3V8/2xvef9sb3n/ -bW9z/2Zobv91d33/cHJ5/2xudf9ucHf/am13/3Byef9nanT/am13/2xudf9wcnn/eHl9/2psc/9tb3P/ -amxz/2xvef91d33/am13/3d5f/9qbXf/am13/3d5f/9sbnX/Z2p0/2xudf9ucHf/bG51/21vc/9nanT/ -Z2p0/2xudf9tb3P/dnh8/3Byef9ucHf/bW9z/25xe/9tb3P/c3V8/2xudf9ucHf/bnB3/3d6g/9ucHf/ -bG51/25wd/9zdn//bnB3/25wd/9wc33/bnF7/3N1fP91d33/d3l//3V4gf9zdn//eXuB/3N2f/93eoP/ -c3Z//3N2f/9sb3n/bnB3/25wd/9nanT/c3V8/21vc/9zdXz/c3V8/2xvef93eoP/bnF7/2ptd/9sbnX/ -c3V8/2dqdP91d33/Z2p0/11gav9kZ3H/bG95/2Zobv9wcnn/Zmhu/2ptd/9nanT/Z2px/3Byef9qbXf/ -am13/25xe/9sbnX/bnF7/2ptd/9qbXf/Zmlz/2xudf9wc33/bnB3/2xvef9vcXX/b3F1/3N1fP9ucHf/ -b3F1/3V3ff9ucHf/am13/3V3ff9wcnn/bG51/25xe/9qbXf/am13/2Zpc/9sb3n/bG95/25xe/9qbXf/ -cHN9/2xvef9wc33/bG95/2ptd/9nanH/amxz/2psc/9qbHP/Zmlz/2psc/9sbnX/amxz/2dqdP9ucXv/ -cHN9/2Zpc/9ucHf/bG95/2xudf93eX//bnB3/25xe/9sbnX/cHJ5/3N1fP9wc33/Z2p0/3Bzff9ydX7/ -cnV+/3F0fv9ydX7/cHN9/3Bzff9wcnn/cHJ5/3p9hv9wcnn/cHJ5/3V4gf9zdn//d3l//3J1fv9ydHz/ -dXZ8/3Fzef9zdXz/amxz/2ptd/9sbnX/am13/2ptd/9sbnX/ZGdx/2xudf9nanT/bG51/2xudf9sbnX/ -Z2p0/2xudf9sbnX/cHJ5/2psc/9zdXz/cHN9/2ptd/93eX//Z2p0/3Byef9ucHf/cHJ5/25xe/9qbXf/ -bnB3/3N1fP9zdn//Z2p0/29xdf9vcXb/dnh//3Bze/96fIL/cHN9/36Biv93eX//e32D/3J1fv9vcnv/ -c3aA/3N2gP9nanT/bG51/3Bzff9nanT/am13/2ptd/9sb3n/am13/2psc/9nanH/bnF7/3N2f/93eX// -bnF7/3Bzff91eIH/bnF7/3d5f/9ucHf/amxz/3Byef9tb3P/d3l//2Zobv9ucXv/dXd9/25wd/91eIH/ -dXd9/2xvef93eoP/cHN9/2ptd/9vcXX/cHN9/25wd/91d33/cHJ5/25wd/9sb3n/eHl9/3N1fP9ucHf/ -bnB3/2xudf9iZW7/dXd9/2xvef9qbXf/bnB3/2xudf9ucXv/amxz/2xudf9tb3P/bnB3/3V3ff9kZ3H/ -bG51/2Zpc/9qbXf/cHN9/2dqdP93eX//bG51/2ptd/91d33/ZGdx/2Jlbv9maG7/amxz/2xudf9qbHP/ -Zmlz/2Zobv9maXP/ZGdx/2xvef9maXP/Zmlz/2dqcf9maXP/amxz/2xvef9sbnX/bG51/2xudf91d33/ -am13/2Zpc/9nanT/cHN9/2xudf9sbnX/bnB3/3Byef9zdXz/dnh8/3V4gf9wc33/c3Z//3t9g/9wc33/ -dXd9/3N1fP9wcnn/bnB3/25wd/9zdXz/bG95/3V3ff9wcnn/d3l//3V4gf9zdn//e36H/3d6g/9wcnn/ -c3V8/3d5f/9sb3n/dXiB/3Byef9nanH/bnB3/3d5f/9wcnn/d3qD/25wd/9wc33/bG95/25wd/92eHz/ -cHJ5/25wd/9ucHf/bG51/3Byef9ucHf/cHJ5/2dqdP9sb3n/c3Z//29xdf9ucHf/bW9z/2xvef9zdn// -cHN9/3Byef91eIH/bnB3/21vc/94eX3/dXd9/25wd/9zdXz/b3F1/25wd/9qbHP/c3V8/3Byef9zdn// -bnF7/3N1fP9wcnn/dXd9/3N1fP9sb3n/amxz/2xudf9qbXf/Z2px/2Zpc/9maXP/Z2px/2xudf9maXP/ -bG95/25xe/9nanT/bnF7/2xvef9tb3P/c3V8/2ptd/9qbXf/ZGdx/2xvef9nanT/bG95/2Jlbv9nanT/ -b3F4/25weP9vcXr/bG94/2tud/9qbXf/amxz/2Rncf9zdn//Z2p0/2ptd/9ucHf/bnB3/3Byef9ucHf/ -b3J3/21wev9oa3X/ZGdx/11gav9gY2z/Zmhu/2Rncf9maXP/ZGZs/1xfaP9maXP/YmVu/2Rncf9kZ3H/ -Zmlz/2psc/9qbHP/bG95/2ptd/9maXP/cHN9/3Bzff9qbXf/dXd9/2Zpc/9ucXv/bG95/3N1fP9zdXz/ -bnB3/2xvef9wc33/c3Z//2xudf9sbnX/bW9z/3J0e/9ucXn/cnR7/29xeP95e4H/bnB3/2xudf9qbXf/ -aWt0/25wef9zdn//bG95/3Bzff91eIH/cHN9/3Bzff9zdn//c3V8/21vc/9ucHf/bG51/2xvef9wc33/ -dXd9/2xudf9zdXz/bnF7/2Zpc/9zdXz/Z2p0/2Jlbv9ucXv/bG51/3V3ff9iZW7/cHN9/3d5f/9qbXf/ -bnF7/25xe/9sbnX/c3V8/2Zpc/9gY2z/Zmhu/2Zpc/9maXP/bG95/2psc/9nanH/Z2px/2xvef9sb3n/ -Z2px/2psc/9maXP/YGNs/3V3ff9qbXf/bG51/2ptd/9nanH/am13/2Jlbv9qbHP/Z2px/2ptd/9ucXv/ -Zmlz/2psc/9kZ3H/bnF7/3V3ff9nanT/dXd9/2xudf9wcnn/d3l//2Zpc/9nanH/bW9z/21vc/9sbnX/ -bnB3/25wd/9ucHf/c3V8/25wd/94eX3/bnF7/25xe/9sb3n/c3V8/21vc/94eX3/bG95/25wd/9ucHf/ -d3l//2ptd/9maXP/amxz/3N1fP9sbnX/b3F1/3Byef9vcXX/c3V8/3Z4fP91d33/bnB3/3Byef94eX3/ -bnF7/3V3ff91d33/bnF7/25wd/9sb3n/bG95/2xvef93eX//cHN9/3t9g/91eIH/cHN9/3V4gf9wc33/ -am13/3Byef9zdn//am13/3d5f/9zdn//Z2p0/29xdf95e4H/bnB3/3d5f/9ucHf/c3V8/2xudf9vcXX/ -dnh8/3V3ff9wc33/bnF7/3V4gf9wc33/bnB3/3Bzff9qbXf/cHJ5/3V4gf9zdn//c3Z//3N1fP91d33/ -eXuB/3d5f/9zdn//e32D/3V4gf9zdXz/eXuB/3N2f/9zdn//eXyG/3V3ff93eX//dnh8/3t9g/97fYP/ -dXiB/3Bzff91eIH/c3Z//3d6g/9zdn//cHN9/3N1fP9zdn//c3Z//3N1fP9sb3n/bnB3/25wd/9ucXv/ -am13/3Bzff9wc33/Z2p0/3N1fP9zdXz/b3F1/3V3ff9sbnX/cHJ5/2dqdP91d33/bnF7/3N2f/9qbXf/ -c3Z//25xe/9tcHn/b3J8/29ye/9ucXv/bnF7/25xe/9ucXv/fH+I/3J1fv9zdn//d3l//3t9g/96fIL/ -d3qA/3Z4ff92eX7/cnN6/2xudf9sbnX/Zmlz/2psc/9nanT/am13/2xudf9maXP/bnF7/2dqdP9tb3P/ -cHJ5/2xudf9sbnX/bG51/2xudf9wcnn/amxz/3N1fP9zdXz/bG51/3Byef9iZW7/am13/2ptd/9sb3n/ -Z2p0/2xudf9nanT/bnF7/25xe/9maXP/Z2p0/2xudf9wc33/bnF7/3N2ff9ydHz/gYOK/3V4gf91eIH/ -b3J8/25xev9zdX7/cnV//2hrdf9sb3n/bnB3/25wd/9wcnn/cHJ5/3N1fP9sbnX/am13/2ptd/9wcnn/ -dnh8/3d5f/9sb3n/cHN9/25xe/9ucHf/dnh8/2xvef9kZ3H/c3V8/2xudf94eX3/Z2px/3N2f/93eoP/ -bG95/3N2f/95e4H/bG95/3V4gf9ucXv/am13/25xe/9wc33/bnB3/25xe/9sb3n/bG95/25wd/92eHz/ -dXd9/29xdf9tb3P/Z2px/2dqcf91d33/am13/21vc/9wcnn/am13/2xvef9kZ3H/Z2p0/2Zobv9maXP/ -am13/2Rncf9maG7/XWBq/2Rncf9wcnn/YmVu/3Byef9maXP/Zmlz/3Byef9iZW7/YmVu/2psc/9nanT/ -bG51/2xudf9qbHP/bG51/25xe/9sb3n/dXd9/3Byef9ucHf/bG51/3N2f/9vcXX/eHl9/25wd/9vcXX/ -bnB3/3d5f/9ucHf/bnB3/25wd/91d33/bnB3/29xdf9wcnn/bG51/3Byef9zdn//d3l//3Bzff9wc33/ -d3l//2xvef9zdXz/dnh8/25xe/9ucHf/bnB3/29xdf9ucHf/dnh8/3Byef94eX3/dnh8/3N1fP92eHz/ -bnB3/2xudf9vcXX/c3V8/2psc/91d33/dXd9/2psc/9vcXX/d3l//3Byef93eX//bnF7/3N2f/9ucHf/ -b3F1/3h5ff9wc33/c3V8/25xe/9wc33/c3Z//25wd/9ucHf/bG95/25wd/9zdn//c3V8/25xe/9wc33/ -cHN9/3l8hv9zdn//cHN9/3d6g/9ucXv/bnB3/3t9g/93eoP/dXiB/3d6g/9wc33/c3Z//3N1fP9wc33/ -bnF7/3Bzff9wcnn/c3Z//3N2f/95e4H/c3Z//25xe/9vcXX/bnB3/2xvef9vcXX/am13/2xudf9vcXX/ -bnB3/2xudf9zdn//cHJ5/2xudf9wc33/bnF7/29xdf93eX//bnB3/3V4gf9ucXv/eXuB/3V4gf95e4H/ -Z2p0/2xvef9wc3z/dHeA/3Z5gv9ydX//b3F4/25wd/9ucHf/am13/3d5f/9ucHf/bnB3/2xudf9wcnn/ -bnF7/2xvef9tcHr/dXd+/3V4gP9wc33/cHJ5/2xvef9wc33/c3Z//3d6g/91eIH/cHN9/3d6g/9wc33/ -bnF7/3V4gf9zdn//cHN9/3Bzff9zdn//d3qD/3Bzff95fIb/e36H/3N2f/97fYP/cHN9/3t9g/9zdn// -c3Z//3N2f/9sb3n/bG95/3N2f/9wc33/bG95/2xudf9ucHf/c3V8/2xud/9ucXr/a210/3d6g/9qbXf/ -bG51/2psc/9sbnX/b3J8/3BzfP9rbXT/bG51/25wd/9ucHf/bG95/3V4gf9zdn//cHN9/3N1fP9ucHf/ -bG95/3V3ff92eHz/bG51/3N1fP9ucHf/b3F1/3V3ff9sbnX/bG51/2xvef9qbXf/c3V8/2Rncf9zdXz/ -dnh8/2xudf9ucHf/dnh8/2xudf91d33/am13/2Rncf9qbHP/bnB3/2xudf9wc33/bG51/2xudf9qbXf/ -cHN9/3Byef9sbnX/bW9z/2psc/9qbHP/dXd9/2xvef9ucHf/c3V8/2xudf9ucHf/Zmhu/3Byef9tb3P/ -bnB3/25wd/9nanT/am13/2dqdP9ucXv/c3V8/2ptd/93eX//bnB3/25xe/94eX3/Zmhu/2dqdP9ucHf/ -bnB3/2xvef9ucHf/bnB3/25wd/9zdn//c3Z//3l7gf9ucXv/bnF7/3Bzff93eX//cHN9/3l7gf9zdXz/ -bnB3/3N2f/97fYP/cHJ5/25wd/9ucHf/c3Z//2xvef9wcnn/c3Z//2xvef9wcnn/c3V8/3Z4fP9ucXv/ -bG95/3d5f/9wc33/c3Z//3d5f/9ucXv/bnB3/3Byef9ucHf/bnB3/3d5f/9zdn//eXuB/3l7gf93eoP/ -d3l//25xe/9sbnX/b3F1/3N1fP9qbHP/c3V8/3N1fP9qbHP/bG51/3N1fP9tb3P/dXd9/2psc/9ucXv/ -bW9z/2xudf92eHz/c3V8/25wd/9wcnn/cHJ5/3N1fP9ucHf/bnB3/25wd/9vcXX/bnF7/2xvef9sb3n/ -bnF7/25xe/9zdn//c3Z//3Bzff95e4H/c3Z//3Bzff99foH/eXuB/36Ahv97fYP/d3l//3V3ff91d33/ -dXiB/3d6g/93eoP/c3Z//3d6g/93eoP/e36H/3l8hv93eoP/cHN9/3N1fP9zdn//cHN9/3Byef9sb3n/ -b3F1/25xe/9ucHf/bnF7/3Byef9qbHP/cHJ5/2xudf9tb3P/dnh8/2xudf9wc33/bG95/3N2f/9zdn// -c3Z//2dqdP9sb3n/cHJ5/29yfP92eYD/cnV+/29xeP9tb3P/b3F1/2xudf93eX//bG51/2xudf9ucHf/ -c3V8/3V3ff9wc33/cnR8/3V3ff9xdH3/cHJ5/2xvef9qbXf/cHN8/25xe/9ucXv/c3V8/2ptd/9zdn// -bnB3/2xudf90dn3/bnF7/2xudf9sbnX/cHJ5/25xe/9sbnX/cHJ5/3V3ff9tb3T/dHd9/2dqdP9zdXz/ -am13/2xvef9sb3n/am13/2Vocf9sb3n/am13/2Nmb/9qbHP/am13/3J0e/9ucHf/cXN6/2tud/93eoP/ -cHJ5/2xudf9sbnX/aGt0/21veP9xdH3/Z2p0/2ptd/9qbXf/am13/2ptd/9ucXv/dXd9/3Byef9vcXX/ -b3F1/25xe/9wc33/dXd9/2xudf9nanT/am13/2psc/91d33/bG51/2psc/9sbnX/Z2p0/3Byef9kZ3H/ -bG95/25xe/9sbnX/am13/3N1fP9qbHP/dXd9/2xvef9gY2z/Zmlz/2dqdP9nanH/bG95/2psc/9qbHP/ -Z2p0/2ptd/9qbXf/Z2px/2dqdP9kZ3H/ZGdx/3Byef9nanH/Z2px/2xvef9nanT/amxz/2BjbP9qbXf/ -amxz/2dqdP9qbXf/ZGdx/2dqcf9kZ3H/am13/25xe/9maXP/cHJ5/2ptd/9sb3n/dXd9/2Rncf9maXP/ -amxz/2xudf9sbnX/bG51/2ptd/9tb3P/bnF7/25xe/9zdXz/cHJ5/3Byef9sb3n/dXd9/2xudf9zdXz/ -am13/2ptd/9sbnX/cHJ5/2dqcf9kZ3H/Zmlz/2xvef9nanT/amxz/3N1fP9sbnX/bnB3/3V3ff94eX3/ -cHN9/29xdf94eX3/bG95/3N1fP91d33/bnB3/2xudf9tb3P/am13/2ptd/9zdXz/cHJ5/3N1fP91d33/ -c3V8/3h5ff9ucHf/bG95/21vc/9zdXz/Z2p0/3N1fP9zdXz/Zmlz/2dqdP9sb3n/bG51/3V3ff9vcXX/ -dXd9/2xudf9qbHP/dXd9/3N1fP9wcnn/cHN9/2xvef9ucXv/bnB3/25wd/9vcXX/bG51/2xudf9sbnX/ -b3F1/2xvef9ucXv/cHN9/25xe/9wcnn/dXiB/3N2f/9zdXz/dXiB/3N2f/93eoP/dXiB/3Bzff9wc33/ -cHJ5/3Bzff9zdn//c3Z//2xvef9ucXv/cHN9/3d5f/9zdn//bnF7/3N1fP9zdXz/c3Z//3N1fP9ucHf/ -cHJ5/3Bzff9zdn//cHN9/3V4gf9zdn//cHJ5/3Bzff9wcnn/cHJ5/3d6g/9ucHf/dXiB/3Byef95e4H/ -eXyG/36Ahv9zdn//c3Z//3Bzff9ydX//dnmA/3J1fv9zdn//bnB3/25wd/9sb3n/dXiB/2xvef9sbnX/ -cHJ5/3Z4fP92eHz/c3V7/3J0ff91d33/bnB3/21vd/9pbHb/Zmhx/2ttdf9sb3n/cXN6/3Fzev9tb3P/ -cHJ7/2ttdf9rbXT/cHN9/25xe/9tb3b/a254/25xev9ucXv/bG95/21wev9xdH7/b3F2/3Z4fv9qbXT/ -dXd9/3Bzff9xc3r/dXd9/3R2fv9sbnb/b3F5/29yfP9sb3b/bG52/2xudv9ydX//cXN7/3Z4fv9wcnn/ -foGK/3d6g/9ucHf/bnB3/25wdf9wc3v/dXd9/2ptdv9rbnf/bnB3/25wd/9ydHv/dHZ8/3N1fP9tcHn/ -bXB3/2tueP9ucXv/dXd9/3V3ff9sb3n/bnF7/25xe/9ucHf/eXuB/25xe/9vcXX/bG51/3N1fP92eHz/ -amxz/3V3ff91d33/bG51/2xudf94eX3/bnB3/3h5ff9zdXz/Z2p0/2xudf9ucHf/bW9z/3Byef9ucHf/ -bnB3/2xudf9zdXz/am13/2ptd/9qbXf/Z2p0/2Zpc/91d33/am13/2psc/9wcnn/amxz/2xudf9maG7/ -c3Z//2ptd/9ucXv/c3Z//2xvef9ucHf/b3F1/3V3ff92eHz/b3F1/3V3ff9ucHf/bnB3/3Z4fP9nanT/ -bnB3/3Byef9zdXz/bnB3/3Byef9ucHf/bnB3/3Byef9ucHf/c3V8/3Byef9ucXv/bG95/3V3ff9sbnX/ -bG95/2Zpc/9qbHP/am13/3N1fP9sbnX/amxz/2psc/9ucXv/bG51/2psc/9ucXv/am13/2psc/9ucXv/ -c3V8/2xvef9qbXf/dXd9/2xudf9ucXv/cHN9/2xvef9qbXf/bG51/2xudf9qbXf/cHN9/2xudf9zdXz/ -dXd9/3N2f/9zdn//bG95/3Byef9ucXv/c3V8/25wd/9zdn//d3l//2xvef9ucXv/cHN9/3Byef95e4H/ -cHN9/3l7gf9wc33/bG95/3l7gf9zdn//dXiB/3N2f/9wc33/c3V8/25wd/9wcnn/cHJ5/3Byef9wc33/ -cHJ5/2xvef9wc33/bnF7/3Byef9ucHf/bW9z/3Byef9wcnn/bG51/3N1fP9sbnX/bnF7/3Bzff9tb3P/ -b3F1/25wd/9ucHf/c3V8/3V3ff9sb3n/cHJ5/2xvef91d33/c3Z//3Byef9ucHf/c3Z//3V4gf93eX// -dXd9/3h5ff95e4H/dnh8/3l7gf9/gYf/eXyG/3l7gf97fof/eXuB/3d5f/9/gYf/dXd9/3t9g/91d33/ -foCG/3t9g/97fof/c3Z//3N2f/9xc3r/cHN6/3J1fP9xc3v/cHJ5/2ptd/9nanT/Z2p0/3V3ff9qbHP/ -Z2px/2ptd/9ucXv/cHJ5/2lsdv9rbnj/b3J5/2xudf9rbnb/a252/2hqcv9naXH/a211/25xef9tcHr/ -a21z/3J0fP9tcHj/bG93/3F0fv9ydX3/b3F5/29xev9ydX3/dHd//3Byef9xdHz/eHqC/3V3ff94e4H/ -cXN6/3l8gv91d3//dnmB/3l7g/96fIP/c3V+/3d4fv92eID/dXd+/3F0fv9xc3v/d3qC/3h6gP99f4b/ -dnh//4OFjP9+f4P/ent//3d5f/94eoD/enyC/3p8gP9ydHv/cHN9/25xe/9vcnv/cnV+/3Z4gP92eH// -cnV+/29yev9wc3v/cHJ5/3V3ff92eHz/bnB3/25xe/9wc33/bnF7/3l7gf9wc33/cHJ5/25xe/9wc33/ -c3Z//2dqdP91d33/dXd9/25xe/9wc33/e32D/3Byef97fof/d3qD/3N1fP9wc33/d3qD/3N2f/9zdn// -c3Z//3N2f/9ucXv/bnF7/25xe/9ucHf/bnF7/2xvef9qbXf/d3qD/3N1fP9wc33/cHN9/25xe/9ucHf/ -Zmlz/3V3ff9sbnX/c3V8/3N1fP9ucHf/bnB3/29xdf9wcnn/dnh8/29xdf95e4H/b3F1/25wd/92eHz/ -Z2p0/2dqdP9ucHf/bnB3/21vc/9sbnX/bG51/2xudf9ucHf/bnB3/2xvef9sb3n/bG95/2ptd/92eHz/ -am13/25xe/9maXP/am13/2xudf9wc33/bG51/2Rncf9qbHP/am13/2psc/9qbHP/bG95/2ptd/9nanT/ -bG95/3N1fP9ucXv/am13/3N1fP91eIH/eXyG/3t9g/9zdn//c3Z//3Bzff9zdXz/bnB3/3N2f/9wcnn/ -dXiB/3l7gf91eIH/dXiB/3Bzff9wcnn/cHN9/3N1fP9vcXX/cHN9/3V3ff9qbXf/bG51/3N2f/9wcnn/ -d3l//2xudf9zdXz/bW9z/2xudf94eX3/c3Z//3V3ff9sb3n/bG95/25xe/9vcXX/bG51/29xdf9vcXX/ -bW9z/21vc/9vcXX/c3V8/2xudf9sb3n/bW9z/25wd/9wc33/cHJ5/29xdf94eX3/bnB3/3N2f/91d33/ -bW9z/2xudf9qbXf/bG51/25xe/9ucXv/bW9z/2xudf9ucHf/dXd9/25xe/9ucHf/amxz/2xudf9sbnX/ -bnB3/2xvef9ucHf/b3F1/2xudf9qbXf/c3Z//3N1fP91d33/dXiB/3N1fP91eIH/foGK/3N1fP93eoP/ -c3Z//3t+h/93eoP/e36H/3N1fP9zdn//cXN7/3N2gP96fIP/eXuB/3p8gv91d33/c3V8/3V3ff97fof/ -dXiB/3Bzff9wc33/dXd9/3V3ff90dnz/dXd+/3J1ff9ucXv/bXB5/3Bze/9pa3P/aWx2/3FzfP90d37/ -c3Z//3F0fP92eH//cnR9/3Bze/90d4H/dHeA/29yfP9xdHz/bXB4/29yfP9vcXv/bG95/21weP9tb3b/ -cHJ5/2ttc/92eHz/bnF6/25wef9ydX3/bXB6/25wd/9tcHn/bW92/29xd/9tb3b/bG54/3Fzd/90dnz/ -dHZ8/2xvef95fIb/cHN9/2xvef9wcnn/bnF7/3R2fP90dn3/cHJ6/21veP9tb3j/bG95/25xe/91d33/ -dHeA/3F0fP9zdn3/bnF6/3Bzff91eIH/d3l//25wd/9ucXv/bnB3/25wd/92eHz/bnB3/2ptd/9qbXf/ -bG51/25wd/9nanH/cHN9/3Bzff9qbXf/bnF7/3V3ff9tb3P/d3l//2xvef9nanT/Zmlz/2xvef9qbXf/ -bG95/2xudf9ucHf/bnB3/3Byef9ucXv/bnB3/25xe/9ucHf/am13/3N2f/9ucHf/bnF7/25wd/9qbXf/ -bG95/2psc/91d33/bG51/3N1fP9wcnn/bnB3/2xudf9sbnX/c3V8/3Bzff9qbHP/dXiB/2psc/9qbHP/ -c3V8/2Jlbv9dYGr/Z2px/2Rncf9maG7/Z2px/2dqcf9qbHP/bG95/2xudf9ucXv/bnB3/3V3ff9sb3n/ -d3l//25xe/9zdn//am13/25xe/9wc33/eXuB/3V4gf9sb3n/c3V8/3V4gf9zdn//d3l//36Ahv95e4H/ -dnh8/3l8hv9+gYr/e32D/3N2f/97fYP/bnB3/3N2f/93eX//cHN9/3N2f/9zdn//c3V8/3N1fP91eIH/ -c3Z//3l8hv97fYP/e32D/3Bzff9ucXv/cHJ5/3Bzff9zdn//c3V8/3V4gf95e4H/cHJ5/2dqdP9zdn// -cHN9/3l7gf9sb3n/dXiB/25xe/9sbnX/dnh8/3Byef91d33/bG51/29xdf9ucHf/b3F1/2psc/9sbnX/ -bG51/21vc/9sbnX/bW9z/3Bzff9wcnn/cHJ5/3Byef9wcnn/dXiB/25xe/9sb3n/eXuB/25xe/9zdn// -bnF7/25wd/9wcnn/bnF7/25wd/9ucXv/cHN9/25wd/9wcnn/cHJ5/3Z4fP9zdXz/cHJ5/2psc/9vcXX/ -bnB3/2xudf9ucHf/am13/2ptd/9qbHP/amxz/3Byef9sbnX/bG51/2xudf9tb3P/bG51/3Z4fP9sbnX/ -bnB3/21vc/9zdXz/bnF7/3Z4fP9tb3P/bG51/25xeP9ydX//dXd9/3V4gf91d33/bnB3/2ptd/9sb3n/ -dXiB/29xdf9sb3n/bnF7/3V3ff9zdXz/cHJ5/3Z4fP9xc3n/cHJ5/25wd/9ucXr/Zmlz/2psc/9wcnn/ -dXd7/25wd/9tb3P/dHd9/2tueP9sb3n/a210/21wef9sbnX/amxz/2hrdf9qbXT/am13/2psc/9ydX// -cnV+/3N2f/9vcnz/eXuA/3J1f/91eIH/enyD/3x/hf95e4H/dnh+/3d5f/96fIH/cnV//3J1fv91eIH/ -eHuF/3p8g/91d33/foGK/3V4gf9wc33/cHN9/3N2f/91eIH/eXuB/3V4fv9wc33/c3Z//25xe/9zdn// -eHqB/3V4gf9ydX7/dHZ8/25wd/9ucXv/cHN9/3N2f/9vcXX/bG95/25wd/9zdXz/dXd9/2xudf9sbnX/ -cHJ5/29xdf9ucXv/am13/3Bzff93eX//bnF7/3V3ff92eHz/b3F1/3d5f/9wcnn/bG51/2xudf9wcnn/ -cHJ5/2ptd/9tb3P/bnF7/2xvef9ucHf/b3F1/25wd/9wcnn/bG95/2xudf9ucHf/am13/25xe/9sbnX/ -am13/2ptd/9nanH/c3V8/2xudf9zdXz/bnF7/2xvef9sbnX/am13/3N1fP94eX3/bG95/3d5f/9ucHf/ -bnB3/3V4gf9sb3n/Z2p0/3V4gf9zdn//cHJ5/3N2f/9zdn//dXiB/3V4gf91eIH/e32D/3d6g/95e4H/ -c3Z//3l8hv91eIH/eXyG/3Bzff91eIH/dXiB/3t9g/93eoP/bnF7/3V4gf95fIb/bnF7/3Byef9ucXv/ -cHJ5/25wd/9zdn//dXiB/3V4gf9wcnn/c3Z//2xvef9qbXf/c3V8/2xvef9nanT/Z2px/2Zpc/9maG7/ -Zmlz/2Zobv9maXP/am13/2xvef9qbHP/bG51/2Zpc/9nanT/bG51/2psc/9ucXv/cHN9/2psc/9nanH/ -bG95/2ptd/9zdn//Z2p0/25xe/9sb3n/am13/3N1fP9ucXv/cHN9/2ptd/9qbXf/bG95/29xdf9sbnX/ -bG51/2xudf9tb3P/bG51/25wd/9wcnn/bW9z/2xvef9qbXf/cHJ5/3N1fP9sb3n/am13/3N1fP9sb3n/ -c3V8/2xudf9ucHf/bnB3/2xvef9ucHf/bnF7/3N2f/9ucHf/cHJ5/3Byef9zdXz/cHJ5/25xe/9sb3n/ -bG95/25wd/9sb3n/bG95/2xvef9sbnX/bG51/2xudf9wc33/bnB3/3Byef9ucHf/bnB3/25xe/94eX3/ -bnB3/3Byef9ucHf/dXd9/3N2f/93eX//b3F1/29xdf9ucHf/dHZ9/3N1fP91d33/eHl9/3Byef9sbnX/ -bnB3/3d5f/9vcXX/bnB3/3Byef92eHz/bnB3/3Byef9wc33/am13/2xvef9qbXf/am13/2dqdP9maXP/ -amxz/3N1fP9nanT/Z2px/2xvef9kZ3H/Zmhu/2RmbP9nanT/Zmhu/2dqcf9kZ3H/Zmhu/2Zobv9kZ3H/ -d3qD/3V4gf93eoP/dXd9/31+gf93eoP/dXiB/3l7gf91eIH/cHN9/3N2f/91eIH/eXyG/3d5f/91d33/ -d3l//3+Bh/97fYP/c3V8/3+Bh/91eIH/c3V8/3N1fP9wc33/d3l//3l8hv97fYP/c3Z//3N2f/9sb3n/ -bnF7/3Bzff9wc33/cHN9/3V3ff9ucXv/bnF7/3Byef9zdXz/bnB3/25wd/9tb3P/cHJ5/25xe/9ucHf/ -bnF7/2xvef9ucXv/cHN9/3N1fP91eIH/d3l//2xvef9zdn//dXiB/25xe/97fYP/dXiB/3V3ff9zdn// -d3l//3l7gf95e4H/dnh8/3d6g/91d33/eXuB/3h5ff96e3//e32D/3d5f/91d33/fn+D/3V3ff97fYP/ -d3l//3d5f/91d33/cHN9/3d6g/9zdn//eXyG/3N2f/9wcnn/c3V8/3N1fP95e4H/e32D/3N1fP97fof/ -cHN9/3Bzff97fof/am13/2Zpc/9ucHf/bG95/29xdf9sbnX/bW9z/2ptd/9sbnX/bnB3/3N1fP91d33/ -eHl9/25wd/93eX//bnB3/25xe/9nanH/bG51/25wd/9zdXz/c3V8/2dqcf9ucHf/c3V8/2psc/9vcXX/ -bnB3/25wd/9qbXf/cHN9/3d5f/9zdXz/bnB3/25wd/9wcnn/cHN9/3h5ff91d33/b3F1/29xdf9ucHf/ -b3F1/3Byef9sbnX/cHJ5/3Byef91d33/bG51/3Byef9qbHP/bnB3/3Byef9vcXX/dXiB/3V4gf9wcnn/ -bnB3/3N2f/9sb3n/eXuB/25wd/9wc33/cHJ5/2xvef93eX//c3Z//3d5f/9ucXv/bG95/3Bzff9ucXv/ -bG95/25xe/9wcnn/c3V8/3V3ff9zdn//d3qD/3N1fP9wcnn/bnF7/3V4gf9+gIb/dXiB/3Bzff93eoP/ -c3Z//3l8hv9zdn//bG95/2xvef9ucXv/cHJ5/3Bzff91eIH/bnF7/25xe/9wcnn/c3Z//3Bzff9wcnn/ -Z2p0/25wd/9vcXX/bnB3/25wd/9ucHf/bG51/25wd/9qbXf/cHN9/29xdf9vcXX/bnF7/3Bzff9zdn// -eXuB/3N1fP91eIH/bnB3/3V4gf91d33/d3l//3Byef9wcnn/bG95/3N2f/9wc33/c3Z//3Z4fP9wcnn/ -bG51/2xudf92eHz/bG51/2ptd/9sb3n/cHN9/2xvef9nanT/Z2p0/2xvef9qbXf/Zmlz/2Zpc/9maXP/ -Zmlz/2xudf91d33/bnB3/3Byef9zdXz/bG95/3Bzff9sb3n/cHN9/3Byef9zdn//c3V8/3Bzff9zdXz/ -cHN9/3Byef9sbnX/bG95/2xudf9wcnn/bnB3/25wd/9zdXz/cHJ5/25xe/9qbXf/bG51/2ptd/9qbHP/ -am13/2psc/9zdn//bnF7/2psc/93eoP/bG95/2dqdP9sbnX/bG95/3N1fP91eIH/dnh8/3Byef9zdXz/ -b3F1/21vc/9ucXv/cHN9/25xe/92eHz/cHJ5/3Byef9wcnn/c3V8/2xudf9wcnn/bW9z/3Bzff9qbXf/ -amxz/2xvef9ucHf/bnB3/2xudf9tb3P/c3V8/3V3ff9sbnX/bG95/25xe/9sbnX/c3V8/2xvef9qbXf/ -Z2p0/2xudf9qbXf/am13/2xudf9sbnX/bG51/25wd/9ucHf/bG95/25xe/9sb3n/bnB3/3N1fP9tb3P/ -cHJ5/25wd/9sbnX/bW9z/2dqcf9ucXv/Z2p0/2ptd/9sbnX/amxz/2xudf9ucHf/eHl9/3d5f/9vcXX/ -dXd9/25wd/9ucHf/eXyG/2ptd/9qbHP/bG95/2xvef9wcnn/bnF7/3Byef9sb3n/bnB3/3Bzff9zdn// -d3qD/3t9g/9zdn//d3qD/3N1fP9zdXz/am13/3Bzff9ucXv/cHN9/3N2f/9nanT/cHN9/25xe/9nanH/ -amxz/2xudf9qbXf/bG51/25xe/93eX//c3V8/29xdf9ucXv/bnB3/3N1fP92eHz/c3V8/2xudf9sb3n/ -bG95/25xe/91eIH/c3Z//3N2f/9wc33/dXd9/2xudf9zdXz/amxz/21vc/9ucHf/b3F1/3V3ff9zdXz/ -b3F1/25wd/91d33/cHJ5/3l7gf9sbnX/dXd9/3Byef9ucHf/c3V8/25xe/9wc33/bG95/2xudf9wc33/ -bG51/2Rncf9qbXf/am13/2dqdP9maXP/am13/3Byef9sbnX/bW9z/25wd/9ucXv/dXd9/2xvef9sb3n/ -c3V8/29xdf92eHz/bnB3/2xudf9qbXf/bnB3/29xdf9vcXX/cHJ5/29xdf91d33/cHJ5/3V3ff9wc33/ -bnF7/3Byef9zdn//cHJ5/3N1fP9wcnn/bnB3/2ptd/9sb3n/am13/3N1fP9vcXX/bW9z/25wd/9ucXv/ -bnF7/3l7gf9vcXX/c3V8/21vc/93eX//c3V8/3V3ff9vcXX/bnB3/2xudf9wcnn/bnF7/3N1fP9ucXv/ -cHJ5/2dqdP9sbnX/eHl9/29xdf9zdXz/dXd9/3Z4fP9zdXz/bnB3/2xvef9sb3n/cHJ5/3Byef9ucHf/ -bnB3/2psc/9sbnX/d3l//25wd/9ucXv/bG95/2xvef9zdXz/bnB3/3Byef9sbnX/bnB3/2xudf9sbnX/ -bG51/2ptd/9ucHf/bnB3/3Byef9ucHf/cHN9/3Byef9zdXz/c3Z//3V4gf91eIH/c3Z//3N2f/91eIH/ -c3V8/3N2f/9zdXz/e36H/3N2f/9ucXv/eXyG/3Bzff9sb3n/bG95/3Bzff9zdn//e36H/3t9g/9zdn// -c3Z//25wd/9ucXv/cHN9/3Z4fP91d33/d3l//3V3ff9ucHf/cHN9/3V4gf9ucXv/c3Z//2xvef9zdn// -bnF7/25wd/9ucXv/bnB3/3N1fP9ucHf/b3F1/2xvef9zdXz/amxz/2xvef9wc33/am13/25xe/9wcnn/ -bG51/2dqcf9ucHf/bG51/25wd/9qbXf/cHJ5/25wd/9wcnn/bG51/25wd/9zdXz/bnB3/25wd/9zdXz/ -amxz/25wd/9sbnX/bG51/21vc/9maG7/bG95/2dqdP9qbHP/bG51/2dqcf9nanH/Zmhu/3Byef9wcnn/ -Z2px/25wd/9gY2z/ZGZs/3Byef9iZW7/XWBq/2BjbP9maG7/ZGdx/2Zobv9maG7/ZGdx/2Zpc/9nanT/ -bnF7/3Bzff9zdXz/bG95/3V3ff9qbXf/bG51/2dqdP9qbHP/am13/2xvef9wcnn/amxz/3Byef9ucXv/ -Z2p0/2ptd/9ucHf/bnB3/21vc/9sb3n/c3V8/3V3ff9sbnX/bG51/2dqdP9nanT/cHJ5/25xe/9qbXf/ -bnB3/2Zpc/9maXP/am13/2xvef9ucXv/bnF7/3Bzff9ucHf/bnF7/2ptd/9sbnX/bnB3/21vc/9ucXv/ -bnF7/2xudf9nanT/dXd9/2ptd/9zdn//amxz/2ptd/9nanT/amxz/2xvef9ucXv/bG95/25wd/9sbnX/ -bnB3/2xudf9qbHP/bnB3/29xdf9ucHf/am13/25wd/9ucXv/bG95/2xvef9wc33/bnF7/3l7gf9wc33/ -cHJ5/3V4gf9wc33/eXuB/3Bzff9sb3n/cHJ5/25wd/9ucHf/bW9z/3Byef9tb3P/cHJ5/25wd/9zdXz/ -bG51/25wd/9nanT/bG51/2psc/9sbnX/bnB3/21vc/9sbnX/bnB3/25wd/9zdXz/bnB3/29xdf9vcXX/ -cHJ5/3Bzff91eIH/bnB3/3Bzff9wcnn/e36H/3d6g/95e4H/cHN9/3N1fP9ydHz/enyC/3p8gv99f4X/ -fn+D/3t9g/92eHz/d3qD/3t+h/9wc33/d3qD/3t9g/97fYP/d3qD/3d6g/94e4X/dXiB/3Z5gv9ydX7/ -dHeA/3Fzev9rbnj/bnB3/3d4ff9vcnz/cnV+/25xe/9vcXn/bnB3/21vdv9tb3b/bG51/25wd/9ucHT/ -bnB4/21wef9sb3n/bnB3/2ttdP9pa3X/aGty/2tueP9pa3X/a210/2tueP9sb3b/c3V7/25wd/9tb3b/ -cHJ5/21vdv9ucHf/bG51/3h6gP9ucHf/am13/3N2f/9qbHP/YmVu/2Jlbv9maXP/Z2p0/3N1fP9tcHr/ -bG95/2ptd/9oanT/am13/2xvef9xc33/cHN8/3R2fP9sb3n/amxz/2dqdP9ucXv/bG95/3V3ff9tb3P/ -cHN9/2ptd/9sb3n/am13/2xudf9wcnn/bnB3/21vc/9wcnn/dXd9/2ptd/9ucXv/cHN9/2xudf9wcnn/ -c3V8/2xudf9kZ3H/am13/25wd/9wcnn/bG51/2xvef9sbnX/am13/2Zpc/9maXP/bG95/2ptd/9qbXf/ -am13/2dqdP9nanT/Zmlz/2Zpc/9nanT/YmVu/2xvef9maXP/Z2px/2xudf9qbHP/Z2p0/2psc/9zdXz/ -cHN9/2dqdP9wcnn/amxz/2psc/91d33/Z2p0/2Rncf9maXP/bG95/2dqdP9sbnX/Z2px/2dqcf9nanT/ -Z2p0/3Bzff9wc33/cHJ5/2dqdP9wcnn/Z2p0/2dqcf9maXP/Zmlz/2ptd/9nanT/am13/2Rncf9sbnX/ -bG95/2Jlbv9nanT/bG51/2xvef9nanH/Z2p0/25xe/9ucXv/amxz/2dqcf9sbnX/bG95/3d5f/9wcnn/ -bnB3/3Byef9sbnX/bG51/3V3ff9ucHf/bnB3/3Byef9ucXv/bG95/3Byef9qbXf/bG51/2xvef9sbnX/ -c3V8/3Byef9vcXX/bG51/3Z4fP9zdXz/eHl9/25wd/9wcnn/bnB3/2xudf9wcnn/cHN9/3Byef9ucHf/ -bnB3/3Byef9sbnX/ZGdx/2xudf9sbnX/Z2p0/2dqdP9sbnX/bnB3/25wd/9vcXX/cHN9/3Byef94eX3/ -cHJ5/2xvef9wc33/cHN9/3d5f/9sb3n/bG95/25xe/9sb3n/bnB3/29xdf9wcnn/bG51/25wd/9wcnn/ -c3Z//25xe/9wc33/bnB3/3N1fP9zdXz/dXiB/2ptd/9ucHf/bG51/2xudf9sbnX/bnF7/2ptd/9sbnX/ -bG51/2xvef9wc33/dXd9/21vc/9zdXz/bnB3/3h5ff9wc33/eXuB/25xe/9qbXf/b3F4/3Bzff9ydHz/ -dHZ9/3V3ff9qbXf/bG51/3N1fP94eX3/bnB3/3N2f/92eHz/dXd9/3Byef9ucXv/cXR9/29xeP9xc3r/ -bnB3/25wev9pa3T/Z2p0/2ttdf9xc3v/bXB6/2xveP9rbnj/am12/2ZpcP9oanH/amxz/2dqcv9kZ3H/ -ZWhy/2Zpc/9maXD/Z2lv/3Bzff9tb3f/b3F6/21vdv9vcnv/bnB3/25wd/9vcXj/cXN6/3J0ev9ucHj/ -bXB6/29yfP9vcXb/bG95/2ttdf90d3//bG52/2xudv91d33/am13/2Rncf9nanT/bG95/21wev90d4D/ -cnR8/3Bzff9rbnj/am13/21wev9vcnz/cXR+/29yfP9zdX3/bXB6/2ptd/9nanT/bG95/2ptd/9ucXv/ -amxz/25xe/9qbXf/bG51/2ptd/9qbXf/bG95/2xvef9qbHP/bnF7/3V3ff9qbHP/bG95/3N1fP9sb3n/ -bG95/3Byef9vcXX/Zmlz/25wd/9zdXz/c3Z//3Byef9zdn//cHN9/25xe/9qbXf/bnB3/3N2f/9wc33/ -bG95/3Byef9sbnX/cHN9/25wd/9wcnn/bG95/2dqdP9wcnn/am13/3Byef9wc33/bG95/2xvef9vcXX/ -d3l//3d5f/9zdXz/c3V8/2ptd/9sb3n/d3l//2xudf9sbnX/Z2p0/3Byef9ucHf/bG51/2xudf9tb3P/ -bG95/2ptd/9zdXz/cHN9/3N1fP9sb3n/bnF7/2Zpc/9nanH/ZGdx/2dqdP9sb3n/am13/3Byef9nanH/ -bG51/3N1fP9kZmz/amxz/25wd/9wcnn/bG51/3Bzff9wc33/d3l//2xvef9qbXf/Z2px/2ptd/9zdXz/ -Z2p0/2dqcf9qbXf/Zmlz/2psc/9qbXf/ZGdx/2Zobv9maXP/am13/2dqcf9nanT/amxz/2ptd/9ucXv/ -bG51/3Byef9ucHf/b3F1/2psc/92eHz/cHJ5/3Z4fP9ucHf/cHJ5/3Byef9ucHf/c3V8/3V4gf9wc33/ -c3V8/2xvef9wc33/bnB3/2dqdP9vcXX/b3F1/25wd/9sbnX/bG95/25wd/9sbnX/am13/25xe/9qbXf/ -dnh8/2xudf9tb3P/cHJ5/3Byef91d33/bG51/2dqdP9sb3n/am13/2dqdP9sbnX/bnF7/25wd/9wcnn/ -am13/3Bzff9ucHf/cHJ5/2xvef9ucHf/bG95/3Bzff9qbXf/cHJ5/2xvef9ucHf/bG95/3N2f/9sb3n/ -bG95/25wd/9wc33/dXiB/3l8hv9ucHf/dXiB/25xe/93eoP/c3Z//3d6g/9ucXv/am13/21weP9xc3v/ -b3F5/3R3fP90dnz/bnF7/21vc/9ucHf/dXd9/2ptd/9sb3n/bnF7/3N1fP9sbnX/bnB4/25xev9ucHj/ -bnF5/25wd/9tcHr/Z2p0/2xvd/9tcHj/cnV9/3Bze/9ydHv/cHN9/3BzfP9vcnz/dHZ8/3N1e/9xc3r/ -bnB5/3J0e/9wcnv/bnF5/21weP9ydHv/bG51/3Fze/9rbXb/bXB6/3Byef9sb3n/bG95/2xvef9rbXb/ -aWx0/21weP9pbHb/b3F6/2lsdv9rbnb/bnF6/2ptdv9qbXf/c3V8/2xvef9kZ3H/Zmlz/2xvef9qbXf/ -cHN7/2xvef9ucHn/am12/2tudv9tb3b/bW92/29yfP9ucHn/dXh//3Fzev91d33/dXd9/3V4gf9wc33/ -c3Z//3Byef91d33/bnB3/29xdf9wc33/bnF7/3N2f/9zdn//bnB3/3d5f/95e4H/cHJ5/3Bzff95e4H/ -dXiB/3d6g/9wc33/cHJ5/25xe/9wc33/dXiB/3l7gf9zdXz/c3Z//25xe/9wc33/bnB3/3Byef93eX// -cHN9/25wd/9ucHf/Z2px/3Byef9ucHf/bW9z/2dqdP9iZW7/am13/2Rncf9sbnX/c3V8/3N1fP9sbnX/ -b3F1/3h5ff93eX//dXiB/3N2f/9sb3n/cHN9/3l7gf9ucHf/cHN9/3V3ff97fYP/eXuB/3l7gf93eX// -dnh8/3t9g/95e4H/foGK/36Biv9/goz/f4GH/35/g/92eHz/dXiB/3Z4fP92eHz/e32D/3l7gf95fIb/ -c3Z//3V4gf93eoP/Zmlz/2ptd/9zdXz/cHJ5/2dqdP9ucXv/bnF7/3V3ff9sb3n/amxz/25wd/9wcnn/ -d3qD/3Bzff9ucXv/c3Z//2ptd/9ucHf/dXd9/25wd/9sb3n/cHJ5/3Bzff9wc33/c3Z//25wd/9sb3n/ -cHN9/25xe/91eIH/c3Z//25xe/9sb3n/e32D/3l8hv95fIb/c3Z//3V4gf9ucXv/bnF7/3V4gf95fIb/ -d3qD/3V4gf9zdn//d3qD/3Bzff9ucXv/bnB3/2xvef9sb3n/bG95/3N2f/91eIH/cHJ5/2xvef91d33/ -cHN9/3d5f/9ucHf/am13/3Byef9wcnn/dnh8/25wd/9sb3n/c3V8/29xdf9qbXf/bG95/3N1fP9wcnn/ -c3Z//3N2f/93eoP/cHN9/3V4gf9wc33/bnF7/25wd/9zdn//bG95/3Byef9ucHf/bG95/2xvef9zdn// -bG95/25wd/9ucHf/c3V8/3Byef91d33/amxz/25xe/9qbHP/c3V8/2xvef9ucHf/Zmlz/2Rncf9sb3f/ -b3J8/2ttdP9ucXr/cnR7/2xvef9tb3P/bnB3/3V3ff9sbnX/cHN9/3N2f/91d33/cHN9/29yfP9zdXz/ -bnF7/3F0fv90dn3/cXN7/2hrdf9vcXn/b3F5/3N2gP9wcnn/cXN8/3Bzff9ydHv/cnV+/3Z5gv92eYH/ -c3Z+/25xe/9zdn7/cnR9/3J1ff9tcHn/cXR9/3Fzev90d4D/bXB6/3N2gP9wc3z/b3J8/3F0ff9vcnz/ -b3F6/21wd/9ydX3/cHJ7/3J0e/9tb3f/a252/3N1fv9tcHj/cHJ5/3Z4f/9zdXz/Z2px/2psc/9wcnr/ -bW92/3J0e/9ucHn/bnF5/2xvd/9ucHT/cHJ5/21vdv9xc3r/b3F4/3N1e/9vcXn/bG95/25xe/91d33/ -c3V8/3N1fP9qbXf/c3V8/2xudf9sbnX/am13/2xudf9wcnn/cHJ5/21vc/92eHz/d3l//2ptd/9ucXv/ -dnh8/3Byef9wcnn/cHJ5/2xudf9maG7/bG51/3N1fP9wc33/bG51/2ptd/9sbnX/amxz/2ptd/9vcXX/ -dnh8/25xe/9ucHf/bG51/2dqdP9ucXv/cHJ5/25wd/9sbnX/Zmlz/3Bzff9nanT/bnF7/3N2f/9wc33/ -am13/25xe/93eoP/e32D/3V4gf95e4H/cHJ5/3Bzff97fYP/bnB3/3Byef9ucHf/cHN9/25xe/9wc33/ -bnB3/25wd/9ucHf/bW9z/3V3ff9wc33/dXiB/2xvef9wc33/bG51/3Byef9sb3n/bnB3/3N2f/9wcnn/ -c3V8/2psc/9zdXz/c3V8/2dqcf9sbnX/cHJ5/2xudf9sbnX/c3V8/3Byef91d33/dXd9/3Byef9wcnn/ -c3Z//3d6g/9ucXv/bnB3/3N2f/9ucHf/cHJ5/3d6g/9zdn//dXiB/3l8hv97fYP/fX6B/3t9g/91d33/ -d3qD/3l8hv93eX//fn+D/3t9g/97fYP/cHJ5/31+gf97fYP/fn+D/3l7gf9+gIb/d3l//3l7gf9zdn// -d3qD/3t9g/91eIH/dXiB/3N2f/9zdXz/c3V8/3N1fP9wc33/bG95/3N1fP93eoP/c3Z//3N1fP9sb3n/ -cHN9/3Bzff93eX//cHJ5/2ptd/9wcnn/bG95/3V3ff9sbnX/bnB3/3V3ff9ucHf/amxz/25wd/9zdXz/ -bG95/25wd/9sbnX/cHJ5/25wd/91d33/bnB3/25wd/9ucHf/dXd9/2xudf9sbnX/bW9z/2ptd/9qbXf/ -cHN9/2xudf9wcnn/bG51/2ptd/9qbXf/dXd9/2psc/9sb3n/Z2px/3N1fP9qbXf/bnB3/2Zpc/9dYGr/ -a210/29yfP9sbnX/bW92/3Fzev9sb3n/amxz/2xvef9ucXv/bG51/2xvef9zdXz/bnF7/2ptd/9rbnf/ -b3F4/21wev90dnv/dHd7/29xef9maW//bW93/3J0e/9zdXz/bnB4/3Byef9wc3z/dHd//3R3f/94eoP/ -dnmC/3V3gP9rbnf/c3V9/29yfP9vcnz/bnB2/21vdv9qbHL/b3J5/2xveP9sb3n/bXB6/21weP9tb3b/ -bG53/21weP9pa3P/cHJ6/29yev9ydHn/bnB3/25wdf91d33/bnF7/3J0fP93eX//c3V8/2Zobv9sbnX/ -c3V8/3BzfP91dnv/cnR5/3N1e/9xc3j/bW91/21veP9sbnT/bW92/29yev91d3//cHJ5/3Bzff91d33/ -d3l//3N1fP91d33/bG95/3l7gf9ucXv/bnB3/25xe/9sb3n/dXiB/3V4gf9ucXv/dXd9/3N2f/9nanT/ -bnF7/3l7gf9wc33/c3Z//3N2f/9sb3n/Z2p0/29xdf91eIH/c3Z//25wd/9ucHf/cHJ5/2xudf9ucHf/ -bG51/3Z4fP9wc33/cHJ5/3N2f/9nanT/cHN9/3Bzff9wcnn/bnF7/2ptd/95e4H/bG95/3N1fP95fIb/ -e32D/3N1fP9zdn//foGK/3l7gf91eIH/dXiB/3Byef9wc33/e36H/3V3ff91d33/dnh8/3t9g/95e4H/ -dXiB/3N2f/9zdXz/c3Z//3N1fP93eX//c3Z//3t+h/93eoP/eXuB/3N1fP9ucXv/bG95/2xvef9zdn// -cHN9/3Bzff9sb3n/cHN9/3N1fP9qbHP/bG51/3Byef9sbnX/amxz/3Bzff9wcnn/dXiB/3V3ff9wc33/ -bW9z/2xvef9ucXv/bnF7/2xudf9zdXz/bG51/2xudf9ucXv/am13/25wd/9wcnn/bG95/3N2f/9zdXz/ -bnB3/2xvef9wcnn/b3F1/3Z4fP9wcnn/cHJ5/2Zobv9ucXv/bnF7/3N1fP9qbXf/bnF7/21vc/9ucXv/ -bG51/2xvef9ucXv/bG51/2psc/9qbXf/ZGdx/2Zpc/9nanH/bG51/2Jlbv9nanT/bG95/2ptd/9qbHP/ -Z2p0/2xvef9ucXv/dXd9/3Byef9ucHf/cHN9/3Bzff97fYP/cHN9/25wd/93eoP/cHN9/2xvef91d33/ -eXyG/3N2f/93eoP/c3Z//3d6g/9wc33/e32D/3d5f/95e4H/dXd9/3t+h/9zdn//dXd9/3Bzff9wc33/ -bnB3/3V4gf9ucHf/bnF7/2xvef9wcnn/c3Z//3d6g/9ucHf/dXd9/25wd/95fIb/c3Z//3t9g/91eIH/ -am13/25xe/91eIH/b3J7/3F0fP92eH7/c3V8/25wd/9wc33/dXiB/3Byef9wc33/c3Z//3V4gf9zdn// -b3J8/3R2ff9xdH7/cnV+/3h6gP9wc3z/aGt0/21wd/90d3//c3Z//3Byef9vcXb/b3F4/25xe/9xdHz/ -cnR8/3N0ev9wcnv/bG95/3J0fP9vcnr/bnB5/21vdf9xdHv/b3F4/3N2fv9tb3j/cnR9/25xev9vcnv/ -bnB3/3R2fP9ydHv/bG52/21vd/9vcnz/b3F4/25xe/9tcHn/d3l//21wd/9ydHz/dnh8/3Byef9kZmz/ -Z2p0/3Byef9ucXv/dHd9/3N1fP9wc3z/dHd+/2xvef9sb3n/cHJ5/3Bzff90dn3/dnmD/3R2f/91eIH/ -eXyG/36Ahv95fIb/foCG/3V4gf95e4H/cHN9/3Byef9ucXv/c3V8/3V3ff9zdn//bnF7/3Z4fP9wc33/ -ZGdx/2ptd/9zdXz/Z2p0/2xvef9sb3n/Zmlz/2Jlbv9qbXf/c3V8/3N1fP9nanT/bG95/2xvef9qbXf/ -bG51/21vc/9zdXz/bnF7/2xudf9qbXf/YmVu/2xvef9sbnX/bG51/2Zpc/9kZ3H/cHN9/2Zpc/9ucHf/ -c3V8/3Byef9nanH/b3F1/3Z4fP9zdn//cHN9/3Bzff9ucHf/bnB3/3l7gf9wcnn/bnF7/25wd/9wc33/ -c3Z//3Bzff9ucXv/bG95/25xe/9ucHf/dXiB/3d6g/9+gYr/c3Z//3N2f/9vcXX/bnB3/25wd/9tb3P/ -cHN9/2ptd/9sb3n/Z2p0/25xe/9qbXf/ZGdx/2Zpc/9ucXv/am13/2Zpc/9wc33/cHJ5/3V3ff91d33/ -cHJ5/2psc/9qbXf/dXd9/3Bzff9tb3P/cHJ5/2xudf9qbHP/bG95/2psc/9qbXf/bG95/2xudf9wc33/ -bnF7/2ptd/9sb3n/bG95/2ptd/91d33/c3V8/25wd/9kZ3H/bG95/3V3ff91d33/bnB3/3Byef9sbnX/ -bG95/2psc/9qbXf/bG95/2xudf9nanT/bnF7/2dqdP9qbXf/bG51/2ptd/9maXP/am13/2xvef9sb3n/ -am13/2ptd/9zdXz/cHJ5/3Z4fP9wcnn/bnB3/2xvef9sb3n/c3V8/3Byef9sbnX/c3V8/2psc/9nanH/ -bG51/25wd/9tb3P/cHN9/2psc/9sbnX/bG51/3V3ff9ucHf/cHJ5/21vc/92eHz/am13/2dqdP9qbHP/ -bG51/2psc/9zdXz/am13/2xvef9qbXf/bG51/2xvef91d33/bnB3/3Z4fP9tb3P/eXuB/3N1fP93eX// -cHN9/2dqdP9ucHf/dXiB/29yfP9xdHz/dXh//25weP9sbnX/cHJ5/3N1fP9qbXf/bnF7/25xe/9sb3n/ -cHN8/3Byef9ydHv/bnB4/25xev9xc3r/am13/2dqdP9sb3j/bG95/3Bye/9rbnj/am12/2tueP9rbnj/ -bG95/29xeP9rbnf/bnF6/21wev9xdH3/cXR+/3F0ff9vcnv/cnR7/2hrdf9sbnb/bG94/25weP9sbnb/ -b3F5/2xvef9wc33/dHZ8/2ptd/9xc33/dnh8/21wev9ydX7/dHZ8/31+gv9ucHf/c3Z//3l7gf93eoP/ -Z2p0/2xvef9zdn//c3Z//3Z4fv92eH7/cHN9/3J1fv9sb3n/b3J8/2xvef9sb3n/dHd7/3Z4fv9tcHr/ -c3V8/3N1fP91d33/c3V8/3Z4fP9ucHf/dnh8/3N1fP9vcXX/bnB3/25xe/93eoP/c3Z//3Bzff95e4H/ -dXiB/2ptd/9zdn//d3qD/25xe/9zdn//dXd9/29xdf9maGz/b3F1/3V3ff91d33/bnB3/3Byef9ucHf/ -bG51/2xudf9sbnX/dXd9/25xe/9qbXf/bG51/1xfaP9qbHP/amxz/2psc/9iZW7/YmVu/2xvef9iZW7/ -Z2p0/25xe/9sb3n/am13/2psc/91d33/bnF7/3Byef9zdXz/bG95/3Byef91d33/bnB3/2xvef9ucHf/ -bnF7/3Byef9zdXz/cHJ5/25wd/9zdXz/bnB3/3Bzff9wc33/e36H/3Bzff91d33/bG95/3Bzff9wcnn/ -cHJ5/3N2f/9wc33/cHN9/25wd/91d33/bnB3/2dqcf9qbHP/c3V8/3Byef9nanH/bnF7/3N1fP93eX// -dXd9/25xe/9tb3P/cHJ5/3V3ff9zdn//bG95/25xe/9vcXX/b3F1/3N1fP9sbnX/bW9z/2xudf9ucHf/ -c3Z//3V4gf9ucHf/bnF7/25xe/9wcnn/d3qD/3V4gf9zdn//bG95/3N2f/93eoP/eXuB/3Bzff91eIH/ -cHN9/25xe/9ucHf/bnF7/3Bzff9ucXv/bnB3/3d5f/9sb3n/bnF7/3Bzff9wc33/bG95/3Byef9zdn// -cHN9/3Bzff9zdXz/d3qD/3V4gf97fYP/cHJ5/3N2f/9wc33/c3Z//3d5f/9zdn//cHJ5/3V4gf9wc33/ -cHN9/3N2f/93eoP/dXiB/3t9g/9zdXz/cHN9/3Bzff91d33/c3Z//3N2f/9sb3n/c3Z//2xudf9ucHf/ -bnB3/25wd/9qbHP/c3Z//3Bzff9zdn//bG95/3Byef9sbnX/d3l//2ptd/92eHz/bW9z/3d5f/9zdXz/ -d3l//3Bzff9maXP/bG95/3Bzff9sbnX/bnF7/3F0fv9xdH3/bnF7/3N2f/93eX//bG95/3Bzff91d33/ -dXd9/3Byef9ucHf/cXN6/21veP9sb3f/bXB4/2tudv9oa3X/am1z/2xud/9zdn3/am13/2tudv9oa3X/ -Zmlz/2hrdf9pbHP/aGt0/2hqcP9naW//Zmhu/2hrdf9oa3L/Z2p0/3N1fP9sbnX/bW9z/25wd/9sb3n/ -bG95/25xe/9sb3n/cHN9/3N2f/9qbXf/bnF7/3N2f/9ucHf/dXiB/3Z4fP99foH/b3F1/3N1fP94eX3/ -c3V8/2dqcf9qbHP/cHJ5/3N1fP91d33/dnh8/3Byef9zdn//bG51/3Byef9ucHf/bW9z/3V3ff91d33/ -bG51/3Byef9ucXv/c3V8/2xvef9zdXz/bG95/3d5f/9ucXv/bG51/3N1fP9ucHf/dnh8/3Byef9ucXv/ -d3l//3Bzff9nanT/c3Z//3d5f/9ucHf/cHJ5/3Z4fP9vcXX/ZWZq/29xdf9zdXz/dnh8/2ptd/9wc33/ -cHN9/25xe/9ucHf/bnB3/3N2f/9wc33/bnB3/3Byef9maG7/bG51/2xudf9qbXf/Zmlz/2Zpc/9sb3n/ -YmVu/2psc/9sb3n/am13/2dqdP9sbnX/bnF7/2xvef9ucXv/bnF7/2xudf9qbXf/bnF7/2xudf9qbXf/ -amxz/2xvef9sb3n/bnF7/2xudf9nanH/c3V8/2xudf9ucHf/bnF7/3d6g/9wcnn/dnh8/25wd/9wcnn/ -b3F1/29xdf9zdXz/bG95/3N1fP9sbnX/c3V8/2xvef9maXP/ZGdx/25xe/9qbXf/Zmlz/3Byef9zdXz/ -eHl9/3Z4fP9wcnn/bnB3/3Bzff91eIH/c3V8/29xdf9ucHf/bW9z/21vc/9wcnn/bG51/2xvef9sbnX/ -bG51/3Bzff9sb3n/ZGdx/2dqcf9maG7/Zmlz/2xvef9wc33/bnF7/2dqdP9ucHf/c3V8/3V3ff9sbnX/ -c3V8/2ptd/9ucXv/am13/2xvef9ucXv/bnB3/2xudf91d33/amxz/2xudf9ucHf/b3F1/2dqcf9ucHf/ -bnB3/25xe/9ucHf/bG95/3N1fP92eHz/dXd9/2xvef9wc33/cHJ5/25xe/9zdn//cHN9/3Byef91eIH/ -bnF7/25xe/9sb3n/dXiB/3V4gf9+gIb/dXd9/3V4gf91eIH/e32D/3N2f/93eoP/bnB3/3V3ff9sb3n/ -bnB3/25wd/9sb3n/bG51/3N2f/9wc33/dnh8/25wd/9zdXz/bG95/3d5f/9qbXf/dXd9/21vc/93eX// -cHN9/3Bzff9sb3n/ZGZs/3Byef9wc33/am13/29yfP9zdoD/c3Z+/3Byef93eoP/eXuB/3Byef93eoP/ -e32D/3l7gf91eID/dnmB/3t9gP92eIH/c3Z+/3R3f/9ydH3/cnV+/3J0ff9wcnn/eHqE/3N1fv9sb3n/ -bG95/25wd/9zdXz/bW9z/2xudf9ucHf/bG95/29xdf9zdXz/cHJ5/25xe/9qbXf/ZGdx/2psc/9qbXf/ -amxz/21vc/9wcnn/b3F1/3Byef9wc33/Z2p0/25xe/91eIH/bnB3/3d6g/95e4H/f4GH/3N1fP93eoP/ -e36H/3d6g/9wc33/bnF7/3t9g/95e4H/eXuB/36Ahv93eoP/eXuB/25xe/91eIH/c3Z//2xvef91d33/ -dXd9/2xudf9ucHf/cHJ5/3N1fP9zdXz/eHl9/3Bzff91eIH/cHN9/25xe/9zdXz/c3Z//3d5f/93eoP/ -dXiB/3d5f/9wc33/amxz/3Bzff93eX//bG95/3V4gf95e4H/cHJ5/2dqdP9ucHf/d3l//3l7gf9ucXv/ -cHN9/25xe/9sbnX/bG51/21vc/9ucXv/cHJ5/2xudf9ucXv/Zmlz/2ptd/9sbnX/am13/2dqdP9nanH/ -bnF7/2Zobv9ucHf/bnF7/25wd/9qbHP/am13/3Bzff9ucXv/bnB3/3Bzff9sbnX/bW9z/3N1fP9wcnn/ -bnB3/29xdf9ucHf/bG51/3Byef9qbXf/Zmlz/25xe/9nanH/bG95/25xe/91eIH/am13/3Bzff9nanT/ -am13/2Zpc/9nanT/cHN9/21vc/9zdXz/bW9z/3V3ff9ucXv/Zmlz/2dqdP91d33/bnF7/2ptd/9wc33/ -bG95/3V3ff93eX//cHN9/2psc/9qbHP/am13/2xvef9qbHP/bnF7/2dqcf9qbHP/bG95/2psc/9ucXv/ -bG51/21vc/91d33/cHJ5/2ptd/9sbnX/bG51/2psc/9ucHf/cHJ5/3Byef9qbHP/cHJ5/3N1fP94eX3/ -bnF7/3Bzff9ucXv/cHJ5/25wd/9wcnn/cHN9/25wd/9ucHf/dnh8/2dqdP9qbXf/bG51/21vc/9kZmz/ -b3F1/25wd/9zdXz/bnB3/25wd/9ucHf/c3V8/3V3ff9ucHf/c3Z//25wd/9ucHf/c3V8/3Bzff9wcnn/ -c3Z//2xvef9nanT/am13/3N2f/9ucXv/d3l//3Bzff9wc33/c3Z//3l7gf9wc33/c3Z//2xvef92eHz/ -bnB3/29xdf9ucHf/bnF7/2xvef91d33/c3Z//3V3ff9sb3n/cHJ5/29xdf91d33/bG51/3Z4fP9tb3P/ -d3l//3V3ff9wc33/cHN9/2Rncf91eIH/c3Z//2xveP9vcnz/c3aA/3V4gP9sb3n/dXiB/3V3ff9sbnX/ -c3V8/3Z4fP91d33/c3V8/29xdf9xc3n/cHJ5/3Fzev9vcXb/bG95/3Bzff9ucHf/bnB3/3V3ff9wcnn/ -bG95/2xudf9nanT/cHN9/2psc/9maXP/amxz/2psc/9qbHP/bG95/25xe/9sb3n/dXiB/3N1fP9wc33/ -d3qD/3N1fP9wc33/dXiB/3l7gf95e4H/d3qD/25xe/95e4H/d3qD/3N1fP91eIH/dXd9/3l8hv9sb3n/ -c3V8/3V3ff9wcnn/Z2p0/2Zpc/92eHz/dXd9/3V3ff91d33/bnB3/3Bzff9nanH/bnB3/2xvef9qbXf/ -bnF7/3Bzff9sbnX/cHJ5/3N1fP9wc33/c3Z//3t9g/91eIH/foGK/3d6g/93eoP/c3Z//3l7gf97fof/ -eXuB/3d6g/97fof/eXuB/3V3ff95fIb/e36H/3V4gf95e4H/eXyG/3Bzff9qbXf/cHJ5/3N2f/93eX// -bG51/3Byef9ucHf/bG51/25wd/9ucHf/c3V8/3V3ff9sbnX/bnF7/2Rncf9qbXf/Z2p0/2dqcf9nanH/ -YmVu/2xvef9iZGr/bG51/25xe/9sb3n/Z2p0/2xudf9wc33/bG95/2xvef9zdXz/bG51/2xudf9wc33/ -bG95/2dqdP9maXP/am13/2ptd/9sb3n/amxz/2Zpc/9zdXz/am13/2ptd/9ucXv/dXd9/2dqdP9qbXf/ -YmVu/2dqdP9iZW7/Z2px/2ptd/9maXP/bG95/2Zobv9qbXf/Zmlz/2BjbP9gY2z/bnF7/2ptd/9maXP/ -am13/2psc/9wc33/bnF7/2dqdP9ucXv/c3Z//3Bzff9wc33/bG95/3N2f/9ucHf/bG95/25xe/9sb3n/ -c3V8/25xe/9tb3P/dXd9/25wd/9ucHf/b3F1/25wd/9qbXf/am13/25wd/9sb3n/Zmlz/2ptd/9ucXv/ -c3V8/2ptd/9ucXv/bG51/2xvef9sb3n/bG95/2xvef9ucHf/am13/3Bzff9nanT/am13/2ptd/9sbnX/ -YmVu/2psc/9nanT/bG95/2psc/9qbHP/am13/25xe/9sb3n/amxz/25xe/9qbXf/bG51/25xe/9sb3n/ -bG51/2xudf9kZ3H/Z2p0/2Rncf9sb3n/cHJ5/3N1fP9sb3n/bW9z/25wd/91d33/c3V8/3V3ff9ucHf/ -eXuB/25wd/9wcnn/am13/2xvef9qbXf/c3Z//3V3ff91d33/b3F1/3Byef9ucXv/d3l//25xe/93eoP/ -cHJ5/3d6g/9ucXv/c3Z//3V4gf9maG7/dHeA/29ye/9rbnf/cHN8/3R2fP9vcnz/bG51/3Bzff91d33/ -bG51/3N1fP9zdXz/c3V8/3N1fP9tb3P/bnB3/3N1fP9ucXv/am13/2psc/9sb3n/am13/2psc/9zdXz/ -Z2p0/2xvef9nanH/amxz/3N1fP9sbnX/bG51/2xudf9tb3P/b3F1/3Byef91d33/cHJ5/3V4gP9zdXz/ -c3Z//3R3gP9ucXv/bnB3/2xvef9ucXv/cHJ5/3J0e/9rbXP/dHZ9/3V3ff9vcXj/cnR7/3R2fP91eIH/ -bW90/25xe/9zdXz/am13/2dqcf9maG7/dXd9/3Byef92eHz/dXiB/25xev90d4D/aGt1/3N2f/9xdH7/ -b3F4/3V4gf92eYH/c3V8/3d6g/95fIb/d3qD/3l8hv9+gYr/eXyG/4GDiv91eIH/dXiB/3V4gf91eIH/ -eXyG/3t9g/9ucXv/d3l//25xe/9ucHf/c3V8/3h5ff9ucXv/d3l//3V3ff9ucHf/Zmlz/29xdf92eHz/ -dnh8/2psc/9tb3P/cHJ5/2ptd/9sb3n/bG95/3N2f/91eIH/c3Z//3V4gf9qbXf/bnF7/25wd/9ucHf/ -bnF7/2Zpc/9zdn//Zmhu/29xdf9wc33/bG95/2dqdP9ucHf/d3qD/25xe/9wc33/cHN9/25wd/9ucHf/ -eHl9/3N1fP9ucHf/bnB3/25wd/9ucHf/bnF7/2xudf9qbHP/dXd9/2xudf9sb3n/cHN9/3V3ff9ucHf/ -cHJ5/2Zpc/9qbXf/Z2p0/21vc/9ucXv/am13/25wd/9vcXX/dnh8/25wd/9kZ3H/Zmlz/3V3ff9tb3P/ -bW9z/3Bzff9ucHf/dXiB/3l7gf9zdn//bG51/3N1fP9ucXv/cHN9/25wd/92eHz/bnB3/25xe/9wcnn/ -bnB3/3Bzff9ucHf/bnB3/3N1fP9wcnn/bG51/2xudf9qbXf/am13/2ptd/9qbXf/bnF7/2dqcf9sb3n/ -bnF7/3Bzff9sb3n/bG95/2xudf9sb3n/Zmlz/2dqdP9nanT/amxz/2dqcf9wc33/Zmlz/2ptd/9qbXf/ -am13/2Jlbv9sbnX/bG95/3V3ff9ucHf/bnB3/3N2f/93eoP/c3Z//3Byef91eIH/c3Z//3N1fP95fIb/ -dXiB/3V3ff91eIH/c3V8/3N2f/9ucXv/eXyG/31+gf9+gIb/dXiB/3V3ff91eIH/e32D/3d6g/93eoP/ -bnF7/3t9g/9sb3n/bG95/2dqdP9wcnn/am13/3V4gf93eX//dXd9/25wd/9wc33/cHN9/3d6g/9wc33/ -eXyG/25wd/94eX3/c3V8/3N1fP9zdXz/Zmhs/3V4f/9zdoD/bnB5/3R3gf92eH7/c3Z//25xe/93eoP/ -dXd9/29xdf9zdn//dXd9/3V3ff9wcnn/bG51/25xe/9zdXz/bnF7/21vc/9tb3P/cHJ5/2xvef9sbnX/ -dXd9/2xvef9wcnn/bG95/2dqdP91d33/bnB0/21vdv9tb3b/am13/2xudP9tcHr/c3V9/2xvef90d4D/ -b3J5/29xef9zdn3/cXN4/29xdv9tb3f/bXB6/2xvef9xdH3/Z2pz/3N1ff91d33/b3J5/3Fzev90dnv/ -dXd+/25wdf9wc33/dXd9/25xe/9qbXf/bnF7/3l7gf9zdn//eXuC/3Z5g/90d4D/d3mA/2xueP91d3// -dHeB/3N1e/95e4L/eXuB/3J0fP91eIH/cHN9/3Bzff9wc33/eXuB/3Bzff95fIb/cHN9/3N1fP9ucXv/ -bG95/3Byef9ucXv/Z2p0/25xe/9qbXf/Z2p0/2ptd/9zdXz/am13/3V3ff9zdXz/bG51/2Rncf9sbnX/ -dXd9/3Z4fP9nanT/bG51/25xe/9qbXf/am13/2ptd/9sb3n/cHN9/2xvef9ucXv/Zmlz/2ptd/9ucHf/ -bnB3/2xudf9kZmz/dnh8/2Zobv9ucHf/c3Z//2xvef9qbHP/bnB3/3d6g/9zdn//cHN9/3N2f/9wc33/ -cHN9/3l7gf9ucXv/bG95/2xvef9ucXv/cHN9/3N2f/9wcnn/bG95/3V3ff9ucHf/bnB3/3V3ff92eHz/ -am13/25xe/9kZ3H/bG51/2psc/9qbHP/bG95/2dqdP9qbXf/amxz/25xe/9qbXf/Zmhu/2Zobv9zdXz/ -bW9z/2psc/9ucXv/ZGdx/3N1fP91d33/c3V8/3Byef91d33/dXd9/3V3ff9ucHf/dXd9/25wd/9ucXv/ -bnF7/25wd/91d33/dXiB/25xe/91eIH/cHN9/2xvef9ucHf/cHN9/2xvef9ucXv/bnF7/3Bzff9ucHf/ -c3Z//3d6g/9zdn//cHN9/3Byef9tb3P/c3V8/25wd/9sb3n/am13/2psc/9qbHP/bG95/2Zpc/9nanT/ -am13/2ptd/9kZ3H/amxz/2ptd/91d33/bG51/21vc/9wcnn/c3V8/3Bzff9nanH/bnF7/2xudf9tb3P/ -cHJ5/2xudf9qbXf/bG51/25wd/9sbnX/Zmlz/25xe/91d33/c3V8/2xudf9sbnX/bnB3/3N1fP9zdXz/ -dXd9/2xudf91d33/Zmlz/2ptd/9maXP/am13/2psc/9wc33/cHN9/3Bzff9qbHP/bG95/2ptd/9sb3n/ -Zmlz/3V3ff9nanH/cHN9/2ptd/9ucXv/am13/2RmbP90dXv/cnR9/2ttdv9ucXn/cnV+/3N1fP9ucHf/ -c3Z//3V4gf9zdXz/dXiB/3N2f/95e4H/dXiB/3Bzff95fIb/eXyG/3t9g/9zdn//c3V8/3l8hv94e4H/ -dXd9/31/hf96fIL/eHuE/3Z5gf9zdXz/en2F/3R3f/9xc3r/cnR7/29xeP9wcnn/cXR8/3d5fv9wc3v/ -c3Z+/3Fzev9vcXj/cnR7/3J0ef9xc3r/b3F2/25wef9vcnr/cnR5/2ptc/9ydHz/dXd//3R2fP9vcnv/ -cHJ5/3R3gf9vcXj/c3Z//3p8gv9wcnn/Z2p0/2dqdP93eX//dnmC/3V3fv9ydX3/bXB6/29yeP9maXP/ -Z2py/2ptdf9nanT/bnF5/3J1ff9sb3b/cHN9/3Bzff9ucXv/cHN9/3l8hv91eIH/d3qD/3N2f/9zdn// -c3V8/3Bzff91eIH/cHN9/3N2f/93eX//c3Z//25wd/9wc33/c3Z//25wd/93eX//d3l//21vc/9iZW7/ -am13/3N1fP93eX//am13/2xudf9wcnn/bW9z/2xudf9sbnX/bG95/3N1fP9ucXv/cHN9/2dqdP9wc33/ -c3V8/3Bzff9ucHf/bG95/3d6g/9sb3n/cHN9/3l7gf9wc33/bnF7/3N2f/9+gIb/eXyG/3N2f/91eIH/ -c3Z//3Bzff91d33/cHJ5/25xe/9sb3n/bG95/25wd/9sb3n/Z2p0/2Rncf9ucXv/Zmlz/2dqdP9sb3n/ -c3V8/2psc/9wc33/am13/2xvef9qbHP/am13/25xe/9nanT/bG51/21vc/9zdXz/bG95/2Rncf9kZ3H/ -cHN9/2ptd/9nanT/bnF7/2dqdP9zdXz/dXd9/3V3ff9ucXv/cHN9/25xe/9wc33/amxz/2ptd/9nanT/ -amxz/2dqdP9qbHP/bnF7/2ptd/9qbHP/Zmlz/2Rncf9iZW7/Zmhu/2Rncf9iZW7/ZGdx/2Zobv9maXP/ -YmVu/2Rncf9maXP/Zmlz/2Zobv9kZ3H/Zmhu/2dqdP9maXP/Zmlz/2dqcf9kZ3H/Z2px/25xe/9qbXf/ -am13/2xvef9sb3n/Zmlz/2ptd/9ucHf/dXd9/3Byef9ucHf/bnF7/3N2f/9zdXz/bnB3/3Bzff9ucXv/ -bnB3/3V3ff9ucHf/bnB3/25wd/9ucHf/am13/2Zobv9zdXz/c3V8/3Byef9sbnX/bW9z/21vc/9wcnn/ -cHJ5/3Bzff9sbnX/dXd9/2dqdP9sbnX/Zmlz/2dqdP9nanT/bnF7/3N1fP91d33/bnB3/3V3ff9ucXv/ -cHJ5/25wd/92eHz/b3F1/3N1fP9zdXz/dnh8/25wd/9kZmz/bnB1/25xe/9tb3f/cHN9/3l7gf91eIH/ -c3Z//3t9g/9wc33/bnB3/3Bzff9zdn//d3l//3V3ff9sb3n/bnF7/3Byef90dn3/bXB3/2ptdv9vcnv/ -cnV+/21wdf9zdXz/bG93/25xev9tcHn/aGpz/3J0ev9wc3v/b3F6/3Bye/9pbHX/bnF5/2xvd/9xdH7/ -a254/2ptd/9zdXv/bG95/29yev9zdXv/bnB2/25wdv9vcXX/b3F4/25wdf9sb3b/cHJ5/3V3fP93eX// -bnB3/3ByeP91eIH/bW94/3V3fv93eX//bW95/2Zpc/9nanT/dXd9/3R2ff9wcnn/cHN7/2xvef9rbnT/ -Zmlz/2RncP9oa3P/Y2Zv/2Vocf9qbXb/a212/25xe/9qbXf/Z2p0/2dqdP9zdXz/bG95/3Byef9ucHf/ -bG95/2ptd/9wc33/c3V8/2ptd/9sb3n/cHN9/2xvef9qbXf/am13/3Bzff9tb3P/dnh8/3l8hv9vcXX/ -Zmhu/2xudf92eHz/d3qD/2xvef9ucXv/c3Z//3N1fP9wcnn/bG95/3Bzff93eX//c3Z//3V4gf9qbXf/ -c3Z//25wd/9wcnn/cHJ5/2ptd/95e4H/am13/3Byef9zdn//c3V8/2ptd/9zdn//foCG/3l8hv93eoP/ -eXuB/3V4gf95fIb/eXyG/3l7gf93eX//cHN9/3d6g/91eIH/d3qD/3N1fP9ucXv/e32D/3N1fP9zdn// -dXiB/3l7gf9wc33/cHN9/25wd/9wc33/cHJ5/25wd/91d33/amxz/2xudf9ucHf/dnh8/25wd/9kZ3H/ -ZGdx/3N1fP9qbXf/bG51/3Bzff9nanT/bnF7/3V3ff9zdXz/bG95/3Bzff9qbHP/bG95/2dqdP9sb3n/ -Z2p0/2xudf9qbHP/am13/3Bzff9ucXv/bG51/25wd/9qbXf/Z2p0/2xudf9qbXf/amxz/2ptd/9nanT/ -Z2p0/2Zpc/9qbXf/bG95/25xe/9ucXv/bG95/2xudf9ucXv/Z2p0/2xudf9qbHP/am13/2xudf9wcnn/ -bG51/2xudf9wcnn/bG95/2Rncf9sbnX/bnB3/3V3ff9wcnn/b3F1/25xe/91eIH/c3Z//25wd/9wc33/ -cHN9/3Byef9zdn//bnF7/2ptd/9ucXv/bG95/25wd/9kZ3H/bnF7/25xe/9sb3n/Z2p0/2ptd/9sbnX/ -bnF7/2xvef9qbXf/Z2p0/3N1fP9kZ3H/Z2px/2BjbP9iZW7/ZGdx/3N1fP9ucXv/am13/2xudf9wc33/ -bG95/2xvef9qbXf/dXd9/21vc/91d33/bnF7/3h5ff9ucHf/ZGZs/3Bydv9ucXv/bG95/25xe/9zdn// -d3qD/25xe/93eX//c3Z//25wd/9zdn//c3Z//3l7gf95e4H/cHJ5/3Bzff9vcnz/dXd+/3Byef9rbnj/ -cHN7/3Fze/9sbnb/cHJ4/2tueP9sb3j/bG95/2psc/9ydXz/cXN7/2lsdv9ydX7/aWtx/3Bye/9oa3T/ -bXB5/2RncP9laHL/bW93/2ptd/9sb3n/bnF6/2ptd/9qbXf/am13/2xvef9qbHT/a210/21vc/90dnz/ -dHZ8/25wd/9vcXb/c3Z//2xvd/9xdH3/cXR+/2tueP9maG7/Zmhu/3V3ff9zdX3/bnF7/3R3fv93eX7/ -c3V8/3J1fv9ucXr/bnF6/2tud/9vcXj/dXiA/3R2fv9wc33/bnF7/25xe/9sbnX/dXd9/3V3ff91eIH/ -dnh8/3N1fP9wcnn/bnF7/3d5f/9ucHf/cHJ5/3N1fP9zdXz/bnB3/3Byef9zdXz/b3F1/3Z4fP93eX// -bnB3/2dqcf9ucXv/dXd9/3l7gf9vcXX/bG95/3V4gf9zdXz/bnF7/2ptd/9wc33/d3l//3Bzff9zdn// -am13/3N2f/9wcnn/c3V8/25wd/9maXP/d3l//2dqcf9ucHf/bnB3/25xe/9nanT/cHJ5/3V3ff9wc33/ -cHN9/3N2f/91d33/cHJ5/3Byef9ucHf/bnB3/2dqcf9zdXz/bnB3/3Bzff9sb3n/Z2p0/3V3ff9ucHf/ -bnB3/3N2f/95e4H/cHN9/3N2f/9sb3n/cHJ5/2xudf9ucHf/dXd9/2xudf9ucHf/bnB3/3Z4fP9ucHf/ -Z2px/2ZobP9zdn//bnF7/25wd/9zdXz/amxz/3Byef91d33/bG95/2xvef9wc33/bG51/25xe/9ucXv/ -c3V8/2xudf9sbnX/Z2p0/2xudf9ucXv/bG95/2dqdP9sb3n/amxz/2Rncf9qbHP/bnF7/2dqcf9sb3n/ -am13/2ptd/9qbXf/bG95/25xe/9ucXv/bnF7/2xvef9qbHP/bnF7/25xe/9qbXf/Z2p0/21vc/9sbnX/ -bnF7/21vc/9ucHf/cHN9/3Byef9maG7/bnB3/3Byef9zdn//c3Z//2xvef9sb3n/cHN9/3N2f/9ucHf/ -cHN9/3N1fP9ucHf/dXiB/3Bzff9qbXf/cHN9/25wd/9ucHf/Zmlz/3V4gf93eoP/cHN9/2xvef9wcnn/ -bG95/25xe/91d33/bnF7/25xe/93eX//amxz/2xudf9qbHP/Zmlz/21vc/92eHz/dXd9/3Byef9tb3P/ -d3l//2xvef9ucXv/amxz/3N1fP9nanT/bG95/2dqdP9sb3n/Zmlz/2Jlbv9sbnX/am13/2psc/9sbnX/ -bnB3/3V3ff9sbnX/dXd9/3Byef9qbHP/bG51/2xvef9zdXz/c3V8/2ptd/9xdH3/bG54/25xe/9ucHf/ -am11/25wd/9tb3b/bG52/2tudP9rbnf/aGt0/2Zpc/9naW//cXN6/3R2fP9qbXf/cnR8/2Zob/9kZ3H/ -ZWhy/25wd/9laHH/aGt1/3Bzff9ucXv/cHN9/3Bzff9ucHf/amxz/29xdv9wcnr/b3F4/21vdv9ucHX/ -dnh8/3V3ff9xc3v/cHN4/3N1fP9ydHz/dHeA/3h6gP9wcnn/Zmlz/2Zobv9wc33/cXN5/3Fzev9ydHr/ -c3V8/29xef9tcHj/b3F3/2xudv9pa3T/bnF5/3N1fP9xc3n/c3V8/29xdf9ucXv/bG95/3d5f/91eIH/ -d3qD/3N2f/9zdn//cHN9/3N2f/95e4H/c3Z//3N2f/9zdn//cHN9/2xvef9ucHf/c3Z//25wd/93eX// -d3l//3N2f/9maXP/cHN9/3N2f/93eX//bnB3/3Byef91d33/b3F1/29xdf9sbnX/dXd9/3N1fP9ucHf/ -cHJ5/2Zobv9ucHf/am13/2ptd/9tb3P/Zmhu/3V3ff9iZW7/am13/2xvef9sbnX/Zmlz/2ptd/9zdXz/ -c3V8/3N1fP91d33/bnF7/2xvef9zdXz/bnB3/25wd/9nanT/dXiB/25xe/9zdn//bnB3/2dqdP9zdn// -am13/25xe/9zdn//dXiB/25wd/9zdn//am13/25xe/9vcXX/bnF7/3N1fP9sbnX/bnB3/3Byef92eHz/ -bnB3/2Zpc/9kZmz/cHJ5/2xvef9nanT/bnF7/2Zpc/9sb3n/c3Z//2xvef93eoP/dXiB/25wd/9zdn// -c3Z//3V3ff9ucHf/bnB3/2ptd/9ucHf/cHN9/3V4gf9wcnn/c3Z//25xe/9ucHf/bG95/3Bzff9wcnn/ -dXiB/25xe/9ucXv/bnB3/3Byef9wc33/cHN9/25xe/9ucXv/bnB3/3N2f/9sb3n/b3F1/2xvef9vcXX/ -bnB3/3N2f/9ucHf/bnB3/3Bzff9wc33/Zmlz/3Byef9zdXz/dXiB/3V4gf9ucHf/bG95/3N2f/91d33/ -bG95/3N2f/91eIH/bnF7/3d5f/9ucXv/am13/3Bzff9ucHf/bnB3/2ptd/93eX//dXiB/3N2f/9sb3n/ -cHJ5/2xudf9ucXv/c3Z//3N1fP9zdXz/dXiB/2xvef9wcnn/am13/2dqdP9ucHf/dXd9/3h5ff9zdXz/ -bnB3/3h5ff9zdXz/c3V8/29xdf92eHz/bnB3/25xe/9qbXf/bnF7/2xvef9kZ3H/amxz/2dqdP9iZW7/ -Z2p0/2xvef9ucXv/amxz/3N1fP9sb3n/ZGdx/2psc/9nanT/bG95/2xvef9oanH/cHN8/2tudv9sb3n/ -bW92/21vd/9vcXj/b3F2/3J0e/9vcXj/dHZ8/2ptd/9oa3L/bW9z/3d5f/94eoD/cHJ5/3p8gv9ucHf/ -cnR7/25wdP90dn3/bG52/3Bzev92eH//bnF7/3N2ff9xc3r/bnB4/2hrcv9tcHf/bXB6/2xudf9sbnX/ -am10/2xvef9ydHr/am10/2ttcv9ucXn/aWx0/3J0fP9vcnn/a213/2Rncf9kZmz/bnF7/3Byef9sb3n/ -dHZ8/3Bze/9sb3f/a212/2xvd/9rbnb/aGt1/25wef9sb3n/bG93/3Bzff9maXP/Z2p0/2psc/9ucXv/ -bG95/3N1fP9maXP/ZGdx/2Rncf9nanT/bG95/2Zpc/9kZ3H/Zmlz/2Zpc/9kZ3H/Zmlz/2Zpc/9iZW7/ -bG51/2xvef9kZ3H/XWBq/2Zpc/9sb3n/cHJ5/2Rncf9nanT/dXd9/2xudf9sbnX/am13/25xe/91d33/ -bG95/3N1fP9nanH/dXd9/25wd/9ucXv/bnB3/2dqcf94eX3/Zmlz/2xvef9ucXv/b3F1/2xudf9sbnX/ -c3V8/3N1fP91d33/dnh8/3N1fP9ucHf/cHJ5/2xudf9ucHf/Z2px/3N1fP9wcnn/bG95/2dqdP9iZW7/ -bnF7/2Zpc/9sb3n/cHN9/3d5f/9qbHP/c3V8/2psc/9wcnn/b3F1/3Bzff9zdXz/bnB3/2xudf9wcnn/ -c3V8/29xdf9qbHP/Zmhu/3Byef9ucHf/bnB3/3V4gf9wcnn/dXiB/3l8hv91eIH/c3Z//3V4gf9sb3n/ -d3qD/3V4gf95e4H/cHJ5/3N1fP9sb3n/bG95/3N2f/9wc33/cHJ5/3V3ff9ucHf/bnB3/25wd/9zdXz/ -bG51/3N1fP9sbnX/bnF7/21vc/9ucHf/c3V8/25xe/9sb3n/am13/2ptd/9sb3n/amxz/2psc/9nanT/ -Z2px/2xudf9ucXv/amxz/2Zpc/9sb3n/bG95/2BjbP9nanT/bW9z/25wd/9ucHf/amxz/2xudf9sb3n/ -c3V8/2ptd/9ucXv/dnh8/3Byef93eX//cHN9/2ptd/9zdXz/bG51/2xudf9qbHP/dXd9/3N1fP9zdXz/ -amxz/25wd/9ucHf/bnB3/3V3ff9wcnn/dXd9/3d5f/9ucHf/b3F1/2ptd/9nanT/bnB3/3V3ff92eHz/ -c3V8/2xudf92eHz/dXd9/3V3ff9wcnn/dnh8/3Byef9wc33/cHJ5/3Byef9zdXz/Zmhu/21vc/9qbXf/ -Zmlz/21vdv9xdH7/dXd9/21vc/9zdXz/bnF7/2Rncf9sbnX/bnF7/25xe/9ucXv/aWxz/3Bze/9ydHr/ -c3aA/3J1fv9ydXv/c3V8/3F0ff92eH//dnmC/3V4gf9sb3n/bXB6/29xef95e4H/eXuE/29yfP93eoT/ -bnF4/3J1f/9zdXz/cnV+/29xdv9zdXz/c3Z+/29yev92eH7/b3F4/2xvef9rbXT/cHJ5/29xeP9xc3f/ -bW9z/29xeP9xc3r/c3V9/3Bye/9zdXv/dXh//3Byef9xc3r/c3V8/29xdf9nanH/Zmhu/25wd/9sb3n/ -bG95/3R2fP9ucXr/bG94/2hrdf9ucXv/aGt1/2dqc/9rbnf/bG94/2lsc/9nanT/XWBq/2Zobv9maG7/ -bG95/2xvef9ucHf/Zmlz/2Zobv9maG7/Zmlz/2ptd/9maXP/ZGdx/2dqdP9nanT/Zmhu/2dqdP9nanT/ -YGNs/2xudf9ucHf/Zmhu/11gav9maXP/am13/3Byef9maXP/Z2p0/25wd/9maG7/Z2px/2Rncf9sb3n/ -bnF7/25xe/9wc33/Zmhu/3Bzff9nanT/bG95/2psc/9maXP/c3V8/2Jlbv9sbnX/bnB3/2xudf9maXP/ -Zmlz/3Bzff9ucXv/bG95/25xe/9ucXv/bnF7/2xvef9sbnX/bnF7/2dqdP9zdXz/c3V8/3Byef9tb3P/ -ZGZs/3Byef9sbnX/cHJ5/3V3ff93eX//b3F1/25wd/9nanH/bnF7/3Byef91eIH/dXiB/3N1fP9zdXz/ -c3Z//3d6g/9wc33/bnF7/2xvef9zdn//c3Z//3N1fP91eIH/bG95/25xe/91eIH/c3Z//2xvef9zdXz/ -amxz/3N1fP9qbXf/cHN9/2psc/9qbHP/amxz/2dqdP9ucXv/Z2p0/2psc/9sb3n/Z2p0/2Zpc/9qbXf/ -bnF7/2ptd/9sb3n/am13/2xvef9vcXX/cHJ5/3Z4fP9zdXz/c3V8/3Byef9wcnn/dnh8/25xe/9sb3n/ -bG95/2xvef9sb3n/dXiB/3N1fP9wcnn/dXiB/3Bzff9qbXf/bnF7/25wd/9sb3n/bnB3/29xdf9sbnX/ -c3V8/3V3ff9sbnX/cHN9/3N1fP9ucHf/c3V8/2xudf9nanH/bG95/29xdf9ucHf/ZGdx/3N1fP9sb3n/ -bG95/2Zpc/9sb3n/Zmlz/25wd/9wc33/bnF7/25xe/9zdXz/Z2p0/25wd/9qbHP/Z2px/2ptd/9zdXz/ -dXd9/2xvef9sbnX/dXd9/2xvef9ucXv/Zmhu/2ptd/9nanH/bG95/2psc/9qbXf/Zmlz/11gav9laHL/ -Z2lv/1xfaP9naW//am12/2xvef9sbnX/Z2p0/2Zpc/9iZW7/amxz/25xe/9ucXv/c3V8/2tud/9ydHv/ -cHJ4/25xev9tb3b/bG51/21wef9ucHf/cXN6/3R2fP9wcnj/bG51/21vdv9rbXb/dHZ+/3J1fP9rbnb/ -dHZ9/2xudf9tb3b/cXN5/2xvd/9ucHf/cHJ7/3Bzev9wcnn/c3V8/2xvef9ucHf/bG94/3J0ff9xc3v/ -dHZ+/29yev9xdHz/bXB5/3BzfP9ucHr/dXeA/3h6gP9ydX7/cHN9/3N2f/9ucHf/am13/2dqdP9wc33/ -cHN9/3N2f/95fIX/cXN9/25xe/9oa3X/c3V8/25wd/9sb3n/cHN9/3V3ff9wcnn/cHN9/2xvef9wc33/ -bG95/3V3ff91d33/d3l//3N1fP9ucHf/b3F1/3V3ff94eX3/dXd9/3Byef9zdXz/cHJ5/2dqdP9sb3n/ -bnF7/2xudf91d33/cHN9/2psc/9iZW7/am13/3Bzff9ucXv/amxz/2ptd/9zdXz/Z2px/2psc/9maXP/ -Z2p0/2dqdP9maXP/Z2p0/2BjbP9ucXv/Z2p0/2xvef9sbnX/amxz/3Z4fP9maG7/bnB3/2xvef9sb3n/ -bG95/2ptd/91d33/c3V8/3N1fP9zdXz/cHJ5/3N1fP9wc33/bnB3/3Bzff9qbXf/dXiB/3d5f/91d33/ -bnB3/2RmbP9ucHf/am13/2ptd/9ucXv/dXd9/2xudf9qbXf/YmVu/2xudf9sbnX/bG95/2xvef9sbnX/ -am13/3Bzff9zdXz/bG51/2Zpc/9kZ3H/bnF7/2xvef9qbHP/bG95/2psc/9sb3n/d3l//25xe/9kZ3H/ -Z2p0/2BjbP9kZ3H/Zmhu/2ptd/9kZ3H/Z2px/2Zobv9nanH/am13/2dqdP9qbXf/c3V8/25xe/9qbXf/ -bG51/25xe/9qbXf/cHJ5/29xdf9zdXz/b3F1/25xe/91d33/c3V8/3N1fP9ucXv/bnF7/3V3ff9wcnn/ -bnB3/25wd/9ucHf/bnB3/3Bzff9vcXX/b3F1/25wd/9sbnX/Zmhu/21vc/9tb3P/bG51/2xudf9qbXf/ -amxz/3Bzff9zdXz/bG51/3Bzff9wc33/bnF7/3Bzff9tb3P/bG51/3N1fP9vcXX/bnB3/2Zobv92eHz/ -cHJ5/3N1fP9nanH/cHJ5/25wd/9zdXz/dXd9/3Byef9wc33/d3l//25xe/91eIH/bG95/3N1fP9zdXz/ -dXiB/3l7gf9ucXv/cHJ5/3V4gf9zdXz/c3Z//25wd/9zdXz/bnF7/3V4gf9wc33/cHN9/3Bzff9qbHP/ -bW93/29ye/9pbHX/b3F6/29yfP9xdH7/bnF7/3Byef9wc33/bG95/2xvef9zdn//bnF7/3Bzff9sb3n/ -dHZ8/25xe/9xc3v/bnF7/21vdv9xc3r/cXN4/29yev9zdX3/cXN6/3F0fP9xdHz/b3J6/3d5gv9xdHv/ -bW93/3R2fv9qbXb/a254/3R2f/9tcHr/cHN8/21wev9tcHn/bnF4/3Bye/9vcnz/bnB3/2tueP9tcHr/ -bG51/25xev9qbXf/cHJ8/2xudf9qbXf/am13/3J0e/9ucXv/am13/2psc/9nanT/Z2px/2Jlbv9gY2z/ -am13/2dqdP9qbXf/c3Z//2ptd/9qbXf/ZGdx/25xe/9sb3n/bG51/3Byef9ucXv/cHJ5/3Byef9tb3P/ -cHJ5/25wd/93eX//d3qD/3d6g/91eIH/c3Z//25xe/93eoP/d3qD/3d6g/9zdn//dXiB/3d6g/9sb3n/ -cHN9/3Bzff9zdn//e32D/3l7gf9wc33/bG95/3N2f/95e4H/foCG/3N2f/93eoP/eXyG/3Bzff9wc33/ -dXd9/3d6g/95e4H/eXuB/3V4gf9wc33/e32D/3N1fP91eIH/c3Z//3Bzff95e4H/bG95/25wd/9ucXv/ -cHJ5/2ptd/9sb3n/cHN9/3V4gf9zdXz/cHJ5/3Byef9wcnn/c3V8/29xdf9ucHf/Z2p0/3Bzff91d33/ -cHN9/21vc/9kZ3H/bG95/2dqdP9sb3n/cHN9/3V3ff9qbXf/am13/2Rncf9nanT/amxz/2ptd/9nanT/ -Z2px/2Zpc/9ucXv/bnF7/2dqcf9ZXGX/XF9o/2Zpc/9maXP/Zmhu/2Rncf9kZ3H/Z2p0/2xvef9maXP/ -Z2p0/2xvef9maXP/bnF7/2xudf9wc33/amxz/2xvef9sbnX/bG51/3V3ff9ucHf/bnB3/3l7gf9ucXv/ -bnB3/25wd/9zdXz/am13/3V4gf9wcnn/cHJ5/3Byef9zdn//d3qD/3N2f/9zdn//cHJ5/3Bzff95e4H/ -cHN9/3Bzff9ucXv/cHN9/25xe/9wc33/bnB3/25wd/9wcnn/bW9z/2dqcf9vcXX/bnB3/25wd/9sbnX/ -am13/2xudf91d33/c3V8/2ptd/9wc33/cHJ5/3Byef9zdn//bG51/2xudf9zdn//am13/25wd/9kZ3H/ -c3Z//3N2f/9zdn//am13/3N2f/9wcnn/dXiB/36Ahv95fIb/eXyG/3t9g/9zdn//d3qD/25xe/9wcnn/ -cHJ5/3N2f/95fIb/cHN9/25xe/93eX//bnF7/3Byef9vcXX/c3V8/25xe/91eIH/cHN9/25xe/9sb3n/ -bG51/29xef9xdHz/aGtz/3Byef9ydHr/dHZ8/25xe/9ucXv/cHN9/25wd/9wcnn/dXiB/3Bzff9zdn// -bnF7/3Z4fv9xc3r/c3Z//21wev9tb3j/dHZ7/3J1ff9tcHr/cnV//29xef90dn//bXB6/3ByeP93eX// -cHF4/25wd/9zdXz/amxz/25wd/92eH7/bnB3/3N1fP9vcXj/aGt1/25wdP9vcXv/bnF7/2xudf9sb3n/ -cHN9/2xudf9zdXz/bG51/3N1fP9sbnX/amxz/2ptd/91d33/bnF7/2xvef9qbXf/bG95/2psc/9kZ3H/ -YGNs/2dqdP9nanH/Z2p0/3V3ff9qbXf/Z2p0/2BjbP9qbXf/Zmlz/2Zobv9nanT/Zmlz/2Zpc/9qbXf/ -Zmhu/2dqdP9maG7/dXd9/3V3ff9zdXz/bG95/3Bzff9qbXf/cHN9/3d5f/9wc33/cHJ5/3N1fP91d33/ -bG51/3Byef9wc33/c3Z//3d6g/93eoP/c3V8/25xe/9ucXv/dXd9/3V3ff9sb3n/bG95/3d5f/9sbnX/ -bW9z/2xudf9sbnX/bG95/2ptd/9qbXf/Zmlz/25xe/9nanT/bG95/2xvef9iZW7/am13/2BjbP9iZW7/ -Z2px/2Rncf9kZ3H/Zmlz/2ptd/9sb3n/bG95/2xudf9sb3n/bnF7/2xvef9sbnX/bnF7/2dqdP9ucXv/ -dXd9/3N2f/9ucHf/Z2p0/25wd/9ucHf/cHJ5/3N1fP92eHz/bG51/2xudf9kZ3H/am13/25wd/9sbnX/ -bG95/2xudf9nanT/cHN9/3Bzff9sbnX/YmVu/2Jlbv9ucXv/am13/2xudf9qbXf/Z2px/2xvef9wcnn/ -bG95/25wd/9sb3n/Z2p0/2xvef9qbXf/c3V8/2xudf9wcnn/bG95/3N1fP97fYP/cHN9/3Byef95fIb/ -dXiB/3Byef9zdXz/d3qD/25xe/97fYP/dXd9/3l7gf91eIH/eXyG/3l8hv91eIH/dXiB/3N2f/9wc33/ -d3qD/3Bzff9ucHf/Z2p0/25wd/9wcnn/cHJ5/25wd/9vcXX/cHN9/29xdf9nanH/bG51/2xudf9qbHP/ -am13/2dqdP9nanT/bnF7/2xvef9qbHP/am13/25xe/9qbXf/c3V8/2ptd/9nanT/bnF7/2dqdP9sbnX/ -ZGZs/3Byef9ucXv/bG95/2Rncf9sb3n/Z2px/25xe/9wc33/am13/2xvef9wc33/am13/2xvef9kZ3H/ -Z2p0/2psc/9qbXf/cHJ5/2dqcf9maXP/cHJ5/2psc/9sb3n/Z2px/2ptd/9nanT/Z2p0/2ptd/9nanH/ -amxz/2dqdP9sb3j/cnV8/2Zpc/9vcXf/a253/25xe/9qbHP/Z2p0/2dqdP9kZ3H/bG51/2xvef9qbXf/ -am13/2xudf9sb3n/aGt1/3V3ff9ucXj/bW92/3Z4fP91d33/bG92/3N1fP9sbnb/c3V8/25wd/9vcXX/ -eHl9/3N1fP9sbnX/bnB3/2psc/9sb3n/dXiB/25xe/9wcnn/bnF7/2ptd/9qbXf/c3V8/25xe/9qbHP/ -bG51/3N1fP9ucHf/cHJ5/25wd/9zdXz/bG51/21vc/9qbXf/d3l//2xvef9qbXf/am13/2psc/9qbXf/ -ZGdx/2BjbP9qbXf/amxz/2xvef91d33/bG95/3N1fP9naW//c3V8/3Byef9sb3n/cHN9/3V4gf9wc33/ -cHN9/25wd/9ucXv/bnF7/3d6g/91eIH/d3l//3V4gf9zdn//cHJ5/3N1fP93eX//c3V8/25wd/91d33/ -c3V8/21vc/9qbXf/bnB3/2xvef9ucXv/am13/2Zobv9maG7/Zmlz/3Bzff9zdXz/bG51/2ptd/91d33/ -bG51/21vc/9tb3P/bnB3/2xvef9sb3n/bG95/2Zpc/9ucXv/am13/3N1fP9ucHf/Z2px/3Z4fP9nanH/ -bnB3/25wd/9vcXX/bG95/2xvef9zdn//c3Z//3N2f/9ucHf/c3V8/3Bzff9ucXv/bG95/3N1fP9nanT/ -c3Z//3l7gf93eX//c3V8/3N1fP91eIH/cHJ5/3d6g/97fYP/f4GH/3d5f/9zdn//bnF7/3N2f/9zdn// -cHN9/3Bzff9ucHf/am13/3V3ff92eHz/bG95/2psc/9maXP/cHN9/25wd/9zdXz/cHJ5/2xvef9zdXz/ -dXd9/3N1fP9ucXv/bnB3/2xudf91d33/bnF7/3V3ff9wcnn/bnB3/2ptd/9sbnX/dXd9/2xudf9sbnX/ -eHl9/3N1fP9qbHP/bnB3/3V3ff9nanH/cHJ5/25wd/9ucHf/bG95/3N1fP9wcnn/cHJ5/3N2f/9ucXv/ -c3V8/3V4gf9ucXv/bnF7/25wd/9wc33/c3Z//3N2f/9wcnn/c3V8/3V4gf9wcnn/Zmlz/25xe/9ucHf/ -b3F1/25wd/9sb3n/cHN9/3V4gf9wc33/bnF7/25xe/9zdn//b3F1/3Z4fP9tb3P/amxz/3Byef9qbHP/ -bnB3/2dqcf9zdn//cHN9/25xe/9nanH/c3V8/2xudf9ucXv/eXuB/3V4gf9zdn//c3Z//2xudf9ucHf/ -bG51/25wd/9vcXX/c3V8/3d5f/9ucHf/cHJ5/3d5f/9ucHf/c3Z//3Byef9wcnn/c3V8/3Byef92eHz/ -bG51/2xudf9nanT/bG95/2xvef9maXP/a210/2Vocv9ucXv/am13/2xudf9sbnX/Z2p0/2ptd/9ucXv/ -bnB3/25xe/9qbXf/bG95/2Zpc/9zdXz/am13/2dqcf9wcnn/bnF7/2psc/9ucXv/am13/25xe/9qbXf/ -am13/3Bzff9sb3n/Z2p0/2ptd/9kZ3H/bG51/3V3ff9ucHf/c3V8/2xvef9sbnX/bG51/3Bzff9ucXv/ -Zmlz/2ptd/92eHz/bnB3/3N1fP9sb3n/dXiB/3Bzff9zdXz/c3V8/3h7hf91eIH/dXiB/3N2f/9zdn// -c3V8/2ptd/9ucXv/dXd9/3d6g/93eoP/fYCJ/3d6g/93eYD/bXB5/3N2f/9ucXv/bXB6/21wev9ydX7/ -c3V8/3V3ff9sbnX/cHJ5/3Byef93eoP/d3l//3h5ff9zdXz/bnF7/2psc/9sb3n/dXd9/2xvef9nanT/ -cHJ5/2ptd/9qbHP/am13/2xvef9sb3n/cHN9/25xe/9sbnX/bG51/2ptd/91d33/dXd9/2ptd/9qbXf/ -c3Z//2dqcf9nanT/amxz/2xudf9sbnX/am13/2xvef9maXP/bG95/2psc/9ucXv/bG51/2Jlbv9wcnn/ -YGNs/2Rncf9maXP/Z2px/2Zpc/9maXP/bG95/2dqdP9qbXf/Zmlz/2ptd/9qbXf/am13/2psc/9sb3n/ -ZGdx/2ptd/9zdXz/cHJ5/2dqcf9iZW7/bG95/2dqcf9sb3n/am13/3N1fP9qbHP/am13/2Zpc/9qbHP/ -am13/2xudf9ucHf/b3F1/2psc/9zdXz/dXd9/2psc/9maG7/Zmhu/3Z4fP9wcnn/cHJ5/25wd/9tb3P/ -c3V8/3V3ff9zdn//bG51/2xvef9qbXf/bnF7/2ptd/91d33/c3V8/29xdf9wcnn/b3F1/3V4gf9ucXv/ -bnB3/3l7gf9wc33/bG95/25xe/93eX//am13/3Bzff9wcnn/cHN9/3Bzff9wc33/bG95/2xvef92eHz/ -bnB3/29xdf9ucHf/bG95/2ptd/9maXP/bnF7/2ptd/9qbXf/Z2px/2Rncf9nanT/Zmhu/2BjbP9nanT/ -Zmlz/2Zpc/9qbHP/ZGdx/2ptd/9qbXf/Z2p0/2xvef9qbXf/cHN9/2xudf92eHz/b3F1/2psc/9wc33/ -cHJ5/3N2f/9maXP/cHN9/3Bzff9wc33/am13/3N2f/9ucHf/c3Z//3V4gf9ucXv/c3Z//3N2f/9ucXv/ -dXiB/3N2f/9zdXz/cHN9/3d6g/9+gYr/c3Z//3d6g/95fIb/c3V8/3l7gf9zdXz/d3qD/3d6g/93eoP/ -eXuB/3N2f/9zdn//c3V8/3l7gf91eIH/bG95/25xe/9qbXf/c3Z//3V3ff9ucHf/bG95/2dqdP9sb3n/ -cHN9/25xe/9zdn//bnB3/3Bzff9ucHf/d3qD/3Bzff9ucHf/dXiB/3V4gf9wcnn/c3Z//3Bzff9zdn// -bnF7/3Byef97fYP/d3qD/2xvef9zdn//Z2p0/25xe/91eIH/bnF7/3V3ff91eIH/cHN9/3V3ff97fYP/ -d3qD/3N1fP9ucXv/dnmC/3Bzff90d4D/bnB3/3R3gP9wc3z/cHJ5/3ByeP90d33/bnF7/3R3gP9vcXj/ -b3F3/3Byef9maXP/Z2px/21vc/9tb3P/bnB3/3V3fP9xc3v/cHN7/2lsdP9sbnb/bW92/2lrdP9tb3f/ -b3F4/3Byev9wc33/bnB3/3Byef9wc33/eXyG/3d6g/93eX//c3Z//3N2f/9ucHf/cHN9/3V4gf9zdn// -bnF7/3d5f/91eIH/bnB3/25xe/9ucXv/bnB3/3V3ff9zdXz/bnB3/29xdf9wcnn/dnh8/3l7gf9wcnn/ -cHJ5/3V4gf9qbXf/bnB3/21vc/9ucHf/am13/25wd/9sbnX/ZGZs/25wd/9tb3P/c3V8/2xudf9qbHP/ -dXd9/2dqdP9sbnX/cHJ5/21vc/9ucHf/bG95/25xe/91eIH/c3Z//25xe/9zdn//cHN9/25xe/9vcXX/ -cHN9/2dqdP9sb3n/dXd9/3Z4fP9tb3P/Z2px/3Byef9sbnX/bnF7/2ptd/91d33/bnB3/25wd/9nanH/ -bW9z/2xudf9sb3n/bG95/2psc/9kZ3H/cHN9/25xe/9maXP/YmVu/2Rncf9sb3n/am13/2xudf9qbHP/ -bG51/3Byef9zdXz/bnF7/3Byef9wcnn/b3F1/3Bzff9ucXv/d3l//3Bzff9ucHf/bnF7/25wd/95e4H/ -bG95/29xdf93eX//bnF7/2xvef9ucXv/c3Z//2dqdP9zdn//bnF7/3Bzff9wc33/cHN9/3V4gf91eIH/ -e32D/3N2f/9wc33/cHN9/25xe/9zdn//cHN9/3d6g/93eoP/dXiB/3N1fP9wc33/c3Z//2xvef9maXP/ -cHN9/25wd/9zdXz/c3Z//2xvef9sb3n/cHJ5/25xe/9wc33/bnB3/3Bzff9ucHf/eHl9/29xdf9qbHP/ -bnF7/29xdf9zdXz/Zmlz/3Bzff9zdXz/cHJ5/2xvef93eoP/cHJ5/3Bzff91eIH/c3Z//3Bzff9wc33/ -am13/25xe/9ucHf/bnB3/25wd/9wc33/dXd9/2xvef9zdXz/eHl9/29xdf92eHz/bG51/2ptd/9qbXf/ -bnF7/25xe/9qbXf/Z2px/2Zobv9sb3n/bnF7/2Jlbv9maXP/Zmlz/25xe/9ucXv/bG51/2xudf9qbHP/ -amxz/25xe/9zdn//c3Z//3Byef9zdn//bnF7/3l8hv9zdn//c3V8/3d6g/97fYP/dXiB/3Z5g/93eoP/ -dnmC/3V3gP9wc33/fYCJ/3p8g/9wc33/d3qD/2ptd/9wc33/dnh+/3Byef90dnz/a254/2tueP9oa3X/ -c3V8/29yfP9pbHX/am13/3N1fv9sb3n/bG95/2xudf9xc3r/bnB0/3Byd/9sbnT/cXN5/25wd/9vcnv/ -cHJ2/25wdf9vcXX/amxz/2dqcf9tb3P/bG51/25wd/9zdXz/cXN6/25wef9sbnb/bnB3/21vdv9tb3X/ -cnR7/3Fzev9ucXn/bG95/2ptd/9sb3n/bG51/3d5f/93eX//c3V8/3Bzff9sb3n/am13/2xvef91d33/ -dXd9/2xudf91d33/dXd9/2xvef9ucXv/cHN9/3N1fP9zdXz/bnB3/25wd/9vcXX/bnB3/3V3ff93eX// -cHN9/25xe/93eoP/Z2p0/2xvef9sbnX/cHJ5/25wd/9sb3n/bnB3/2RmbP9ucHf/bG95/3N2f/9ucXv/ -bG51/3d5f/9ucHf/bnB3/3Bzff9wcnn/bnB3/2xvef9ucXv/dXiB/3d6g/91eIH/d3qD/3N2f/9wc33/ -cHJ5/3Bzff9sb3n/bnF7/3N2f/91d33/cHJ5/2ptd/9zdn//bG51/3Byef9wcnn/bnF7/2ptd/9sb3n/ -Z2p0/21vc/9ucHf/bG95/3Byef9ucHf/amxz/3V3ff92eHz/bnB3/2dqcf9qbHP/dXd9/3Byef9sbnX/ -b3F1/29xdf9ucHf/c3V8/3N1fP9sbnX/am13/2psc/9sb3n/Z2px/25xe/9nanT/amxz/2dqcf9nanH/ -dXd9/2psc/9sbnX/dXd9/2xudf9maXP/amxz/25xe/9nanT/bG95/2xvef9qbXf/bnB3/2xudf9qbXf/ -am13/3N1fP9tb3P/bG51/2xvef9sb3n/am13/2Zpc/9ucXv/am13/2psc/9kZ3H/Z2px/2ptd/9nanT/ -Zmlz/2ptd/9sbnX/bG51/21vc/9sbnX/bnB3/2xvef9wcnn/c3V8/2xvef93eX//cHN9/3d5f/9sb3n/ -am13/25xe/9wcnn/c3Z//2ptd/93eoP/c3Z//3N2f/9ucHf/c3Z//25wd/9wcnn/cHJ5/25wd/9wcnn/ -c3V8/2xudf9wcnn/bG51/2xudf9sbnX/am13/3Bzff9sbnX/cHJ5/3h5ff9tb3P/dXd9/3Byef9zdXz/ -c3V8/3V3ff92eHz/cHJ5/25wd/9ucHf/cHN9/3N2f/9sb3n/cHN9/3Bzff93eoP/eXuB/3V4gf91eIH/ -bG95/3N1fP95e4H/fn+D/3t9g/95e4H/fX6B/3Bzff99gIr/cnV+/3J0e/90d4D/d3mA/3R3gP90dn// -dHeA/3V4gf90dn7/b3F4/3l8hP94eoD/bG95/3BzfP9pa3L/b3F6/3V3ff9ucXr/dHZ9/2ptdv9rbXb/ -a212/3R2fP9wc33/bG52/25weP90dnv/bnB3/21weP9pbHb/am11/2lsc/9sb3f/bG5z/21veP9vcXj/ -bG95/29xef9ucHf/bW90/2Zobv9nanH/bG51/2xudf9sbnX/dHZ7/25weP9rbnj/Zmly/2Zpc/9nanL/ -Y2Zw/2ptd/9qbXX/am13/2xvef9qbXf/bG95/2xudf9zdn//c3V8/3Bzff9wc33/am13/2psc/9nanT/ -dXd9/3N1fP9qbXf/dXd9/3Bzff9sbnX/bG95/25xe/9wcnn/dnh8/3N1fP9ucHf/bW9z/2xudf93eX// -dXiB/25xe/9ucHf/eXuB/2xudf9wcnn/bG51/2xvef9ucHf/bG51/2ptd/9kZ3H/am13/2dqdP9qbXf/ -am13/2Zpc/9zdXz/bG51/2dqdP9sb3n/Z2px/2dqcf9qbHP/bG51/25xe/9ucXv/bG95/2xvef9qbXf/ -bG51/2dqdP9qbXf/Zmlz/2xudf9sb3n/cHJ5/2psc/9kZ3H/Z2p0/2dqdP9sbnX/bG95/2ptd/9qbHP/ -bG51/2BjbP9qbHP/Z2px/2psc/9qbXf/bG51/2Zpc/9qbXf/bnF7/2dqdP9gY2z/YmVu/2ptd/9nanT/ -Z2p0/2dqcf9qbHP/am13/2xvef9ucXv/bnB3/25wd/9ucHf/c3Z//25wd/9zdn//cHN9/2xvef9sb3n/ -bW9z/3l7gf9vcXX/bnB3/3V3ff9ucXv/bG95/25wd/9wc33/bG51/3Byef9ucHf/bnB3/3N1fP9ucHf/ -bnB3/29xdf91d33/b3F1/21vc/9sbnX/bnB3/25wd/9ucHf/c3V8/25wd/9ucHf/bnB3/29xdf91d33/ -b3F1/2Zobv9wcnn/am13/2dqdP9qbHP/Zmlz/2xudf9sb3n/bG95/2ptd/9qbHP/cHJ5/2Zpc/9sb3n/ -Zmhu/11gav9iZW7/Zmhu/2Zpc/9dYGr/am13/2dqdP9maG7/YmVu/2dqdP9kZ3H/Zmhu/2Rncf9kZ3H/ -am13/2dqdP9iZW7/Z2px/2BjbP9iZW7/Zmhu/2Zpc/9nanT/ZGdx/2Zpc/9ucXv/Zmlz/3Byef9nanT/ -Z2p0/2xvef9ucXv/bG95/25xe/9sbnX/bG51/3J0e/9xdHv/aGt1/2tueP9pbHb/bG95/2xvef9sbnX/ -bnB3/2Zobv9maXP/am13/3Bzff9ucXv/am13/25xe/9qbXb/dHeA/25xe/9rbnb/bnF6/3Bzff9ucXr/ -bXB5/3Fzev9xc3v/b3F5/29xef91d3//d3l//3F0fP92eID/cHJ5/3R2fP93eYH/cHJ6/3d5gf95fIX/ -eHqC/3d5fv98foT/fH6F/3N1fP90dnz/eXuA/3d5gP9ydHz/c3V9/3Z4fv90dnz/dnh8/3F0ev9zdXv/ -dXd9/3h6gP90dn3/dHZ+/3Bzff9sb3n/bG95/3N1fP9wc33/c3Z//3d6hP90dn3/c3Z//2lsdv9tcHr/ -bW93/21vd/9zdXz/am13/29xeP9wc33/am13/3Byef9ucHf/eHl9/3Z4fP91d33/dXd9/25wd/9sb3n/ -bnB3/3V3ff91d33/bnB3/3V3ff92eHz/b3F1/3Byef9wcnn/dXd9/3V3ff9ucHf/am13/2xudf9qbXf/ -dXd9/3l7gf9ucHf/bG95/3V4gf9maXP/am13/2dqcf9qbHP/amxz/2dqdP9nanH/XWBq/2Zpc/9maG7/ -am13/2xvef9nanT/c3V8/2dqcf9qbHP/bG95/2dqdP9qbHP/bG51/2xudf9wc33/am13/25xe/9qbXf/ -am13/2ptd/9qbXf/bG95/2ptd/9qbHP/cHN9/3d5f/9sb3n/bnB3/3Byef9tb3P/bW9z/25wd/9zdXz/ -b3F1/2xudf9sbnX/bG95/2xudf9ucHf/bG95/2ptd/9qbXf/bnF7/3d5f/9nanT/amxz/2psc/9ucXv/ -bnF7/3N2f/9wcnn/bnF7/2xvef9zdXz/dnh8/3Byef9ucHf/am13/25xe/9tb3P/dXd9/3Bzff9sbnX/ -amxz/2xudf9zdn//am13/2xudf91d33/bG95/2ptd/9qbHP/bG95/2Rncf9nanT/Z2p0/2psc/9ucXv/ -amxz/2dqdP9sb3n/bnF7/2xudf9qbHP/am13/2ptd/9sbnX/am13/3Byef9sb3n/bnB3/25wd/9wcnn/ -dXd9/25wd/9maXP/dXiB/25wd/9ucHf/cHJ5/25wd/9zdXz/cHN9/3N2f/9wc33/cHN9/3d6g/9wc33/ -eXuB/3N2f/9ucXv/cHJ5/25wd/9ucXv/Z2p0/3V3ff9sbnX/bnB3/25wd/94eX3/bnB3/25wd/9sb3n/ -bG95/3N1fP9qbXf/Z2p0/2ptd/9sbnX/bW9z/25wd/9zdXz/dXd9/25wd/9zdn//d3l//2xvef93eX// -c3Z//3Bzff91eIH/d3l//3l7gf9zdn//c3Z//3V3ff93eoT/enyD/3V3ff94e4P/eHqB/3V4gv90d4D/ -bnF7/3V4gf9qbXf/Z2p0/2xvef9wc33/c3V8/25wd/9ydHz/bnF6/3R3f/9ucHn/bG93/29yfP9ydHv/ -b3F4/25wdf9wcnf/bW92/25wdP9vcnr/cnR8/3V3fv9ucHf/dXh//2xud/9ydHz/dHd//25xef9zdn// -c3V8/3J0ef9wc3z/c3V9/3R3gP9sb3f/bXB6/3V4gv9ucXv/b3J8/2xvef9vcXj/bnB4/3Bzev9vcXj/ -cXN6/25wd/9ydXz/cHJ4/21wef9tb3P/Zmhu/2dqcf9sbnX/bW9z/2ptd/91d33/bnB0/25xe/9maXP/ -bnB3/21vc/9tb3P/c3V8/2ptd/9qbXf/bnF7/2xudf9sb3n/amxz/3V3ff9zdXz/bnF7/3Bzff9nanT/ -amxz/2Zpc/9wcnn/bG95/2xudf9qbXf/bG95/2Zobv9maXP/Zmlz/2Zpc/9qbXf/Z2p0/2dqcf9maG7/ -amxz/25wd/9zdn//am13/2ptd/9zdn//am13/2xvef9qbXf/am13/2ptd/9zdXz/bnB3/2dqcf91d33/ -b3F1/3N2f/93eoP/c3V8/3t9g/9zdXz/c3V8/3Bzff9sb3n/bnB3/25xe/9sb3n/c3Z//25wd/9zdXz/ -bnB3/2xudf9sbnX/amxz/2xudf9qbXf/bG51/2xvef91eIH/am13/2dqcf9nanH/Zmhu/2Rncf9maXP/ -am13/2Zobv9qbHP/Zmlz/2psc/9nanH/amxz/2xudf9qbHP/amxz/2xvef93eX//am13/2dqdP9nanH/ -bnF7/25xe/9wc33/b3F1/29xdf9ucHf/cHJ5/3Z4fP91d33/bG51/21vc/9ucHf/bW9z/3N1fP9wc33/ -am13/3Byef9ucHf/d3l//3Byef9sbnX/dXd9/2xvef9nanT/Z2p0/2xvef9maXP/amxz/2ptd/9sbnX/ -c3V8/2xudf9nanT/bG95/25xe/9qbXf/bG51/2ptd/9qbHP/bG51/2ptd/9sb3n/bG51/2ptd/9sbnX/ -cHJ5/3V3ff9wcnn/Z2px/3N2f/9nanT/bnB3/25wd/9ucHf/cHJ5/3Byef9wc33/cHN9/3Byef93eoP/ -c3Z//3V4gf9sb3n/bG95/25wd/9vcXX/cHJ5/2dqcf9zdXz/bG95/2ptd/9maXP/d3l//2dqcf9qbXf/ -amxz/2Zpc/9qbXf/Zmhu/2Jlbv9maG7/Zmlz/2Rncf9nanH/am13/2xvef9maXP/am13/3V3ff9qbXf/ -dXd9/3N1fP9ucHf/dXd9/3N1fP93eX//cHN9/25wd/9sb3n/bG95/25xef9qbXX/b3J8/3N1e/9xc3z/ -c3Z//25xe/9zdn//am13/3Byef9wc33/d3qD/3l8hv90d4D/dHeB/29xev90d4H/cXN7/21wef9tcHr/ -dHZ8/29yev9wc3r/dXh//3N1fv9wc3v/cnV9/3Z4gf94en//c3V8/3p8gf9rbnf/b3F7/3V3ff9ucXv/ -dHeA/3V4gf9ydX//cnR7/3h7hP98foX/cnV+/3d6hP99gIr/dnmB/3R3gP9zdXz/dnmB/3R3gP9wc33/ -bnF7/3J1fv9tcHr/dnh8/21vdv9wc33/bnB3/2dqdP9qbXf/bnF7/25wd/9wcnn/d3l//3N1fP91eIH/ -cHN9/3V4gf9wc33/c3Z//36Ahv93eoP/c3Z//3V4gf9wcnn/bnF7/3Byef95e4H/dXiB/3l7gf95e4H/ -c3Z//25xe/9ucXv/d3qD/3Bzff9ucHf/bnF7/3V4gf9wcnn/cHJ5/25wd/9ucHf/c3V8/3Byef9vcXX/ -bG51/3N1fP92eHz/dnh8/25wd/9wcnn/dXd9/2xudf9ucHf/bnB3/29xdf9ucXv/c3Z//3N2f/9maXP/ -c3Z//3Byef9wc33/c3Z//2xvef91d33/cHJ5/25wd/9ucXv/am13/25wd/9wc33/cHJ5/3V3ff9ucHf/ -c3V8/25wd/9ucHf/cHJ5/29xdf9tb3P/bnB3/2ptd/9sb3n/d3l//25wd/9tb3P/bG95/25wd/9tb3P/ -cHJ5/3Byef9sbnX/bG51/2xudf9tb3P/am13/2xudf9ucHf/bG51/21vc/9zdXz/dXiB/2xvef9sb3n/ -am13/25xe/9wc33/c3Z//2xvef9vcXX/bG95/25xe/9zdn//dXiB/25xe/9ucHf/bnF7/2xvef9zdn// -dXd9/25wd/9ucHf/bnB3/3d5f/9zdXz/bnB3/3N1fP9sbnX/Zmlz/2psc/9qbXf/ZGdx/2dqcf9qbXf/ -Zmhu/2xvef9nanH/ZGdx/2dqdP9sb3n/amxz/2xudf9sb3n/bG51/2ptd/9sbnX/cHJ5/25xe/9sb3n/ -bnF7/25xe/93eX//cHN9/2ptd/93eoP/cHN9/3Byef9wcnn/dXd9/3V3ff94eX3/e32D/3l7gf93eX// -f4KM/3l8hv97fYP/d3qD/3N1fP91d33/c3Z//3V4gf9wc33/eXuB/3V4gf9wcnn/bnB3/3l8hv9ucHf/ -c3Z//3Bzff9wcnn/cHN9/3Byef9wcnn/cHJ5/25wd/9sbnX/bG95/3Bzff9ucXv/bnB3/25xe/93eX// -bnB3/3V3ff9zdXz/bnB3/3V3ff9zdXz/d3l//3Bzff9ucHf/bG95/3R3gP91dnz/bnB3/3J0fP92eHz/ -b3F4/3J0e/9ucHf/c3V8/2psc/9qbXf/bG51/3Bzff9ucXv/c3V8/3J0e/9rbnT/c3V8/21wef9ucHf/ -bW92/3V3fP9tb3b/a212/21wev9qbXf/b3F4/2ttdf92eH//cnR7/25xeP91d33/Z2py/2xvef91d33/ -bnB3/3N2fv9vcnv/a254/2hrdf90d33/cHN9/2dqcv9nanT/dXiB/2dqdP9maG7/ZGdx/2Zpc/9qbHP/ -ZGdx/2BjbP9maXP/XWBq/25wd/9gY2z/Zmlz/2Zobv9maXP/Z2p0/2xudf9sbnX/bnB3/3N1fP9vcXX/ -cHJ5/2Zobv9sbnX/bG51/25wd/9wcnn/bnB3/25wd/91d33/cHN9/25wd/9ucHf/dXd9/3V3ff91d33/ -c3Z//3N1fP9ucHf/cHJ5/3V3ff9qbXf/bG51/25wd/9wc33/am13/2xvef9sbnX/cHJ5/3Byef9ucHf/ -bG51/25wd/9zdXz/c3V8/3V3ff9ucXv/bnF7/3V3ff9qbXf/bG51/21vc/9sbnX/am13/3N1fP9wcnn/ -Zmlz/3N2f/9ucHf/cHN9/3V3ff9wcnn/cHN9/29xdf9sb3n/bG95/2ptd/9sb3n/bnF7/2xvef91eIH/ -cHN9/3N2f/9ucXv/bnF7/3N2f/9wcnn/bnF7/2xvef9ucHf/cHJ5/3Z4fP9ucHf/bW9z/2ptd/9sb3n/ -bG51/3Byef9ucHf/am13/2xudf9qbXf/am13/25wd/9tb3P/bG51/2dqdP9qbHP/bG95/3V3ff9qbXf/ -Zmlz/2xudf9ucHf/dXd9/3V3ff9ucXv/cHJ5/3Bzff9ucXv/c3Z//3Z4fP9sbnX/b3F1/2xvef9ucHf/ -d3l//3V4gf9ucHf/bnF7/2xvef93eoP/cHJ5/25wd/9wcnn/bnB3/2dqdP9sbnX/am13/2Zpc/9qbXf/ -am13/2dqdP9wc33/Z2p0/2dqdP9zdXz/bnF7/2psc/9sbnX/bG51/2xudf9sbnX/bG51/2ptd/9sbnX/ -Z2p0/2xvef9qbXf/dXd9/2xudf9nanH/cHJ5/2psc/9sbnX/bG51/2xudf9sbnX/bnB3/3Byef9ucHf/ -bnB3/3l7gf91d33/c3Z//3Byef9sbnX/am13/2xudf9sb3n/ZGdx/25xe/9qbXf/am13/2xudf95e4H/ -bnB3/2xudf9sbnX/bW9z/3Byef9sbnX/bnB3/25wd/9qbXf/bG51/25wd/91d33/cHJ5/2xudf9wcnn/ -d3l//2xvef93eoP/dXiB/3N2f/91eIH/c3Z//3l8hv91eIH/cHJ5/3N1fP9ydHz/cXN5/3Byef90d3// -dXd9/3BzfP9wc3z/bG95/3Bzff9nanT/bnB3/3Bzff9zdn//cHN9/3V4gf90d4D/aGt1/3Z5g/9ucXr/ -dHeA/3BzfP94e4T/cHN9/3BzfP9wc33/dXiA/3N1fv9sb3n/eXuB/3N2f/9wcnn/d3qD/2ptd/93eoP/ -eXyG/3V4gf95fIb/eXuB/3Byef9sb3n/e32D/3d5f/9ucHf/bnB3/3t9g/9ucHf/b3F1/2xudf9ucHf/ -bW9z/2dqcf9kZ3H/am13/2psc/91d33/amxz/25wd/9tb3P/bG51/29xdf9wcnn/b3F1/3N1fP91d33/ -bnB3/2xvef9kZ3H/bG95/3Bzff9ucXv/d3qD/3V4gf9wc33/d3qD/3V4gf9wc33/dnh8/35/g/9+gIb/ -fX6B/36Ahv97fYP/dXiB/3d6g/95e4H/c3Z//3Bzff91eIH/e32D/3d6g/93eoP/c3Z//3d6g/93eoP/ -dXiB/3N2f/9wc33/dXd9/3d5f/95e4H/dXiB/3V3ff94eX3/bnB3/25wd/9sbnX/bG51/2xudf9ucHf/ -bnF7/2ptd/9wc33/bnB3/25xe/9zdn//bG95/3Bzff9ucHf/cHJ5/25xe/9sbnX/bG51/3Byef9wcnn/ -dXd9/2xudf9zdXz/bG51/25wd/9zdXz/bnB3/25wd/9ucHf/bG95/3N1fP92eHz/bG51/21vc/9wcnn/ -c3V8/2xudf91d33/bG95/2xudf9sbnX/amxz/2ptd/9sb3n/am13/2psc/9qbHP/bG51/2xudf94eX3/ -am13/2dqdP9ucHf/bnF7/3V3ff92eHz/bnB3/29xdf9zdXz/cHJ5/25wd/9zdXz/bG51/2ptd/9qbXf/ -amxz/25xe/9wcnn/Z2p0/2xudf9ucHf/d3qD/2ptd/9ucXv/bnF7/2xudf9qbXf/am13/2xvef9maXP/ -bG51/2ptd/9sbnX/cHN9/2dqdP9maXP/c3V8/3Bzff9sbnX/bG51/2xudf9sbnX/bW9z/2ptd/9qbXf/ -amxz/2dqdP9sb3n/bG51/3N1fP9qbHP/ZGdx/2dqdP9maXP/amxz/2ptd/9nanH/am13/2dqdP9sb3n/ -bG51/25wd/95e4H/dnh8/3V3ff9zdXz/bnB3/25wd/9ucHf/bG95/2Zpc/9zdn//bnF7/2xvef9wcnn/ -foGK/3N1fP9wc33/c3Z//3Bzff9ucXv/am13/2xvef9vcXX/bG51/21vc/9vcXX/dXd9/3Bzff9nanT/ -bnF7/3V3ff9nanT/dXd9/3Byef9sb3n/dXd9/25wd/91d33/bG95/2dqdP9qbHP/c3Z//3N1ff9rbXT/ -cHJ5/25wd/9rbnj/bnF7/2ptd/9wc33/bG51/21vc/9ucHf/bnF7/2xvef9wc33/am13/2Vocv9zdn// -bG51/25xe/9maXP/bnB3/2dqcf9nanH/amxz/2ptd/9maXP/YmVu/25wd/9kZ3H/YmVu/2Zpc/9cX2j/ -Z2p0/2xvef9maXP/Z2p0/3V3ff9sb3n/bG95/3l7gf91eIH/bnB3/3Bzff9+gIb/bnF7/29xdf9sb3n/ -bnF7/25wd/9sb3n/Z2p0/25xe/9qbXf/d3l//2dqdP9ucXv/bnB3/2ptd/9ucHf/bnF7/2xvef9zdXz/ -dXd9/25wd/9sb3n/aGp0/2xvef9tb3f/bnB3/3J1fv9tcHr/bnF6/3V4gf9wc33/c3V8/25wd/9zdn// -c3Z//3N2f/9ucXv/dXiB/3Byef9wc33/c3Z//3Byef9ucHf/cHN9/3d5f/9wc33/cHN9/25wd/91eIH/ -c3Z//3Bzff9vcXX/bnB3/3d5f/91eIH/dnh8/3V3ff91d33/d3l//3Byef9ucXv/bG95/2xvef9ucHf/ -c3V8/3N1fP9sbnX/c3V8/29xdf9wcnn/dXd9/25wd/9zdXz/am13/2xudf9sb3n/Z2p0/2xvef9sb3n/ -amxz/25xe/9sbnX/cHN9/2psc/9sb3n/bnF7/2psc/9nanH/Zmlz/2Zpc/9nanT/bnB3/2Zobv9qbHP/ -Z2p0/25xe/9nanT/bnF7/2xudf9sbnX/cHJ5/21vc/9ucHf/bG95/2xvef9ucXv/am13/25wd/9ucHf/ -dnh8/2xudf9nanH/b3F1/25xe/91d33/c3Z//2xvef9wcnn/c3Z//3Byef9ucHf/dXiB/3Bzff9ucXv/ -bnF7/3N2f/91eIH/c3Z//2xvef9wc33/c3V8/36Ahv9ucHf/dXd9/3V3ff9tb3P/Z2p0/2xudf9qbXf/ -Z2p0/2xudf9vcXX/b3F1/3V3ff9ucHf/bnB3/3V3ff91eIH/bnB3/2xvef9ucXv/cHN9/25xe/9zdn// -d3qD/3d5f/9zdXz/e32D/3l7gf9+f4P/e32D/3l7gf9+gYr/d3qD/3l7gf9+gIb/d3l//3V3ff91d33/ -eXuB/3V3ff93eX//gYOK/36Biv97fYP/d3qD/3Byef9ucHf/bnF7/25wd/9maG7/cHN9/2xvef9kZ3H/ -Z2p0/3V4gf9nanH/Z2px/2psc/9nanH/Z2px/2Jlbv9kZ3H/Zmlz/2Zpc/9maG7/ZGdx/2Rncf9maXP/ -YGNs/2dqdP9wcnn/ZGdx/3V3ff9sb3n/bG51/3N1fP9sbnX/d3l//3Byef9vcXX/bG51/3V4f/90d37/ -bW90/3N1fP9ucHf/bnB3/3N2f/9sb3n/cHJ5/2dqdP9ucHf/cHN9/3Bzff9ucHf/c3V8/3Byef9maG7/ -d3qD/2xudf9wcnn/am13/3N1fP9sb3n/bW9z/25wd/9ucHf/bnB3/2xudf91d33/cHJ5/2xudf9wc33/ -ZGdx/2xvef9wcnn/bG95/2xudf91d33/c3V8/2xudf94eX3/d3qD/25wd/9ucXv/foCG/3Bzff9wcnn/ -bnF7/25xe/9ucHf/am13/2psc/9rbnj/a254/3d6hP9wcnn/dXiB/3N1fP9ucXv/cHN9/3Bzff9wc33/ -eXuB/3Z5gv91eIH/cHJ8/2lrdP9rbnj/bW93/29xef9xdH3/bnF7/21wev9zdn//c3Z//3Bzff9ucXv/ -d3qD/3N2f/91d33/bnB3/3N1fP9vcXX/bnB3/3Byef9ucHf/b3F1/3Byef92eHz/bnB3/3Byef9ucHf/ -dXd9/3Byef9wc33/bG95/3Bzff91d33/d3l//3N1fP9sb3n/bnF7/3Z4fP9tb3P/am13/2xudf9qbHP/ -am13/25wd/9sb3n/Z2p0/3Bzff9sbnX/bnF7/3Bzff9nanT/bnF7/2ptd/9qbHP/am13/2Zpc/9qbXf/ -bG95/2xudf9wc33/bG51/25xe/9qbXf/bnF7/3Bzff9qbXf/bG51/2dqdP9qbXf/bnF7/3N1fP9sbnX/ -am13/25wd/92eHz/bnB3/3N2f/9sb3n/bG95/3Bzff9ucHf/bG51/29xdf9wcnn/bnF7/3Byef9wc33/ -bG95/3d6g/9sb3n/bnF7/3N1fP9zdn//dXiB/3d6g/9ucXv/cHJ5/3d6g/91eIH/cHN9/3N1fP9qbXf/ -bW9z/25wd/9ucHf/cHN9/3Byef9nanT/bG95/3Byef93eoP/bG95/3N1fP9wcnn/bG51/2psc/9qbXf/ -bG51/2Zpc/9sbnX/amxz/2dqdP9ucXv/bG51/2dqdP9ucXv/bG95/2psc/9nanH/Z2px/2xudf9sbnX/ -am13/2psc/9maG7/YGNs/2Rncf9kZ3H/bG95/2Zpc/9maXP/Z2p0/2Zpc/9kZ3H/bG95/2psc/9nanT/ -Zmlz/2xvef9sb3n/Zmlz/3d5f/91d33/dXd9/3Byef9ucHf/bnB3/3Byef9wcnn/am13/3d6g/9zdXz/ -bG95/3Byef95fIb/bG95/25wd/9sb3n/bG95/2xvef9qbHP/bG51/2xudf9qbHP/bG51/2psc/9sb3n/ -am13/2Zpc/9sb3n/dXd9/2Rncf9sb3n/Zmlz/2dqcf9maXP/Zmlz/3N1fP9qbXf/Z2px/2dqdP9xdH3/ -c3V8/2psc/9ucXv/amxz/2psc/9sb3n/am13/2xvef9qbXf/bG51/3Bzff9ucXv/bG95/3N1fP9wcnn/ -amxz/36Ahv9zdXz/cHJ5/2xudf93eX//bG95/21vc/9ucHf/bG95/2xvef9nanT/dXd9/2xvef9qbXf/ -cHN9/2Rncf9ucXv/bG95/2ptd/9sbnX/b3J7/29ye/9oa3X/c3V8/3J0fP9nanT/bG52/3h6gP9rbXT/ -bG51/21vdv9sbnX/bG51/21vdf9pa3L/bG92/2hrdf9zdn3/bXB6/2xvef9tb3b/Z2px/21vc/9sbnX/ -bG51/3Z4fP90dnz/cHJ7/2xvef9pbHP/bW92/2ttdv9sb3f/dHZ8/25wef9sbnf/cHJ5/25wd/9qbXf/ -am13/3N1fP9ucXv/c3V8/2xudf9ucXv/amxz/2ptd/9qbXf/bG51/2psc/9qbXf/am13/2psc/9qbHP/ -bG51/2xvef9sb3n/am13/2ptd/9sb3n/c3V8/3N2f/9wc33/cHN9/3V3ff94eX3/bnB3/3Bzff9zdXz/ -bnF7/25xe/9zdn//c3Z//2xvef97fYP/c3Z//3t9g/97fYP/c3V8/36Ahv91eIH/c3Z//3d5f/94eX3/ -d3qD/3l8hv91eIH/e32D/3N2f/9zdn//cHJ5/3d6g/91d33/bG95/25wd/9sb3n/bnB3/3V4gf91d33/ -bnB3/2xvef9ucXv/dXiB/3Byef91eIH/bG95/25wd/9wcnn/bW9z/2psc/9vcXX/cHJ5/2xvef9sb3n/ -bnF7/25xe/91eIH/am13/2xvef9zdXz/bnF7/3V3ff91d33/b3F1/29xdf91d33/bnB3/2xudf9zdXz/ -bnB3/25wd/9zdXz/cHN9/3N2f/9zdXz/bG95/25xe/9wc33/eXuB/3N1fP91eIH/dXiB/3Byef9sb3n/ -bnF7/25xe/9ucHf/bnF7/25xe/9wcnn/c3Z//25xe/9sb3n/cHN9/3Bzff9vcXX/bG95/2xvef9vcXX/ -bnB3/3Bzff9wcnn/b3F1/25wd/9zdXz/bnB3/3d5f/9ucHf/bG95/3N2f/9ucHf/cHJ5/3Bzff9zdXz/ -bnB3/25wd/9wc33/cHN9/2dqdP93eX//dnh8/3Z4fP9zdXz/bG51/2xudf9ucHf/bW9z/2dqcf9zdXz/ -bW9z/2xudf9sbnX/eXyG/2xudf9nanT/Z2px/2Zpc/9sbnX/Zmlz/2Zpc/9nanH/ZGdx/2xudf9qbHP/ -bnF7/2xudf9kZ3H/bG95/3V3ff9maXP/c3V8/25wd/9sb3n/c3Z//25xe/93eoP/dXd9/25wd/9ucXv/ -b3J6/3J0fP9ucHf/dXd9/29xdf9ucHf/cHN9/25xe/9zdn//bG95/2xvef9wc33/cHN9/25wd/9zdn// -bnF7/2ptd/94e4X/dHZ8/3J0fP9sbnX/dHZ8/29xeP9sbnX/b3F4/29xeP9tcHr/bnB0/3V3e/9wcnn/ -aGt1/21wev9jZm//cHJ5/25xev9tb3P/bW92/3Z4fP9ydHv/cHJ3/3V3fP9ydHv/aGtz/21vdv96fIP/ -bW93/2xvef9tb3f/aWx2/2xudf9rbXb/aWx1/2hrcv9pa3T/dnh+/25wd/9tb3f/a254/2dqcf9tb3P/ -bG51/25wd/91d33/cnV+/3F0ff9vcXr/aWxy/21vd/9tb3b/b3F5/3BzfP9rbnj/bnB4/25wd/9wcnn/ -bG51/25wd/94eX3/cHJ5/3N2f/9wcnn/c3Z//3Byef9zdXz/d3qD/3N1fP9wcnn/cHN9/3N2f/9sb3n/ -bG95/3Byef9zdXz/c3V8/29xdf9ucHf/bnF7/3l7gf93eX//dXd9/3N1fP91d33/dXd9/25wd/9ucHf/ -b3F1/25wd/9ucHf/bnF7/2ptd/9kZ3H/dXd9/2ptd/9zdXz/dnh8/25wd/94eX3/cHJ5/29xdf9wcnn/ -bG51/3Bzff9ucXv/bG51/3N1fP9tb3P/c3V8/2xudf9zdXz/cHN9/2psc/9qbXf/Z2p0/2ptd/91d33/ -dXd9/25wd/9ucHf/bG51/3Bzff9sbnX/bG95/2ptd/9sbnX/cHN9/21vc/9qbHP/am13/2xvef9tb3P/ -bG51/21vc/9qbHP/c3Z//2dqcf9sbnX/bW9z/21vc/9zdXz/c3V8/2xudf9tb3P/cHN9/25wd/9ucHf/ -Zmlz/2Zobv9maG7/am13/2Zpc/9qbXf/bG95/2psc/9qbXf/am13/3N2f/9qbXf/cHN9/3Bzff9nanH/ -ZGdx/2dqdP9qbXf/am13/2xudf9sbnX/bG51/25xe/9sbnX/am13/3Byef9zdXz/b3F1/2xudf9sbnX/ -bG51/2xvef9ucXv/am13/21vc/9sbnX/dXd9/2xudf93eoP/cHN9/21vc/9wcnn/bG51/2dqdP9sbnX/ -amxz/2dqcf9maXP/Z2p0/2ptd/9maXP/c3Z//3d5f/9wcnn/Z2p0/2Rncf9kZ3H/bG51/2ptd/9maXP/ -bG95/2xudf9maXP/Z2p0/3d6g/9qbHP/bG51/2psc/9maXP/bG51/2Zpc/9kZ3H/bG51/2dqdP9qbHP/ -amxz/2ptd/9nanT/YGNs/2ptd/9zdXz/YmVu/25xe/9sbnX/Z2px/2ptd/9qbXf/dXd9/25xe/9maXP/ -am13/25xe/9xc3r/a254/3ByeP9sbnX/a210/2ptd/9sbnX/am13/2dqdP9qbHP/Zmlz/2dqdP9maXP/ -am13/2hrcv9iZW7/cnR6/25xev9ucXr/a253/3R2ev9ucHn/bG51/21veP9rbnj/bnF7/21weP9vcnz/ -b3J6/2tueP9vcnz/ZWhx/3F0fP9wcnn/am11/2ptd/90d4D/cnV9/21weP9xc3v/cXN6/2psc/9qbXX/ -dXd//2ttdP9tcHr/a254/2lsdP9tb3T/aWx1/2hrdP9tbnX/aGt0/3d4ff9xc3j/bXB6/21vdv9maXP/ -amxz/2dqdP9qbXf/bnF7/3N1fP9vcnv/bXB6/2Vocv9qbXf/am13/3N1ff9xc3v/bW92/25xev9sb3n/ -bG95/2dqdP9sbnX/c3V8/2ptd/9qbXf/Z2px/2Zpc/9nanH/Z2px/2ptd/9nanH/Zmhu/2Zpc/9qbXf/ -YmVu/2Jlbv9maG7/Zmlz/2ptd/9sbnX/YmVu/2Zpc/9sb3n/c3V8/3Bzff9zdXz/cHN9/3d5f/9qbXf/ -bW9z/2xudf9ucHf/bnB3/3V3ff9sbnX/Z2px/3V3ff9wcnn/dXd9/3V3ff9sbnX/c3Z//3Bzff9tb3P/ -b3F1/29xdf92eHz/c3V8/2xudf91d33/am13/2ptd/9nanT/bnF7/2ptd/9iZW7/Z2px/2Jlbv9iZW7/ -Z2p0/2dqdP9nanH/Z2p0/2psc/9zdXz/bG51/3Byef9sbnX/bnB3/3N1fP9sbnX/YmVu/2psc/9qbXf/ -bG51/2dqdP9qbHP/Z2p0/3d5f/9nanH/bG51/21vc/9sbnX/c3V8/3V3ff9wcnn/bW9z/3Bzff9sbnX/ -amxz/25xe/9sb3n/b3F1/3d5f/9sb3n/cHN9/3Bzff9ucHf/bnF7/2xvef97fof/bnF7/3d6g/95e4H/ -c3V8/2xvef91eIH/c3V8/25wd/9ucXv/bnF7/25wd/9wc33/cHJ5/2xvef9zdn//cHJ5/2xudf9sbnX/ -am13/2ptd/9ucXv/cHN9/25wd/9ucHf/Z2p0/3V3ff9ucHf/eXuB/3N1fP9vcXX/cHJ5/25wd/9vcXX/ -c3V8/2xudf9sbnX/bnB3/3Byef9sbnX/bG51/3l7gf93eX//d3l//3Byef9sb3n/am13/25xe/9ucXv/ -am13/3N2f/9vcXX/amxz/2ptd/9+f4P/bnF7/3Byef9ucHf/bnB3/25wd/9sb3n/am13/3Bzff9wcnn/ -cHJ5/3N1fP93eoP/c3Z//25xe/95e4H/e36H/2dqdP91eIH/d3qD/3N2f/93eoP/d3qD/3t+h/97fYP/ -c3Z//3V4gf9sb3j/bnB2/25xef9ydXz/cXR9/3Bzff9vcXj/bG95/25wd/9sb3n/bG95/3Byef9sb3n/ -bG51/3J1fP9ucHf/Z2px/3J1fv9zdXr/cHJ5/2tueP9ydHr/cHJ6/29xd/9wc33/b3J8/3F0ff9xc3z/ -cXR9/3N2fv9ucHn/c3Z+/2hrdP9zdn7/dXh//29xeP9ucHf/dXiA/3F0ff9tcHr/dHZ7/3R2e/9pbHT/ -bnF4/3V4f/9sbnb/bnB3/2xudf9sbnX/bW90/2hrc/9rbXT/a254/2dqdP9wc33/bnB0/21wef9tb3P/ -amxz/21vc/9nanT/bG51/2xvef9sb3n/am13/3Byef9nanT/Zmlz/2dqdP9ucXv/cHN9/2ptd/9ucHf/ -bG51/25wd/9qbXf/am13/3V3ff9wcnn/cHJ5/2xudf9ucHf/bG51/2xudf9ucXv/Z2p0/2psc/9qbXf/ -bnF7/2psc/9qbXf/bG95/3Bzff9sb3n/am13/2dqdP9ucXv/cHN9/3d5f/94eX3/dnh8/3V3ff93eX// -bG51/2xudf9sb3n/bG95/2xudf9wcnn/cHJ5/2xudf92eHz/bnB3/3N1fP91d33/am13/2xvef9sb3n/ -bG51/21vc/9sbnX/dXd9/3N1fP9ucHf/cHN9/2ptd/9qbXf/Z2p0/3V3ff9wcnn/Z2p0/2ptd/9nanT/ -bG51/3Bzff9ucXv/bnB3/2xudf9tb3P/dnh8/29xdf9ucXv/cHN9/25xe/91d33/bG51/2dqcf9tb3P/ -cHJ5/2xudf9tb3P/bW9z/2ptd/93eX//Z2p0/2psc/9sbnX/am13/3V3ff92eHz/cHN9/29xdf91d33/ -bnB3/25wd/9qbXf/ZGdx/2psc/9ucXv/am13/2psc/9nanT/Z2px/2xudf9qbXf/dXiB/2xudf9wc33/ -dXd9/2xudf9nanT/bnF7/21vc/9sbnX/bG51/2ptd/9nanT/am13/2dqcf9nanT/bnF7/2ptd/9qbXf/ -am13/2ptd/9qbXf/bG95/25xe/9sb3n/Zmlz/2BjbP9qbXf/Zmhu/25wd/9qbXf/Z2px/2dqdP9maXP/ -Zmhu/2dqdP9kZ3H/Zmlz/2Zpc/9sb3n/am13/2dqdP93eoP/c3V8/3V3ff9nanT/ZGdx/2Jlbv9nanH/ -Z2px/2dqdP9sb3n/Z2p0/2Jlbv9nanT/eXuB/2ptd/9qbXf/bG51/2xudf9ucHf/b3F1/2dqdP9ucHf/ -bG51/21vc/9sbnX/c3V8/2xudf9qbHP/dnh8/3V3ff9maG7/c3Z//3N2f/9sb3n/c3V8/3N1fP94eX3/ -dXd9/3Byef9zdXz/c3Z8/3J0e/9ucXv/cnV7/29xef9vcXj/bW93/3Byef9ucHf/b3F1/29xdf9sbnX/ -bW9z/25wd/9wcnn/bG95/2hqcf91d37/cnV6/21wef9tb3b/dXd9/3R2fv9ucHf/b3F6/3F0ff9ucXv/ -cXN6/3J0ff9zdn7/cnR7/3Z5gf9rbnf/c3Z//3R3f/9vcXb/b3F2/3N2f/9wc33/bnB3/3R3gP90dnv/ -am10/3J0e/90dn3/bG51/29xef9sbnX/am12/2xvc/9gY2z/Zmlz/2dqdP9kZ3H/bG95/2dqcf9qbXf/ -amxz/2ptd/9qbXf/bG51/2xudf9wcnn/bnB3/21vc/9ucXv/Z2p0/2Zpc/9nanT/bG95/25xe/9wcnn/ -cHJ5/25wd/9ucHf/bW9z/25wd/9zdXz/dXd9/3Bzff9ucHf/bG95/2xvef9sb3n/dXd9/29xdf9ucHf/ -bnF7/3Bzff9vcXX/bG95/3V4gf91eIH/bnF7/3N1fP9wc33/d3qD/3d6g/95fIb/e36H/36Ahv9+f4P/ -e36H/3Bzff9wc33/dXiB/3N2f/9wc33/cHN9/25xe/9qbXf/eHl9/3N2f/91d33/dXd9/2xvef9wcnn/ -cHJ5/29xdf9sb3n/bnB3/3N1fP9zdXz/cHJ5/25xe/9qbXf/am13/2dqdP91d33/c3V8/2xudf9sb3n/ -cHJ5/3Byef9zdn//dXiB/3V4gf9zdn//cHJ5/3t9g/9wc33/dXiB/3d6g/95fIb/e32D/3d6g/9wc33/ -dXd9/3N2f/9zdn//cHN9/3N1fP9zdXz/d3qD/2ptd/9sb3n/cHJ5/25wd/91d33/dnh8/3V3ff9ucHf/ -dXd9/25wd/9tb3P/bG95/2ptd/9wcnn/c3Z//3Bzff9ucXv/dXd9/2xudf9ucHf/bnB3/3t9g/9vcXX/ -c3V8/3Z4fP9ucHf/amxz/25xe/9qbXf/am13/2xudf9qbXf/bG51/2psc/9nanH/bG51/25xe/9qbXf/ -am13/2xudf9qbXf/ZGdx/2xvef9ucXv/bG95/2Zobv9kZ3H/am13/2dqdP9zdXz/am13/2dqdP9zdXz/ -bG51/2xudf9zdXz/b3F1/2xvef9sb3n/c3Z//25xe/9vcXX/e32D/3d5f/93eX//bnB3/2xudf9nanT/ -bnB3/25wd/9sb3n/dXiB/25wd/9ucHf/bnB3/31+gf9ucHf/bG95/2xudf9nanT/Z2p0/21vc/9nanT/ -bG51/2psc/9sbnX/Zmlz/2xvef9nanT/Z2p0/3Bzff9zdXz/ZGdx/3N1fP9ucXv/bG51/3N1fP9ucXv/ -cHN9/3Bzff9sb3n/bG95/3Fze/9ydHv/b3J5/3R2fP9vcXb/bW95/2hrdf9oa3X/am13/2psc/9qbHP/ -bG95/2Zpc/9maXP/Z2p0/2dqc/9gY2z/cXR9/29xef9sb3j/bG52/3J0e/9vcnv/b3F1/25weP9wcnn/ -cHJ2/25weP9wcnn/bnB3/25weP9ydX7/Z2p0/3N2f/9xc33/bnB3/3Bzff9wc33/bnF7/21vc/9zdXz/ -dnh8/2xudf9zdn//d3qD/29xdf9wcnn/bG95/2xvef9sb3n/Zmhu/25wd/9ucHf/amxz/3V3ff9sb3n/ -cHJ5/29xdf9sbnX/bnB3/2xudf9tb3P/c3V8/2xudf9sbnX/bnF7/2Zpc/9qbXf/Z2p0/2ptd/9wc33/ -bG95/3Bzff9sb3n/bG51/25wd/9ucHf/c3V8/3N2f/9zdXz/b3F1/25wd/9ucHf/bG51/3V3ff9vcXX/ -bG51/25wd/9wcnn/bG95/25wd/91eIH/e32D/3Bzff9wc33/c3V8/3N2f/91eIH/eXuB/3d5f/9zdn// -dnh8/3d5f/9nanT/b3F1/25xe/9wc33/cHN9/3Bzff9ucXv/bnB3/3V4gf9wc33/c3Z//3V4gf9ucHf/ -cHN9/25xe/9ucHf/bG95/2xvef91d33/c3Z//25xe/9wc33/bnB3/25wd/9nanT/c3V8/3N2f/9qbXf/ -bG95/25wd/9sb3n/c3Z//3Bzff9zdn//c3Z//3Bzff95fIb/cHJ5/25xe/9zdn//cHN9/3Bzff9wc33/ -Z2p0/25wd/9zdn//bnF7/3Byef9wcnn/cHJ5/3d6g/9ucHf/cHJ5/3Bzff9sb3n/d3l//3Z4fP91d33/ -bnB3/3N2f/9ucHf/bnB3/25wd/9ucHf/cHJ5/3d5f/91eIH/c3Z//3l7gf9ucXv/bnF7/3N2f/9+gYr/ -c3V8/3d6g/97fYP/cHN9/3Byef9ucXv/bG95/2xvef9sb3n/bG95/3Bzff9ucXv/bnB3/3Bzff97fYP/ -dXiB/3Bzff9ucXv/cHN9/25xe/93eoP/e32D/3l7gf9zdn//cHJ5/3N2f/9wcnn/eXuB/3Bzff9ucHf/ -d3qD/3N1fP9zdXz/eXyG/3V3ff91d33/c3V8/3d6g/91eIH/c3V8/3l8hv93eoP/d3l//3Bzff9sb3n/ -Zmlz/25wd/9sbnX/b3F1/3Byef9ucHf/bnB3/2xvef97fYP/bnF7/25xe/9ucHf/bG51/2ptd/9qbHP/ -amxz/2xudf9ucHf/bnB3/2dqdP91eIH/am13/2xvef93eoP/c3Z//2Zpc/91d33/c3Z//3Bzff93eX// -c3Z//3V3ff9wc33/bnF7/25wd/91d3v/dXd7/3Byef91d3z/bnB0/3Byef9qbXf/bG95/25wd/9tb3P/ -bG51/25xe/9maXP/YmVu/2dqdP9kZ3H/YGNs/3J1fv9sb3n/Zmhu/2RmbP9sb3n/Z2py/2dqcf9oa3L/ -Z2lz/2dpb/9laHH/bG95/2ptd/9sbnX/bG95/2Rncf9wc33/bG95/2xudf9qbXf/c3Z//3V4gf9vcXX/ -cHJ5/3V3ff9sbnX/dXd9/3d5f/9tb3P/bnB3/2xudf9ucHf/bnF7/2Zobv9sbnX/bnB3/2dqcf91d33/ -bG51/25wd/9ucHf/b3F1/25wd/9ucHf/am13/3Bzff9sbnX/am13/2xvef9maXP/Z2p0/2Vocv9tb3T/ -c3V8/25wd/9ydHv/c3Z//2xvef9ucHf/bG95/3Bzff9zdXz/c3V8/25wd/9ucHf/b3F1/21vc/9wcnn/ -bW9z/25wd/9ucXv/c3Z//3Bzff9wcnn/dXiB/3d5f/9sb3n/bG95/29xdf9ucHf/cHJ5/3Z4fP9ucXv/ -c3V8/3Bzff9zdXz/ZGdx/2psc/9qbXf/am13/2ptd/9sb3n/bnB3/2dqdP9zdXz/bnF7/25xe/9wc33/ -bG51/2xvef9sb3n/am13/2psc/9sbnX/c3V8/3Bzff9ucHf/cHJ5/2xudf9tb3P/Z2px/2xvef9wc33/ -bG51/25wd/9ucHf/b3F1/3N1fP9zdXz/bnB3/25xe/9tb3P/dXd9/2xudf9sb3n/bnF7/25xe/9ucXv/ -am13/2Zpc/9sbnX/c3V8/25wd/9sbnX/bW9z/2xudf94eX3/bnB3/25wd/9ucXv/bnB3/3Z4fP91d33/ -eHl9/25wd/9zdXz/bG51/29xdf9ucHf/bnB3/3Byef91eIH/c3Z//3Bzff93eoP/bnF7/3Bzff9ucXv/ -eXyG/25wd/9zdXz/dnh8/25wd/9ucHf/bnF7/3Byef9qbXf/bnB3/25wd/9ucXv/bnB3/25wd/9sbnX/ -dnh8/25wd/9tb3P/bnB3/25wd/9qbXf/cHN9/3V3ff92eHz/cHJ5/2xudf9wc33/cHJ5/3l7gf9wc33/ -bnF7/3V3ff9tb3P/bnB3/3Byef9ucHf/b3F1/25wd/9zdXz/cHJ5/29xdf95e4H/dXiB/3l7gf9ucHf/ -bnB3/2RmbP9sbnX/Z2p0/2psc/9sbnX/am13/2Zpc/9qbHP/c3Z//2ptd/9qbXf/am13/2dqdP9maXP/ -am13/2Zpc/9qbXf/bG51/2xvef9nanT/bG95/2Rncf9maXP/bG95/2ptd/9iZW7/bnF7/2xvef9sbnX/ -cHN9/25xe/9zdXz/bnF7/2xvef9qbHP/cHN9/3Byef9sb3n/dnh8/21vc/9ucHf/bG51/25wd/9qbXf/ -bG51/21vc/92eHz/bnB3/2dqcf9zdXz/bnB3/2dqdP97fof/c3Z//25xe/9ucXv/eXuB/2xvef9ucHf/ -bG95/25xe/9ucHf/bnB3/25xe/9qbXf/bG51/2xvef9kZ3H/c3V8/25xe/9qbXf/bG51/3N2f/93eoP/ -cHJ5/3Bzff91d33/bG51/3V3ff95e4H/bG51/3Byef9ucHf/b3F1/3Byef9maG//Z2p0/2dqc/9hZG3/ -cHN9/2ttdP9oa3X/a21z/2psc/9qbXf/bG51/2ptd/9wc33/bG95/25xe/9tcHr/Z2p0/2dqdP9oa3P/ -bXB3/3J1fv9ucXv/bG95/3Byef9qbHP/amxz/2psc/9sb3n/bG95/2xvef9sbnX/bnF7/2psc/9sbnX/ -bnF7/2psc/9maXP/Zmlz/2ptd/9maXP/Z2px/25xe/9ucXv/amxz/2Zobv9kZ3H/Zmlz/2dqdP9wcnn/ -bG95/25xe/9wc33/c3V8/2Rncf9sbnX/am13/2psc/9nanT/bG95/2dqcf9qbHP/c3V8/25xe/9ucXv/ -cHN9/2psc/9qbXf/bnF7/25wd/9tb3P/b3F1/3V3ff9zdXz/c3V8/3N1fP9sbnX/bnB3/2psc/9ucHf/ -eHl9/25wd/9sbnX/bG51/2xvef9zdn//bnF7/2xudf9ucHf/bnB3/3V4gf9ucHf/cHJ5/3N1fP9ucXv/ -bnF7/3N1fP9qbHP/amxz/3V3ff9ucHf/bnB3/25wd/9ucHf/dnh8/21vc/9ucHf/c3V8/25wd/92eHz/ -dXd9/3Z4fP9ucXv/dXiB/25xe/9zdXz/am13/2Zpc/9qbHP/cHN9/2xvef9sbnX/cHN9/2ptd/9sbnX/ -bnB3/3l7gf9wcnn/c3Z//3V4gf9ucXv/bnB3/25xe/9ucHf/am13/25wd/9sb3n/bnF7/25wd/9ucHf/ -bG51/3d5f/9wcnn/b3F1/2xudf9ucHf/Z2px/2xvef9wc33/bnF7/2xvef9qbHP/bG95/2Zobv9sb3n/ -Z2px/2dqcf9qbXf/Z2p0/2Zpc/9sb3n/am13/2ptd/9qbXf/bG51/3V3ff9sb3n/eXyG/3l7gf95e4H/ -cHN9/25wd/9qbXf/c3Z//3N1fP9zdXz/dXiB/3V3ff91eIH/d3l//4OFjP97fYP/eXuB/3V4gf9zdn// -cHN9/3N2f/9wc33/d3qD/3V3ff91eIH/cHN9/3l7gf9zdXz/bnF7/3V4gf9wc33/am13/3d6g/91eIH/ -cHN9/3N2f/93eoP/e32D/3N2f/9wcnn/b3F1/3V3ff91eIH/bnF7/3l7gf9ucHf/c3V8/29xdf9ucHf/ -bW9z/21vc/9vcXX/dXd9/25wd/9sb3n/bnF7/2dqdP9nanT/e32D/3V3ff9wcnn/bnB3/3Z4fP9tb3P/ -b3F1/25wd/9ucHf/bG51/2psc/9zdn//bnF7/25wd/9zdXz/Zmhu/3Z4fP9ucXv/b3F1/21vc/99f4X/ -e32D/3V3ff93eoP/fX6C/3V3ff98foX/f4GI/3N2f/92eYL/cnR7/29yfP9zdn//aGt1/25wd/9qbHP/ -ZWhy/29ye/9sbnX/bW92/21vdv9nanH/am13/2dqcf9maXP/bnB3/2Zpc/9nanT/bG92/2hrdP9lZ3D/ -ZWhw/2xudP9ucXr/a212/2hqc/9qbXf/bG51/2xudf9qbXf/bnF7/3Byef9wcnn/b3F1/3N1fP9wcnn/ -bG51/3N1fP9vcXX/bnB3/3Byef9zdXz/bnB3/3Byef9wc33/dXd9/25xe/9sb3n/bnB3/25xe/9zdXz/ -eHl9/3N1fP9zdXz/cHN9/3Z4fP9nanH/bG51/3Bzff9sbnX/bnB3/3V3ff9tb3P/bG51/3Z4fP9wcnn/ -cHJ5/3N1fP9sbnX/bG51/2xvef9zdXz/bG51/2xudf9wcnn/c3V8/3Bzff9zdXz/bnB3/25wd/9sb3n/ -bG95/3d5f/9ucHf/cHJ5/2xvef9vcXX/c3Z//3Bzff9sb3n/bG95/25xe/91eIH/bnB3/3N2f/9zdn// -c3Z//3N2f/93eX//bnB3/2xvef9wc33/bG95/2xudf9sbnX/bG51/3Z4fP9qbXf/am13/3Byef9sbnX/ -c3V8/3N1fP9ucXv/bG95/3N1fP9qbHP/bW9z/21vc/9sbnX/bnB3/3V3ff9wc33/bG95/3N2f/9ucHf/ -bnF7/25xe/93eoP/cHN9/3N2f/95fIb/d3qD/3V3ff91eIH/dXd9/3N2f/9zdn//c3V8/3V4gf9wcnn/ -cHJ5/3Bzff91eIH/cHN9/25xe/9ucHf/cHJ5/2psc/9zdn//eXuB/3N2f/9ucXv/bG95/3N1fP9vcXX/ -c3V8/2xudf9sbnX/dXd9/25xe/9ucHf/cHN9/3Byef9wcnn/bnF7/3N1fP91eIH/bnF7/3l8hv95e4H/ -eXuB/25xe/9qbXf/Zmlz/3Byef9ucHf/am13/3Bzff9sb3n/cHN9/25wd/93eoP/c3Z//3Byef9ucHf/ -b3F1/2psc/9vcXX/bG51/3Byef9vcXX/am13/2xudf9zdXz/bG51/2xudf9wc33/bG95/2Zobv9wcnn/ -cHJ5/25xe/9sb3n/c3V8/3V3ff9ucXv/bG95/21vc/91d33/eXuB/25wd/91eIH/bG51/3Byef9tb3P/ -bnB3/2xvef9ucXv/cHJ5/3V4gf9wcnn/bG95/25xe/9qbXf/Zmlz/3Z5gv9zdn//cHN9/21vef92eH7/ -bnB3/29xdf9sb3n/bnB3/29xdf9vcXb/dHZ9/3Byef9ucHf/bG94/2Nmb/91d3z/bG95/2lsc/9nanT/ -bnF7/3V4gf9xc3v/c3Z//3N2fv9tcHr/dXd+/3J1f/9rbnj/bnF7/2xveP9tb3j/cXN6/29xeP9tb3P/ -aWty/2ptdP9wc3v/b3F4/3Bze/9ucXr/Z2p0/2xvef9qbHP/Zmlz/25wd/9nanL/aGt0/25xef9sbnb/ -aGt1/21wef9ydX7/dHeB/29xef9sb3j/bnF7/2xudf9qbHP/amxz/25xe/9sb3n/bG95/21vc/9ucXv/ -bnF7/2xvef92eHz/bnB3/3Byef9zdXz/cHJ5/21vc/9qbHP/bnF7/3N1fP9sbnX/bG51/2dqdP9sb3n/ -bG95/3Bzff9sb3n/c3V8/25xe/9wc33/Z2p0/2ptd/9ucXv/amxz/2dqdP9sb3n/Zmlz/2dqcf9sb3n/ -am13/2xvef9zdXz/amxz/2xudf9qbXf/bnF7/2ptd/9tb3P/bnF7/3V3ff9zdn//cHN9/25wd/9ucHf/ -bnB3/25wd/91eIH/bnB3/3Byef9ucHf/cHJ5/3N2f/91eIH/c3V8/3Bzff9wc33/e32D/25wd/9wc33/ -dXiB/3l7gf91eIH/d3l//2xvef9qbXf/bnF7/25wd/9qbHP/bnB3/2xudf94eX3/bnB3/2xudf9sb3n/ -am13/3Byef9zdXz/c3V8/2ptd/9zdXz/amxz/2xvef9ucHf/am13/21vc/92eHz/c3V8/25wd/91d33/ -b3F1/29xdf9vcXX/dnh8/25wd/9ucHf/bnB3/25xe/9qbXf/bG95/2psc/9sbnX/bG51/2xudf9qbXf/ -Z2p0/2dqdP9nanH/dXd9/2dqdP9nanH/ZGdx/2Zpc/9dYGr/Z2p0/3N1fP9sb3n/bG51/2ptd/9qbXf/ -amxz/2xvef9sbnX/am13/25xe/9wcnn/amxz/25xe/9qbHP/Z2p0/2xudf9sbnX/c3V8/2ptd/93eoP/ -cHN9/3Bzff9sb3n/am13/2psc/9ucHf/bW9z/2xudf9ucHf/bG51/3Byef9tb3P/d3l//3Bzff9sb3n/ -cHJ5/2xudf9maXP/bG51/2dqdP9wc33/am13/2xudf9ucHf/c3Z//25wd/9ucHf/dXiB/3V4gf9kZ3H/ -dXd9/25wd/91d33/bG51/3Bzff95fIb/c3Z//2xvef9sb3n/cnV+/3Z5gv9sbnX/enyC/29ydv9vcnz/ -bnB3/3Bzff9wc33/bG95/2xvef9wcnn/b3F1/2dqcf9ucHf/bG92/2hrdf91eIH/dXd+/3R2fv9ydHv/ -dXd8/29yd/9wcnf/b3F3/3J0e/9ucHj/b3J5/3V3ff9wcnj/cHJ3/3Fzev9sbnX/dHZ8/29xd/9tcHn/ -bG51/25xef9ydX7/bnB5/2xvef9vcXj/bG93/29yev9wcnj/aWx1/3Bze/9tcHr/a254/3Byef9tcHr/ -bW92/2dqdP9rbnb/dHZ9/3R2ff9zdX3/c3V8/29yef92eYL/dXd9/3Z4fP9+gYr/cXR+/3N2f/92eID/ -bW93/2hrdP9sb3n/b3J8/3V3ff9oa3X/YmVu/35/g/93eX//c3V8/3N1fP93eoP/c3Z//3N2f/9ucXv/ -cHN9/3V4gf9zdn//eXyG/3N2f/9wc33/cHN9/3Bzff9ucHf/am13/3Bzff91d33/bnF7/3Byef9sbnX/ -cHJ5/25wd/9zdXz/cHJ5/3V3ff9zdXz/cHN9/2ptd/9ucHf/d3qD/3Bzff9wc33/cHN9/2xvef9ucHf/ -dXiB/3Bzff91eIH/e32D/3V3ff93eoP/eXuB/3t9g/93eX//d3l//3l8hv97fof/e32D/36Ahv97fYP/ -eXuB/3V3ff91d33/gYOK/3Z4fP93eX//eHl9/3h5ff97fYP/d3qD/3N1fP95fIb/d3qD/3t+h/9wcnn/ -c3Z//3d6g/91eIH/dXiB/3l7gf9zdXz/c3V8/3V4gf9zdXz/Z2p0/2xvef9nanT/d3l//25wd/9qbXf/ -bnB3/2ptd/9ucXv/dXd9/3Z4fP9wcnn/c3V8/2xudf9vcXX/YmVu/2Jlbv9maG7/bnB3/2dqdP9iZW7/ -ZGdx/2BjbP9kZ3H/ZGdx/25wd/9kZ3H/Zmhu/2Zpc/9maXP/Zmlz/2Zobv9dYGr/YGNs/2Zobv9maG7/ -Z2p0/2Zpc/9nanT/Zmlz/3V4gf9sb3n/am13/2psc/9qbXf/Zmhu/25wd/91d33/c3V8/3N1fP9sb3n/ -bnF7/3Byef91eIH/c3Z//3N2f/91eIH/d3qD/3N1fP93eoP/cHN9/3Byef9wc33/c3V8/3d5f/9ucXv/ -eXyG/3l7gf91eIH/c3Z//25wd/9qbXf/c3V8/3Bzff9wc33/c3Z//25wd/9ucXv/bG95/3l7gf91d33/ -bnB3/3Byef9ucHf/bnB3/25xe/9wcnn/cHN9/2xvef9sb3n/bG95/3Bzff9ucHf/bnB3/3N1fP9zdXz/ -Zmhu/3Bzff9qbXf/bnF7/2ptd/9sb3n/dXiB/3Bzff9ucHf/bG51/3V2e/92eYD/bG52/3R2fP9sbnX/ -cXN6/21vd/9vcXn/cHJ5/3Byef9ucHf/bnB3/25wd/9qbHP/bG51/2psdP9pbHT/cHJ4/25weP9sb3f/ -bnB5/21vd/9ucHf/aGt1/2hrdP9qbXf/aGt0/2xvd/9sb3n/aWx0/21weP9nanT/ZWhv/25xev9vcnr/ -a254/25xeP9ydHz/dHZ9/29xe/9vcnz/b3J8/3N1ev9xdH3/cnR9/3F0ff92eYH/dXiA/25xev9zdXz/ -c3Z//3Byef9rbnj/b3J8/3h6gP90dn//cnR7/29xef9pbHb/cHJ5/21vc/9vcXX/d3l//29xdf90dnz/ -dnh8/2tud/9maXP/c3V8/3N1fP93eX//bG51/2psc/9zdXz/b3F1/25wd/9sbnX/bnF7/2ptd/9qbXf/ -amxz/2xvef9ucXv/bG51/3d5f/9vcXX/bnF7/3N1fP91d33/bnB3/2ptd/9zdn//c3Z//25xe/9wc33/ -am13/3Bzff9wc33/dXd9/3N1fP91d33/bnB3/25wd/9sbnX/bG95/3N2f/9ucXv/c3Z//3V4gf9zdXz/ -cHJ5/3d5f/91d33/cHJ5/3V3ff9tb3P/bG95/2xvef9wc33/am13/25xe/9ucXv/c3V8/3Byef91d33/ -bnB3/25wd/9ucHf/cHJ5/3l8hv9sb3n/bnB3/25wd/9ucHf/cHJ5/25wd/9qbXf/cHJ5/3Byef94eX3/ -bnB3/25wd/9zdXz/bnF7/3V4gf91d33/am13/29xdf9wcnn/bW9z/2Zpc/9qbXf/Zmlz/3Bzff9sbnX/ -Z2p0/2xvef9qbHP/Z2p0/2xvef9ucHf/Z2px/2dqdP9iZW7/ZGZs/25wd/9sb3n/bnF7/3d5f/91d33/ -bG95/3V3ff9qbXf/bG95/29xdf93eX//cHJ5/25xe/9wcnn/bnF7/2psc/9sbnX/Zmlz/2ptd/9sbnX/ -bG95/2xudf9tb3P/bnB3/25wd/97fof/c3Z//3V4gf9zdXz/dXiB/25xe/91eIH/e36H/3V4gf93eoP/ -d3qD/3d6g/93eX//eXyG/3l8hv95fIb/eXuB/3t9g/9zdn//d3qD/3N2f/9wcnn/bnB3/2xvef92eHz/ -b3F1/3l7gf93eX//c3V8/3N2f/9ucHf/Z2px/21vc/9sbnX/bG51/2xvef9qbHP/am13/2dqcf9zdn// -bG95/2psc/9sb3n/bG51/2ptd/9qbXf/bG51/25xe/9sb3n/bG51/2xudf9ucHf/bG51/2dqdP9sb3n/ -bG95/11gav9qbXf/am13/3Bzff9sbnX/bnF7/3V4gf9ucXv/bG51/2xudf9ydHz/dHZ8/29xef9ucXv/ -bG50/25xef9nanT/am13/2dqdP9nanT/Z2px/2Zpc/9nanH/Zmlz/2ttdP9oa3T/bnB4/3V3ff9ydX// -c3aA/3J1fv9tcHn/cnV+/29ye/9tb3f/cXR+/3J1fv92eH7/c3aA/25xev91d33/cXR9/21wd/9vcnz/ -c3Z//3J1ff90dnz/cnR8/3N1fP9wcnj/bnB3/3Byef91d3v/cHJ5/25wd/9tcHf/c3V8/3J0fP9sbnX/ -bW9z/3N2f/9wcnn/amxz/25xe/93eX//dHeA/3J0fP9vcnv/a211/29yef9ucHf/bW9z/3d5f/9vcXb/ -c3V9/3V3fv9sb3j/Z2p0/3N2f/91d33/d3l//25wd/9sbnX/c3V8/2psc/9nanT/bG51/2ptd/9sbnX/ -bG51/2ptd/9sbnX/cHJ5/2xudf94eX3/bG95/25xe/9zdn//cHN9/2xvef9nanT/dXd9/3N2f/9sb3n/ -dXd9/2xvef9wc33/dXiB/3d5f/9zdXz/dXd9/25wd/9zdXz/amxz/2xudf9wcnn/am13/3Byef9sb3n/ -amxz/2Zpc/9wcnn/am13/2dqdP9wc33/amxz/2xvef9sb3n/bnF7/2xudf9zdXz/cHJ5/3Byef9wc33/ -bnF7/2ptd/9sbnX/bG51/2xudf93eX//bW9z/2xudf9sbnX/bG51/3Byef9wcnn/b3F1/2xvef9ucXv/ -dXiB/2xvef9ucHf/dXd9/3N1fP9zdn//dXd9/2xvef9ucHf/c3Z//25xe/9qbXf/cHN9/2ptd/95e4H/ -dXiB/3Bzff93eoP/c3Z//3t9g/9+f4P/eXyG/3d6g/91eIH/c3V8/3N2f/9qbXf/bW9z/25wd/93eX// -dXd9/3Byef93eX//cHJ5/3Byef9wcnn/e32D/3V4gf9wc33/bnF7/3Bzff9nanT/bG95/2ptd/9sbnX/ -bW9z/25wd/9ucHf/bG51/2dqdP9qbHP/dXiB/2xvef9ucXv/bG51/2ptd/9kZ3H/Z2p0/3Byef9maG7/ -am13/2dqdP9qbXf/Z2p0/2dqdP9sb3n/am13/3Bzff9ucXv/bG51/2xvef9sb3n/bG51/2dqdP9qbXf/ -dXd9/25wd/93eoP/dXiB/3V3ff91d33/b3F1/2Zobv9ucHf/bW9z/2xudf9ucXv/bG51/3Byef9tb3P/ -dXiB/3Bzff9qbHP/am13/2dqdP9sbnX/bG51/2ptd/9sb3n/bG95/2psc/9sbnX/Z2p0/2Zpc/9maXP/ -amxz/2xvef9iZW7/bG95/25xe/9wc33/amxz/2ptd/91eIH/bnF7/25wd/9sb3n/b3F4/3R2ff9wcnn/ -cXN4/21vc/9ydHv/bG51/25xev9wc33/cHN9/25wd/9wc33/cHN9/3Byef9wc33/bG94/25xef9xc3v/ -c3V8/29xeP91d33/bG95/3R3gP9ucXv/amx0/2xvef9ucXv/cHN8/3Bzff9wcnn/c3V8/3Byef9vcXj/ -cHN9/3Bzff9zdn//c3Z//3Bzff9wcnn/dXd9/3Byef9ucHf/d3l//25wd/9wcnn/bnB3/3V3ff91d33/ -bnF7/3Byef91eIH/bnF7/2ptd/9sb3n/c3Z//3Z4fP9xc3r/c3V8/21vdv93eoT/dXiB/3V3ff9/goz/ -cHJ8/3h6gf91d37/aWx2/2Vocv9ucXv/c3V8/3N1fP9qbXf/am13/3t9g/9wcnn/bnB3/3N1fP9ucXv/ -bG95/2xvef9wc33/bnF7/3N2f/9sb3n/d3l//2xvef9ucXv/bnF7/3V4gf9zdXz/Z2p0/3N2f/91d33/ -bG51/3V3ff9ucHf/cHJ5/3N2f/9zdn//c3Z//3N2f/9ucXv/c3Z//2ptd/9wcnn/cHN9/3Byef9wc33/ -c3V8/29xdf9ucHf/dnh8/3N1fP9wcnn/c3V8/21vc/9zdXz/bnB3/2xvef9ucHf/bnF7/2ptd/9ucHf/ -bnF7/25xe/9sbnX/bG51/2xudf9tb3P/dXiB/2psc/9qbHP/bG51/2dqdP9sb3n/bnF7/2ptd/9qbXf/ -am13/3V3ff9maXP/Zmhu/2ptd/9sb3n/bnF7/2xvef9maXP/Zmhu/2ptd/9maG7/XWBq/2Rncf9gY2z/ -bG95/2dqdP9qbHP/Z2p0/2psc/9qbXf/cHN9/3N1fP9ucXv/bnF7/2xudf9sbnX/am13/21vc/9ucHf/ -eXuB/3N1fP9wcnn/cHJ5/2xudf9qbHP/am13/3Bzff9sb3n/bG95/25wd/9wcnn/amxz/21vc/9sbnX/ -am13/2dqdP9qbXf/bG51/2xudf9sbnX/am13/3d5f/9sb3n/bnF7/2xvef9sb3n/bG51/3Byef92eHz/ -bG51/3N1fP9wc33/c3Z//3Bzff9zdXz/c3V8/3N1fP9wcnn/dXd9/2xudf9wcnn/bnB3/2ptd/9sbnX/ -am13/3Bzff9qbHP/d3l//3d5f/9zdXz/dXd9/25wd/9kZmz/bG95/2xvef9wc33/c3Z//29xdf9wc33/ -bnB3/3d6g/91eIH/bnF7/25xe/9sb3n/cHJ5/3Byef9wcnn/c3Z//3N1fP9wcnn/cHN9/3N2f/9wcnn/ -cHJ5/25xe/9zdn//Zmlz/3V4gf9wc33/d3l//2xudf9ucHf/d3l//25xe/9sb3n/bG95/3p8g/97fYP/ -dnmC/3V3ff91d3z/dHeA/3F0fP9zdXz/cXN6/3V3ff9ucHf/cHJ5/3Byef9sbnX/bnB0/29xeP9ucXr/ -b3F4/3N1fP9zdXz/bnB3/21vc/95e4H/dnh8/21vc/9sb3n/bnF7/3Bzff9wc33/c3V8/25xe/9ucXv/ -bG95/2xvef9sb3n/cHN9/3Bzff9ucXv/cHN9/25xe/9qbHP/bG51/3N1fP9nanT/amxz/2psc/9ucXv/ -cHJ5/2Zobv9kZ3H/Zmlz/2Zpc/9dYGr/Zmlz/2dqdP9sb3n/ZWhx/2Zpc/9jZnD/a254/2xudf9maXP/ -dXd9/2lrc/9wcnn/bXB4/2dpcP9laHL/am13/2xvef9zdXz/bG95/2xudf94eX3/bG95/25wd/9sb3n/ -bnF7/25xe/9ucXv/bnB3/3Byef9zdXz/bnB3/3h5ff9vcXX/bnF7/25wd/9zdn//cHJ5/2Zpc/9zdn// -cHN9/25xe/93eX//cHJ5/25xe/9zdn//c3Z//3Byef9zdXz/c3V8/3Byef9nanH/bG51/3Byef9sbnX/ -cHN9/3N1fP9ucHf/bG51/3V3ff9wc33/amxz/3V3ff9qbXf/bnB3/3Byef9ucHf/bG95/2ptd/9sbnX/ -bG95/25xe/9zdXz/am13/2xudf9qbXf/bG51/3V4gf9qbXf/bG51/25wd/9tb3P/bnF7/2xvef9sbnX/ -cHJ5/25wd/95e4H/bG51/2xudf9qbXf/bG95/2xvef9sb3n/Z2p0/2Zpc/9ucXv/am13/2Zpc/9sb3n/ -Zmlz/3N1fP9ucXv/bG51/2xvef9qbXf/dXd9/3Z4fP94eX3/c3V8/3Byef9sbnX/am13/3V3ff9zdn// -dXiB/3t+h/91eIH/cHN9/3N2f/9sb3n/bG51/25wd/95e4H/bG95/2xudf9sb3n/am13/2Rncf9nanH/ -YGNs/2Rncf9maXP/bG51/2ptd/9qbXf/am13/2ptd/91d33/bG95/3Bzff9sb3n/cHJ5/2xudf9sb3n/ -dXd9/2ptd/9sb3n/cHN9/3Bzff9ucXv/bG95/3Bzff9zdXz/bnF7/3N1fP9ucHf/dXd9/3Byef9tb3P/ -b3F1/2xudf9zdn//bnB3/3d5f/93eX//cHN9/3d6g/9ucXv/Zmlz/3Byef9ucHf/cHN9/3N2f/9sb3n/ -c3Z//25xe/91eIH/dXiB/3Bzff9zdn//cHJ5/25wd/9vcXX/bG51/3Byef9sbnX/am13/2xudf9sbnX/ -amxz/2psc/9qbHP/am13/2Jlbv9ucXv/bnF7/3N1fP9nanT/bnB3/3Z4fP9wcnn/bG51/2xudf95e4H/ -c3Z//25xe/9ucHf/bG95/25xev9vcXj/bXB6/21vef92eHz/cHJ5/25xe/9sb3n/bnB3/3Bydv9rbnf/ -bG94/29xeP9wcnn/dXiB/3Bzff9wcnn/eXyG/3l8hv9zdXz/bnF7/3V3ff9zdn//c3Z//3d5f/9wc33/ -cHN9/25xe/9wc33/cHN9/3h5ff91d33/c3V8/3N1fP9wcnn/am13/2psc/91d33/am13/2xudf9maXP/ -bG95/3N1fP9nanH/Z2px/2ptd/9qbXf/Zmlz/2xudf9zdXz/dnh8/3Byev9zdXz/cXR9/3R3gP9wc33/ -bnF7/3+CjP9zdn//dnmD/3h7hP9xc3r/c3V8/3t9g/9+gIb/e32D/3d6g/9wc33/e32D/3Bzff9zdXz/ -cHN9/25xe/9zdn//bnF7/2xvef9ucXv/dXd9/29xdf91eIH/bnB3/2xvef9ucHf/dXd9/2xvef9kZ3H/ -cHN9/3N2f/9ucXv/d3l//2xvef9ucXv/dXiB/3V4gf9zdn//c3Z//3V4gf9wc33/am13/2xvef91eIH/ -bnF7/3V4gf91eIH/bnF7/2xvef93eX//cHN9/3Byef91eIH/bnB3/25xe/9wc33/c3Z//3Bzff9wc33/ -cHN9/25xe/9wc33/dXd9/25wd/9ucHf/bG95/25wd/93eoP/bnB3/25xe/9wc33/cHJ5/3Bzff9vcXX/ -bnB3/3Byef9tb3P/d3l//2ptd/9sbnX/am13/25xe/9wcnn/cHJ5/2xudf9qbHP/cHJ5/2xvef9qbHP/ -cHN9/2dqdP91eIH/d3qD/3Bzff9zdn//cHJ5/3d6g/95e4H/e36H/3V4gf93eoP/cHN9/3V4gf9sb3n/ -bG95/3Byef91eIH/c3Z//25xe/9wcnn/bG51/2dqcf9ucHf/dnh8/21vc/9qbXf/bG95/3Byef9sbnX/ -b3F1/2RmbP9sbnX/bG51/2ptd/9sb3n/Z2p0/2dqdP9sbnX/dXd9/2xudf9ucXv/bnF7/2xvef9nanT/ -bG51/3N1fP9sbnX/cHJ5/3Bzff9ucXv/bnF7/25xe/9wc33/cHN9/2xvef91d33/bnB3/3V3ff9zdXz/ -b3F1/2xvef9sb3n/c3Z//3Byef93eoP/d3qD/3N2f/91eIH/cHN9/2dqdP9ucHf/bnF7/3N2f/9wc33/ -bnB3/3N2f/9wcnn/eHl9/3V3ff9sbnX/bG95/2xudf9sbnX/bG51/2Zpc/9sbnX/amxz/2Zpc/9maXP/ -Zmhu/2Zobv9maG7/amxz/2xvef9gY2z/Z2p0/2xvef9ucXv/Zmlz/2xudf91d33/bG95/2xudf9ucHf/ -bnF7/25xe/9ucHf/bG51/2xudf9sb3n/am13/3J0e/9zdn//d3l//3Bzff9wc33/cHN9/25xe/9xc33/ -bnB2/25weP9wcnn/cHJ5/3N1fP9sb3n/bG51/3d5f/91d33/am13/2xudf9ucXv/bG95/25xe/9wc33/ -bG51/2xvef9sbnX/Z2p0/2xvef9wcnn/bG95/2dqdP9wc33/bG95/2xvef9qbXf/dXd9/2ptd/9qbXf/ -am13/3Z4fP92eHz/bnB3/25xe/95e4H/cHN9/3Byef9zdn//d3qD/3l7gf93eoP/dXh//29yfP9vcnv/ -b3F1/2xudf93eoP/b3F4/3d5f/97fYb/dHZ//3V3ff97fYP/foCG/3t9g/9zdn//cHJ5/3l8hv9wc33/ -c3V8/3N2f/91eIH/d3qD/3d6g/9ucXv/cHN9/3N2f/9wcnn/d3qD/3N1fP9zdn//c3V8/3N2f/9sb3n/ -Zmlz/3N2f/91d33/bG95/3l7gf9sb3n/bnB3/25wd/9zdXz/bnB3/25wd/91d33/bnB3/2xudf9qbHP/ -cHJ5/21vc/92eHz/cHJ5/2xudf9sb3n/eHl9/3V3ff9wcnn/d3qD/25wd/9wc33/bnF7/3V4gf9wc33/ -bnF7/2xvef9sb3n/c3Z//3N2f/9wcnn/bG95/2xvef9sb3n/d3l//25wd/9vcXX/b3F1/29xdf9zdXz/ -bnB3/25wd/9ucHf/b3F1/3d5f/9qbXf/bG51/25wd/9wcnn/bnF7/3Byef9sbnX/amxz/3Byef9wcnn/ -amxz/3Byef9qbHP/cHN9/25xe/9tb3P/bnB3/21vc/91d33/dXiB/3V4gf9zdn//cHN9/25wd/9ucHf/ -c3V8/3Bzff91eIH/foGK/3t9g/93eoP/d3qD/3Byef9ucXv/dXiB/3d5f/9sb3n/bnB3/3Bzff9wc33/ -Z2p0/25wd/9maG7/bG51/2xudf9tb3P/bG51/2psc/9sb3n/bnB3/3l8hv9wc33/c3Z//3Bzff9wc33/ -am13/2xvef93eoP/cHJ5/3N1fP91d33/dXd9/3V3ff9zdXz/dXd9/3V3ff9wcnn/dXd9/29xdf91d33/ -dXd9/3Byef9sb3n/b3F1/3Byef9tb3P/dXd9/3d5f/9ucHf/cHJ5/3Byef9kZ3H/am13/2Zpc/9sb3n/ -bnF7/2ptd/9zdXz/bG51/3V3ff9zdXz/bnB3/3N1fP9sb3n/bG95/25wd/9ucHf/bG95/25wd/9wcnn/ -c3V8/29xdf9ucHf/bG51/29xdf9zdXz/Z2px/2xvef9zdn//eXuB/3Byef9wcnn/eXuB/25xe/9sb3n/ -bnB3/3Byef9ucHf/bnB3/29xdf9sbnX/bnB3/2xvd/9vcXn/am13/3Bzff9qbXf/am13/2psc/9ucHf/ -am13/2xudf9sbnb/bW92/3Byef9ucXv/bG95/2ptd/93eX//dXd9/3Byef9ucHf/c3V8/3N1fP91d33/ -c3V8/25wd/9wcnn/bnB3/3Bzff9zdn//eXuB/3N2f/9wc33/eXuB/3Bzff9wc33/cHJ5/3Z4fP9zdXz/ -bG51/2xvef91d33/c3V8/2xudf9qbHP/bG95/2ptd/9qbHP/bG95/2xvef9wcnn/am13/2tueP9maXD/ -Z2p0/2dqcf9iZW7/cHJ5/2hqcf9xc3r/bnB5/2xudf9qbXf/cHN9/3Z4fP9wcnn/bnB3/2xudf93eX// -Zmlz/2ptd/9ucHf/am13/25xe/9ucXv/bW9z/25wd/9sb3n/am13/3V3ff9qbXf/bG95/2ptd/9sb3n/ -ZGdx/11gav9qbXf/am13/2xvef9zdXz/Z2p0/2xudf9wcnn/bnB3/2xudf9ucHf/cHN9/25wd/9sbnX/ -am13/25xe/9sb3n/d3l//3Bzff9ucXv/bnF7/3l7gf91eIH/cHN9/3l8hv9zdXz/d3qD/25xe/91d33/ -c3V8/3N1fP9vcXX/bG51/3N1fP9wcnn/b3F1/21vc/9tb3P/bG51/3d5f/9sb3n/amxz/2xudf9sbnX/ -c3V8/2xudf9ucHf/bnB3/25wd/93eX//bnB3/2xudf9wcnn/c3V8/25xe/9wc33/bG95/25wd/91eIH/ -d3qD/3Bzff93eoP/cHN9/3l7gf91eIH/dXd9/3l7gf95e4H/e32D/4GDiv9/gYf/foCG/36Ahv9wc33/ -cHN9/2ptd/9sbnX/bG95/3N1fP9wc33/bnF7/25xe/9qbXf/Z2p0/25xe/9wc33/am13/2Zpc/9nanT/ -Z2p0/2Rncf9maXP/ZGdx/2dqdP9qbXf/amxz/2xudf9kZ3H/am13/2xudf97fYP/cHN9/3N1fP9ucXv/ -dXiB/2xvef9ucHf/d3l//25wd/9zdn//d3l//3V4gf91d33/cHN9/3l7gf95e4H/dXiB/3l8hv9wcnn/ -eXuB/3V4gf9wc33/cHN9/3N2f/91eIH/bnF7/3d5f/93eX//bnF7/3N1fP9tb3P/Z2px/25wd/9sbnX/ -dXd9/25wd/9qbXf/c3V8/2xudf9wc33/c3V8/2ptd/9wcnn/bG51/2xvef9tb3P/b3F1/2xvef9sb3n/ -bG95/25xe/9ucHf/bnF7/3N2f/9wcnn/d3l//2xvef9wc33/eXyG/3t+h/9zdn//d3qD/36Ahv93eoP/ -d3qD/3V4gf9ucXv/bnF7/25xe/9vcXX/amxz/3R2ff9wcnr/c3V6/25wd/92eHz/c3Z//25xe/9ucXv/ -bG95/29ye/9tb3f/bnB3/25wdP9sb3n/c3V8/25wd/9qbXf/dXd9/3V4gf9wc33/bG95/3N2f/91eIH/ -d3l//3N2f/9zdXz/dXiB/3V4gf95fIb/dXiB/3t+h/93eoP/dXiB/3t+h/9zdn//dXiB/25xe/97fYP/ -c3Z//2xvef9wc33/c3Z//3d5f/9vcXX/b3F1/3Bzff9wc33/bnB3/3Bzff9zdn//c3V8/29xeP9ucXn/ -bW90/2xveP9qbXf/Z2px/3d5f/9tb3T/c3V8/3N2fv9ucHj/cHJ5/3V4gf93eoP/c3Z//3N2f/9zdn// -c3Z//2Rncf9maXP/Z2p0/2Zobv9qbXf/bG95/2psc/9nanT/am13/2dqcf9ucHf/ZGdx/2Zobv9maG7/ -Z2p0/2Rncf9gY2z/Z2p0/2dqdP9qbXf/cHN9/2dqdP9sbnX/bnF7/2xvef9qbXf/bG95/25xe/9sbnX/ -bG51/25wd/9wcnn/b3F1/3l7gf93eoP/c3Z//3N1fP95e4H/eXuB/25xe/93eX//bnB3/25xe/9sb3n/ -dXd9/3Byef9zdXz/bG51/2xudf9wc33/bG95/2xudf9sbnX/bG51/2ptd/91eIH/bnF7/2dqdP9nanH/ -Z2px/2Zpc/9maG7/Zmhu/2dqcf9qbHP/c3V8/2Zpc/9kZ3H/am13/25xe/9qbXf/bG95/2dqdP9qbXf/ -cHN9/3Bzff9nanH/cHN9/2ptd/9zdn//cHJ5/29xdf9wcnn/cHJ5/3N1fP91d33/dXd9/3Bzff9ucXv/ -bW9z/21vc/9ucHf/bnF7/3N2f/93eX//d3l//3d6g/9zdn//c3Z//3Bzff93eoP/foCG/3l8hv91d33/ -dXiB/3N2f/9ucXv/cHJ5/2xvef9zdXz/bnB3/25wd/9sb3n/amxz/29xdf9wcnn/e36H/3V4gf9zdn// -cHN9/3N2f/9ucHf/bnB3/3Z4fP9tb3P/c3V8/3Z4fP9wc33/cHN9/25xe/93eX//d3l//3Bzff95fIb/ -bnF7/3d5f/91eIH/cHN9/3N1fP9wcnn/bnF7/2xvef92eHz/dXiB/25xe/9ucXv/bG95/2ptd/9qbXf/ -bG95/3V3ff9wcnn/b3F1/3Z4fP9ucHf/c3V8/3V3ff9ucHf/c3V8/2ptd/9sbnX/bW9z/21vc/9ucHf/ -bG95/2xudf9ucHf/bW9z/21vc/9ucXv/am13/3V3ff9maG7/am13/2xvef92eHz/bnB3/29xdf91d33/ -am13/3Bzff91d33/d3l//3t9g/93eX//d3l//3d5f/98fYL/dniA/3Z4gP9xc3r/d3l//3Bzff9ucXv/ -bnF7/3Bzff9tcHr/b3J8/3F0ff9zdXz/cHN9/3l7gf9wc33/bnF7/3V3ff91eIH/bnF7/25xe/91d33/ -bnF7/3N1fP9ucXv/am13/3Byef9ucHf/dnh8/29xdf94eX3/bnB3/25wd/93eX//cHJ5/3Byef9ucHf/ -eHl9/3Byef9ucHf/dXd9/3N1fP95e4H/b3F1/21vc/9wcnn/bG95/2xudf9ucXv/cHJ5/3J0e/9sbnb/ -bG52/2Vocv9maXP/Zmhu/2Rncf9zdn//Z2px/21wd/9rbXb/Zmhv/2Nmb/9qbXf/cHJ5/2xvef9ucXv/ -bG95/3V4gf9qbHP/bG95/25xe/9ucXv/dXd9/3N1fP9vcXX/cHJ5/3N1fP9sbnX/c3V8/2ptd/9qbXf/ -bG51/25wd/9nanT/Zmlz/2ptd/9sbnX/am13/3V3ff9qbXf/am13/3Bzff9qbXf/bG51/2ptd/9qbXf/ -amxz/2Zpc/9kZ3H/bG95/2psc/9zdXz/cHN9/2xvef9qbHP/bG95/3N1fP9qbXf/dnh8/2ptd/9ucHf/ -bG95/3N2f/9ucXv/dXd9/25wd/9wcnn/c3Z//3Bzff9wcnn/bnB3/3Byef9wc33/f4GH/3V4gf9zdn// -bnF7/3Bzff9zdn//cHJ5/3Byef9wc33/cHN9/3l7gf9sb3n/bG95/2xvef92eHz/bnB3/25wd/9ucHf/ -b3F1/3Z4fP9wcnn/Zmlz/25xe/9qbHP/bG95/2xvef9qbXf/cHJ5/25wd/9wc33/dnh8/3Z4fP9zdn// -c3Z//25wd/9sb3n/Z2p0/2ptd/9ucXv/c3V8/3N1fP9wcnn/bW9z/2psc/9maG7/bG51/3V3ff9sb3n/ -bG51/3Byef9ucHf/bG51/3Byef9sbnX/bnB3/25wd/9tb3P/cHJ5/2Rncf9sbnX/bG95/3V4gf9ucXv/ -bG95/25xe/92eHz/bnB3/25wd/92eHz/bG51/3N1fP92eHz/dXd9/3Bzff9ucXv/c3Z//3Z4fP9vcXX/ -d3l//25wd/9zdXz/cHJ5/3Byef9ucHf/cHJ5/3Bzff9ucXv/eXuB/3l8hv91eIH/cHN9/25xe/9qbXf/ -bnF7/25xe/97fYP/dXiB/3N1fP95e4H/bG95/25xe/9wc33/bnB3/3N2f/9sb3n/cHJ5/3Byef9zdXz/ -dXiB/3N2f/9zdXz/c3Z//3N1fP9zdXz/d3qD/3N2f/97fof/bnF7/3Bzff9wc33/eXuB/25wd/9ucXv/ -dXiB/3Bzff95e4H/e32D/3V4gf91eIH/cHN9/3Byef9qbXf/dnh8/3Fzev9zdXz/cHJ5/3N2f/9zdn// -bnF7/2xvef9wc33/bG51/2xudv9rbXb/aWxz/2dpb/9ucXv/am13/2Rncf9qbXf/am13/2Zpc/9nanH/ -am13/2dqdP9sb3n/cHN9/2ptd/9ucXv/bW9z/3Byef9ucHf/eHl9/25wd/9sbnX/dnh8/3N1fP9wcnn/ -cHJ5/3d5f/9wcnn/bnB3/3N2f/9wcnn/d3qD/25wd/9sb3n/bnF7/25wd/9vcXX/c3V8/3Byef9vcnz/ -b3F4/3N1ff9ucXv/dHeA/3N1fP9zdXz/foCG/25wd/91d33/c3V9/21vdP9sb3b/c3V8/3V3ff9wc33/ -bG95/3Byef91d33/Z2px/2xvef9ucXv/cHN9/3N2f/9zdn//bG95/25xe/9wc33/bnF7/3V4gf9ucXv/ -bnB3/2xudf9zdXz/bnB3/2psc/9ucHf/bG51/3N1fP92eHz/bnB3/2xvef91d33/bnB3/25wd/9wcnn/ -cHJ5/2xudf9sbnX/bnB3/3V3ff9tb3P/eHl9/2xvef9ucXv/amxz/2xvef9zdXz/bG51/3N1fP9sbnX/ -c3V8/2xudf9zdXz/cHJ5/25xe/9ucHf/bG95/3Bzff9wc33/b3F1/25wd/9vcXX/cHJ5/3t9g/9ucHf/ -c3V8/2xudf9ucHf/bnF7/25wd/9ucHf/cHJ5/3Bzff93eX//bnB3/2xvef9ucHf/c3V8/25wd/9sbnX/ -am13/2ptd/9wc33/bnF7/2Rncf9qbXf/Z2p0/2ptd/9qbXf/amxz/25wd/9sbnX/bG95/3V3ff9wc33/ -cHN9/25xe/9sbnX/amxz/25wd/9wc33/cHN9/3d5f/91eIH/d3qD/3N2f/92eHz/bnB3/36Ahv9/gYf/ -eXuB/3p7f/9+gIb/e36H/3d6g/97fof/d3l//3l7gf92eHz/c3Z//31+gf9zdXz/eHl9/3t9g/9/goz/ -e32D/3d6g/9zdn//eXuB/2xvef9vcXX/dnh8/2ptd/9ucXv/c3V8/3Bzff9qbXf/am13/25xe/9ucXv/ -Z2px/3Byef9maXP/bG95/2ptd/9sb3n/Zmlz/2Rncf9kZmz/Zmhu/25wd/9wcnn/Zmlz/2xudf9qbXf/ -Zmlz/2dqdP9sbnX/dXd9/3Byef9ucHf/eHl9/25wd/9sbnX/c3V8/2xudf91d33/bG51/29xdf9wcnn/ -bG95/3V3ff9ucXv/bG95/3Bzff9sb3n/b3F1/3Byef9ucHf/dnh8/2Rncf9ucHf/bG51/3d5f/9qbXf/ -am13/3N1fP9sbnX/dnh8/3Z4fP9tb3P/bG95/25xe/9ucHf/amxz/3R2fP9tb3f/c3V6/2xudf9wcnn/ -cHJ5/25xe/9qbXf/c3V8/29xeP9xdH7/cXR+/3F0ff9wc33/dXd9/25xe/9sb3n/eHl9/3d5f/9ucHf/ -bnB3/3V4gf9sb3n/c3Z//3V3ff9vcXX/c3V8/25wd/9zdXz/bG51/3l7gf9ucHf/bnB3/3Z4fP9ucXv/ -bnF7/2ptd/91d33/bG95/2psc/92eHz/cHJ5/3h5ff9vcXX/b3F1/3Byef9sbnX/bG51/25xe/9sbnX/ -cHJ5/25wd/9xc3r/bnB0/29xeP9ucHf/bG51/3t9g/9ucHX/dHd+/3N1e/9vcXX/b3F1/3N1fP91d33/ -cHN9/25xe/9wc33/d3l//2Rncf9sbnX/cHJ5/2xvef9wc33/am13/2xudf9ucHf/bnF7/25xe/9wc33/ -am13/2xvef9nanT/bG95/2psc/9kZ3H/am13/2xudf9ucXv/c3V8/2dqdP9qbHP/bG95/2ptd/9sb3n/ -bG95/2ptd/9sbnX/am13/2ptd/9wc33/bG95/3V3ff9wc33/bnF7/2xudf9zdXz/dnh8/25wd/93eoP/ -bG95/3V3ff9ucXv/c3Z//3Byef91d33/cHJ5/25xe/91eIH/dXiB/25wd/9ucXv/cHJ5/3V4gf97fof/ -c3Z//3V4gf9zdn//bnF7/3N2f/9wc33/cHJ5/3Byef9ucXv/d3qD/3Byef9sb3n/cHN9/3V4gf9wc33/ -bnF7/25wd/9sbnX/dnh8/3Byef9sbnX/cHJ5/2xudf9qbXf/bG51/2psc/9sb3n/bW9z/3Byef92eHz/ -dXd9/3V3ff9wcnn/bG95/25xe/9ucHf/dXd9/3Bzff93eX//dnh8/3N2f/9wcnn/bG95/2Rncf9zdn// -dnh8/25xe/9qbXf/cHN9/25xe/9ucHf/cHN9/2dqdP9wcnn/bG95/25wd/91d33/Z2p0/2xvef9wc33/ -eXyG/3Z4fP9wc33/c3V8/3d5f/9sb3n/bnB3/3Z4fP9sb3n/c3Z//3d6g/91eIH/cHN9/3N2f/95e4H/ -d3l//25wd/95e4H/bnF7/3V3ff9zdn//c3Z//3Bzff9wcnn/cHN9/25xe/93eX//d3l//3N2f/9ucXv/ -bnF7/2dqdP9sb3n/bnB3/3Z4fP9ucHf/bG95/3V4gf9ucHf/b3F1/3Bzff9ucHf/eXuB/2ptd/9ucHf/ -bnB3/29xdf91d33/cHJ5/25wd/9zdXz/bnB3/29xdf9wcnn/b3F1/3Z4fP9kZ3H/am13/2xvef91eIH/ -am13/2xudf9ucXv/Zmlz/3Bzff9zdXz/c3V8/3V4gf91eIH/bnF7/2ptd/9vcnz/bG95/3N1fP9naXD/ -Z2p0/2ptd/9sb3n/am13/25xe/9tb3b/cXN7/3F0fP9vcnv/cHN9/3V3ff9wc33/b3F1/3V3ff91eIH/ -bnF7/25wd/91d33/bG95/25xe/91eIH/bnB3/3N2f/9sb3n/c3V8/2xudf95e4H/bnB3/3N1fP93eX// -dXd9/3Byef9wcnn/dnh8/2xvef9qbXf/cHN9/2xvef91d33/am13/2Zpc/9nanT/bG51/2psc/9sb3n/ -bG51/2xvef9qbXb/am13/2lsdf9rbnj/am13/2dqdP91eIH/a211/3N1ff9sb3n/am12/2xudf9wcnn/ -dXd9/3N1fP9zdXz/dXd9/3Byef9dYGr/YmVu/2Zpc/9nanT/am13/2Rncf9maG7/ZGdx/2Zpc/9maXP/ -Z2p0/2Zobv9nanT/ZGdx/2Rncf9iZW7/XF9o/2Zobv9maG7/am13/25wd/9kZ3H/Zmlz/25xe/9sb3n/ -bnF7/2ptd/9sb3n/bnF7/2ptd/9tb3P/dXd9/3Byef95e4H/cHN9/3Bzff9vcXX/dXd9/3V3ff9ucXv/ -dXiB/25wd/92eHz/bnB3/3Z4fP9wcnn/c3Z//25wd/9ucHf/cHJ5/3Byef9tb3P/bG51/21vc/9zdXz/ -d3l//2xvef9sb3n/bG95/2xudf9qbXf/am13/2ptd/9nanT/bG51/3V3ff9ucHf/bnB3/25wd/9zdn// -cHJ5/25wd/9sbnX/bnB3/3N1fP9zdXz/bG51/3Byef9sbnX/bG51/25xe/9wcnn/cHN9/3Bzff9zdn// -e36H/3l7gf91eIH/cHN9/3Byef9ucXv/bG95/3Bzff91d33/d3qD/3d5f/93eoP/cHN9/25xe/9qbHP/ -eXuB/36Ahv95fIb/dXd9/3d6g/91eIH/c3Z//3V4gf9wc33/d3qD/3Bzff9zdn//eXyG/2xvef9ucHf/ -cHJ5/3l7gf9zdXz/cHJ5/3Byef92eHz/bnB3/3Byef9wc33/bG95/3N2f/91eIH/c3V8/2xvef9wcnn/ -e32D/3l7gf9sb3n/dXiB/3Byef9zdn//cHN9/3N2f/9zdn//bnB3/3V4gf9wc33/d3l//3V4gf91eIH/ -c3V8/3Bzff9qbXf/b3F1/21vc/91d33/bG95/2xudf91d33/am13/2xudf9qbXf/bG51/3V3ff9qbXf/ -bW9z/2xudf9tb3P/dXd9/2ptd/9tb3P/cHJ5/2ptd/9sbnX/bG95/2xudf91d33/Zmhu/25wd/9sbnX/ -dXd9/2xudf9vcXX/dnh8/2xudf92eHz/cHN9/21vc/9wcnn/c3V8/3Byef9nanT/bnF7/29ye/9wc33/ -bG51/2xvef9qbXf/am13/2xvef9zdXz/bnB0/3J0ev9xdHv/bnB6/25xe/91eIH/cHN9/25wd/95fIb/ -d3qD/3Bzff9wc33/d3qD/25xe/9wc33/eHl9/2xudf9ucHf/bG95/25wd/9qbHP/d3qD/2ptd/9sb3n/ -d3l//25xe/9qbXf/bnB3/3V3ff9ucHf/amxz/3Bzff9sbnX/dnh8/2xvef9qbXf/am13/2xudf9qbXf/ -c3V8/2xudf9wcnn/bW92/3ByeP9vcXX/bnB3/2dqcf9nanH/d3l//25xdf90dnz/bW94/2tueP9nanT/ -bnF7/3V3ff9sb3n/cHN9/25xe/92eHz/YmVu/29xdf9zdn//d3l//3V4gf9wc33/bG95/25xe/9zdn// -dXiB/3d6g/9ucXv/eXuB/3N2f/97fYP/cHN9/2xvef9zdn//cHJ5/3N2f/97fof/c3Z//3Bzff93eoP/ -c3Z//3d6g/9wc33/cHN9/3Bzff9sb3n/bnB3/3V4gf9zdn//foGK/3N2f/9wc33/bnB3/3V3ff9zdn// -bnB3/3V4gf9sbnX/dnh8/25wd/92eHz/cHN9/3Z4fP9ucHf/bG95/25xe/91d33/b3F1/3Byef9wc33/ -d3qD/36Biv91eIH/dXiB/25xe/9ucHf/cHN9/2xvef9ucXv/bG95/25wd/9wc33/bG95/2xvef9wcnn/ -dXd9/3Byef9tb3P/bW9z/2dqdP9wc33/bG95/2dqdP9sb3n/ZGdx/2Zpc/9sb3n/Zmlz/2dqcf9maXP/ -bG51/3V3ff9sb3n/c3V8/25wd/9ucHf/bG51/2tueP9vcnz/dXeA/3h7hf9ydX7/dXd9/25wd/9ucHf/ -Zmds/3Byef9wcnn/c3V8/2dqdP9wcnn/cHJ5/2xudf9qbXf/Zmlz/2psc/9maXP/aGty/25xe/9nanT/ -a210/2hrdf91eIH/bnF7/2xvef9qbXf/c3V8/2dqdP9qbXf/am13/2xudf9ydHv/dHZ8/2ptd/9sb3n/ -bW92/3N1fP9ydHv/am12/3d4ff9wcnn/dXiA/3J1fv91eIH/cnR8/2xudf9wcnn/cHJ5/3V3ff9wcnn/ -cHJ5/21vc/9ucHf/Z2px/25wd/9ucHf/dHZ8/29xeP9sb3b/dnh//29xdf9sb3n/bnF7/29xdf94eX3/ -amxz/29xdf9tb3P/cHJ2/3V3ff9wcnn/b3F4/3R2fv9ucXj/bW93/3Fze/9vcXX/dXd+/2dpb/9sbnX/ -bnB6/3d5f/9sb3b/a254/3V3e/9sbnT/dHZ6/3Bzff92eHz/e32D/36Ahv99foH/d3l//3l7gf91d3z/ -c3Z+/2tudf9sb3n/am13/2Zpc/9nanT/bnF6/2ptdv9zdX7/c3V9/3V4gP9wc33/e32D/3V4gf9ucXv/ -e36H/3d5f/9ucXv/bG95/3Bzff9vcXX/bnF7/3Z4fP9sbnX/am13/25wd/9wcnn/bG51/3l7gf9ucHf/ -c3V8/3h5ff9zdn//bG51/25wd/94eX3/bnB3/2psc/9zdXz/bnB3/3Z4fP9ucHf/bnB3/21vc/9tb3P/ -bG95/3Bzff9sbnX/cHJ5/25xeP9ucHn/bG52/2tudv9nanT/am12/3F0fv9pbHX/bXB6/2psdP9nanH/ -Y2Zv/2Zpc/9ucHf/am13/25xe/9ucXv/b3J7/2Zpcv9rbnf/bW94/29yfP9ucXr/b3J6/21vdv9vcXj/ -bG93/2lsdP9rbXb/bXB4/21wev9nanP/aGt0/2Fkbf9gY2z/amxz/2dqcf9oa3X/cnV8/2Zocf9qbXb/ -a212/2xudf9sbnf/bW92/3Byef9ucHn/b3F4/2psdf9ucXv/bnF6/29ye/9sb3n/bW94/25wdf9xc3r/ -bnF3/3F0e/9vcnv/bXB4/3J0fP9ucHf/cHJ5/21wev9ucXv/amx1/2ptc/9tcHj/b3F4/3J0ef9tb3b/ -bXB4/3Bze/91d33/dHZ+/3Bze/9wcnn/b3F4/3h6gv93eH3/dHZ7/3Z4f/92eYL/d3qB/3d5gv90d3// -eXyF/3t+h/99f4f/e32G/31/hf98foX/fYCI/3p9hv9+gIb/e32E/3V3fv95e4P/enyD/3d5f/95e4H/ -enyE/3l8g/97fYL/dnh//3V3fv92eYL/cnV9/3Fze/9sb3j/bnF5/3F0ff9zdXv/bXB5/3R2ff9rbXX/ -amx1/2Rmbf9pbHX/aWx2/25wev9fYmz/Zmlz/2dqdP9kZ3H/Zmlz/2BjbP9maG7/XmFr/2Vocv9qbXf/ -Y2Zw/2Zpc/9oa3T/b3F5/2dqdP9maXP/ZGdx/25wd/9kZ3H/Zmlz/2Zpc/9oa3T/cXN6/3N1fP9rbnj/ -bnF6/2xvef90dn3/cHN7/2ttdf90dn3/b3J6/3V3ff9vcnv/dHd//3Byef9ucHf/cnV+/25xe/93eX// -cHJ5/3N1fP9ucHf/cHJ5/2dqcf9ucHf/bnB3/3R2ev9sbnb/a211/3N1fP9tb3T/bG51/25wd/9ucHf/ -dXd9/2dqdP9sbnX/bW95/25weP9xdHz/bnF5/2xveP9xc3z/bnB3/2xudf9xdHz/bnB3/3F0ff9sbnf/ -bnB5/29xeP92eH7/b3F4/3J0eP9xc3r/bG93/3Fzev9vcXr/am13/3N1fP9sb3n/cHN9/2xudf9zdX3/ -dHZ9/3V4gP9ucXv/c3Z//3N2f/9sb3n/cHJ5/3R2fP9vcXr/dnh+/3FzfP9vcnz/bnF7/3N2f/9sb3n/ -bG51/3d5f/92eHz/bnB3/2ptd/9qbXf/amxz/25xe/93eX//amxz/2ptd/9sbnX/Z2p0/2Jlbv9wc33/ -ZGdx/2ptd/9ucHf/am13/2psc/9qbHP/bnF7/2psc/9kZ3H/bG95/2xudf9wc33/am13/2Zpc/9sb3n/ -am13/25wd/9zdn//bnB3/25xe/9ucHj/b3F5/2hrc/9qbHT/Zmlz/2lsdv9rbnf/Z2py/25weP9xdHz/ -bW90/2hrdf9sb3n/cHN9/2xvef9zdXz/c3V8/3Bzff9rbnf/b3J8/29yfP9ydX//dXd+/3R2ff9tb3b/ -cnR6/2xveP9tcHr/bnB4/3J1ff9vcnz/bG52/3Fzff9oa3X/ZGdx/21vc/9tb3P/c3Z//3Z4f/9vcnr/ -cXN7/3F0ff9wcnz/bnF6/3Bzff9ydX7/c3Z//3N2f/9sb3n/c3Z9/3J1fv9ydX//dnmC/3N2f/92eYH/ -dXiB/3J1fv98foX/dHeB/3F0ff9ydX7/cHN8/3R3f/91d33/cHN8/29xef9vcXX/cHJ5/3Fzd/91d33/ -bnB3/25xe/9ucXv/cnR6/3F0fP9xc3j/bG52/21wef90dn3/dXh+/21vd/90d3z/bnF4/29xef9wc3z/ -bG95/3Bzff9xdH7/cnV+/25xev9wc3z/cnV+/3N2f/9wc3z/d3qE/3BzfP9rbnf/bnF6/3Byef9vcXn/ -cnR7/29xef9ydHv/bW92/2hrcv9qbXf/am13/2xudf9tb3P/cnR8/3N1fP90dn7/c3V6/3N1fP91eH// -bXB4/3F0e/9rbXP/bXB6/2xvd/90dnz/aGt0/3J0e/9zdXz/bnB3/3N1fP9ucHf/bnB3/2ttdP9wc3n/ -c3V7/3ByeP9wcnj/cXN5/3V3gP9ydHv/cHJ5/3Byef95e4H/bG51/2tud/9rbXb/bG95/25xe/9xc3r/ -bG53/29xeP9zdXn/dHd+/3Fzef9sbnT/cnR9/3F0ff9ydHz/bW94/3V4f/9ucXn/bG94/21wev9wc33/ -d3l//3Byef9wcnn/bW9z/25wd/9maG7/bG51/21veP90dnv/b3F6/21wev94eoH/cnV//3Fzev9sb3n/ -cHJ5/3Z4fP9sbnX/bW92/25xe/9wc33/dnmA/3FzfP9wc3z/dnmD/3R2fv9vcnr/dniB/3Z4gf92eH3/ -cnV+/3R3gf9ydHz/fH6E/3d5gP94eoD/c3Z+/2xveP9ucXr/bnF4/2Zpc/9sb3n/am13/25xe/9kZ3H/ -cXN9/25xev91eID/bnF7/2xvef9zdXz/bW92/3Byef91d37/cXR9/3t9h/90d3//cXR9/3N2f/95e4H/ -c3Z//3V3ff9/goz/foCG/3d6g/9zdn//d3qD/3Bzff95fIb/f4GH/3d5f/93eoP/c3Z//3d6g/91d33/ -foGK/3Bzff91eIH/d3qD/3N2f/9ucHf/bG95/3N2f/9zdn//am13/25xe/9ucXv/c3Z//3Bzff9qbXf/ -c3V8/3Bzff9ucXv/dXd9/29xdf9ucHf/bXB3/3V3ff9tb3j/bnF6/25xe/90dn3/cXN7/29yfP9vcnz/ -cHN9/3Fzev9ucHf/cHJ5/3V3ff91d33/d3l//3Z4fP9tcHn/aWx2/2xvef9rbXT/am13/21wef9vcnz/ -am13/29yfP9nanT/bG95/2tueP9vcnv/bnF5/2tudv9ydHv/bG51/2Zpc/9vcXX/bnB3/3Bzff91eIH/ -bG95/25xe/9ucXv/bG95/21vdv9ucHf/c3Z//3N2f/90d4D/bnF7/21wev9zdn//b3F4/3N2f/9ucXv/ -c3V8/3N2f/9zdXz/eXuF/3Bzff9zdn//c3Z//3N2fv9zdn//eHqA/25xe/9tcHr/cnR8/3Byef9wcnn/ -cHN8/3Byef9ucHf/bnB3/21vdv9wcnn/b3F1/2dqcf9qbXf/cHN9/3Bzff9qbXf/dHZ8/25wd/9ucHf/ -cHJ5/21vd/9zdXz/bG95/3V4gf9ucXv/cHN8/3N2f/9ucXv/bnF7/3h7hf95fIX/dnh8/3x9gP99f4b/ -foCG/3x9gf9+gIf/foCG/3d6g/93eoP/eXyG/3t9g/95e4H/dnh8/25wd/9ucXj/b3J7/3Fzev9ydHv/ -eXt//3R2ff90dnz/bG94/3Byef9wcnr/dHd//3J0ff98foT/fX+F/3V3ff97fYP/dnh8/3Z4fv91dnv/ -d3l+/3F0fP90d37/cHJ6/3V4f/90d4H/cHN7/3Byef9zdXz/dXiB/2ptd/9tb3b/bW92/29yev9xdH7/ -b3F4/2lsdv9tb3f/c3V7/3N2f/9tcHr/bW92/3F0fv9ydX3/c3Z8/2xudf9ydX7/a210/2hrdf9maXP/ -bXB5/3N1fP9wc33/am13/2xudf9sbnX/Z2px/2xudf9vcXX/cHJ4/2ttdv9ucXr/dHd+/29yd/9sbnb/ -b3F1/3Bzff93eX//bnB4/2xvef9ucXr/cXN6/3Fzev9vcXj/bnB3/3h6gP9ydHv/bG51/29xeP9ydHv/ -bW92/2tudf9ucHf/amxz/3N1fP9ydHv/bnF6/2dqdP9nanT/aGt1/2xvef9nanT/bG95/2ptd/9ucXv/ -ZGdx/29xe/9xc3n/cnR9/2xvef9ucHf/c3V8/2xvef9tcHn/dHZ+/25xeP9zdn//a254/2ptdv9nanT/ -bG95/2Zpc/9kZ3H/dXd9/3Byef9qbXf/bG51/2xudf9qbHP/cHN9/3N2f/9qbHP/Z2p0/2dqcf9nanT/ -Zmlz/3V3ff9qbXf/bnF7/2xvef9sb3n/bG51/2xudf9sb3n/c3V8/2dqcf9ucHf/bnB3/25xe/9ucHf/ -Z2px/2xudf9ucHf/c3V8/3Z4fP9vcXX/cHJ5/25wd/91d33/aWx1/2xudf9sb3n/cHN8/2tueP9ucHf/ -bXB5/3J0fP9ucXb/b3F1/2xvef9zdXz/c3V8/3d5f/92eHz/cHN9/2ptd/9qbXf/Z2p0/2ptd/9sb3n/ -bnF7/2Zpc/9qbXf/YmVu/2dqdP9laHL/aGt0/2lsdf9oanH/bW95/2dqdP9iZW7/bG51/2ptd/9rbnj/ -bnF4/2Zpc/9naW//ZGdx/2Rncf9kZ3H/Zmhu/2ptd/9kZ3H/ZGdx/2BjbP9maG7/Z2p0/2Zpc/9nanT/ -Z2p0/2dqdP9ucXv/bG51/3d6g/9qbXf/am13/2xudf9sbnX/cHJ5/3V3ff9ucHf/bnB3/25xe/9wcnn/ -cHN9/3d6g/9zdXz/cHN9/3Byef9wc33/c3Z//3N1fP9sb3n/cHJ5/3d6g/91eIH/bnB3/3d5f/9ucXv/ -bnB3/25xe/9ucXv/cHN9/3N2f/93eoP/dXiB/3d6g/9wc33/cHN9/2xvef94eX3/c3V8/25wd/91d33/ -c3V8/3N2f/91eIH/c3Z//3Bzff9qbXf/Z2p0/2xvef9ucXv/bG95/25wd/9qbXf/bG51/2tud/9rbXT/ -bG95/3V3ff9wc33/dHZ8/2tueP9sbnb/Z2p0/2ttdf9oanP/amxz/2ptd/9maG7/bG95/2dqdP9sbnX/ -amx0/21weP9rbXb/bnF6/2xvef9zdXz/b3J8/25xe/9zdn//eXuB/36Biv9wcnn/cHN9/3F0fP9ydX3/ -bnF6/2ptd/9laHL/bW92/3N1fP9xdH3/b3F4/3Bydv9tcHr/dXd9/3h5ff9vcXj/eHqB/25xev9ucHf/ -am11/3Fzev91d33/cHJ5/29xdf9ucHf/bnF7/2dqdP9rbnj/b3F4/3Bze/9rbnf/b3J8/3Z5gv9xc3v/ -a253/25wd/9ucHf/d3qD/29xd/9sb3n/bXB6/3J0e/9tcHr/am13/2ptd/95e4H/cHJ5/2psc/9ucXv/ -cHJ5/25wd/9sbnX/bnB3/2dqcf9zdXz/c3V8/25xe/9qbXf/am13/2Zpc/9ucXv/YmVu/2Zpc/9kZ3H/ -am13/11gaP9rbnj/bG93/21wd/9tcHr/am13/2xvef9sbnX/a253/3R2fP9tb3P/dXd+/2lsdv9pbHX/ -Z2p0/25wd/9qbHP/Zmlz/3N1fP91d33/am13/25wd/9qbXf/bG51/2xvef9zdn//amxz/2xudf9qbHP/ -bnB3/21vc/93eX//am13/3N1fP9wc33/bG95/2ptd/9qbXf/bG95/25xe/9maXP/bG51/2xudf9ucXv/ -bG95/2psc/9sbnX/bnB3/3Byef91d33/bnB3/29xd/9zdXz/cnR7/2tudv9sb3n/bnF7/25xe/9qbXf/ -c3V8/3J0e/9wc3v/b3F4/3N1fP9wc33/e32D/3t9g/9+gYr/eXuB/3N1fP9sbnX/bnB3/2xudf9wcnn/ -bnF7/3Bzff9qbXf/bG95/2Zpc/9sb3n/bnF7/3R2e/9ucXn/bG51/3Fzev9ucHf/Z2p0/25xe/9zdn// -b3J8/3Byev9rbXT/aGtx/2dqcf9kZ3H/ZGdx/2Zobv9nanT/am13/2Zpc/9kZ3H/Zmhu/2xvef9nanT/ -bG51/2Zpc/9qbXf/bnF7/2ptd/93eoP/bnF7/2xudf9ucHf/c3V8/3N1fP9zdXz/bnF7/3N2f/9zdn// -c3Z//3N1fP93eoP/bnF7/25xe/9sb3n/bnF7/2xvef9sb3n/Z2px/2xudf9zdXz/cHJ5/2xudf9zdXz/ -bG51/2ptd/9sb3n/bG51/2ptd/9qbXf/am13/2dqdP9sb3n/ZGdx/2dqcf9nanH/bnB3/2ptd/9maXP/ -bG95/2ptd/9qbXf/bnF7/2ptd/9qbXf/Z2p0/2Zpc/9qbXf/bG95/2xudf9sb3n/bnB3/25wd/9ucXv/ -bnB3/3V3ff91eIH/dXd9/3Z4fP9ucHf/bG92/2hrcv9xc3r/a252/25wdv9ydX7/cHJ5/3Bzff9sb3n/ -b3J5/2tudv9xc3r/bG51/3V3e/9ydHv/c3V8/3N1fP9ucHf/bW92/3V3ff91eIH/amxz/2xudf9tb3b/ -b3F2/25weP9tb3b/amxz/29xdf91d33/c3V8/2xvef9wcnn/bnF7/3l7gf95e4H/cHJ5/3d5f/9ucHf/ -bnB1/2lsdf9ucHr/bG95/25xe/9qbXf/am13/3N1fP9sbnX/bW93/2xvef9vcXj/ZWhy/2ptd/90dnz/ -bnB1/2psc/9sbnX/bG51/3d5f/9tb3T/bW92/21vdv9rbnf/a254/2xudf9sbnX/eXyG/3Byef9sbnX/ -bnB3/25wd/9sbnX/bG95/2xvef9nanH/dXd9/3Z4fP91d33/cHJ5/3Byef9ucHf/c3Z//2psc/9zdXz/ -cHJ5/3N1fP9maG7/cHJ5/3Byev9wcnr/b3J7/2xudf9wcnn/bG51/2tud/9ydHv/bG52/3d5f/9tcHj/ -cHN8/3N2fv91d33/bnB3/2xvef93eX//dXiB/25wd/9sbnX/bG51/25wd/9zdXz/d3l//2ptd/9qbXf/ -bnB3/3Byef9vcXX/dnh8/21vc/9zdXz/cHN9/2xvef9qbXf/bG51/2xudf9qbXf/Zmlz/2xudf9qbXf/ -bG95/2xudf9maXP/bG51/2ptd/9ucHf/d3l//2ptd/9tb3b/cHN9/3F0fP9xc3r/cnV+/3d6g/9zdn// -cHN9/3R3gP90dn7/b3J6/25wd/9ucXv/cHJ5/3l7gf93eX//e36H/3d5f/91d33/bG51/25wd/9sb3n/ -cHN9/3N1fP9zdXz/bnB3/3V3ff9sbnX/cHJ5/3Byef9wc3r/aWx2/2VocP9kZ3H/ZGdx/11gav9kZ3H/ -Zmlz/2dqc/9rbXb/ZWhy/2ZpcP9nanH/bG95/2ptd/9sbnX/c3V8/3Byef9zdXz/bG51/2psc/9qbXf/ -Z2px/2psc/9maXP/Z2p0/2xvef9sbnX/eXuB/3Byef9ucHf/bG51/3Byef9wcnn/bnB3/2xudf9ucHf/ -bG95/2xudf9nanH/bG95/2dqcf9nanT/ZGdx/2Zpc/9sbnX/bG51/2Rncf9nanT/bnF7/2xvef9qbHP/ -dXd9/2ptd/9nanH/bG95/2dqcf9ucXv/bG95/25xe/9wcnn/bnF7/2xvef9qbXf/bnF7/3V3ff91d33/ -b3F1/3Byef9wcnn/bnB3/25xe/9sbnX/am13/2psc/9qbHP/bnB3/25wd/9sbnX/bG51/3N1fP9sbnX/ -bG95/21vc/9zdXz/dXd9/25xe/9wc33/am13/2dqdP9dYGn/aWx1/2ptdf9sbnP/b3F4/2xudf9ucXv/ -bG51/29xeP9rbXX/bnF5/21wef9ydHv/dHZ8/3R2ff9wcnn/bW92/2xvef9wc33/d3qD/2xudf9rbXX/ -a253/3Fzev9vcnv/b3F4/2xvef9vcXX/c3V8/3Byef9ucHf/bW9z/2xudf91d33/c3V8/21vc/94eX3/ -b3F1/25wdf9qbHL/cnR7/3N1fP9zdn//bnF7/25wd/9zdn//bG95/3Byef9vcnr/cXN5/21vdv9ydHv/ -dniB/3J0e/9wc3z/cHN9/3N1fP99gIn/b3F4/21wef9ucHf/bnB3/25wd/9nanT/bG51/3l7gf9ucXv/ -bG51/25wd/9ucHf/Z2p0/2ptd/9qbXf/ZGdx/2xvef9ucXv/Zmlz/2Zpc/9nanT/Zmlz/2xvef9qbXf/ -c3Z//3V3ff91d33/amxz/3Fze/93eX7/dXiC/3N2f/9wc33/eXuB/3J0e/9vcnz/cXR+/2ttd/91eH7/ -bG92/3Byef90dnz/dXd9/2xvef9nanT/cHJ5/3V3ff9sb3n/am13/2ptd/9wcnn/cHJ5/3l7gf9wcnn/ -bG51/21vc/9sb3n/b3F1/3h5ff9sbnX/c3V8/3V3ff9wcnn/bnB3/25wd/9ucHf/bnB3/2xudf9tb3P/ -bG51/25wd/9sbnX/Z2p0/2xudf9qbHP/am13/3N1fP9qbXf/aGty/2hrdf9tb3b/Z2py/2lrcv9sb3n/ -Z2p0/2Zobv9rbnj/bG95/2dqdP9jZm//ZWhy/2Rncf9sb3n/Zmlz/3Bzff9zdXz/dXiB/3Byef93eoP/ -cHN9/3l8hv97fYP/e32D/3V3ff99foH/dXd9/3l8hv95fIb/e3yB/3l8g/9ydH3/b3J7/25wd/9qbXf/ -bnB3/3Fzev92eH7/eXp//3p8gv92eH7/dXd9/3d6g/93eoP/dXd9/3d6g/9zdn//d3qD/3N1fP9wcnn/ -c3Z//3N1fP9zdn//c3V8/3Bzff91eIH/bnB3/3d6g/9wc33/bnF7/3Byef9wc33/dXd9/2ptd/9sb3n/ -bW9z/25wd/9ucHf/bnB3/3h5ff9ucHf/dXd9/2xvef9ucHf/bW9z/25wd/9nanH/bG51/3Z4fP91d33/ -b3F1/3Z4fP9vcXX/bW9z/3N1fP9qbXf/cHN9/2xvef9wcnn/dXd9/3Byef9sb3n/amxz/25xe/9wc33/ -bnF7/2psc/9qbXf/Z2p0/2Zobv9maXP/ZGdx/2dqcf9kZ3H/Zmlz/2psc/9qbXf/amxz/2psc/9zdXz/ -bnB3/2xudf9sbnX/bnF7/3N1fP9zdXz/dXd9/3N1fP9sbnX/ZWdt/2psdv9rbnj/a252/29yfP9sb3n/ -cHN9/2xvef9wcnn/aWxz/3Byef9tcHn/dHZ8/3R2fP9zdXz/cXN5/21wef9vcnv/dXiB/3t+h/9zdXz/ -b3F4/21wef9xc3r/am12/2hrdf9maXP/am13/25xe/9sb3n/bG51/2ptd/9qbHP/cHN9/3Bzff9sbnX/ -c3V8/21vdv9wcXf/c3V8/3t9g/97fYP/fX6B/3l7gf92eHz/foCG/3h5ff91d37/dHZ8/3Fzd/9ucHj/ -cXN6/3d6gv9vcnv/bG95/3Bzff9wc33/en2G/3N1fP9xdH3/cXN5/25xeP9xc3n/bG51/29xdf91eIH/ -bnF7/2dqdP9sbnX/bnB3/2psc/9sb3n/bnF7/2Zpc/9sb3n/c3V8/2xvef9wcnn/dXd9/2xudf9zdXz/ -Z2p0/3N2f/9wc33/cHN9/2ptd/9wc33/dHd//3N0e/9tcHT/bnB3/3N1fP9qbHP/bG95/3N1fv9rbXf/ -dXd9/21vdf9zdXz/dXd8/3N1fP9sb3n/Z2p0/3V3ff91d33/bnB3/2xvef9sbnX/bnB3/25wd/91d33/ -bW9z/2xudf9tb3P/bW9z/2ptd/91d33/bG51/3N1fP91d33/bnB3/25wd/9ucHf/bnF7/3Bzff9ucHf/ -bnB3/2xvef9wc33/bnB3/2dqdP9sb3n/bnB3/3N1fP91d33/bnB3/21vdP9wcnr/cXN5/21vdf9ucHf/ -c3Z//3N1fP9sb3n/cnR7/3N1e/9rbXT/aWx2/2xudf9nanT/c3V8/2xvef91d33/dXd9/2Rncf9kZ3H/ -Zmlz/2Jlbv9nanT/Z2p0/2Zpc/9kZ3H/Zmlz/2Rncf9qbXf/bG95/25wev9xdHz/bW93/29xef9sbnX/ -am13/25wd/9vcXn/cnR7/3ByeP9ydHv/bnB3/2xvef9zdn//bG95/25wd/9wcnn/cHJ5/3Bzff9qbXf/ -bW9z/25wd/9tb3P/bnB3/25wd/9sbnX/cHJ5/21vc/91eIH/cHN9/3N2f/93eoP/d3qD/3d5f/9wc33/ -cHJ5/21vc/9ucHf/cHJ5/21vc/91d33/b3F1/3V3ff9sbnX/bnB3/29xdf9sbnX/Zmhu/2xudf91d33/ -c3V8/29xdf93eX//b3F1/2xudf9ucXv/Z2p0/3Bzff9sb3n/bG95/25xe/9ucXv/bG95/2psc/9wc33/ -cHN9/3N1fP9sbnX/cHJ5/3N1fP9sb3n/bnF7/25wd/9ucHf/bnB3/2xudf9vcXX/bnB3/2xvef9sbnX/ -d3qD/3Bzff9zdn//c3Z//3d6g/95e4H/dXiB/3l7gf91eIH/am13/2ptd/9xc3r/bnB2/2xudf9ucHf/ -bW9z/3V3ff9ucHf/cHJ5/2lsc/9ucXv/b3F6/3V3ff90dnz/b3J7/3Byev9vcXj/b3F4/3V3ff93eX// -bG51/2hrdf9rbnj/bXB4/2Zpc/9rbXT/ZGdx/2dqdP9wcnn/am13/2dqcf9nanT/ZGdx/2Zpc/9maXP/ -Zmhu/2dqdP9jZm//aGpx/2hqcv9wcnr/cHJ5/3Byef9ucHf/bnB3/2xvef9ucHf/bW91/25xe/9qbXb/ -Zmlz/2lrdP9wcnr/bXB0/2dqcf9sbnX/bW9z/3Z5gv9tb3b/a254/21vd/9tb3b/c3V8/2xudf9vcXX/ -d3qD/3V3ff9ucHf/cHJ5/3Bzff9qbXf/bnF7/25wd/9qbHP/c3V8/3Z4fP9ucHf/cHN9/3Z4fP9ucHf/ -bnB3/2BjbP9qbXf/Z2p0/2ptd/9iZW7/am13/21wev9xdHr/bnB4/25wd/91d33/bXB3/29xef9ydX7/ -a213/3h6fv9vcXf/cnV9/3h6gP93eoP/c3Z//25xe/9+gIb/foGK/3l7gf97fYP/d3l//3t9g/93eoP/ -foGK/3V4gf93eoP/c3Z//3V4gf9zdn//eXyG/3N2f/95e4H/e32D/3N1fP9wcnn/cHJ5/25xe/9zdn// -c3V8/25wd/9ucHf/c3Z//3Byef9qbXf/b3F1/29xdf9wc33/dXiB/3Bzff9wcnn/bXB6/3Fze/9ucXr/ -bnB3/3N2f/9ucXv/bG95/3BzfP9xdH3/bnF5/2xvef9ucHf/cHJ5/3h5ff9wcnn/foCG/3t9g/9qbXf/ -am13/3Bzff9qbHP/bG95/2xvef9nanT/amxz/2xvef9maXP/bnF7/3Bzff9wc3z/cXR+/25xeP9vcnz/ -c3V8/2ptd/9qbXf/b3F5/3J0ev9vcXf/am13/2dpc/9nanT/cHN9/2xudf9sbnX/cHN9/25xe/9wc33/ -Zmlz/2xudf9qbXf/amxz/2dqcf9kZ3H/Zmhu/2dqcf9qbHP/cHJ5/2ptd/9qbHP/am13/2Zpc/9sb3n/ -amxz/2ptd/9nanT/amxz/25xe/9qbXf/c3V8/2psc/9sb3n/Zmlz/2psc/9qbHP/amxz/2Jlbv9maXP/ -bnF7/2xvef9sbnX/dXd9/2psc/9sbnX/cHJ5/2xudf91d33/bnB3/2xvef92eHz/bnB3/25wd/9tb3P/ -eHl9/3N1fP9zdXz/cHJ5/3N1fP9zdXz/bnF7/25xe/9sb3n/bW9z/2xudf9ucHf/bG95/25wd/9wcnn/ -b3F1/3Byef9qbXf/bG95/2ptd/9wc33/cHN9/2xvef9wc33/bG95/2Jlbv9hZG3/bG51/21wef9qbXf/ -bnB6/3Byef91eIH/bnB3/2xvef9naXP/cHJ5/29xef91d37/dHZ9/25xev9vcXr/bnF4/3Byef91d33/ -d3l//25wd/9vcXj/cHJ5/3F0e/9ucHf/b3F4/25wd/9wcnn/dXd9/25wd/9qbHP/bnF7/3Byef9sb3n/ -bnF7/2xudf9wc33/b3F1/21vdv9sb3b/dXd9/25wd/9zdXz/bnB3/2xudf9sbnX/bW9z/2hrdP9wc3v/ -bXB6/2ptdP9qbXT/c3V8/21vdf9iZW7/ZGdx/2dqcf9ydX7/a211/2tueP9rbnj/bXB3/3N1fP9sbnX/ -bnB3/3t9g/91d33/bnB3/25xe/9zdn//am13/3Bzff9sb3n/bG95/3Bzff91d33/cHJ5/3N1fP91d33/ -bG51/3Byef9qbXf/dXiB/3N1fP9zdn//bnB3/3N2f/9xdH7/dnh+/3F0fv9wcnn/dXd9/2xudf9vcXf/ -dHZ8/21veP91d37/bW92/21wev90dnz/c3V8/21vc/9ucHf/dXd9/3d5f/9ucHf/bnB3/2xudf9sb3n/ -bnB3/3V4gf9qbXf/bnF7/25wd/9sbnX/bnB3/3V3ff9vcXX/dXd9/3V3ff9ucHf/bnB3/2xvef9wc33/ -cHN9/3Byef9wcnn/cHN9/3V4gf9zdn//bnF7/3N2f/91d33/eXyG/36Biv91eIH/dHeA/3Fze/9wc3v/ -a252/2hrcv9maXP/YmVu/2Zobv9nanP/bG94/2xudv9pbHb/cHJ5/2ptd/91d33/bG95/36Ahv97fYP/ -am13/2xudf91d33/amxz/3V3ff9wc33/bG95/2xudf9zdn//Z2p0/3N2f/91d33/cnR7/3Byef9ucHf/ -cHJ5/2xvef9maXP/amxz/29xef9vcXj/cHJ3/25wev9qbXf/Zmlz/3Bzff9sbnX/am13/3Bzff9ucXv/ -cHN9/2ptd/9sbnX/bG51/2psc/9qbHP/Zmlz/2dqcf9nanH/bG51/3V3ff9wc33/bG51/3N1fP9sb3n/ -c3V8/2xudf9wcnn/am13/21vc/9zdn//cHN9/3d5f/9vcXX/dXd9/2psc/9ucXv/bnF7/25xe/9nanH/ -bG95/3V4gf97fYP/c3V8/3l8hv9wcnn/cHN9/3N2f/9ucHf/dXiB/3N2f/9wc33/eXuB/3Bzff9ucXv/ -bG95/3Z4fP9wcnn/c3V8/3Byef91d33/cHJ5/25wd/9qbXf/am13/21vc/9qbXf/am13/2xvef9sbnX/ -cHJ5/25wd/9wcnn/cHJ5/25wd/9wc33/dXd9/3l7gf91d33/dXd9/3Bzff9sb3n/am13/3Bydv9tb3b/ -am13/2ptd/9sbnX/dXd9/25wd/9wcnn/Z2px/3Byef9ucHn/dHd//3d4ff9vcXj/cXN5/2tud/9sb3n/ -c3V8/3V3ff9sbnX/aGt1/21wev9tb3j/Zmlz/2hrdf9maXP/cHN9/3Bzff9qbXf/Z2p0/2xvef9ucXv/ -bG51/25xe/9qbHP/bG95/2xudf9ucXr/aWx0/3J0e/9sbnX/cHN9/25xe/9nanT/bG95/2xudf9sbnX/ -c3V9/3R2fv9tcHr/cHJ3/3R2fP9wcnn/am13/2dqdP9ucHf/dnmC/25xe/9ucXv/bnF7/25xe/91d33/ -bnB3/29xdf93eX//cHN9/2ptd/9qbXf/cHN9/2Rncf9sbnX/Z2p0/2Rncf9nanT/bG95/2Zpc/9maXP/ -bG95/2dqcf9qbXf/YGNs/2xvef9sb3n/bG95/2psc/9sbnX/a212/3N1e/9zdXz/b3F1/3d5f/9tcHr/ -cXR8/3Z4gP9ucXr/dnh//25wdf9ucHf/dXd9/2xvef9qbXf/bG51/3V3ff93eX//bG95/3Byef9ucHf/ -bG95/25wd/97fYP/b3F1/3Byef9wcnn/bG51/2xudf93eX//am13/3Bzff9wc33/bW9z/2ptd/9nanT/ -am13/2xvef9sbnX/Z2p0/2xudf9nanT/amxz/11gav9sbnX/Z2px/2ptd/9zdXz/bG95/2xvef9sbnb/ -cHJ6/21wev9sb3n/bnF7/2xvef9ucXv/dHeA/3Z4f/9xdH3/am13/3Bzff9zdXz/e32D/3V4gf+Fh43/ -f4KM/25xe/9sb3n/d3l//2xvef93eX//cHN9/3Bzff9zdXz/dXiB/2xvef94eoH/dnh+/25xev9ucXr/ -aGp0/2dqcf9nanT/XWBq/2Rncf9qbXb/bG93/21vd/9ucXj/bG51/2psc/9zdXz/Z2p0/2xvef9sb3n/ -bnB3/25wd/9qbXf/am13/2psc/9sb3n/bG51/2ptd/9sbnX/am13/2xudf93eX//eHl9/3Byef91eIH/ -c3Z//3d5f/9ucHf/c3Z//25wd/9ucHf/c3Z//25wd/93eX//bnB3/3Z4fP9nanH/bnB3/29xdf9ucHf/ -Z2px/2psc/91d33/c3V8/2psc/91d33/amxz/2psc/9sb3n/ZGdx/2dqdP9maXP/Zmlz/25wd/9qbXf/ -Z2p0/2ptd/91d33/bnF7/25xe/9tb3P/dXd9/3Bzff9ucXv/cHJ5/25xe/9ucHf/bnB3/3Byef9zdn// -c3Z//3V4gf9wcnn/eXuB/3l8hv91eIH/e32D/3t+h/97fof/eXuB/3l7gf93eoP/bnF7/2ptd/9xc3r/ -cnR7/2xvd/9tb3f/bnB3/3N1fP9sb3n/cHN9/2dqdP9wc3v/cXN8/3V3ff92eHz/bnB6/3Bye/9tcHj/ -bnB3/3V3ff94eX3/b3F1/21vdv9tcHr/bnF5/2tueP9qbXf/Z2p0/3N1fP9sb3n/amxz/2dqdP9sb3n/ -bG95/2psc/9nanT/Z2px/2xvef9maG7/Zmly/2Rncf9ucXr/bG51/3Bzff9ucXv/Z2p0/25xe/9sbnX/ -Z2p0/2hrdf9oa3X/ZWhv/2Rmbv9maXP/a254/2dqdP9iZW7/Z2px/29xeP9maXP/aWx0/2ptd/9rbnj/ -cHN9/2ptd/9qbXf/d3qD/3N1fP9sbnX/bnB3/3Byef9sb3n/bnF7/3Byef9ucHf/bG95/3V3ff9sb3n/ -bnB3/3Z4fP9vcXX/dXd9/2BjbP9sb3n/cHN9/2xvef9tb3P/b3F4/21wev9xdH3/bnF7/2xvef93eX// -bG95/2xud/90dnz/bG94/3Bzff9rbnb/bG95/3V3fP9ucHf/bnB3/2psc/92eHz/dXd9/25xe/9ucXv/ -bnF7/3Byef9ucXv/f4GH/3Byef9wc33/c3Z//25xe/9ucXv/d3qD/2xvef9wc33/cHN9/25wd/9ucXv/ -bnF7/3V4gf91eIH/bnF7/25wd/9ucHf/cHJ5/21vc/9iZW7/amxz/2psc/9qbXf/cHN9/2dqdP9ucXv/ -bG51/29xev9rbnj/cnV+/3Bzff9ucXv/bG95/3J1fv91dnv/cHN6/2hrdf9oa3X/Z2p0/3V3ff9ucHf/ -fX6B/3d5f/9wcnn/bnF7/3Z4fP9ucHf/dnh8/2xvef9ucXv/Z2p0/2ptd/9kZ3H/bnF7/3Byef9pa3T/ -bG95/2dqc/9sbnX/am13/2dqcf9qbHP/bnB3/21weP9tb3f/cnR7/25wd/9nanT/cHN9/2Zpc/9qbHP/ -amxz/2ptd/9ucXv/Z2p0/2xvef9qbXf/bG95/2xudf9nanT/Z2p0/2xudf9maXP/bnB3/2xvef9maG7/ -am13/2xvef9ucXv/Zmlz/2dqdP9maG7/Zmhu/2ptd/9nanH/c3V8/2psc/9zdXz/ZGdx/2ptd/9qbHP/ -amxz/2Jlbv9maXP/bnF7/3N1fP9nanH/cHN9/2psc/9sbnX/bG95/2psc/9sb3n/am13/2xvef92eHz/ -cHJ5/3Byef9ucHf/dXd9/25wd/9wcnn/bG51/3N1fP9wcnn/cHJ5/29xdf9vcXX/bG51/25wd/9sb3n/ -bnF7/2xvef9ucHf/bG51/25wd/9zdXz/bG51/3Bzff93eX//d3l//3V4gf9wc33/c3Z//2dqdP9nanT/ -b3J7/21wef9sb3f/bW91/25wd/9zdXz/bG95/3N1fP9qbHP/cHJ5/3Bzff91d37/eHl+/3V3ff9ydHn/ -bnF6/3Byef91eIH/eXuB/3N1fP9xc3r/cnV+/25wef9ucHf/bG51/2xudf9wc33/dXd9/25wd/9sbnX/ -c3V8/3V3ff9tb3P/bnB3/21vc/9ucXv/am13/21vdf9qbHH/cXN6/21vc/92eHz/c3V8/29xdf9ucXv/ -am13/2xvef9xdHv/cHN8/21vdv9tb3j/b3J8/3R3gP9qbXf/am13/25wd/91d3v/cXN3/3Byd/9tb3j/ -bG95/3h5ff9ucHf/bnB3/3l7gf9zdXz/amxz/2ptd/9wc33/Z2p0/2ptd/9qbXf/Zmlz/2xudf9wc33/ -bG51/2psc/9wc33/amxz/25xe/9sb3n/dXiB/3t9g/91eIH/dXd9/3h6gP91eH//dnh+/25xev9qbXf/ -cHN9/2hrc/9sb3f/dnh9/21wev90doD/cnV9/3V4gf96fIL/d3qD/3Bzff9wcnn/eXyG/3t+h/9wc33/ -bnF7/25wd/9wc33/cHN9/3l8hv9vcXX/c3V8/25wd/9tb3P/bG51/3V3ff9sbnX/cHN9/3N2f/9ucHf/ -bnF7/2ptd/9wc33/cHN9/3Bzff9sb3n/bnF7/3Bzff9vcXX/ZGZs/29xdf9ucHf/cHJ5/3V3ff9ucHf/ -dHZ9/21vdv9xc3r/cXN7/3Byef9wc33/cHN9/29ye/9ydX7/cnR7/21vdv9sbnX/cHJ5/2dqcf94eX3/ -bG95/3t9g/91d33/cHJ5/25wd/92eH7/bnB3/3h5ff9wc33/cnV+/21wd/9rbnj/bG95/29yfP91d33/ -bnB4/21wef9rbXf/bG51/2ptd/9kZ3H/Z2p0/2xveP9tcHj/a253/3Fze/9sbnX/Z2px/3R2fP9qbHP/ -bG51/25wd/9wc33/cHN9/2xudf9wc33/bG51/2ptd/9sbnX/Z2px/2xudf9qbXf/bnB3/3Z4fP9wc33/ -bG95/3V3ff9zdn//c3Z//25wd/9ucXv/bnB3/25wd/9zdn//bG95/3V4gf9ucHf/dXd9/2ptd/9zdn// -bnB3/3Byef9nanT/bnB3/3V4gf93eoP/bG95/3V3ff9tb3P/bG51/3Byef9tb3P/bnF7/25xe/9ucHf/ -dnh8/3N1fP9qbXf/amxz/3Bzff9ucXv/c3V8/2xudf9zdXz/bG95/2xudf9qbHP/am13/2ptd/9qbXf/ -am13/25wd/9ucHf/c3V8/2xvef9sbnX/dXd9/25xe/91eIH/eXyG/3l8hv93eoP/c3Z//3V4gf9ucXv/ -bnF7/3V4gf9wcnr/cHJ3/3BzeP9vcXX/dXd9/25wd/9wcnn/bG51/25weP91d3//dnmA/3h7hf9zdoD/ -dnh+/29yfP9ucXv/c3Z//3d5f/9wcnn/bnB0/3Fze/9ucHj/bnB4/29xdf9vcXX/c3V8/3N1fP9ucHf/ -amxz/3N2f/91d33/bG51/3Byef9sb3n/bG95/2xudf9sbnX/ZGdv/3Fzff9qbHP/dXd9/25xe/9nanT/ -bG95/2ptd/9qbXf/bXB4/21wef9sb3j/am1z/25wd/9wc33/ZGdx/2dqcf9ucHf/dnd8/29xef9ucHn/ -bG94/25wd/94eX3/bnB3/3Bzff97fof/dXd9/2psc/9sbnX/dXd9/2xudf9sbnX/bnB3/2xudf9sbnX/ -dnh8/25wd/9ucHf/dXd9/25wd/9zdXz/YGNs/2xudf9sb3n/amxz/2psc/9rbnj/bG51/3Fzef9wcnn/ -bG95/3l7gf9ucHf/bnB5/3d5gf9vcXj/c3Z//2xvdP9pbHX/am13/2dqdP9maG7/Zmlz/3Byef9zdXz/ -bG95/2xvef9tb3P/am13/2ptd/9zdn//am13/2xvef9sb3n/bG51/21vc/91d33/am13/2xvef9zdXz/ -bG51/2xvef9maXP/bnF7/25xe/9ucXv/am13/2xudf9nanT/Zmhu/2BjbP9qbHP/am13/2ptd/9ucXv/ -bnB3/3V3ff9tb3b/b3F5/25weP9vcXj/bnB3/3ByeP9ucHb/cHJ5/29yfP9vcnz/bG54/29ye/9qbXf/ -dXiB/3N2f/9/gYf/eXyG/3h6gP93eX//fH6E/3J0e/95fIX/c3Z//3R3f/9wcnj/bXB5/25wd/9zdn// -dHeB/3F0fP9xdH7/bnB3/3Byef9zdXz/bG95/2xvef90dn//cnV//29yfP91d33/cHJ5/21vdv91d33/ -bnB3/3Byef9vcXv/dnh9/3V3ff9ucXr/dnl//3N1fP9ydX//bG95/2xveP9vcXj/cXR9/29ye/94eoH/ -d3qD/3N2f/96fIL/enyC/3t9g/91d3z/dnh//3Z4fv9zdn//enyC/3V3e/9+gIb/enyC/31+gv9zdXz/ -eXuB/3h5ff91d33/cHJ5/3d4ff96fIP/gIKJ/3V4gf94eoH/d3mC/3V3ff93eYL/cHJ5/3Z5gv91eID/ -cHN9/3p8gv91eID/cHN9/3N1fP93eoP/c3Z+/3Bzff9sb3n/c3Z//3Bzff9vcXX/bG51/25wd/9qbXf/ -Z2pz/2xudf9wcnn/bnB3/3N1fP9sbnX/bG51/3V3ff9sbnX/cHJ5/3V3ff93eX//c3Z//25xe/9wc33/ -bG95/2xudf9wcnn/b3F2/2xudf9rbnj/bG51/25xe/9qbXf/bG51/2Jlbv9pa3X/b3J6/3J1ev91d37/ -cnV+/3Byef9sb3n/bG92/3Bzff91d33/Z2p0/2lsdf9tcHr/bG93/21wef9ucHf/b3F1/3V3ff91d33/ -cHN9/2xvef91eIH/dXd9/25wd/9wcnn/cHJ5/3Byef9ucHf/cHJ5/2lrc/92eYD/bG95/3l7gf91d33/ -bnB3/25xe/9sb3n/bG95/3J0e/9xc3j/bnF5/2lsdP9sbnX/bnF7/2Jlbv9maXP/bG51/3J0e/9sbnf/ -a252/25wd/9ucHf/dnh8/2xudf9ucHf/dXiB/3Bzff9nanT/bnB3/3Z4fP9sbnX/bG51/25wd/9qbXf/ -am13/3Bzff9qbXf/am13/3V4gf9tb3P/cHJ5/2dqdP9sb3n/c3V8/3Byef9ucHf/dHeA/3Bzff91d3// -dHeB/2xvef95fIb/cHJ5/25xev93eYD/bW92/3R3f/9vcXj/bW92/3N1fP9wcnn/bnB3/2xvef91d33/ -dnh8/3V3ff9wcnn/bG95/3Bzff9zdn//eXyG/3Byef9ucHf/bnB3/25wd/9vcXX/dnh8/25wd/9zdXz/ -cHJ5/2xudf9wcnn/amxz/3Bzff9zdn//dXd9/25wd/9ucHf/cHJ5/2psc/9kZ3H/bG51/2xvef9nanT/ -cHN9/2dqdP9sb3n/aGt1/25weP9tcHf/cHN7/21vdv9ydXz/cHN7/3ByeP9ydHz/am12/2dqdP9rbXT/ -ZGdx/2xvef9qbXf/c3Z//3N1fP9xdHz/b3F4/3Z4fv9ucHf/dnh9/29xeP9wcnv/bG51/2lsdP9sbnT/ -bG93/3Byev9tb3b/cnR7/2xudf9ucHf/bG51/2dqcf9maG//bXB3/25wd/9tb3X/cnR6/29xev9rbnb/ -cnR5/3J0ev9wcnv/cHN8/3N1fP92eID/cHN9/3J1fP9ucHj/cXR9/29xeP9vcXj/bnB4/29yef9ucHj/ -d3h9/3BzfP9xc3r/dXd+/3J1fv91eID/bnF6/3N2gP9ucHf/b3F5/3J0e/9sbnb/dHZ7/2xvef9zdXz/ -am12/3F0ff9sb3j/bG94/2Zobf9rbXT/cXN6/3l7gf9vcXb/cnV+/3Bze/9tcHn/cXN9/25wd/9wcnz/ -cHJ5/2xvdv91d37/cHJ8/21vc/9ucHf/dHZ8/3J0e/9xdH3/bnB3/3J1fv9ydX3/bnB3/25wd/9ucHj/ -bW93/2ttdP9sbnX/bG95/2xudf9pbHb/Zmlz/25xe/95e4H/c3V8/3V4gf97fof/e36H/3d5f/9wc33/ -c3Z//25wd/9qbXf/dXd9/29xeP9sb3f/b3F3/25wd/91d33/bnF7/25xe/9sb3n/b3J7/3J1f/90d37/ -dnh//3N2f/9ydH3/b3J7/25wd/9wc33/dXiB/25wd/9tcHr/dXd+/25xef9sb3n/bnB3/25wd/93eX// -dnh8/2xvef9qbXf/dXd9/3N1fP9ucHf/c3Z//3Bzff9wc33/cnV+/3N2f/9pbHT/dniA/25wd/91d33/ -bnF7/21vc/9tb3P/bG51/2tueP9xdH7/cXN8/3Bze/9rbnj/a254/3N1fP9nanH/bG51/21vc/9zdnz/ -b3J6/29xdv9ucHT/bnB3/3d5f/9vcXX/cHJ5/3V4gf9wc33/bG95/2xvef91d33/bG95/3Byef9wcnn/ -bnB3/29xdf91d33/b3F1/25wd/97fYP/bnB3/3Byef9ucXv/c3Z//3d6g/9zdn//cHN9/3N2f/9wcnv/ -cXR8/25xe/9kZ3H/dXiB/2psc/9laHL/c3V8/2hrdP90dn3/bnF5/2xvef9vcnz/bnF7/25wd/9sbnX/ -bnF7/25xe/9zdXz/cHJ5/25wd/9wcnn/bnB3/3t+h/9sb3n/bnF7/3V4gf9sb3n/bnB3/3d5f/9ucHf/ -dXiB/3N2f/9ucXv/cHN9/2ptd/9ucXv/c3V8/3V3ff9ucHf/cHJ5/25wd/9ucHf/bG51/2ptd/9ucXv/ -cHJ5/3V3ff9sb3n/bW95/2hrdf9ucHf/bG52/21vd/9qbHP/bnB2/3J0e/9oanL/bG53/2hrcv9iZW7/ -a210/2BjbP9nanT/am13/3V3ff9zdXz/cHN9/21vd/9wc33/a254/3h6gP9rbnf/bW95/2hrdf9iZW// -aWxz/2lsdP9tb3X/aWx2/25xe/9qbXf/bG51/2Zpc/9iZW7/YmVu/2ptd/9ucHf/bW94/29xeP9tcHr/ -bnF7/25xef91d33/cnR7/3F0e/9wc3z/dHeB/3R3gP9ydHr/bnB2/3R2fP91d33/cXN7/3Fze/9zdn7/ -b3J6/3J1fP9ydX3/dHZ9/3V3ff9xdH7/cnV//21weP9ydHz/bW92/29xeP9sb3f/bG51/25xef9sb3f/ -cHN7/2ptdv9ucHn/a252/29xeP9kZ3H/aGt1/25xe/91eH//bG51/21wev9tb3b/bG53/29yfP9pbHb/ -aWx2/2xud/9rbXX/cXR7/21wev9oa3P/a212/29yfP9vcXr/c3aA/25xe/9xdH7/bnB5/2xvdv9wcnr/ -bnB4/2xvef9ucHj/bnB1/3Byef9vcXX/bnB4/2lsdf9wcnn/c3V8/2ptd/9sb3n/dXd9/3V3ff92eHz/ -dXd9/25xe/9ucHf/bG95/3V4gf9zdXz/bW94/25xe/9ucHX/c3V8/25wd/9sb3n/Zmlz/21wdP9zdn3/ -c3V7/3Z3fP9zdXz/cXN5/25wdv9sb3n/cHJ5/3V3ff9ucHf/b3F4/3R2e/9tb3b/a253/2hqdP9sbnX/ -bnF7/2ptd/9nanH/ZGdx/25xe/9maXP/YmVu/2Rncf9nanH/Zmlz/2ptd/9oanT/Y2Zu/29ye/9nanT/ -cHJ5/2dqdP9kZ3H/Zmhu/2Zobv9jZm//bG95/25xe/9sb3n/amxz/2ttdP9sb3n/ZGdx/2Zpc/9sbnX/ -dHZ8/3Fzd/9tb3f/b3F2/29xdf95e4H/b3F1/3N1fP94eX3/c3V8/25wd/9ucHf/dXd9/2xudf9ucXv/ -bnF7/25wd/9sb3n/c3V8/2xvef9wcnn/foCG/2xvef9wc3z/Zmhu/2xudf9wcnn/cHJ5/25wd/9wcnn/ -bnB3/3J0ev9ydHv/Z2px/3l7gf9ucHf/Z2p0/3l7gf9wcnn/eXuB/3J0ef9ydHv/cHJ5/25wd/9vcXX/ -bnB3/3Bzff9wc33/c3Z//3N2f/9ucXv/c3Z//3N2f/9+gYr/c3Z//3N2f/93eoP/d3l//3V3ff9/gYf/ -dXd9/36Ahv99foH/dXiB/36Ahv9ucXv/d3qD/3l7gf95e4H/dXiB/3d6g/9zdn//dXiB/25xe/9wc33/ -dXiB/3V4gf9zdn//bG95/3N1fP9ucHj/cnV9/25xev9vcnv/a253/3Byef93eX//aGpu/3BzfP9tb3b/ -aGt1/25wd/9nanT/cHN9/3N2f/91eIH/d3l//3R2fP9vcXj/d3mC/21wev93eoP/cnV+/25xe/9ydHv/ -aGt0/3J1fv9wc33/dXiB/3V3ff97fYP/dnh8/3V4gf91d33/cHN9/2xvef9zdn//c3Z//3R3gf90dn// -eHqA/3p8gP92eH3/foCH/3x9gf90d4D/c3Z//3Z4gP93eoT/dHZ8/25wd/93eX//eHqA/3V4gP9zdn7/ -dXeA/25wev9ucXr/cXR9/3R2ff9vcXr/bnF6/3J1ff9tb3b/cXN6/25wdv9ydHr/bnB3/21vdv9vcXf/ -aWx1/3R2fP9vcnz/dHd+/3J0ff91eID/bXB6/3Fzev90d4D/eHuE/29yfP9vcnv/cHN9/3R3fv93eoL/ -d3qC/3V4gP94eoD/d3l+/3l7gf93eX//cnV+/3N2gP93eYD/d3l+/3+Bh/93eYH/eHqA/3h6gv94e4L/ -dXh//3l8g/91eH//dnh//3Fze/9ydHr/b3J6/3F0fv9wcnr/d3qD/3t9g/91eIH/d3qD/3t+h/97fof/ -d3qD/3d6g/9wc33/bnF7/2xvef91d33/bG95/21wef9tcHr/bG51/3J1fP9ucHf/c3V8/25wd/9tb3f/ -bXB6/29yev9xdH3/a253/21weP9tb3b/bG95/3N1fP93eX//bnB3/29xeP9ydHv/bW92/2tud/9qbXf/ -bG95/3d5f/9wc33/am13/2Zpc/91d33/cHN9/2ptd/9ucXv/bG95/3Byef9ydHz/c3V7/2hqcv92eH// -am13/3V3ff9zdXz/bnB3/25wd/9ucXv/bW92/3Fze/9ydX3/cnR8/2xudv9vcXj/cHJ5/2dqcf9qbHP/ -bG51/3N2f/90dnz/dHeA/3R2ff9ucXv/d3l//25wd/9zdXz/d3l//2xudf9qbXf/Z2p0/25xe/9nanT/ -am13/2dqdP9qbHP/Z2p0/25xe/9qbXf/am13/3l7gf9tb3P/cHJ5/2BjbP9sbnX/cHJ5/2xudf9ucHf/ -cHJ5/21wev9ydHv/dHeA/2Zpc/93eX//bnB3/2ptd/92eHz/bnB3/3p7gP9ydHr/cnV//25xe/9vcXX/ -b3F1/2ptd/9wcnn/cHJ5/3V3ff91d33/b3F1/2xudf9qbXf/d3qD/2ptd/9sb3n/bnF7/21vc/9sbnX/ -bnF7/2psc/9sb3n/bnF7/2xudf9wc33/XWBq/2xvef9ucXv/bnF7/2Zpc/9qbXf/bG51/2xvef9kZ3H/ -amxz/2ptd/9sb3n/bnF7/25wd/90dn3/bG92/25xe/9sb3n/aGt0/2Rncf9qbHT/c3V8/2RmbP9wc33/ -cHN6/21wev9zdn//cHN9/3l8hv93eoP/f4KM/3+Bh/94eX3/bG95/3N2f/9wcnn/eXyG/3N2f/9wcnn/ -bnB3/2ptd/9ucXv/c3Z//3Bzff9zdXz/d3qD/3Byef9ucXv/bnF7/25xe/9sb3n/c3Z//3N2f/91eIH/ -bnF7/3N2f/96fIL/c3Z//32Aif95e4H/c3Z+/3Bzff9zdn//fYCJ/3d5f/92eH7/en2G/3p9hv92eYL/ -dXiB/3V4gf90d4H/c3Z//3V4gf96fIL/b3F4/3Bzff9ydX7/cHJ5/3Bzff9wcnn/dHeA/25weP9ucHf/ -bW92/2hrcf9xc3n/cHJ5/3Z4fP9ucXr/cHN8/2ptdv9qbXf/c3V8/3d5f/9qbXf/aGt1/2xudf9sb3n/ -bG95/21wev9tb3b/a254/2hqcf9maXP/a210/2Vocf9nanT/a210/2hrcv9ucXv/a210/2Nmb/9naXP/ -aGt0/2dqdP9maXL/Z2lw/2hrdf9kZ3D/ZGdw/2Zpc/9iZW//ZWhw/25xe/9wc33/bnB3/25wd/91d33/ -d3l//3N2f/91d33/bnF7/2xvef9sb3n/dXd9/25wd/9ucHj/cHJ7/2xveP90dnz/bnF7/2dqdP9zdXz/ -bG51/29xeP9ydH3/dHeA/3N1fv9maXP/a211/2xudv9qbXf/am13/3Bzff9vcnv/bXB6/2lsdP9sbnX/ -bW92/2ptd/91d33/bnF7/2dqdP9nanT/cHN9/3N1fP9qbHP/bG95/2ptd/9qbXf/bnF6/25xe/9laHL/ -bnF6/2Nmb/9qbXf/bG51/2Rncf9maXP/bG51/2xvef9qbXb/bG51/2ptdP9oa3P/c3V8/3Bzff91d33/ -ZGdx/2psc/9tb3X/cXN5/29xef9sb3n/bG51/3d5f/9sbnX/cHN9/3d5f/9qbXf/Z2p0/2Zpc/9zdXz/ -bW9z/29xdf9ucHf/amxz/21vc/9zdXz/cHJ5/3N1fP9+gIb/bnB3/3Bzff9kZ3H/bnB3/3N2f/9sb3n/ -bnB3/29xeP9wcnn/cXN7/2xudf92eHz/cHJ5/2xudf9ucHf/eHl9/21vc/91d37/b3F4/29xeP9ucHf/ -bnB3/3Byef9sb3n/dXiB/3N2f/93eoP/eXuB/3Bzff91eIH/c3Z//3+Bh/9zdn//d3qD/31+gf9zdn// -c3Z//3l8hv9zdn//e32D/3V4gf9zdXz/eXuB/2Zpc/93eX//c3Z//3Z4fP9ucHf/bnB3/25wd/9wcnn/ -am13/25wd/9wcnn/bG51/25xe/9qbXf/bXB6/2ttdP9oa3P/aGty/2ttdf9nanT/c3V8/2dqdP9rbnj/ -cXN7/2ttdP9kZ2//bW91/2dqdP9sb3n/cHJ5/3d5f/93eX//bG51/2xudf9wcnn/dXd9/2xudf9sbnX/ -c3V8/25wd/9wcnn/bnF7/3Bzff9ucXv/bnB3/2ptd/9ucHf/bnB3/3Bzff9ucXv/eXyG/3V3ff93eX// -c3Z//3N2f/9wcnn/dXiB/3l7gf91eIH/cHJ5/3t9g/97fYP/foCG/3t9g/9ucXv/c3Z//3l7gf9wcnn/ -eXuB/3Bzff9wc33/bG95/2Zpc/91d33/cHN9/2psc/9ucHf/bG95/3N1fP9vcXX/cHJ5/25wd/9zdXz/ -am13/3V3ff9wcnn/bG95/2ptd/9kZ3H/bG51/25wd/9tb3P/cHJ5/25xe/9zdn//cHJ5/25xe/9zdXz/ -c3V8/3d6g/9wc33/d3qD/3t9g/93eoP/d3qD/3t+h/97fYP/eHuF/31/hf96fIP/c3Z//3J1f/95e4H/ -am13/3N1fP9wcnn/bG95/3R2fP9ydHv/dXd7/2dqcf9ucHX/bnB3/21vd/9ucXv/dnh8/2xudf9ucHf/ -dXd9/3d5f/9zdXz/bnF7/2ptd/9qbXf/bG51/3N1fP9qbXf/bG95/2xvef9qbXf/dHZ8/2xvef9maXP/ -dXd9/2ptd/9sb3j/cnR7/3F0ff9xdHz/Z2lx/21vdv9wcnn/bnB3/3N1fP92eHz/cHJ5/3Byef9sbnP/ -am13/21vdv9wc33/dXd9/25xe/9qbXf/b3F1/3Z4fP9zdn//b3F1/3Byef9wc33/bnF7/3Bzff90dnz/ -bG93/3R3gP9nanT/bnF7/25xe/9sb3n/bG95/3V4gf92eYL/c3V9/3N2fv9vcnr/b3F4/3d5f/91d33/ -d3qD/2xvef9ucHf/b3F4/3J0ev9ucXv/cHN8/2xvef93eoP/bW9z/3Byef92eHz/am13/2dqdP9qbXf/ -cHN9/2xudf9ucHf/bG95/2xudf9ucHf/dXd9/3Byef91d33/fn+D/25wd/9ydHz/Z2p0/25wd/9wc33/ -bnB3/2xvef9sb3j/cXN5/21wev9nanT/bnF7/2psc/9nanT/bG51/3h5ff9vcXX/eXuB/3Byef9vcXn/ -bnB3/2ptd/9qbXf/Zmlz/2xvef9ucXv/am13/3N1fP9qbHP/Z2p0/2dqcf91eIH/am13/2ptd/9wcnn/ -bW9z/21vc/9wcnn/bW9z/3Byef9sbnX/bG51/3N1fP9iZW7/c3V8/25xe/9zdXz/bG51/2xvef9sbnX/ -cHJ5/2xudf9ucHf/c3V8/25wd/9wcnn/cHJ5/3N1fP9tb3P/bW92/2ptd/9sbnX/Z2p0/3N1fP9nanH/ -b3F5/3F0ff9sb3f/Zmhv/29xeP9sbnX/cHJ5/3V3ff97fYP/eHl9/21vc/9sb3n/c3Z//3N2f/9sb3n/ -bnB3/25xe/9ucHf/bnB3/3N1fP91d33/bnF7/25wd/9ucHf/bG95/25wd/9ucXv/bnB3/3l7gf9zdXz/ -eHl9/3N1fP9wc33/bG95/3N1fP9wcnn/cHJ5/2xudf9zdXz/dXd9/3V3ff9zdXz/Z2px/29xdf91d33/ -b3F1/3V3ff9ucHf/c3V8/21vc/9maG7/cHN9/2xudf9nanT/Z2p0/2xudf9sb3n/am13/2dqdP9nanH/ -am13/2Zobv9ucHf/Zmlz/2Zobv9gY2z/XWBq/2dqcf9nanT/YmVu/2Zpc/9kZ3H/ZGdx/2Jlbv9iZW7/ -ZGdx/2Jlbv9maXP/Z2px/2dqdP9wcnn/Z2p0/2Rncf9qbXf/Z2p0/2Zpc/9maXP/Z2p0/2Zobv9qbHP/ -am13/2Jlbv9maG7/ZGdx/2dqcf9sb3n/bG95/2xvef9nanT/bG95/2psc/9sbnX/bnF7/3N1fP9qbHP/ -am13/25xe/91d33/bG95/2ptd/9nanH/amxz/2Rncf9qbXf/amxz/2tueP9rbnj/am11/3V3e/9wcnn/ -amxz/3d5f/9sb3n/bnF6/3F0fv9xdH3/dHZ8/2dqcv9tb3b/cHJ5/2xudf9zdXz/dXd9/21wev9tcHr/ -aWx2/2xvef9tb3n/dXiB/3d6g/9wcnn/bnB3/21vc/91d33/dXd9/2psc/9sb3n/bG95/3Byef9qbXf/ -bnF6/2xudf9ydH3/am13/25wd/9ucHf/bG95/3Byef9zdn//dHeA/3J0fP9tcHj/bG53/3J0e/94eoH/ -c3Z//3t+h/9sb3n/bG95/25xe/90dn3/bnB4/25wd/9tb3P/dXiB/2dqdP9nanT/cHN9/2xudf9nanT/ -ZGdx/2xvef9qbHP/ZGdx/2dqcf9kZ3H/Z2p0/2xvef9sb3n/bG95/3t9g/9qbXf/c3V8/2Zpc/9sb3n/ -cHN9/25wd/9wc33/bnB3/3ByeP9zdXr/bG95/3N2f/9wcnn/bG95/2xvef91d37/b3F2/3l7f/9xc3n/ -bnB3/3N2f/9vcXX/bW9z/2psc/9wcnn/c3V8/3Byef92eHz/bnB3/2ptd/9sbnX/c3Z//2ptd/9sb3n/ -bnF7/2ptd/9qbHP/c3V8/21vc/9zdXz/bnB3/3Bzff91d33/Zmhu/3Bzff9wc33/eHl9/25wd/9wcnn/ -b3F1/3Byef9sbnX/bnB3/3Byef9ucHf/bnF7/25xe/94eoD/cXN7/29xef9vcnf/bG95/2xveP9ydX7/ -Z2p0/25xev9xdH3/a254/2RncP9rbnj/Z2p0/2xvef9wc33/c3Z//3N1fP9sb3n/cHJ5/3Fzff9ydX7/ -b3J8/3Byef9ydX7/cHJ5/3Bzff90d4D/cHN9/3V3ff9vcXX/bG51/2xudf9tb3P/bnB3/2xudf95e4H/ -cHN9/3R2fP91d3v/c3V8/2ptd/9sb3n/bG51/2xudf9qbXf/cnV8/3N1fP9wcnn/am13/2Fkbf9qbHP/ -c3V8/2xudf9ydXz/am13/25xe/9sbnX/ZWhx/3N1fP9sbnX/bG51/2xudf9sbnX/bG95/2ptd/9ucHf/ -b3F1/3N1fP9tb3P/dnh8/25xe/9sbnX/amxz/2Jlbv9qbHP/bG95/2Zpc/9qbXf/am13/2xudf9qbXf/ -am13/2xudf9qbXf/cHN9/2xvef9ucXv/d3l//3V3ff92eHz/dnh8/3Byef9sb3n/bnF7/3Bzff9sbnX/ -bW9z/3V3ff9qbHP/bnB3/2xudf9tb3P/c3V8/3Bzff9sb3n/Z2p0/2xvef9qbHP/bW9z/3N1fP92eHz/ -cHJ5/25wd/91d33/c3V8/25xe/9wcnn/am13/25xe/9qbXf/cHN9/2xvef9tcHr/bXB4/21veP9zdoD/ -bnF7/2xudf93eX//bG51/2tueP9wc3v/cnR7/3R2ev9naXD/bnB2/3N1fP9ucHf/dXd9/3V3ff9vcXj/ -b3F5/2xuc/9ucHf/cHJ2/3N2f/93eX//cHN9/2xvef9sb3n/dXiB/3h5ff9ucHf/c3V8/3N1fP9wcnn/ -bG95/3J1ff9sb3f/cnN5/2Vocv9qbHP/Z2p0/2BjbP9kZ3H/Zmlz/2dqc/9rbnT/aWtz/2Zob/9pa3L/ -cHN9/2xvef91eIH/Z2lz/2xudf9sb3f/cXR7/2ptd/9sbnX/am13/3V4gf9kZ3H/am13/3Byef9maG7/ -ZGdx/11gav9nanT/Zmhu/2Rncf9maG7/Zmhu/2Rncf9qbXf/ZGdx/2dqdP91eIH/YmVu/2dpc/9nanH/ -cHN9/3V4gf9wcnn/bnF7/25xev9wcnn/c3V8/2ptd/9ucXv/am13/2dqdP9sbnP/dnd8/2tueP90d37/ -cXN5/25xev9wc33/b3F1/25wd/9qbXf/c3V8/3V3ff9wcnn/eHl9/25wd/9ucHf/bW9z/3V4gf9ucXv/ -cHJ5/3N2f/9wcnn/c3V8/3V4gf9wcnn/c3Z//25xe/9wc33/dnh8/2ZobP9zdXz/c3V8/3Z4fP9vcXX/ -c3V8/2xudf9ucHf/bW9z/2xudf9wcnn/bG51/2xvef9qbXf/c3V8/2dqcP9sb3n/bW92/2xveP9sb3n/ -dXd+/2ptd/9wc33/cnV+/2xvef9maHL/bXB6/2dqdP9ucXv/bnF7/3V3ff94eX3/cHJ5/21vdv90dnz/ -bnF7/3F0fv9ydX7/cnV+/29xeP9vcnv/c3Z9/3N2gP91eIH/cHN9/3N1fP9zdn//d3qD/3d5f/91d33/ -gIKJ/3p8gv92eYP/dXiB/3d6g/9zdX3/eHqB/3h7hP91d37/dHZ9/3p7gP97fYH/enyC/3R3f/9ucXr/ -cnV+/3p8gv9ydHv/cnV9/3Byef90d4D/cnV9/29ye/94eoD/bnB3/29xeP9ucHf/bW92/21wev9rbnj/ -bnB6/2tueP9xdHv/b3F4/3d4ff9vcXj/bnB3/2xuc/9iZW//bW92/2xvef9rbnj/dHeA/3J1fv9xdH7/ -bW93/2xveP9ucHf/b3F4/3J1fv9vcnz/c3Z//3h7hf96fIL/eXyG/31+gv96fIL/enyC/3p8gv94e4X/ -d3qC/3V3ff97fYP/d3l//3Z4f/92eHz/d3l//31+gv99foL/enyD/3d5f/96fIP/dXd9/3N2f/91d33/ -eHl9/3Byef9wcnn/dXd9/3N1fP9wcnn/bnB3/2psc/9ucXv/bG51/2xvef9sb3n/aGt1/2lsdP9qbXX/ -cnV+/25wd/9nanT/d3l//2xveP9rbnj/cnV9/2xvef9ucHf/X2Jr/2ttc/9tcHr/bnB3/3N2f/92eH// -bnF7/21wev9qbHX/bXB3/2ttdP9ucXv/d3l//2ptd/9maXP/bG51/3V4gf93eX//bG51/3N1fP9wcnn/ -c3V8/2xvef9zdXz/am13/3J1ff9nanT/bG51/25xe/9kZmz/bG51/2xudf9ucHf/b3F1/21wd/9qbXX/ -a253/3V3ff9ucXv/d3l//25wdP9tcHf/c3V9/3R3f/9wc33/b3F1/2xudf97fYP/bG51/25wd/92eHz/ -b3F1/25wd/9qbHP/eHl9/3Byef9tb3P/b3F1/29xdf9sbnX/dXd9/3N1fP92eHz/f4GH/2dqdP9sb3n/ -am13/3Bzff95e4H/dXd9/3V4gf9vcnz/c3V+/3V3ff9tcHr/bnF7/21wef9sb3j/cHJ5/3d6gP9xc3v/ -dHd+/3R3gP9zdn//dnmC/3Bzff9zdn//c3V8/3N2f/91eIH/bnB3/3d5f/9sb3n/bnB3/25wd/93eX// -bG95/25wd/9wc33/bnB3/25wd/9wc33/bnB3/3Bzff9ucXv/dXiB/3V4gf9nanH/cHN9/3N2f/95e4H/ -cHJ5/3N2f/9wcnn/cHN9/3N1fP9wcnn/dXiB/25xe/93eoP/bnF7/3V4gP9ucHf/cHN8/29xeP9ucXn/ -a254/3V3ff9pbHb/cXR8/29yfP9wc3z/bG95/2xvef9qbXf/cHN9/3Byef91eIH/d3l//3Fze/9ucHj/ -dHd+/2ptd/92eYD/cHJ6/3V3f/9tcHr/cXR8/3V3fv92eYD/dXiB/29xeP9tcHn/bnF7/3Bzff9wc33/ -cHN9/3l8hf9ydX7/dHV7/3J0fP9ydX//cXN6/3Fzev9ydX3/b3J6/3Fzef9ydHz/dXiB/3Z4f/9vcnr/ -bW94/25xef92eHz/b3F2/3Bze/9wc3v/c3Z//25xe/9vcXr/d3l//21vdv9xc3r/b3J6/21weP9vcXv/ -bW94/25wef9rbnj/b3J8/21wef90dn3/cXN7/3Bze/9tb3X/ZWdu/2Zpc/9pa3P/Zmly/2tueP9rbnb/ -bG92/2Vocf9sbnX/aWxz/2dpb/9oanT/a210/21veP90dn3/b3J5/3R2fP9zdXr/bnF4/29ye/9ucXv/ -b3J8/3BzfP9xc3r/cXR9/3Bye/9ydHv/cXN9/3J1ff93eX//e32D/3R3f/9xdH3/c3Z//3F0ff9vcnz/ -dXd9/3d5f/9ucHf/cHJ5/3Byef9wcnn/cHJ5/3V3ff9sbnX/cHJ5/21vc/9ucXv/bnF7/2xvef9sb3j/ -bXB4/3V3fv9sb3n/Z2p0/3d5f/9sbnX/a210/29xd/9tcHr/cnR6/2Rmbv9sbnT/am13/2dqdP9ucXv/ -c3V8/2xudP9tcHr/a252/2xvef9ucXv/cHN9/3d5f/9ucXv/bG95/25xe/97fof/d3qD/25wd/91d33/ -cHJ5/3Byef9ucHf/cnR7/21vdv9ydXz/aGty/2xudf9ucXv/ZGZs/25wd/9ucHf/bW93/25weP9ucHf/ -bnB2/2xveP9zdXz/c3V8/3V4gf9sbnX/bG51/21wev9zdXz/am13/2xudf9qbXf/dXiB/2psc/9sbnX/ -dXd9/2xudf9tb3P/amxz/3Z4fP9vcXX/bnB3/2xvef9ucHf/am13/3d5f/91d33/c3V8/4GDiv9qbXf/ -cHN9/2dqcf9vcXX/c3V8/2ptd/9ucHf/bW92/3Bye/9ydX7/cnR7/3V4gf91d4D/cHJ7/3d5gP96fYf/ -eHqB/3R2fv9ydX3/bXB5/2xvef9sbnX/bG51/2ptd/9ucHf/c3V8/2xvef91d33/bnB3/3Byef9sb3n/ -dXiB/2xvef9sb3n/bnF7/25xe/9ucHf/cHJ5/25wd/9ucXv/bnF7/3V3ff93eoP/ZGdx/3N2f/93eoP/ -d3qD/25wd/9zdn//bnF7/25xe/9wcnn/bnB3/3Bzff9sbnX/c3V8/25wd/91d33/bG95/3F0ff9ydH3/ -dHd//3Bzff95e4H/c3Z+/3d6gP9wc3z/b3F5/2xudf9sbnX/Zmlz/2xvef9sb3n/dXd9/3N1fP9rbnj/ -bG52/3Z4f/9qbXb/dnh9/3Byd/9zdn3/bW93/25weP9ucXv/dHd//3V3f/90dnz/d3l//3d5f/9+gIb/ -d3l//3R3gP96fYb/dXd+/25xe/9wc33/c3V9/29yfP9xc3r/dHZ+/29yef9zdX3/c3V9/3N2f/9xdH7/ -bG95/3Bzev9ucHX/dHZ+/21vdv9qbXf/bG92/3Bze/9sb3f/bG94/3R2fP9tb3P/cnR5/3F0e/9ucHf/ -bG95/2xvef9ucHn/bnB3/3Bye/9vcXr/c3V9/3V3f/9xdHz/b3F4/2ttc/9rbXT/bnF5/2ptdf9sbnX/ -bG50/3F0fP9qbHP/bW92/2xvef9tb3b/cHJ3/2lsdv9wc3v/dXh//2tudv90dnv/cXN6/25xef9wcnn/ -dHZ+/25xe/9tcHr/bnB5/3F0ff9vcnv/bW94/3Byev9sb3j/a252/3J1fP9vcXn/a210/21wev9vcnz/ -bnB3/3N2f/93eoP/cHN9/3N2f/9zdn//c3Z//3V4gf91eIH/cHJ5/3d6g/9wc33/d3qD/3l8hv93eoP/ -dnmB/3Bzff90d4D/dXiB/3N2f/97fYP/d3l//21wev94e4P/dXd//3V4gv9vcnz/a251/3N1fP9vcXX/ -Z2px/2psc/97fYP/cXR7/2xudf9vcXj/bnF7/3N1fP93eX//bnF7/2dqdP9ucXv/d3qD/3d6g/9ucXv/ -cHN9/3V3ff9wc33/bnF7/3Z4fv9kZ3H/dniA/2xvef9qbHP/dXd9/2Zpc/9nanH/ZGdx/2Rncf9pbHL/ -a213/21wev9laHL/ZGdx/2Rncf9qbXf/Z2lv/2tud/9qbXb/c3V8/25wdf9sb3n/bnF7/3V4gf9qbXf/ -bnF7/3l7gf9sb3n/bG95/2dqdP91d33/bG95/2xvef9ucXv/bnF7/2dqdP93eX//c3Z//3N2f/+Bg4r/ -bG51/3Byef9maXP/bnB3/3Byef9sbnX/bnB3/25weP9ucHf/amxz/25wd/9vcXX/d3h9/3N1ev9tcHj/ -dXd7/3V3ff9wc3z/c3V9/3Byev9sb3n/bG51/2ptd/9maXP/am13/2xvef9ucXv/cHJ5/2dqcf9nanT/ -Z2px/3Byef9kZ3H/YGNs/2Zobv9kZ3H/Zmhu/2Zpc/9maG7/Zmlz/2Zobv9sb3n/c3V8/1lcZf9maXP/ -Zmlz/25wd/9kZ3H/am13/2dqcf9nanH/YmVu/2Jlbv9nanT/Zmhu/2Zpc/9kZ3H/cHJ5/2dqdP9qbXX/ -bnB4/29yfP9sbnX/c3V8/25xe/9xdHv/bXB5/3J1ff9pbHX/bW90/2ptd/9sb3n/am13/3Bzff9ucXv/ -cnR8/3J0e/94e4X/bG95/3l7gf9ucHf/dXiB/3Byef9ucXv/b3J8/3N1e/9wc33/cHJ6/2ttdP9zdXz/ -c3V8/21vc/9vcnz/bnF6/25xef9ucHf/cnR7/3R2fP9ydHv/bW92/3R3ff9vcXj/c3Z//25xe/9vcnz/ -c3V+/3F0ff94eoD/cHJ3/3R2e/9vcXX/a21z/25wd/90dnv/b3F5/3Fzev9xc3r/b3F1/3V3ff9ydX7/ -bnB1/2xudv9ucHf/bXB1/2tueP9tb3f/bG51/21wev9vcnz/b3J7/29ye/9qbXf/aWxz/29xef9nanH/ -bG92/2xveP91eIH/a21z/2lsdv9vcXX/b3F4/25wd/9tb3b/dHZ7/3N2ff9pbHb/d3mA/3J0e/91d33/ -cXR+/3R3gP9zdn7/dHeA/3R3gP97fof/d3qD/3d5gP91eH//cHN8/21wev9wc3z/dnmC/3N2f/9wc3v/ -eXuC/3V4gf9zdXz/dXd9/25wd/91d33/cHJ5/3Byef9wcnn/cHJ5/21vc/9wc33/am13/2xvef9qbXf/ -bnF7/2xueP9rbnX/bG52/29xef9ucHf/dXd9/3N1fP9rbnj/cXN6/3Byef9zdXr/bW5z/2hqcf9wc3z/ -cHJ5/2dqdP9nanT/d3qD/25xe/9sb3n/bnF6/25xe/9zdn//d3qD/25xe/9qbXf/bnF7/3l7gf95e4H/ -bW9z/3N1fP9zdXz/bG51/2xudf9zdXz/Zmhu/3R2fv9ydHv/am13/3d6g/9nanT/Z2p0/2dqdP9nanH/ -a254/21wef90dn3/bG51/2ptd/9qbXf/bnF7/2xvef9ydHv/am13/3Fze/9sbnb/am13/2xudf91d33/ -amxz/21vc/91d33/bnB3/25wd/9sbnX/cHN9/2xvef9ucHf/bG95/25wd/9qbHP/dnh8/3Bzff9wc33/ -f4KM/25wd/9wc33/am13/2xvef91d33/bG51/3N1fP9tb3n/bG51/2dqcf9nanT/bW92/3V3ff9zdX3/ -cXR8/3d6hP91eIH/cXR7/3J1ff9zdXz/am13/3Byef9wcnn/Z2p0/2xvef9wc33/c3V8/3V4gf9tb3P/ -bnB3/21vc/92eHz/bW9z/29xdf9sbnX/bnB3/25wd/9qbXf/am13/2ptd/9nanT/c3V8/3d6g/9kZ3H/ -bG95/2xvef93eoP/Z2p0/25xe/9qbXf/am13/2xudf9sbnX/cHJ5/29xdf9wc33/bnF7/3l8hv9ucXv/ -cHN9/3R3gP94eoD/cHN9/3l7gf9zdn//dHeA/3Bzff9xc3r/am13/25wd/9vcXX/cHJ5/25wd/9zdXz/ -c3V8/2ptd/9qbXf/d3l//25wd/94eX3/bnB3/3N1fP9qbXf/b3J8/29yfP90d37/d3mC/3Z4gf9zdn// -e32D/3l8hv9zdXz/dXd9/25xev9sb3j/aGt0/25xe/91d33/c3V8/2xudf9zdXz/bnB3/3V3ff9sbnX/ -bG95/25xe/9vcXj/dXd9/21vdv9zdXz/a213/2dqdP9rbnj/cXR9/3Byef9wcnn/dXd9/21vdv91d3z/ -c3Z//25wd/9sb3n/cHJ5/2xudv9sbnb/bnF4/25wd/9zdXz/c3V8/3Fzev9wc33/bG51/2dqdP9sb3n/ -Y2Zu/2ptd/9wcnn/enyC/2xvef9sbnX/bW92/2tud/9ucHf/aGt1/3V3ff92eHz/aGt1/3Z4f/9wcnn/ -bnB3/25xeP9zdn//bnB3/3Bzff9ucXv/eXuC/3Z5gv9ydHv/dnh//25xe/9sb3n/bG95/3Bzff9vcnv/ -Zmly/3J1fv9vcnv/dXd9/3d5f/9wcnn/c3V8/3Byef9zdXz/cHJ5/3V3ff9tb3P/dXd9/25wd/9wcnn/ -c3V8/25xe/9qbXf/a210/2tueP9qbXf/bG51/3d5f/9ucXv/bG51/29ye/9ucHf/cXR8/2ttdP9laG// -bnF6/2ptd/9maXP/Zmlz/3R3gf9tcHn/bG93/2xvdv9wcnn/c3V8/3d6g/9sbnX/amxz/25wd/93eX// -d3l//25wd/91d33/dXd9/25wd/9ucXv/dnh//2hrdP91d4D/a253/2psc/9zdXz/Zmlz/2Rncf9maXP/ -Z2px/21wev9sb3n/c3V8/25xe/9wcnn/cHJ5/3Z4fP9wcnn/dHZ6/2xudf92eH7/bW91/29xdf9ucHf/ -eHl9/2psc/9sbnX/dXd9/2xudf9qbXf/amxz/25xe/9sbnX/b3F1/29xdf9vcXX/Z2px/3V3ff91d33/ -c3V8/3+Bh/9nanT/bnB3/2dqdP9ucXv/cHN9/2ptd/91eIH/bG95/21veP9qbHP/ZWhy/2xudf9xdH3/ -cXN5/21vdv90dnz/c3V8/21wef9wcnr/bnB6/21wd/9ucHf/cHJ5/2psc/9sbnX/cHN9/3Bzff9zdn// -bG51/25xe/9nanH/cHN9/2Zpc/9nanH/Z2px/2xudf9sb3n/am13/2xudf9ucHf/bG51/3V3ff99foH/ -Zmhu/3N1fP9wcnn/eXuB/2ptd/91d33/bnF7/2ptd/9qbXf/am13/25xe/9ucHf/c3V8/3V3ff95e4H/ -bnB3/3Fze/9wc3v/dHeA/3N2f/93eX//c3Z//3Z5gv9zdn7/cHJ4/2hrdP9qbXf/bG51/3N1fP9ucHf/ -c3V8/3V3ff9qbXf/Z2p0/3d5f/9sbnX/eHl9/25wd/91d33/b3F1/3Byef9wcnr/cXR8/3R3f/91eIH/ -cHJ5/3N2f/9zdn//bnB3/3Z4f/9ucXr/bnB4/21vc/9wcnn/dXd9/3h5ff9ucHf/dXd9/25wd/92eHz/ -bG51/3Byef9zdXz/am13/3V3ff9sbnX/dnh8/29xdf9qbHP/bG95/3Bzff9ucXv/am13/3Bzff9qbXf/ -dXd9/3V3ff9ucHf/bnB3/3Byef9vcXX/bnB3/25xe/9ucHf/c3Z//3V4gf9zdn//c3Z//2xvef9qbXf/ -c3V8/2dqcf9sbnX/bnB3/3d5f/9ucHf/am13/3Byef9wcnn/bnB3/2ptd/91eIH/eXuB/2dqdP93eX// -bW9z/2xudf9sbnX/bG95/2ptd/9qbXf/bG95/3N1fP9ucXv/aGty/3Z4fP9qbHP/Z2px/2xudf9ucXv/ -cHN9/2Zpc/9zdn//b3F1/2xvef9sb3n/Zmlz/2ptd/9nanT/bnF7/2ptd/9qbXf/bG51/3Bzff9sbnX/ -bG95/2xvef9ucXv/b3F4/21vdv9sbnf/bG51/2dqcf9wcnn/am13/2hrcv9ucHr/bW91/3BzfP9oanP/ -X2Jq/2hrdf9nanH/XWBq/2Rncf93eX//bnF6/29xev9sb3j/c3Z+/3d6g/95fIb/cHJ5/2xvef9wc33/ -eXyG/3t+h/9wc33/e32D/3t9g/91d33/cHN9/3p8gv9pbHb/e32E/3N2f/9sb3n/d3l//25wd/9vcXX/ -bG51/2xudf9vcXj/cHJ6/3R2fv9ucXv/bG95/3N1fP91d33/bnB3/3J0e/9tcHn/dniB/25xe/9ucHf/ -bnB3/3Z4fP9sbnX/cHJ5/3h5ff9sbnX/bG95/2ptd/9ucXv/am13/2xudf9qbXf/bG51/2Zpc/9wc33/ -cHN9/3N1fP9/gYf/am13/25xe/9sbnX/bnB3/3Bzff9nanT/bnF7/3Byef9wc3v/a253/2dqc/9wcnn/ -cXR9/25xeP9pbHX/Z2pz/2dqdP9laHD/bnB2/2ptd/9rbXX/bG95/2xvef9nanT/am13/3N1fP9wc33/ -d3qD/2xudf9wc33/bG51/3V3ff9nanT/amxz/2xudf9qbHP/bG95/2ptd/9qbXf/bG95/2xudf91d33/ -e32D/2Jlbv9ucXv/bG95/3N2f/9qbHP/c3V8/3Bzff9nanH/amxz/2Jlbv9nanT/Z2px/2ptd/9sb3n/ -dHeA/2lsdP9sb3j/b3F3/3Byef9wcnn/cHJ5/3Byef91d3v/b3J7/3Z4fv9ucHf/bnB3/2xvef9wc33/ -bG95/25xe/95e4H/cHJ5/2ptd/91eIH/bnB3/3d5f/9ucHf/dXd9/2xvef9ucXv/cnR7/3Bze/9xdHv/ -cHN9/2tueP9zdXz/dXd9/29xdf92eH//bXB6/21vd/9rbXf/bnB3/3V3ff94eX3/bG95/3l7gf9zdXz/ -e32D/3Bzff91eIH/eXuB/3N2f/97fof/c3Z//3t9g/9wc33/c3Z//3d5f/95fIb/d3qD/3N2f/93eoP/ -c3Z//3t9g/91eIH/c3V8/2xvef9sb3n/bG95/25wd/9wcnn/bW9z/3Byef91d33/c3Z//3V3ff9ucHf/ -bG51/25xe/9iZW7/bG51/2xvef9zdn//Zmlz/2Rncf9nanH/Z2p0/2dqdP9kZ3H/bnF7/3N1fP9nanT/ -d3l//2ptd/9nanT/bG51/3Byef9sbnX/am13/2xvef9ucXv/am13/2Zpc/9wc33/Z2p0/2BjbP9nanT/ -cHN9/2xvef9iZGr/bnF7/2xudf91d33/dnh8/3N1fP9wcnn/bG95/25xe/9ucXv/am13/2psc/9ucXv/ -am13/2psc/9qbXf/cHN9/29yfP9rbXb/bG93/2tueP9sbnX/dXd9/3Byef9tb3P/cXN6/21wef9ydHz/ -a251/2dqcv9ydHv/cHJ5/2psc/9sbnX/dnh//3Byef9sbnX/aWx1/2xvef9ucXv/dXd9/2Zpc/9gY2z/ -Z2px/3Byef9wcnn/Z2px/25xe/9sb3n/amxz/2Zobv9rbnj/Y2Zu/3Z5gv9vcnv/bG95/3d5f/9ucHf/ -bnB3/2xudf9tb3P/bnB3/3Fzev90dnz/c3Z+/25xe/9wc33/d3qD/3J0fP9ydHr/a254/3N2f/9tb3b/ -am13/2xudf92eHz/bnB3/3Byef9zdXz/bW9z/21vc/9tb3P/bnB3/3Byef9ucHf/bnB3/29xdf9nanH/ -c3V8/3N2f/9zdn//f4GH/2xudf9xc3r/ZGdx/2ptd/9sb3n/Z2px/3Byef9vcXb/b3F4/2xudf9nanT/ -cHN9/3V4gP90dnz/dHZ9/3N1fP91d33/bnB3/3N0eP9ydHr/cHJ5/3Byef9wcnn/amxz/2xudf92eHz/ -cHJ5/3V4gf9sbnX/bnF7/2xudf9wcnn/Z2px/2Rncf9maXP/Z2px/2dqcf9maG7/YmVu/2Zobv9maG7/ -am13/3N2f/9ZXGX/Zmlz/2dqdP9wcnn/ZGdx/2xvef9sb3n/amxz/2ptd/9maXP/am13/2xudf9sb3n/ -cHN9/3R2ff9oa3X/bG95/3F0ff9vcnz/dXd9/3N1fP9wcnn/dHZ8/3N2f/91d37/b3J5/2xudv9sbnX/ -cHN9/2xudf9sbnX/dXd9/2xvef9qbXf/e32D/3N1fP93eoP/bG95/3Z4fP9qbXf/c3Z//3J0e/9ucHn/ -cXN6/3R2fP9tb3P/c3V8/3Bzff9ucHf/c3V8/29yfP9ucXv/bnB3/3Byef93eX//e32D/3Byef97fYP/ -cHJ5/3t9g/9ucXv/cHN9/3V3ff9wc33/eXuB/3Byef9zdn//bG95/2ptd/9sb3n/c3V8/3N1fP9ucHf/ -bnB3/25wd/9zdXz/bG95/2ptd/9qbHP/am13/2Rncf9nanH/am13/2dqcf9nanT/am13/25xe/9wc33/ -amxz/2xudf9zdXz/amxz/25wd/9wc33/eXyG/2xvef9ucHf/cHJ5/3N1fP9ucXv/bG95/3N2f/97fYP/ -c3Z//36Biv91eIH/c3Z//3Bzff93eoP/c3Z//3l8hv93eoP/e32D/3l7gf9wc33/d3qD/25wd/9maG7/ -bG51/25wd/9sbnX/ZWZq/3N1fP9zdXz/c3Z//3V4gf9wc33/dXd9/3V3ff91d33/cHN9/3Bzff9wc33/ -dnh8/3Bzff9wc33/c3Z//3Z5gv91eIH/bXB5/3Bze/9sb3n/bG51/3V3ff9sb3n/bG51/3F0ff9tcHn/ -c3Z+/21vd/9naXP/am13/2xvef9iZW7/ZGdx/3V3ff9qbXX/Z2p0/2hrdf9xc3r/cnV8/3Z4f/9sbnX/ -amxz/2tudf91eIH/dHZ8/25wdf9ydX7/cnV+/2xvef9ucHf/cXR9/2dqdP90dn7/Zmlz/2Zpb/9sb3n/ -YmVu/2Zobv9kZ3H/Zmhu/2lsc/9sbnj/dHZ9/2xvef9sbnX/bG95/3V4gf9tcHn/cHN7/2tud/92eYH/ -b3J7/25wd/9vcXX/d3l9/3Byef9wc33/dHZ8/25wd/9sb3n/b3F1/25wd/9ucHf/bW9z/2xudf9ucHf/ -aGt1/25xev92eH7/dXeA/36Ahv9ucHf/dXiB/2Zobv9qbXf/bG95/2Zpc/9wcnn/bW90/2tueP9sbnX/ -Z2pz/2xvef9vcnv/cHJ7/3N1e/92eYH/c3Z//29yfP9zdX3/cnV9/3J1fv91eIH/d3qD/3N2f/9zdn// -foGK/3l8hv+Bg4r/cHN9/3d6g/9zdXz/d3l//3Byef9wc33/cHN9/25xe/9ucXv/bnB3/29xdf9wcnn/ -bnF7/3l7gf9+gIb/Z2p0/3N2f/9wcnn/d3l//21vc/92eHz/dXd9/25wd/9ucXv/Z2p0/2xvef9ucHf/ -bnF7/3V4gf94e4X/bnB3/3Fze/90d4D/cHN8/3V3ff9wc33/bnF7/3N1fP9ydHr/cnR6/21wd/9sb3n/ -bnF7/3d6g/9ucXv/cHJ5/3N2f/9ucHf/amxz/3V3ff9vcXX/dXd9/2xvef9zdn//bXB6/3V3fv9ydX7/ -cHN9/3N2f/90dnz/bnB3/3N2f/9wc33/bG95/3Fze/9ucXv/bXB6/2xveP9ucXv/dHeA/3p8gv9ucHf/ -dHd9/2xudf92eHz/cHJ5/3Byef9zdXz/bG95/3N1fP9sbnX/bnF7/2dqdP9nanT/bG51/2xvef9sb3n/ -amxz/2xudf9sbnX/dXd9/3N1fP9ucHf/bW9z/2xvef9maXP/am13/2xvef9sbnX/c3V8/3N1fP9zdXz/ -c3V8/29xdf9vcXX/cHN9/2ptd/9wcnn/c3V8/3d6g/9sbnX/bnB3/29xdf9vcXX/bG51/2psc/9ucXv/ -cHN9/2ptd/93eX//am13/2psc/9qbXf/bnF7/2xudf9ucXv/am13/3Bzff9ucXv/ZGdx/25xe/9nanH/ -YGNs/2Rncf9qbXf/bG51/2RmbP9ucXv/bnF7/3Bzff91eIH/c3Z+/3R2fP9zdXz/c3V8/3Fzef9ucHf/ -cHJ5/3Z4fP9wcnn/bnB4/29xeP9ydHz/cnR7/2xudv9wc3r/dXiB/3N1fP91d33/bnF7/29xdf91d33/ -bnF6/3F0fv9zdXz/aGt1/25xe/9ucXv/am13/25wd/95fIX/cnR6/2xvef9rbnj/cnV8/3V3ff93eX// -bnB3/21vdv9wcnb/d3l9/3d5gP9tcHX/cnR7/3N1fP9sb3n/bG94/3R2ff9qbHP/eHl+/25xe/9tb3P/ -dnh8/2Zpc/9qbXf/bG51/21vc/9sbnX/cHJ5/3V3ff9ucHf/bW9z/25wd/97fYP/cXN6/3FzfP9rbnf/ -dHeA/25xev9qbXb/bG92/3N2f/9tb3b/cnR7/21wev9sb3n/bG95/21wdf9tb3b/bnB4/2xudf9rbXP/ -bnB3/2lsdf9sbnj/dXd+/3J0e/97fYL/bG90/3ByeP9gY2z/bG51/2xudf9kZ3H/bG95/2xudv9sb3j/ -bG95/2ptdv9wcnn/dHZ9/25weP9ucHj/bnB5/3N1fP9tb3b/cXN7/29ye/9ucHf/bG95/2ptd/9maXP/ -bG95/3V3ff9wc33/dXiB/21vc/9ucXv/bG51/3N1fP9tb3P/bG51/3Bzff9qbXf/am13/25xe/9qbXf/ -bG51/2xudf9wcnn/d3l//2Rncf9sb3n/bnF7/3V3ff9sbnX/dnh8/3V3ff9ucHf/bG51/2psc/9sb3n/ -b3F1/25wd/9wc33/dnmC/2tud/9sb3j/bXB6/2hrdf9xc3r/a254/21wef9vcnz/cnR9/3R2fP9vcnz/ -bnB3/25xe/91d33/b3F1/29xdf9zdXz/ZWhx/2Zpcv9wcnr/bW92/3d5gP9rbnj/cXR+/21wd/90dn3/ -c3Z9/3J1ff91eIH/enyC/3Byef9zdn//c3V8/2xvef9vcnv/cnR7/21wev9sb3j/bnB3/3BzfP92eH7/ -bXB6/3R2fP9rbXT/eHl9/25weP9ucHf/cnR7/3Fzev92eH3/bG94/3N1fP9ucXv/bG51/25wdf9vcXj/ -b3F4/21vdP9sbnb/bW92/3R3gP9ucXv/bG52/2xudf9wcnn/Z2p0/2xudf9tb3P/bG51/3Bzff9zdXz/ -dXh8/3Z5f/9ucHf/a254/25xe/9qbXf/b3J8/29yfP94eoD/bG95/25wd/9ucXv/bnF7/2ptd/9oa3T/ -c3Z//3V4gf9wcnn/eXuB/25xe/9sb3n/bnB3/3V4gf9ucXv/d3l//25wd/92eHz/c3V8/2ptdP9zdXz/ -am13/2Zobv9sbnX/bnB3/2ptd/9gY2z/cHN9/25xe/9vcnz/cHJ8/3J1fv9ydX7/cHN8/3Byef91d33/ -b3F4/25weP90d37/cHJ5/3Byev9xc3v/c3V8/3J0e/9wc3v/cHN8/3N2f/9wcnn/d3qD/3N2f/9ucHf/ -d3l//25xe/91d4D/dHeA/2ptd/9wc33/cHN9/25xe/9wcnn/en2G/3N2fv9vcnz/b3J6/29yfP92eH7/ -dnh//3BzfP9ydHv/cnR5/3p8gv94e4T/cHJ4/3J1fv9ucXv/cHN8/3Bze/92eH7/am13/3h6gP9ucXv/ -c3V8/3l7gf9sb3n/bnB3/3Byef9ucHf/b3F1/3Byef91d33/cHJ5/29xdf9ucHf/eXyG/25xe/9vcnv/ -am13/3J0ev9vcXr/aGt1/2tudv9ydHz/a252/21vdv9tb3f/bW92/2xudf9rbXT/bG51/25xef9rbXT/ -aWx2/2xvef9qbXf/amx0/3F0ev9tb3b/cnR6/2hrcf9sbnf/am13/3Byef9wc33/bG95/3Bzff9tb3X/ -a252/2dqc/9fYWv/ZGZt/2xveP9qbXb/bG95/3F0e/91d3//b3F3/3J1ff9zdXz/bG95/3N1fP9wcnn/ -bG51/3N1fP91d33/bnF7/3N1fP9qbHP/bnF7/2ptd/9zdXz/bG51/2xudf91d33/bnB3/3Byef9wcnn/ -bG95/25wd/9ucHf/dnh8/4CChv9ucHf/dXd9/3N1fP93eX//bnB3/3Z4fP92eHz/bnB3/2xudf9sbnX/ -bG51/2xudf9qbXf/bG95/3V4gP9nanT/bW95/3F0ff9vcnn/dXd9/3N1e/90dnz/c3V7/21vdv9sb3j/ -Zmlz/2FkbP9maXP/ZGdx/2Zobv9iZW7/am13/2lsdv9rbnb/dHZ7/3Byef9zdXv/bG51/2xvef9qbXf/ -bnF5/21wev9rbnf/b3J8/2xvef9nanH/bnF7/2xvef9oa3T/a253/25xef9tb3j/bG51/21vdv9tb3f/ -cHN6/2lsdv9qbXf/ZGdw/3N1fP9nanT/Zmlz/2ptdv9ucHf/b3J8/21vdv9vcnz/bXB6/2hrdf9tb3f/ -bG95/29yfP9qbHP/aGtz/2ttdP9zdX7/bnB5/21vdv9sbnX/b3J8/2hrdf9sbnX/bnB3/21vdv9xc3r/ -dHZ8/3V3fv91d37/bnB3/2ptd/9vcnv/am13/25wd/90dnz/dXd+/2xudf9tb3b/a254/29xeP9nanL/ -aWt1/2ptd/9sb3n/amx0/25xe/9qbHP/Y2Zv/2hrdf9ucXv/bG94/29yfP9nanH/b3F4/2tueP9oa3X/ -cnR7/2ptd/9jZm//Zmlz/2ptd/9qbXf/YGNs/25xe/9qbXf/bW94/25xe/9ydX//cnV//3N2gP91eIL/ -dXd//29xeP9xc3v/dHd//29ye/9tcHn/cnR6/21wev9ucHn/a253/21wev9rbnj/amxz/3V3ff9wcnn/ -bG51/3V3ff9qbXf/b3J8/3J1fv9maXP/bnB3/21vc/9qbXf/Z2p0/3R2ff9sbnX/bW91/3Fzev9rbnj/ -dHZ9/3F0ff9vcnz/dXd9/3F0fP90d3//dXiB/21vdv90d3//b3J7/3R3f/9wcnv/cXR9/2dqdP94eX3/ -cHJ5/29xdf94eX3/amxz/21vc/9tb3P/am13/2xudf9ucHf/dXd9/2xvef9sbnX/am13/3d6g/9nanT/ -a253/2VocP9rbnT/bG93/2RncP9laHD/bG93/2hqcP9pbHP/ZGdx/2hqcP9maXP/amx0/2lsc/9rbnf/ -a210/2ttdP9tcHr/bXB5/2hqc/9ucXn/bW95/3Fzef9rbXT/cHJ5/2xvef9wcnn/cHN9/2xvef9ucXv/ -bnF6/3Byd/9ucHf/bnB3/3Byef94eX3/c3V8/3Byev9ydHv/dXd9/3Byd/9ydXr/dHZ9/2xudv9wcnn/ -bG51/2psc/9zdXz/eHl9/3V3ff91eIH/bnB3/3Byef9wcnn/dnh8/2xvef9wc33/d3qD/3N2f/9zdn// -c3V8/25wd/9ucHf/c3V8/3h5ff9/gYf/bnB3/3Z4fP9wcnn/d3l//25wd/93eoP/eXuB/25wd/9wcnn/ -bG51/25wd/9qbHP/am13/2ptd/94e4X/Z2pz/25xef9ydHv/a254/3Bzff9rbnj/dHd+/3J0ff9tb3f/ -cnR8/21vd/9qbHP/cHN9/3Bzff9sbnX/Zmlz/3Bzff9nanT/am13/21vef9tcHr/bXB6/2ptdf9tb3f/ -b3F5/3Byev9sb3n/cXN6/3J0fP91d33/bG51/3N1fP9wc33/bG51/25wd/9xdHv/cnR6/25wd/9wcnr/ -a252/29xef9sb3n/bnB5/2ttdv91eH//a253/2ptd/9rbnb/b3F4/29yfP9wcnn/bnB5/21vdv9rbnX/ -cnR6/29xev9ydXz/b3F4/21vdv9ydHv/c3V9/2ptd/9vcXj/bW92/25wd/9tb3b/bW92/25wd/9xc3r/ -cHN6/3R2fP93eX7/dXd//3Bzff9tcHr/dHZ8/25wd/9vcXj/b3F6/3R1fP9xc3r/cnR6/3Bzff9wc3z/ -aWx0/2xvdv9tb3X/cHJ6/25wdv93eH3/b3F3/2ttdP9tb3f/c3V7/3R3fP90d37/b3F4/3Z3ff91d33/ -cXN6/3Z4f/9xdH3/bXB6/3Byev9vcnz/cXR+/2hrdf9ydX//cXR9/2lsdv9sb3n/cXN8/25wd/9sb3j/ -bnB6/21wef9nanT/am12/3N1fP9vcXn/c3V7/3N1ev9qbXf/a210/21vdv9vcXj/bnB3/29xdf9zdXz/ -cHJ5/25wd/9wcnn/bG51/3N2f/90d4D/am13/21vc/9ucHf/b3F1/2xvef93eX//b3F4/2xudf9wc33/ -bG94/3R2ff9xc3r/bW92/3V3fP90d33/dHZ9/3Z4fv9wcnb/b3F4/3Fzev9xc3r/c3V8/3N2f/9oa3H/ -eHl9/3Byef9sb3n/d3qD/25xe/9wcnn/bnB3/25wd/9wcnn/cHN9/3d6g/9zdn//cHN9/3N2f/9/gYf/ -cHN9/3N2f/9qbXf/cHJ2/3R2ff9ucHf/cHJ5/3N2f/9ucXv/b3F4/21wev9sb3n/bG95/29xeP9vcnb/ -cHJ5/2xudv9tb3P/dXd7/3R2fP9sbnX/cXR9/25xe/9tcHr/b3F1/25wd/9nanT/Z2p0/2ptd/9qbXf/ -bnB3/3Byef9vcXj/bG51/29xdf9ucHf/dXd9/3Byef9wcnn/cHJ5/3N1fP9ydHr/c3V6/3J0fP9tb3T/ -c3V8/21vc/9sbnX/c3Z//3d6g/91eIH/eXuB/25xe/9zdn//dXiB/3t9g/9wcnn/dXiB/3l7gf93eoP/ -d3qD/3d6g/9wc33/cHN9/25xe/91eIH/gYOK/2xvef91d33/cHN9/3l7gf9ucXv/e36H/3l7gf9zdXz/ -c3Z//2xvef91eIH/cHJ5/3d6g/91eIH/foCG/25xeP9zdn//dnh//25wd/9xc3n/a253/3Z4fv9zdXz/ -b3F4/3Z5gf91eIH/c3V+/3t9g/95e4H/c3Z//3N1fP93eoP/bnB3/3F0ff9wcnn/cnV+/3d6gv9ydX7/ -cHN9/3d5f/95fIL/dXiB/3h6gP95e4H/foCG/3V3ff97fYP/e32D/3N2f/92eYL/eHqA/3d5gP9ydX7/ -dHeA/2ttd/9ucXr/cHJ8/3Fzev9xc3v/eXuC/3J0e/9ucHj/b3F5/3R2fP9xc3r/dHZ8/21veP9sbnX/ -aGt1/3N2f/9sb3n/cXN7/2lsdv9qbXT/cnR7/25xe/9rbnj/b3J7/2xueP9tb3f/bXB6/29xev9tcHj/ -cXN6/3J0e/9zdXz/dHZ9/3BzfP9xc3r/aGt0/21wef9qbHT/a210/2hrdf9sbnf/bG52/25xev9tcHr/ -bW94/2hqc/9ucHf/aGty/2hrdf9pbHP/b3F6/2psdf9oanP/am13/25xe/9sb3f/bW94/2dqdP9ucXn/ -bXB3/3FzeP9vcnj/bnF7/2hrdf9sbnX/bnB4/3F0e/9laG//bnB4/2xvef9sbnX/bG51/3N1fP9sbnX/ -bG95/25xe/9wcnn/bW9z/2xudf9zdXz/bnF7/25xe/9wcnn/a253/2tud/9tb3P/c3V8/29xdf9sbnX/ -bG95/3Bzff9sbnX/bnB3/2psc/9zdn//eXuB/25wd/9ucHf/cHN9/25xe/9ucHf/eXuB/2xvef9qbXf/ -c3Z//25xe/91d33/cHN9/2xvef92eHz/c3Z//3Byef91d33/b3F1/3Byef91d33/cHJ5/25xe/9ucXv/ -Zmhu/3N1fP9qbXf/bG51/3V3ff9nanT/Z2p0/2psc/9qbHP/amxz/3Bzff93eX//am13/25wd/9qbXf/ -eXuB/2ptd/9wc33/am13/2xudf9ucXv/Z2p0/2dqcf9qbXf/amxz/2psc/9iZW7/bG51/2dqdP9sbnX/ -bG51/25xe/9qbXf/am13/3Bzff9zdXz/Zmlz/2xvef9ucXv/amxz/2xudf9sbnX/ZGdx/2Rncf9kZ3H/ -YmVu/2Zpc/9oanP/bG53/2ptd/9vcXj/c3Z//3N2f/9wc33/bnF7/25xe/9zdn//b3J7/3Fze/9tcHr/ -bW91/3Bzff9tb3P/amxz/3V3ff91d33/dXd9/3h5ff9ucHf/b3F1/25wd/92eHz/bnB3/3N2f/92eHz/ -dXd9/3Byef9zdXz/bnB3/25wd/9ucHf/dXd9/3+CjP9wcnn/c3Z//25xe/93eX//bG95/3t9g/94eX3/ -bnB3/3Bzff9qbXf/c3Z//2xvef9wc33/cHJ5/3t+h/9ucHf/cHN7/3R3gP9ucHf/dXiB/25xe/95fIb/ -cnV+/29ye/91eIH/cHN9/25wd/9zdn//c3Z//25wd/9sbnX/cHJ5/2xvef9ucHf/bG51/3Byef91d33/ -bnB3/29xdf9zdXz/c3V8/2xvef91d33/cHN9/3Bzff9qbXf/cHJ5/3N1fP9ucHf/cHJ5/3Byef9zdn// -c3Z//3N2f/9qbXf/bXB5/3N2f/9wc33/cnV+/3d6g/90d4D/c3V8/3N2f/96fIL/enyC/31/hf90d4D/ -cnV+/29yfP95fIX/dHeA/3h6gP9ydX7/cnV+/3Z4fv9tcHn/am13/3R2fP9ucHf/b3F1/3J1fv9zdX7/ -bG95/3J1fv90dnz/d3l9/3h5ff9xc3r/dHZ9/2xudf9wcnr/bnB3/21wev9rbnj/b3F5/3Bzev9zdX7/ -dnmC/3J1f/9sb3n/dnh+/3Byev91eIH/b3J8/3R3f/9ucXv/b3F5/3F0fv91eIH/cXN5/3J1fv9wcnr/ -cXR9/3J0e/90d4D/cXN7/3V3ff9wc3v/cHJ5/3N1ff92eH//am11/3N1ff9ydHz/bG51/2xudf91d33/ -bnB3/3Byef9ucXv/c3Z//25wd/9sb3n/dnh8/25xe/9wcnn/c3V8/2xudf9nanT/bW9z/3Byef9vcXX/ -b3F1/3Bzff91d33/bnB3/25xe/9qbXf/c3Z//3h5ff9sbnX/bG51/2ptd/9sb3n/am13/3N1fP9sbnX/ -Zmlz/2xvef9qbXf/bG95/2dqdP9kZ3H/bnB3/2ptd/9maXP/Z2p0/2Rncf9maXP/Z2p0/2Zpc/9nanT/ -ZGdx/1xfaP9kZ3H/ZGdx/2Rncf9ucHf/YmVu/2Jlbv9maG7/ZGdx/2psc/9nanT/bnB3/2Zobv9kZ3H/ -Z2px/3d6g/9nanT/cHN9/2psc/9qbXf/dXd9/2xudf9nanH/bG95/2xudf9tb3P/Z2px/25wd/9ucHf/ -bG95/25wd/9zdn//c3V8/3Bzff93eoP/eXuB/25xe/93eoP/d3qD/3Byef9wc33/cHN9/2xudf9vcXX/ -c3V8/21vc/9sbnX/cHJ5/29xeP9tb3b/cHJ5/3V4gf91eIH/c3Z//3N2f/9ucXv/d3l//3Bye/90dnz/ -cXN9/2xvef9zdn//bnF7/25wd/93eX//eXuB/3d5f/93eX//bG95/3Byef9vcXX/dnh8/25wd/9zdXz/ -dnh8/3V3ff9zdXz/cHJ5/29xdf9sbnX/cHN9/3V3ff+Agob/bW9z/25xe/9sbnX/dXd9/21vc/93eX// -dnh8/21vc/9sbnX/Z2px/3Bzff9sb3n/cHJ5/25wd/93eX//bW92/29yfP9xc3v/aGt1/2xvef9kZ3H/ -dXd9/2xvef9pbHP/cXR7/25xe/9ucHf/cHN9/3Z4fP9sbnX/amxz/25wd/9ucHf/bG51/2psc/9ucHf/ -c3V8/2xudf9qbXf/c3V8/3V3ff9sb3n/c3V8/3Bzff91d33/bG51/3V3ff9zdXz/b3F1/3N1fP9ucHf/ -c3V8/3N1fP9zdXz/Zmlz/2ptd/9ucHf/bG95/3Bzff93eX//bnF7/29xdf9sbnX/c3V8/3V3ff91d33/ -bnB3/25wd/9ucHf/dXd9/25wd/92eHz/bnB3/2xvef91d33/bW9z/2xudf92eHz/bG51/2xvef9ucXv/ -am13/2ptd/9ucXv/c3V8/3V3ff94eX3/c3V8/3d5f/9vcXX/cHJ5/25wd/9sb3n/am13/2ptd/9wcnn/ -cHN9/3J1fv9wc33/am13/3R2fP9vcXX/cHJ5/2xudf9ydHz/bnB3/2xvef9vcnz/dnmC/25xe/9zdn// -bnF6/3N2fv9qbXf/dnh8/21vdv90dnz/b3F4/2tueP9ucXr/cHN9/2Vocv9tcHr/cnR8/2Jlbv9nanH/ -bnF7/2ptd/9qbXf/amxz/2Zpc/9maG7/Zmhu/2dqdP9maG7/Z2p0/2xvef9maXP/ZGdx/2Rncf9qbXf/ -Z2p0/2dqdP9ucXv/cHN9/2ptd/9sb3n/Z2p0/3Bzff92eHz/bG51/29xdf9ucHf/bnB3/3Byef97fYP/ -c3Z//25xe/91eIH/c3Z//3V4gf9zdn//bG95/3N2f/9wc33/bnF7/3N1fP9tb3P/bnB3/25wd/9sb3n/ -bnF7/2xvef9nanT/bnF7/2xvef9sbnX/dXd9/2Rncf9maG7/ZGdx/2Rncf9maG7/am13/25wd/9nanH/ -Z2p0/2ptd/95e4H/bG95/3N1fP9sbnX/amxz/3V3ff9sbnX/bG51/3Bzff9ucHf/bnB3/2ptd/9ucHf/ -b3F1/29xdf9ucHf/c3V8/25wd/9tb3P/dXd9/3N1fP9nanT/dXd9/3N1fP9qbXf/am13/2psc/9nanT/ -amxz/3Byef9nanH/Zmhv/2tueP9nanT/ZWhy/2ttdf9qbXf/am13/2ptd/9nanT/Z2px/3Bzff9sb3j/ -b3J8/2xvef9sbnX/c3V8/2ptd/9nanT/bnF7/3N1fP91d33/dXd9/2xudf9ucXv/bG51/2xvef9qbXf/ -bnF7/25xe/91d33/dnh8/3Byef9sbnX/bW9z/3N1fP93eX//gIKG/21vc/9sb3n/bG95/3h5ff9sbnX/ -d3qD/3V3ff9qbXf/am13/2Zpc/9zdXz/cHJ5/3N2f/9wc33/en2G/21vd/9vcnz/cnV8/2hqdP9nanT/ -ZGdx/3Byef9ucXv/aWxz/3F0fv9vcnz/bG95/3Bzff9zdn//bW9z/2xudf9zdXz/cHJ5/25wd/9qbXf/ -cHN9/3l7gf9ucHf/bnB3/3l7gf97fof/c3Z//3t+h/97fYP/e32D/3N2f/95e4H/eXyG/3N2f/95fIb/ -eXuB/36Ahv97fYP/foCG/3V3ff91d33/cHN9/3Bzff91eIH/eXyG/25xe/9qbXf/bnB3/3N2f/93eX// -dXiB/2ptd/9sb3n/bG95/3l7gf9wc33/eXuB/3Bzff9ucXv/dXd9/29xdf9sbnX/dnh8/2xudf9wcnn/ -cHN9/25xe/9wc33/c3Z//3V3ff91eIH/eXuB/3V4gf93eX//bnB3/25xe/9ucHf/bnB3/2xudf9nanH/ -bG51/3N1fP9wc33/c3V8/2psc/9zdXz/bG51/2xudf9qbXf/cHN9/3Byef9nanT/bG95/3l7gf9sbnX/ -bW9z/2xudf9sb3n/Zmlz/3Bzff9qbHP/cHN9/2ptd/9sb3n/bnF7/3Bzff9kZ3H/bG95/2xvef9nanT/ -bnF7/3N2f/9wcnn/bnF7/3Bzff9ucXv/cHJ5/3Byef91eIH/cHJ5/3N2f/91d33/cHN9/2xvef9sb3n/ -dXiB/3Byef9wcnn/c3Z//3Bzff9ucHf/bG51/2xudf91d33/c3V8/2psc/9qbHP/am13/2xudf9nanH/ -c3V8/2psc/9maXP/bG95/2xudf9wc33/cHJ5/2xudf9wcnn/c3V8/2xudf9wc33/amxz/2xvef9sb3n/ -bG51/3N1fP9wcnn/Z2p0/3Bzff9zdXz/bnB3/3d5f/9qbXf/bnB3/25wd/9sbnX/bG51/3V3ff94eX3/ -b3F1/25wd/9zdXz/f4GH/2xvef9zdXz/bG95/2xudf92eHz/am13/2ptd/9ucXv/bG95/2psc/9maXP/ -bG51/2dqcf9kZ3H/Zmlz/2xvef9maXP/Z2p0/25xe/9zdXz/Z2p0/3N1fP9ucXv/am13/2ptd/9vcXX/ -b3F1/2xudf9zdXz/bG51/2tud/9ydHv/bXB6/29ye/9wc3z/d3qD/3l8hv95fIb/d3qD/3Bzff97fYP/ -dHeA/3h7gv95e4H/dHZ9/3t9g/91eIH/c3V8/3d6g/97fYP/foCG/36Biv9zdn//e32D/3V4gf93eoP/ -cHN9/3V4gf9zdn//dXiB/3N2f/9wc33/bnB3/25wd/9zdXz/dnh8/4CChv9sb3n/bnB3/25wd/92eHz/ -am13/3N2f/9zdXz/amxz/2ptd/9gY2z/bnF7/2dqdP9ucXv/cHN9/3V4gf9rbXX/bnF7/3R3gP9ydHv/ -c3Z//2ptd/93eX//cnV+/25weP9ydHz/bXB5/2dqcv9sb3n/bnF7/2psc/9maXP/bG95/2xvef9sb3n/ -am13/25wd/91d33/bG95/2xvef91eIH/d3qD/3Bzff93eX//dXiB/3Bzff9ucHf/c3V8/3N1fP9sbnX/ -bG95/2xvef9wc33/cHN9/3N1fP9qbHP/bW9z/2xudf9sbnX/c3V8/3d5f/9ucHf/am13/2xvef9zdn// -eXuB/3d6g/9ucXv/bnF7/3Byef95fIb/c3Z//3l8hv9wc33/dXiB/3l8hv91eIH/dXd9/3t+h/9ucXv/ -dXiB/3V4gf9wc33/bnF7/3N1fP91d33/d3qD/3d5f/9wcnn/dXd9/2dqdP9nanT/amxz/2Zpc/9iZW7/ -YmVu/2xudf9qbXf/cHN9/25xe/9nanT/cHN9/2ptd/9sbnX/am13/3N1fP9ucHf/Z2p0/25xe/93eoP/ -bG51/2ptd/9qbXf/bG95/2ptd/91d33/Z2p0/3Bzff9sb3n/cHJ5/3Byef91d33/Zmhu/3V3ff9zdXz/ -am13/25xe/9zdn//dXiB/3Bzff9ucHf/cHN9/25xe/9sb3n/dXd9/25wd/9wcnn/dnh8/3Byef9ucHf/ -bG95/3d5f/9wc33/cHJ5/25xe/91eIH/bnF7/3N1fP9sb3n/eXuB/3l7gf9wc33/dXd9/3l7gf93eX// -dXiB/36Ahv9zdXz/bnF7/3N2f/9wc33/eXyG/3l8hv92eHz/eXuB/35/g/95e4H/fX6B/3Bzff91eIH/ -dXiB/3Bzff93eoP/c3Z//25wd/93eoP/d3qD/3Bzff95e4H/am13/2xvef9ucHf/bG95/2xvef9zdn// -dXd9/2xvef9ucHf/c3V8/3+Bh/9sbnX/dXd9/2xudf9qbXf/eHl9/25wd/9sb3n/dXiB/3V4gf9zdXz/ -bnB3/2xvef9ucHf/cHJ5/25wd/9zdn//c3Z//3N1fP9+gIb/e36H/3V3ff9+f4P/fX6B/3Z4fP91eIH/ -c3Z//2xudf9sbnX/cHN9/2xvef9rbnj/dHZ8/3R2fP9ydHr/enyC/36Ahv97fYP/eXuB/3V4gf9wc33/ -enyD/3N2fv90dn7/cXN6/21vdv91d33/bG51/2dqdP9wcnn/cHN9/3Z4fP93eX//bnB3/3N2f/9sb3n/ -c3V8/2xvef9ucXv/bnB3/3N2f/9zdn//cHN9/25wd/9ucHf/c3Z//3l7gf+Bg4r/bnB3/25xe/9wc33/ -eXuB/3Bzff93eoP/d3qD/3Byef9zdn//Zmlz/3V3ff9wc33/dXd9/3N2f/95fIX/bG51/29xeP90d37/ -am13/3Bzff9sb3n/eHl9/3N1e/9rbnf/cXN7/25xe/9sb3n/dXiB/3V4gf9ucXv/bG95/3N2f/9ucXv/ -c3V8/2ptd/9sb3n/dXd9/25wd/9ucXv/dXiB/3l8hv9wc33/dXd9/3Bzff9zdXz/bnB3/3V3ff9wcnn/ -bG51/25wd/9ucHf/cHN9/3Bzff91d33/bW9z/2xudf9nanT/am13/25xe/9ucHf/Z2p0/2Rncf9qbHP/ -ZGdx/2dqdP9maG7/YmVu/2dqcf9maXP/cHJ5/2dqcf9sb3n/Z2px/2psc/9sb3n/amxz/2dqdP9zdXz/ -Z2p0/25xe/9zdXz/bG95/2xudf9ucHf/c3V8/3V3ff93eX//c3V8/3Z4fP9ucHf/cHJ5/3Byef9vcXX/ -am13/25wd/9ucHf/cHJ5/3Z4fP9wcnn/bG51/3N1fP9ucHf/bnB3/25wd/9zdn//bnF7/2psc/9ucXv/ -eXuB/29xdf9ucXv/bnB3/2xvef9qbXf/d3l//2xvef9zdn//dXiB/3Bzff9sb3n/cHN9/2Zpc/9zdn// -dXiB/2ptd/9wc33/dXiB/3N2f/9zdn//cHN9/3V4gf9zdn//c3Z//3t9g/95e4H/e32D/3t9g/95e4H/ -c3V8/3N1fP95e4H/cHJ5/2xvef9ucHf/cHN9/25wd/9sb3n/amxz/3N2f/9zdn//b3F1/25wd/9wcnn/ -bG95/25wd/9wc33/bG51/2psc/9ucXv/am13/3Bzff9ucXv/bG51/25wd/9zdXz/bnF7/3d6g/9zdXz/ -c3Z//3V4gf91eIH/e32D/3V4gf9zdXz/e32D/3d6g/9wc33/e36H/3Z4fP91eIH/dXd9/3V4gf9zdXz/ -eXuB/3t+h/9wc33/cHN9/3N2f/+Bg4r/bnB3/3V3ff9ucHf/bG51/3h5ff9vcXX/bG95/3V3ff91d33/ -bG51/2xudf9sbnX/Z2p0/2psc/9maXP/bG95/2dqcf9maXP/cHN9/3d5f/9nanT/cHN9/3N1fP9qbXf/ -bG51/2xudf9zdXz/c3V8/3l7gf9zdn//cHJ5/3Z4f/9wc3r/aGt1/2ptd/9wc33/amxz/2ptd/9qbXf/ -am13/3N1fP9rbnX/cHN8/3Fzev9wcnn/dXd9/3Byef9ucHf/c3V8/3Bzff9zdXz/dXd9/2xvef9zdXz/ -bnB3/3N1fP9ucHf/cHJ5/25wd/9zdn//dXiB/3N2f/9sb3n/bnF7/3N2f/91eIH/g4WM/3V3ff91d33/ -e32D/3+Bh/97fYP/f4GH/4WHjf97fYP/eXyG/3N2f/9+gYr/foCG/36Ahv99foH/gIKJ/3N1ev9zdX3/ -dXd+/2lrdf9ucXv/am13/3N1fP91d33/a254/3N1fP9xc3n/amxz/3Bzff9wc33/amxz/2Rncf9qbXf/ -bG51/2ptd/9qbHP/bnB3/3V3ff9sbnX/amxz/3V3ff93eX//cHJ5/3V3ff9ucXv/cHN9/2xudf9qbXf/ -bG95/2dqdP9sb3n/bG51/25xe/9wc33/cHN9/2dqdP9qbHP/am13/25wd/91d33/dXd9/3N1fP9ucHf/ -bG95/3Bzff9zdn//bnF7/2xvef9sb3n/bG95/3d5f/9sb3n/dXd9/25xe/9wc33/c3Z//29xdf9ucHf/ -dnh8/2psc/91d33/dXd9/25wd/9qbXf/bnB3/2xvef9wc33/bnF7/2dqdP9qbXf/Zmhu/2ptd/9sb3n/ -bG51/2dqdP9qbXf/bW9z/25wd/92eHz/cHJ5/2Zpc/9wc33/bG95/2xudf9nanT/bnF7/25wd/9qbHP/ -bnB3/3d5f/9tb3P/cHJ5/25wd/9ucHf/am13/3V3ff9qbXf/cHN9/3Bzff9ucHf/bnB3/3Bzff9maXP/ -c3Z//3N1fP9sbnX/cHJ5/3N2f/9wcnn/bnB3/25wd/9wcnn/cHJ5/3Byef91d33/bnB3/25wd/92eHz/ -c3V8/2xudf9qbXf/cHN9/2xudf9sbnX/bnB3/3Byef9qbXf/Z2p0/2Zpc/9ucXv/am13/2Zpc/9maXP/ -Zmlz/2Jlbv9nanH/Z2p0/2Rncf9maXP/bG95/2psc/9ucXv/bG95/2Rncf9qbXf/bG95/2ptd/9wc33/ -bW9z/2ptd/9ucXv/am13/25xe/9sb3n/bG51/3V3ff9sb3n/bG95/3N1fP9nanT/bG95/2ptd/9ucHf/ -bnB3/3Byef91d33/bW9z/21vc/9wcnn/f4GH/21vc/9wc33/am13/25wd/91d33/bG95/2xudf9zdXz/ -bnF7/2ptd/9tb3P/bnB3/2xvef9sb3n/bnB3/3d5f/9wcnn/bnB3/3h5ff93eX//bG51/3V3ff93eX// -bnB3/25wd/9ucHf/bnF7/3Bzff93eoP/eXyG/3N2f/97fYP/cnV//21wev9wc33/c3Z//2xvef9ucXv/ -bnB3/25wd/91d33/cHJ3/3V4gP91eIH/c3Z//3d6g/9zdn//bG95/3N2f/9zdn//dXiB/3d6g/9wc33/ -cHN9/3Bzff9ucXv/bnF7/3Bzff9wc33/dXiB/3N2f/9zdn//bnB3/21vc/9zdXz/dXd9/35/g/9ucHf/ -bG95/3V4gf93eX//bnF7/3d5f/93eoP/c3Z//25xe/9qbHP/cHN9/3Byef91d33/c3V8/3l7gf9sbnb/ -cXR8/3V4gv9wcnz/eXyG/3V3ff99foH/fH6F/3J1f/92eID/cXN6/2hrdf9wc33/dXd9/21vc/9nanH/ -cHJ5/3l7gf93eX//dXd9/3V4gf95e4H/c3V8/25xe/91eIH/eXyG/3N2f/95fIb/c3Z//3d6g/9wc33/ -cHN9/25xe/9sb3n/bG95/2xvef9zdn//c3Z//3d5f/9vcXX/bnB3/25wd/9wcnn/dXd9/3N1fP9ucXv/ -b3F1/2xvef9wc33/d3l//3N2f/9wcnn/cHJ5/2xvef91d33/bnF7/3d5f/9wcnn/d3qD/3d6g/9zdn// -c3Z//35/g/91d33/fX6B/31+gf91eIH/dXiB/3l7gf9+gIb/f4GH/36Ahv97fYP/fX6B/3d5f/95e4H/ -foCG/3d5f/93eX//dnh8/3N2f/91eIH/foCG/3t9g/9ucXv/d3qD/3N2f/9zdn//cHJ5/3V4gf9zdn// -cHN9/3V4gf95fIb/cHN9/25xe/9sb3n/bnF7/2ptd/92eHz/Z2p0/3Byef9ucXv/bG95/2xudf9zdXz/ -amxz/3V3ff9zdXz/am13/25xe/91eIH/c3Z//25xe/9ucXv/cHJ5/25xe/9ucXv/dXd9/2xvef9sb3n/ -c3V8/25wd/9sbnX/bG51/3Bzff9sbnX/bnB3/2psc/9wcnn/bW9z/2ptd/9nanT/cHN9/25xe/9nanT/ -ZGdx/2ptd/9kZ3H/amxz/2ptd/9sbnX/am13/2xvef9sbnX/cHJ5/3N1fP9qbHP/bG51/25wd/9ucHf/ -dXd9/2xudf9sb3n/cHN9/2ptd/9wc33/bG95/2xudf9wc33/bnB3/3Byef91d33/bG51/3N1fP9ucHf/ -bnB3/2xudf9zdXz/d3l//2psc/9qbXf/cHJ5/3+Bh/9sbnX/bnF7/2ptd/9vcXX/dnh8/3Byef9vcXX/ -dnh8/3N1fP9ucHf/b3F1/2xudf9tb3P/bG51/2xudf9wc33/bG51/21vc/94eX3/d3l//21vc/9zdXz/ -c3V8/2ptd/9sbnX/bG51/25wd/9wcnn/d3l//3N2f/9ucHf/c3V7/3N1fP9vcXj/bG95/3N2f/9ucXv/ -c3Z//2xvef9ucXv/c3Z//21wev92eYD/eHqB/3V3gP97fof/c3Z//3N2f/97fYP/eXuB/3d6g/97fYP/ -cHN9/3V4gf95e4H/cHN9/3V4gf91eIH/c3V8/3d6g/95e4H/dXiB/25wd/9wcnn/cHN9/3Bzff97fYP/ -b3F1/25wd/93eX//c3Z//25xe/93eX//dXiB/25xe/9ucXv/am13/3Bzff9ucXv/dXiB/3Bzff94e4X/ -b3F4/25xev91d33/aGt0/2xvef9sbnX/c3V8/3N1fP9tcHr/dXd9/3J0ff9wcnn/d3l//3V3ff9sb3n/ -am13/3Bzff9ucHf/bnF7/2xvef9ucXv/d3l//3Byef9sb3n/c3Z//3l8hv9wc33/eXyG/2xvef9wc33/ -bG95/3Bzff9ucXv/bG51/2xvef9sbnX/c3V8/3N1fP93eX//b3F1/29xdf9sbnX/bG95/3V3ff9zdXz/ -am13/2psc/9sbnX/bG95/25xe/9qbXf/Z2p0/2psc/9nanT/dXd9/2ptd/9zdXz/bG51/2xvef9qbXf/ -bG51/2xudf9zdXz/Z2p0/25xe/9qbXf/amxz/2Zpc/9qbXf/am13/25xe/9sb3n/am13/25xe/9sb3n/ -bG95/3Bzff9sbnX/bG51/2xudf9sbnX/bG95/3Bzff9sb3n/amxz/3Bzff9sbnX/bG51/2psc/9wc33/ -cHJ5/25wd/9ucXv/d3qD/3Byef91eIH/bG95/25xe/9qbXf/dXd9/2xvef9wc33/cHJ5/3N1fP9ucXv/ -cHN9/2xvef91eIH/dXiB/2psc/9sbnX/c3V8/2xvef9ucHf/cHJ5/25wd/9wcnn/bnB3/3V3ff9wcnn/ -bnF7/3N1fP9zdXz/am13/2xudf9wc33/am13/2psc/9maXP/bnF7/21vc/9ucHf/bnB3/3V3ff9wcnn/ -bG51/2psc/9ucHf/bG95/3Bzff91d33/bnB3/25wd/9wcnn/bG51/3Byef9ucHf/bnB3/2xvef9zdn// -bnF7/3V4gf9ucXv/cHN9/3V4gf9zdXz/dXiB/3Bzff9zdXz/dXiB/3Bzff93eoP/dXiB/25xe/9wc33/ -bnB3/2xvef9sb3n/dXd9/3l8hv9ucHf/bnB3/3N2f/+BhI3/c3V8/3N2f/9sb3n/c3V8/3l7gf91eIH/ -cHN9/3t9g/91eIH/c3V8/3Byef9ucXv/cHJ5/25xe/9ucHf/d3qD/3N2f/9wc33/e36H/36Biv9zdn// -eXyG/3l7gf9wc33/c3Z//25xe/9qbXf/bW9z/3V3ff9zdXz/bnB4/3N1fP9xc3j/bnB2/25wd/91d33/ -cHJ5/25xe/9ucHf/bnF7/25xe/9tb3f/cXR9/3N1fP9vcXn/d3l//3N1fP9qbHP/eHl9/3Z4fP92eHz/ -dXd9/2xudf9ucXv/cHN9/2xudf9ucXv/bG95/2xudf9ucXv/dXd9/2xudf9ucHf/b3F1/3N1fP9wcnn/ -e32D/25wd/9tb3P/c3V8/3N1fP9ucHf/dXd9/3V3ff9wcnn/cHJ5/2psc/9sbnX/bG95/3Bzff9wc33/ -dXd9/2xudf9tcHr/c3V8/2xvef9zdXz/b3F1/3Byef90dnz/bnB3/3J0ev9wc3v/bG95/3V4gf9zdn// -bG95/2xvef9ucXv/c3Z//25xe/9nanT/cHJ5/3d5f/9vcXX/Z2px/3V3ff94eX3/bnB3/3l7gf9sbnX/ -bG51/21vc/9zdXz/bnF7/25wd/9ucHf/bG95/3Byef9wcnn/dXd9/25wd/9vcXX/b3F1/25wd/91d33/ -bnF7/25xe/9sbnX/am13/25xe/9wc33/bG95/2dqdP9sbnX/amxz/3Z4fP9ucHf/bnF7/25wd/9wc33/ -bnB3/25wd/9vcXX/dnh8/25wd/92eHz/cHJ5/21vc/9ucHf/bnB3/3Byef9zdn//dXiB/3N2f/93eoP/ -cHN9/3Bzff9wc33/bG95/2xudf9sbnX/bG51/25wd/9wc33/bnF7/2Zpc/9sb3n/amxz/2dqdP9kZ3H/ -bG95/2ptd/9maXP/bnB3/3V3ff9sbnX/bG95/2xudf9ucXv/Z2p0/3N1fP9nanT/bG95/2xvef9ucXv/ -am13/2xvef9nanH/dXd9/3Byef9maXP/am13/25xe/9ucHf/am13/2xudf9tb3P/bG95/2psc/9ucXv/ -bnF7/2ptd/9wc33/cHN9/2Zpc/9sbnX/cHN9/2ptd/9qbXf/Zmlz/2ptd/9sbnX/Z2p0/2ptd/91d33/ -bnF7/21vc/9nanH/bG51/2dqdP9qbXf/bnF7/2psc/9nanT/bG95/2psc/9qbXf/bG95/2Jlbv9qbHP/ -am13/2psc/9sb3n/bG51/2xvef9wc33/am13/3Z4fP9vcXX/bG51/3Byef9ucHf/c3V8/3Byef9sbnX/ -c3Z//25wd/9qbXf/Z2p0/3Bzff95fIb/cHJ5/3N1fP9zdn//g4WM/3N1fP9wc33/am13/25wd/9zdXz/ -cHJ5/2xudf94eX3/cHJ5/2xudf9qbXf/am13/2xudf9sbnX/am13/3N1fP9ucXv/b3F1/3d5f/91d33/ -am13/3N1fP9wc33/Z2p0/2xvef9sbnX/bnB3/2ptd/94eX3/c3Z//25xe/92eYP/c3V8/21vdv9ucHf/ -cHN9/2xvef9sbnX/bG51/2xvef9rbnj/bXB6/3J1fv9ydX7/dHeA/3d6g/91eIH/cHN9/3t+h/97fYP/ -e36H/3l8hv9wc33/eXuB/3d6g/9ucHf/cHN9/25xe/9wcnn/dXiB/3d6g/9wc33/bnB3/25wd/9wc33/ -cHN9/3t9g/9sb3n/bW9z/3V3ff91d33/cHJ5/3l7gf94eX3/cHJ5/25xe/9qbXf/bnB3/25wd/91eIH/ -d3qD/3p8gv9xc3v/cHN9/3R3fv9ucHf/bnF7/25wd/9zdn//c3Z//25xe/9zdXv/bnF7/25wd/9zdn// -dXd9/25wd/9qbHP/bG51/3N2f/9sb3n/am13/2xvef93eX//bnB3/2ptd/9zdn//eXuB/3Byef95fIb/ -bnF7/25xe/9wcnn/c3Z//3Bzff9ucHf/bnB3/3Bzff9wcnn/cHJ5/3V4gf9ucXv/bnB3/29xdf9ucXv/ -dXd9/3N2f/9zdn//bnB3/2xvef9zdXz/dnh8/3V3ff9ucHf/cHJ5/25wd/92eHz/b3F1/3Byef9sbnX/ -am13/2ptd/9sbnX/am13/3N1fP9nanT/cHJ5/2psc/9nanT/Z2p0/2dqdP9qbXf/bG95/25xe/9qbHP/ -am13/2ptd/9nanT/Z2p0/2Zobv9kZ3H/Z2p0/2xudf9qbXf/cHN9/3N1fP9sbnX/bnB3/2xudf9ucHf/ -Z2p0/3N2f/91eIH/bnB3/3Byef93eX//bnB3/3Byef9sbnX/cHJ5/2ptd/93eX//bG95/2xvef91eIH/ -c3Z//29xdf9wcnn/amxz/3V3ff9ucXv/amxz/25wd/9ucXv/am13/3Byef9tb3P/bG51/2xvef9qbHP/ -bnF7/25xe/9sbnX/dXd9/3Bzff9nanT/bG51/25xe/9sbnX/amxz/2Rncf9nanT/Z2p0/2Zpc/9maXP/ -dXd9/25xe/9qbHP/YmVu/2xudf9qbXf/bG95/3N1fP9sbnX/bG51/25xe/9ucXv/bnF7/3N1fP9qbHP/ -cHJ5/25xe/9wcnn/d3l//29xdf91eIH/dXiB/3V4gf95e4H/c3V8/25wd/91eIH/bnF7/3N2f/93eoP/ -cHN9/3V4gf9ucXv/bG95/2ptd/9wc33/d3l//2xudf9ucHf/c3V8/35/g/9ucHf/bnB3/2dqdP9sbnX/ -cHJ5/25xe/9sbnX/cHN9/3Byef9tb3P/bG95/2xudf9vcXX/bnB3/2xvef9zdn//bnF7/2xvef95fIb/ -eXuB/25xe/95e4H/eXuB/3N1fP91eIH/d3qD/3N2f/9wc33/e32D/3N2f/9tcHn/d3qD/3N1ff9tcHr/ -cHN9/3d6g/9zdn//bG95/25wd/9ucHf/c3V8/3Byev9xdH7/dnmC/3R3gP97fof/eXuB/25xe/95fIb/ -d3l//3l7gf95e4H/bnB3/3d5f/93eoP/c3V8/3l7gf93eoP/c3Z//3l8hv93eoP/dXiB/3N1fP9zdXz/ -c3Z//3V4gf95fIb/cHN9/2xvef91d33/dXd9/3Byef93eX//eHl9/3Byef9ucHf/Z2p0/2xvef9ucXv/ -dXd9/3Z4fP91d33/a211/2ttdv9zdXv/a210/25xe/9tb3P/bnF7/25xe/9tb3f/cXR9/3J0ff9sb3n/ -c3Z//3V3ff9ucXv/am13/25xe/9sb3n/amxz/2Zpc/9sb3n/dXd9/2ptd/9kZ3H/bG95/3Byef9nanH/ -c3V8/2Zobv9sbnX/bG51/2ptd/9nanT/ZGdx/2Zpc/9maXP/ZGdx/2Zpc/9wcnn/Z2p0/2Jlbv9maXP/ -Z2p0/3Bzff9sb3n/bnF7/2psc/9qbXf/bnF7/3V3ff9wc33/am13/25wd/9qbHP/dnh8/25wd/9wcnn/ -bnF7/3Bzff9zdXz/cHN9/3N1fP95e4H/bnB3/3V3ff9ucXv/bG95/2xvef9ucXv/bG51/25wd/91d33/ -bnB3/25xe/9ucXv/am13/25xe/9sbnX/Z2p0/2xudf9nanT/Z2p0/2dqdP9sb3n/YmVu/2dqcf9nanH/ -ZGdx/2Jlbv9ucXv/Z2p0/2Zpc/9sbnX/c3V8/2xudf9sb3n/bG51/2xvef9kZ3H/c3V8/2xudf9sb3n/ -c3Z//2xvef9vcXX/bnB3/2psc/91d33/bnB3/2xudf9qbXf/cHJ5/2ptd/9wc33/bG51/2xudf9ucHf/ -bG51/25xe/9ucXv/am13/3N1fP9wc33/Zmlz/2dqcf9qbXf/Z2p0/2psc/9maXP/am13/2ptd/9sbnX/ -bG51/3Z4fP9sbnX/bnB3/2dqdP9ucHf/bnB3/25xe/9zdn//bnB3/2xvef9ucXv/bnF7/25xe/9zdn// -am13/3Bzff9zdXz/cHN9/3l7gf9wcnn/c3Z//3Z4fP9zdXz/eHl9/2xudf9sbnX/cHJ5/25wd/9wcnn/ -c3V8/2psc/9wcnn/am13/2dqdP9qbHP/bnB3/3d5f/9tb3P/bG51/3V3ff9+f4P/bnB3/3Byef9ucHf/ -b3F1/3V3ff9wc33/bG95/3Bzff9zdn//cHJ5/3N2f/9wc33/cHN9/3V4gf9zdXz/eXuB/3l7gf95e4H/ -g4WM/36Ahv97fYP/foCG/36Ahv9zdn//dXiB/3V4gf9wcnn/bnB3/3h5ff91d33/a254/3x+hf9ydX7/ -b3J6/3R3gP95e4H/cHN9/2xvef9vcXX/bnF7/3N2f/9tcHr/b3F4/3Fzev9sbnX/dnh8/3V3ff9nanT/ -dXd9/25xe/9zdXz/bnF7/2dqdP9wc33/cHN9/2xudf9sb3n/amxz/2dqcf9nanT/Z2p0/2ptd/9qbHP/ -Z2px/2xvef9nanT/c3Z//2Zpc/9kZ3H/Z2p0/2xvef9qbHP/cHJ5/3Byef9maXP/bG51/2dqdP9qbHP/ -am13/3Bzff9wc33/dnh//2ttdf9qbXX/cXN6/2ptd/9ucXv/Z2px/2ptd/9rbXf/bnF4/3J1fv91eID/ -bnF6/3l7gf91eIH/bnB3/2Rncf9sb3n/cHJ5/29xdf9qbHP/cHJ5/3Z4fP9nanT/Z2p0/2ptd/91d33/ -b3F1/3d5f/9tb3P/bG51/2xvef9wcnn/bnB3/2ptd/9sb3n/am13/2ptd/9nanT/cHJ5/2dqdP9nanT/ -Z2p0/25xe/91d33/bG95/2xvef9nanH/bG51/2xvef9zdXz/bnF7/2psc/9qbXf/Zmlz/3Bzff9qbXf/ -am13/2xvef9nanT/Z2px/2xudf9nanH/bG95/2dqdP91d33/bG51/2Zpc/9maXP/am13/2Zpc/9qbXf/ -cHJ5/2dqdP9sb3n/cHN9/2dqdP9qbXf/Z2px/2dqdP9qbXf/Zmlz/2dqdP9nanT/am13/2Rncf9qbHP/ -amxz/2psc/9kZ3H/cHN9/2ptd/9qbHP/am13/3Byef9qbHP/am13/2psc/9maXP/YGNs/25xe/9nanH/ -am13/3Bzff9sbnX/am13/2psc/9nanT/bnF7/2ptd/9zdn//c3Z//3l8hv93eX//fn+D/3N2f/9zdn// -eXyG/3V3ff93eoP/d3qD/25xe/95e4H/c3Z//2ptd/9ucHf/dXiB/3N2f/9wc33/bG95/25xe/9sb3n/ -bnB3/3Byef97fYP/c3Z//25xe/9nanT/bnB3/2xudf9ucHf/dnh8/25wd/9qbXf/bnF7/25xe/9wc33/ -bnF7/2xvef9ucXv/c3V8/25wd/9zdXz/bnB3/3V3ff92eHz/cHJ5/3V3ff9qbXf/bnB3/2xvef9ucHf/ -cHJ5/3Byef9nanT/cHJ5/25xe/9qbXf/bG51/25xe/91d33/bW9z/2xudf9wcnn/fX6B/2xvef9qbXf/ -Z2p0/2dqdP9ucXv/bnF7/2ptd/9sb3n/bG95/2xudf9nanT/Z2px/2Zpc/9maXP/Z2p0/25xe/9qbXf/ -Z2p0/3Byef9wcnn/ZGdx/25wd/9sb3n/Zmhu/2xvef9maXP/cHJ5/21vc/91d33/dXd9/2xudf93eYD/ -b3J5/2ptd/9sb3n/bnF7/2xvef9tb3P/bW9z/25wd/9zdXz/bnB3/3Bze/9zdn3/b3F1/3V3ff91d33/ -Z2px/3d5f/9ucXv/dnh8/3Byef9ucHf/dnh8/3N1fP9sb3n/bnF7/2xvef9qbHP/bnF7/25xe/9sbnX/ -b3F1/25wd/9zdn//bnB3/3t9g/9zdXz/bnB3/3V3ff9zdn//bnF7/3V4gf91d33/cHN9/25wd/9ucHf/ -b3F1/2xudf9wcnn/dXd9/3h5ff9ucHf/bnF6/3V2fP9tb3T/cHN9/25wd/9wc33/cHJ5/29xeP9xdHz/ -cnR6/2xudf9zdXz/bnF7/2ptd/9kZ3H/bG95/25xe/9ucHf/bG95/3Bzff95e4H/bnF7/25wd/9sb3n/ -dnh8/2xudf93eX//bG51/2xudf9qbXf/am13/2xudf9maXP/am13/2ptd/9qbXf/am13/3N1fP9qbXf/ -Zmlz/2psc/91d33/dnh8/3N1fP91d33/bG51/2dqcf9ucXv/cHN9/3Byef9sbnX/bnB3/2ptd/91d33/ -bnB3/3V3ff9sb3n/cHN9/25wd/9ucHf/am13/25wd/9ucHf/d3l//29xdf9sbnX/bG51/2ptd/9wc33/ -cHN9/3Bzff9sb3n/bG51/3Bzff9qbXf/bG95/2xudf9nanT/bG95/2xudf9nanH/Z2p0/2ptd/9nanT/ -Z2p0/2dqdP9sbnX/Z2p0/25xe/9qbXf/amxz/3Bzff93eX//bnB3/3Byef9sb3n/c3Z//2ptd/9zdn// -cHJ5/3Bzff97fYP/c3Z//3d6g/9zdn//dXd9/3d6g/9zdn//bnB3/3Byef9ucHf/cHJ5/3N1fP9ucHf/ -b3F1/3N1fP9tb3P/cHJ5/3N1fP9sbnX/bnF7/3N1fP9qbXf/bnB3/3V3ff9zdXz/c3V8/25wd/9vcXX/ -cHJ5/2xudf9qbXf/c3V8/25wd/9ucHf/Z2px/25wd/9sbnX/bnB3/3N1fP9tb3P/Zmlz/2xvef9qbXf/ -cHJ5/3Byef9ucHf/bG51/21vc/9sbnX/bnF7/2xudf9wc33/c3V8/2xvef92eHz/bG51/2ptd/9sbnX/ -bnB3/3N1fP9ucHf/Z2p0/2xvef9ucHf/bG51/2psc/9wcnn/dnh8/21vc/9sbnX/cHJ5/3l8hv9ucHf/ -dXd9/25wd/9sb3n/dXd9/3V3ff9sb3n/bnF7/3N1fP9sb3n/bnF7/2xvef9wcnn/c3V8/25wd/91eIH/ -d3qD/3V4gf93eoP/d3qD/3V4gf93eoP/eXuB/3Byef91eIH/c3Z//3Byef9vcXX/eXuB/3Z4fP9tb3b/ -d3qD/3N1fP9ucHf/bnF7/3N1fP9zdXz/b3F1/29xdf9vcXX/cHJ5/25wd/9tb3j/b3J5/21vc/91d33/ -dXd9/2dqdP91eIH/bnF7/3N1fP9nanT/Zmlz/25wd/9qbXf/Z2p0/2dqdP9maXP/ZGZs/2Zobv9nanT/ -Zmhu/2Rncf9maG7/Zmlz/2Rncf9wc33/Zmlz/2Rncf9sb3n/bG95/2psc/91d33/cHN9/25xe/9qbXf/ -am13/2psc/9sbnX/bG95/3V3ff9ydHz/bG5z/21vdP9wc3z/amx0/2xvef9qbXf/am13/2ptd/9rbXT/ -a252/21wef9sbnX/dnh8/3Byef9ucHf/amxz/25wd/9ucXv/bnB3/2xudf9ucHf/c3V8/2Zpc/9nanH/ -bG51/3N1fP9ucHf/d3l//2xudf9vcXX/bG51/2xvef9wc33/bnF7/3l7gf93eoP/cHN9/25xe/94eX3/ -bnB3/2xudf9qbHP/dXd9/3Z4fP91d33/eHl9/25wd/9vcXX/c3V8/3Byef9zdXz/bnB3/25wd/9sbnX/ -eHl9/29xdf91d33/bG95/2ptd/9qbXf/bG51/2dqdP9sb3n/ZGdx/3d5f/9qbXf/ZGdx/2Rncf9sb3n/ -cHJ5/3Byef9wcnn/cHJ5/25xe/9zdn//bnF7/3Bzff9ucHf/b3F1/3N1fP9sbnX/bG51/2xvef9zdXz/ -b3F1/3Byef9sbnX/b3F1/2xudf9zdXz/bnF7/3Bzff91eIH/e32D/3N2f/9zdn//c3V8/3d6g/9qbXf/ -cHN9/25wd/9ucHf/eHl9/3N1fP9ucHf/bnB3/25wd/9sb3n/cHJ5/2ptd/9sb3n/bG95/3Byef9zdXz/ -am13/2xudf9wcnn/bW9z/25wd/9sb3n/amxz/3V3ff9zdXz/bG51/2xudf9zdXz/cHJ5/2xvef9tb3P/ -am13/3N1fP9ucHf/bnB3/3V4gf9ucXv/c3V8/2ptd/9ucHf/bnB3/25xe/9zdn//bnB3/2xudf9wcnn/ -cHN9/3N2f/9wc33/bnB3/25xe/9ucXv/cHJ5/3N2f/9wcnn/d3l//3V4gf9wc33/d3l//2ptd/9ucXv/ -bnB3/3Bzff9wc33/cHJ5/25wd/9wc33/cHJ5/2xudf9ucHf/cHJ5/3h5ff9vcXX/bnB3/3Bzff97fof/ -c3Z//3V4gf9ucHf/bnF7/3l7gf91eIH/am13/3Bzff9zdn//bnB3/25wd/9ucHf/cHJ5/3N1fP9ucHf/ -c3V8/3N1fP9zdXz/dnh8/3Z4fP9zdXz/dXd9/3N1fP9sbnX/bnF7/2ptd/9wc33/bG95/3d6g/91d33/ -bnB3/3l6gP9wc3v/bW91/3Bzff9ucXv/bnF7/2dqdP9sb3n/am13/3Byef9ucHj/bW94/3Byef9ucHf/ -dXd9/3V3ff9sb3n/d3qD/3V4gf97fYP/c3Z//2xvef91eIH/c3Z//3N2f/9zdn//dXiB/2xvef9wc33/ -dXd9/25wd/9vcXX/cHJ5/3N1fP9sbnX/e32D/25wd/9qbXf/dXd9/3V3ff9tb3P/dXd9/25xe/9sb3n/ -Zmlz/2Rncf9maG7/amxz/2dqdP9ucHf/am13/2Zobv9pa3H/cHN5/21vdP9zdXz/bG51/3Byef9wcnn/ -a211/2tudv9ucHn/aGt0/3V3ff9sb3n/Z2p0/2Zpc/9ucXv/am13/2xudf9maXP/bG95/3Bzff9kZ3H/ -YmVu/2xudf9zdXz/bG51/3V3ff9ucHf/bnB3/25xe/9ucHf/bnB3/2psc/92eHz/cHJ5/25wd/9sb3n/ -d3l//3Byef9sbnX/bG51/3Byef92eHz/c3V8/3h5ff9ucXv/bnB3/3V4gf91eIH/dXiB/3Bzff9zdn// -cHJ5/3d5f/9sb3n/dXd9/3Bzff9wcnn/cHJ5/21vc/9ucHf/cHN9/2ptd/93eoP/bnB3/2psc/9nanH/ -b3F1/3N1fP9ucHf/cHJ5/3Byef9ucHf/dXd9/25xe/9ucXv/amxz/21vc/9wc33/bG51/29xdf9wcnn/ -cHJ5/25wd/9ucHf/bnB3/21vc/9qbXf/bG95/25wd/9ucHf/c3V8/3h5ff9sbnX/c3V8/2dqdP91d33/ -ZGdx/25xe/9qbXf/bnB3/3h5ff9wcnn/bG51/21vc/9qbXf/am13/2xudf9sbnX/bG95/2xvef9ucXv/ -c3V8/2dqdP9sbnX/am13/2dqcf9nanT/Z2p0/2Zobv9qbXf/am13/2Rncf9qbHP/am13/2xvef9sb3n/ -Z2px/2Zpc/9wc33/am13/2xudf91d33/cHJ5/3N1fP9sb3n/cHJ5/25xe/9zdn//bnF7/2xvef9sb3n/ -cHN9/3Byef9wc33/c3Z//25xe/9ucHf/bnF7/3Bzff93eoP/c3V8/3t9g/97fYP/dXiB/3l7gf9zdn// -d3qD/3V4gf93eoP/c3Z//3Bzff9wcnn/d3qD/3d6g/9wc33/c3V8/3N1fP95fIb/cHN9/3Bzff9zdn// -e36H/3Bzff9zdn//bG95/2xudf91d33/c3Z//2dqdP9sb3n/c3Z//2xvef9sb3n/bG95/25xe/9wc33/ -cHJ5/25xe/9zdn//dXiB/3d5f/95e4H/d3qD/3d6g/93eX//cHJ5/3N2f/93eoP/cHN9/2ptd/91d33/ -cHN9/2hrcv91eID/b3J7/2xueP9zdn7/cHN9/3Byef9ucHf/bnF7/2xvef9ucXv/cHJ6/21wef9tb3f/ -bG51/3N1fP9wc33/Zmlz/3V3ff9nanT/cHN9/25xe/9nanT/c3V8/25xe/9sb3n/bnF7/25xe/9qbXf/ -bG51/25xe/9nanH/Zmhu/2dqcf9nanT/ZGdx/3V3ff9qbHP/Z2px/25wd/9sb3n/Zmhu/25xe/9qbXf/ -bnF7/2Zpc/9qbHP/amxz/2xvef9sb3n/cHJ5/3Byef9oa3X/bG51/29ye/9tcHr/c3Z//25wd/9ucXv/ -dHZ9/21vd/9tb3b/b3F6/2xudf92eHz/dXd9/25wd/9maXP/cHJ5/2ptd/9sbnX/bG51/25wd/9zdXz/ -am13/2RmbP9tb3P/dXd9/2xudf92eHz/bW9z/2xudf9zdXz/bG51/2xudf9qbHP/dXd9/2xudf9ucHf/ -bnF7/3V4gf9wc33/am13/2dqdP9zdn//dXd9/3Bzff92eHz/bnF7/2ptd/9zdn//c3V8/3Byef9sbnX/ -cHJ5/2xudf91d33/am13/3Bzff9zdXz/cHJ5/3Byef9sbnX/amxz/25wd/9nanT/dXd9/2dqdP9kZ3H/ -ZGdx/2dqcf9qbXf/amxz/25xe/9qbHP/am13/3N1fP9sb3n/bnF7/21vc/9sbnX/bnF7/2xudf9sbnX/ -bG95/2xvef9qbXf/bG51/2xudf9vcXX/b3F1/25wd/9ucXv/bnF7/3V4gf95e4H/bnF7/3d5f/9wcnn/ -d3l//2dqdP9zdn//cHJ5/3Byef93eX//bnF7/2xvef9qbXf/b3F1/29xdf9vcXX/bG51/29xdf9sbnX/ -c3Z//3N2f/9ucXv/bnB3/3Bzff9zdn//c3Z//3N2f/9ucXv/dXiB/3V4gf9sb3n/bnB3/3Bzff9wc33/ -cHN9/3Byef9wcnn/d3qD/25xe/9sb3n/eHl9/3Byef9zdXz/amxz/2ptd/9sbnX/am13/2ptd/9sbnX/ -ZGdx/2xudf9nanT/bG51/2xudf9sbnX/Z2p0/2xudf9sbnX/cHJ5/2psc/9zdXz/cHN9/2ptd/93eX// -Z2p0/3Byef9ucHf/cHJ5/25xe/9qbXf/bnB3/3N1fP9zdn//Z2p0/29xdf9vcXX/dXd9/2xudf9ucHf/ -dXd9/3t9g/9ucHf/cHJ5/2ptd/9nanT/bnF7/3Bzff9maXP/bG51/3Bzff9nanT/am13/2ptd/9sb3n/ -am13/2psc/9nanH/am13/2xvef9wc33/cHJ5/2xvef9wc33/bnF7/2psc/9sb3n/bG95/3Bzff9qbXf/ -d3l//3d5f/9oa3L/d3l//3N1e/9sb3n/b3J8/3d6g/91eIH/cHN9/3d6g/9zdn//dnmC/3J1fP9rbnf/ -aWx2/2dpb/9qbXf/Z2p0/2Rncf9ucHf/Zmlz/2dqdP9nanT/ZGdx/25wd/9kZ3H/Zmhu/2dqdP9qbXf/ -ZGdx/2Rncf9nanT/Z2p0/2dqcf9nanH/Z2p0/2Jlbv9wcnn/amxz/2psc/9zdXz/bnF7/2xudf92eHz/ -bnF7/2xvef9maXP/amxz/2psc/9ucXv/bG95/3Z4fP91d33/bG95/2xveP9ydH3/cXN7/3V4gf9wcnn/ -c3Z//3R3gP9ucHf/bG93/21wef9oa3X/dXd9/25xe/9sbnX/bG51/3Byef9sb3n/bnF7/3N1fP9wc33/ -c3Z//2xvef9nanH/bnB3/3d5f/9sb3n/d3qD/2xvef9wc33/dXiB/25wd/9sb3n/bG51/3V3ff9ucHf/ -bG51/2xvef91d33/bnF7/2ptd/9maXP/c3V8/3N1fP9wcnn/dnh8/2xudf9sbnX/c3V8/25xe/9wc33/ -bnF7/3Bzff9zdXz/dXiB/25xe/91eIH/dXiB/3Bzff91eIH/dXiB/3Bzff97fYP/c3Z//36Biv91d33/ -am13/2xvef9ucXv/cHN9/2xvef9zdXz/bnB3/3Bzff91d33/cHJ5/3Bzff9qbHP/amxz/25xe/9qbHP/ -Z2px/2xvef9sb3n/bG51/2xudf9nanT/bG51/2psc/9sb3n/am13/2xvef91d33/dnh8/2ptd/9zdXz/ -bG51/25xe/9kZ3H/bG95/2xudf9sbnX/dXd9/2xvef9qbXf/am13/29xdf9ucHf/b3F1/2xudf9ucHf/ -b3F1/3N1fP9zdXz/cHJ5/3N1fP92eHz/cHJ5/3Byef9zdXz/bG51/3V3ff9zdXz/amxz/21vc/9ucXv/ -bG95/2xvef9nanT/Z2px/2ptd/9nanH/Z2px/25xe/9nanT/ZGdx/11gav9gY2z/Zmhu/2Rncf9maXP/ -ZGZs/1xfaP9maXP/YmVu/2Rncf9kZ3H/Zmlz/2psc/9qbHP/bG95/2ptd/9maXP/cHN9/3Bzff9qbXf/ -dXd9/2Zpc/9ucXv/bG95/3N1fP9zdXz/bnB3/2xvef9wc33/c3Z//2xudf9sbnX/bW9z/3N1fP9qbXf/ -bG51/3V3ff97fYP/b3F1/3N1fP9sbnX/bG51/25wd/9zdn//bG95/3Bzff91eIH/cHN9/3Bzff9zdn// -c3V8/21vc/9ucHf/bG51/3Byef9zdXz/dnh8/3Z4fP9zdXz/dnh8/3N1fP9ucHf/c3V8/3Byef9zdXz/ -am13/3h5ff93eX//b3F1/3p9g/9vcnr/bW92/25xe/9zdXz/cHN9/2xudf9sb3n/am13/2xudf9qbXb/ -a254/2tud/9sb3n/c3V8/3Byef9vcXX/d3l//3V3ff9zdXz/cHJ5/29xdf92eHz/cHJ5/25wd/9wcnn/ -cHN9/25wd/9ucHf/c3V8/3N1fP9tb3P/bG51/2xvef9nanT/c3V8/2xudf9sb3n/dXd9/3Byef9ucHf/ -d3l//3Byef9zdXz/amxz/25wd/9sb3n/dXd9/3N2f/93eX//dXd9/3J1fv9sb3j/bW94/2psc/9wc33/ -amxz/2ptd/9sb3n/aGtz/2ttdf9vcnz/bW92/3h6gP9zdn//c3V8/25wd/9zdXz/Zmlz/2Rncf9gY2z/ -Zmhu/2Zpc/9gY2z/XWBq/2Rncf9sb3n/ZGdx/3Byef9kZ3H/am13/2dqdP9iZW7/Zmhu/2Jlbv9nanT/ -amxz/2psc/9sbnX/c3V8/25xe/9qbXf/Z2p0/2xvef9ucXv/c3V8/3V3ff9sbnX/bnB3/3N1fP9sb3n/ -cHN9/25xe/9wc33/cHJ5/3V4gf9zdXz/c3Z//3V4gf9zdXz/c3Z//3N2f/9ucXv/d3qD/25wd/95e4H/ -am13/2ptd/9qbXf/bnF7/25xe/9sb3n/c3Z//3N2f/91eIH/eXyG/3N2f/91eIH/bnB3/25wd/92eHz/ -bnB3/29xdf91d33/c3Z//25xe/9wcnn/am13/2xvef9ucHf/bG95/2xvef9ucXv/dXd9/3Z4fP9vcXX/ -dnh8/2ptd/9ucXv/YGJo/2psc/9qbXf/bG51/3d5f/9tb3P/bW9z/2xudf9vcXX/bG51/2xudf9ucHf/ -bG51/29xdf91d33/dXd9/3N1fP9sbnX/dXd9/25xe/9qbXf/cHN9/2psc/9sb3n/Z2p0/2Rncf9maG7/ -ZGdx/2Zpc/9nanT/Zmhu/2dqcf9sb3n/am13/21vc/92eHz/cHJ5/2xudf9sbnX/Zmlz/2psc/9nanT/ -am13/2xudf9maXP/bnF7/2dqdP9tb3P/cHJ5/2xudf9sbnX/bG51/2xudf9wcnn/amxz/3N1fP9zdXz/ -bG51/3Byef9iZW7/am13/2ptd/9sb3n/Z2p0/2xudf9nanT/bnF7/25xe/9maXP/Z2p0/2xudf9wc33/ -Z2p0/2Zpc/9sb3n/c3Z//2ptd/9ucXv/am13/2psc/9ucXv/cHN9/2dqdP9sb3n/bnB3/25wd/9wcnn/ -cHJ5/3N1fP9sbnX/am13/2ptd/9ucXv/c3V8/3h5ff9zdXz/cHJ5/3Bzff9ucXv/bnB3/3N1fP9ucXv/ -d3l//2xvef92eHz/eXuB/2xudf96fIP/bnF5/2xudf9sb3n/c3V8/25xe/9nanT/Z2p0/2xudf9sbnX/ -bW93/21veP9vcXn/am13/3Byef9wcnn/am13/3V4gf9wc33/c3V8/2xvef9sbnX/c3V8/3Byef9wcnn/ -cHJ5/3V3ff9wcnn/bnB3/25wd/9sb3n/bG95/2ptd/9nanT/Z2p0/3Bzff9sbnX/amxz/3N2f/9sb3n/ -Z2p0/25xe/9qbXf/bnF7/2dqcf9tb3P/bG51/3h5ff9wc33/c3Z//3d5f/9ucXv/a251/2lsdv9nanT/ -bnF7/2psc/9qbXf/bnF7/21vd/9ucXv/cHN8/2xudf93eX//cHJ5/21vc/9tb3P/c3V8/3N1fP9wcnn/ -bG95/2xvef9zdn//am13/2dqdP9wc33/eXuB/3Bzff97fYP/c3V8/3N2f/9zdn//bG95/2xvef9sbnX/ -c3V8/25wd/9ucHf/bG51/3V3ff9ucXv/bG51/2psc/9wc33/cHN9/3N1fP93eoP/bnB3/29xdf9wc33/ -bG95/2ptd/9qbHP/amxz/2Zpc/9sb3n/bG51/2xvef9ucXv/am13/2xvef9qbXf/bG51/3V3ff9sbnX/ -d3l//2ptd/9maXP/Zmlz/2ptd/9qbXf/Zmlz/2psc/9maG7/Z2p0/3Byef9qbHP/bG95/2dqcf9nanT/ -bG95/2Jlbv9gY2z/Zmlz/2Zpc/9maG7/Zmhu/2dqdP9kZ3H/Z2px/2dqcf9qbXf/am13/3Bzff9wc33/ -bG51/3N1fP9sbnX/c3V8/2Vmav9ucHf/bG51/2xudf95e4H/b3F1/29xdf9qbHP/bW9z/21vc/9ucXv/ -bnB3/3Byef9ucHf/d3l//3V4gf95e4H/dXiB/3l7gf9wc33/dXiB/3d6g/9wc33/eXuB/3l7gf9ucXv/ -cHJ5/3Bzff9ucXv/cHN9/25wd/9ucHf/c3Z//25xe/9ucXv/eXuB/3V4gf9wc33/cHJ5/2xvef9wc33/ -c3Z//3d6g/91eIH/cHN9/3d6g/9wc33/bnF7/3V4gf9zdn//cHN9/3Bzff9zdn//d3qD/3Bzff95fIb/ -e36H/3N2f/97fYP/cHN9/3t9g/9zdn//c3Z//3N2f/9sb3n/bG95/3N2f/9wc33/bG95/2xudf9ucHf/ -dXd9/2xudf9ucHf/cHN9/3t9g/9ucXv/cHN9/25wd/9sbnX/bnF7/25xe/9qbHP/bG51/25wd/9ucHf/ -bG95/3V4gf9zdn//cHN9/3N1fP9ucHf/cHN9/3N2f/93eoP/c3Z//3V4gf91eIH/cHN9/25xe/9wc33/ -cHJ5/3Z4fP9wcnn/d3l//3t+h/9ucXv/fX+G/3Fze/9rbnf/cHJ5/3N1fP9zdXz/bG95/2ptd/9qbHP/ -aGpx/2ptdP9sb3n/cnV+/21wev91eIH/c3Z//3Byef9/gYf/d3qD/3l7gf9zdn//cHN9/3V4gf9zdn// -c3Z//3t9g/93eoP/eXuB/3V4gf9zdn//dXiB/3N2f/9sb3n/bnF7/2xvef95e4H/cHN9/3N2f/95fIb/ -cHN9/29xdf9wc33/bG95/3N1fP9maXP/bW9z/3Byef92eHz/dnh8/3V4gf94eX3/cnR7/21veP9vcXj/ -a21z/3Z4fP9sbnX/bnF7/2xvef9rbnX/b3J6/3F0ff9qbXf/dXiB/3N2f/9sb3n/cHJ5/3Bzff9zdn// -cHN9/2xvef9ucHf/dXd9/2psc/9qbHP/cHJ5/3N1fP9vcXX/dnh8/25wd/9wcnn/c3V8/2ptd/9wcnn/ -cHJ5/3d6g/9wc33/bnF7/2xvef91d33/c3V8/21vc/9tb3P/dXd9/3Bzff9zdXz/c3Z//2xudf9nanT/ -bnF7/2ptd/9qbXf/Z2p0/2psc/9qbHP/bG95/2xudf9wc33/bnF7/2ptd/9ucXv/bG51/2dqdP9ucXv/ -Zmlz/3V4gf9qbXf/Zmlz/2psc/9tb3P/bG51/2psc/9sbnX/am13/25xe/91d33/b3F1/3Byef9vcXX/ -cHJ5/3Z4fP9ucHf/am13/3Byef9wcnn/bG51/2ptd/9sbnX/am13/2ptd/9nanT/cHN9/25wd/91d33/ -dXd9/2xudf91d33/bG51/3V3ff9nanH/cHJ5/2xvef9sb3n/eXuB/25wd/9ucHf/Z2px/21vc/9tb3P/ -c3V8/2psc/9tb3P/bG51/3V3ff9wcnn/dnh8/3Bzff92eHz/cHJ5/25xe/91eIH/bnF7/3V4gf9wc33/ -am13/25wd/9wc33/bnF7/3Bzff9vcXX/bnB3/3V4gf9ucXv/cHN9/3d5f/9wc33/cHJ5/2xvef9qbXf/ -cHN9/25xe/9ucXv/c3V8/2ptd/9zdn//bnB3/2xudf91d33/bnF7/2xudf9sbnX/cHJ5/25xe/9sbnX/ -cHJ5/3V3ff9tb3P/dXd9/2dqdP9zdXz/am13/2xvef9sb3n/am13/2Rncf9sb3n/am13/2Jlbv9qbHP/ -am13/3N1fP9qbHP/bG51/3Byef9+gIb/cHJ5/3Byef9sbnX/bG51/25wd/9wc33/Zmlz/2ptd/9qbXf/ -am13/2ptd/9ucXv/dXd9/3Byef9vcXX/b3F1/3N1fP9zdXz/eXuB/25wd/9zdXz/cHJ5/2xvef9sb3n/ -cHJ5/2ptd/91d33/bG51/3V3ff95e4H/b3F1/36Bif9ydHv/bG52/3N1fP9zdXz/dnh8/3V3ff9ucHf/ -bG51/25wd/9rbnj/cXN6/3V3gP9wcnn/cHN9/3N2f/9zdXz/f4GH/25xe/95e4H/cHN9/3N1fP95fIb/ -d3qD/3Bzff93eoP/cHN9/3N2f/9ucXv/bnF7/3Bzff9wc33/bnF7/3Bzff9wcnn/d3qD/3Bzff9wc33/ -d3qD/3V4gf9wc33/dXiB/3V4gf91eIH/am13/3Bzff9wc33/eXuB/3N2f/95e4H/eXuB/3Z4gf9vcnz/ -b3J4/21wev91d33/bnB3/3Bzff91eIH/b3J5/3Bzff9xc3r/bnB3/3d5f/9zdn//bG95/2xvef9ucXv/ -dXd9/3Byef9qbXf/bW9z/3V3ff9nanH/bG51/25xe/9ucXv/bW9z/3Z4fP9sbnX/bG95/25xe/9nanT/ -bG51/2ptd/9wc33/bG51/25wd/9ucHf/cHJ5/25xe/9sbnX/bG51/3V3ff9zdXz/dXd9/3l7gf9wcnn/ -bnB3/3V4gf9wc33/cHN9/2xvef9ucHf/am13/25xe/9sb3n/c3Z//3N2f/9sb3n/bnB3/25wd/9sbnX/ -c3V8/2xudf97fYP/bnB3/2xudf9qbXf/am13/25wd/9nanT/am13/2dqdP9sb3n/dXd9/2psc/9qbXf/ -Z2p0/2xudf91d33/bG51/2dqdP9wcnn/cHN9/2xudf9qbHP/am13/2ptd/9sb3n/Z2p0/2xvef9nanT/ -bG95/2xvef9maXP/am13/2psc/9ucXv/YmVu/2xudf9nanT/am13/3V3ff9qbXf/am13/2Rncf9sbnX/ -am13/2ptd/9ucHf/bnB3/2ptd/91d33/c3Z//3V3ff9wc33/dXd9/3Bzff9wc33/c3Z//25xe/91eIH/ -cHN9/2xudf9ucHf/bnB3/25wd/9wcnn/bG51/2xudf9wcnn/bG51/3Byef94eX3/bG51/2xudf9nanT/ -ZGdx/2xudf9sb3n/cHJ5/3Byef9tb3P/bnF7/2psc/9qbHP/cHN9/25xe/9sbnX/am13/25xe/9ucXv/ -am13/2xvef9wc33/bW9z/3V3ff9nanH/c3V8/25xe/9wcnn/c3V8/3N1fP9qbHP/bnB3/25xe/9qbHP/ -amxz/2psc/9ucXv/Zmlz/2psc/9sb3n/dXiB/2ptd/9ucXv/am13/2xudf9sbnX/c3V8/2Zpc/9qbXf/ -bnB3/25wd/9zdXz/c3V8/3N1fP9sb3n/bG51/2ptd/9wcnn/cHJ5/3l7gf9ucHf/dXd9/25wd/9zdXz/ -bG51/25xe/9sbnX/c3V8/2ptd/92eHz/dXiB/2xudf97fYT/cXN6/2dqc/9qbXf/am13/3Bzff91d33/ -bnB3/2xvef9sb3n/bG94/21wd/91d3z/bG51/3Byef9ucHf/bG51/3l7gf9qbXf/dXd9/2xudf9nanH/ -d3l//2ptd/9sb3n/bnF7/2ptd/9ucXv/amxz/2xudf9qbXf/bG95/3Byef9ucHf/bG51/3V3ff9sb3n/ -bnB3/3d6g/9wc33/bnF7/3N2f/9ucXv/bnF7/2dqdP9sb3n/bnF7/3l7gf91eIH/d3qD/3Z4fP9ydHv/ -a252/2xudP9qbHP/c3V8/21vc/9wcnn/cHJ5/25wd/9sbnX/a212/2Nmb/9sb3n/Z2p0/2Zpc/9sbnX/ -bG95/3V3ff9ucXv/bG95/29xdf93eX//Zmlz/25wd/9wcnn/c3V8/3Byef97fYP/c3V8/3Bzff91eIH/ -bG95/25xe/9wcnn/dXiB/3Bzff9wcnn/bnB3/25xe/91d33/bnB3/2xudf91d33/dXd9/3N1fP94eX3/ -bnB3/29xdf92eHz/cHJ5/3Byef9qbHP/b3F1/2psc/9ucHf/bnB3/3N2f/91eIH/cHN9/3Bzff9ucHf/ -cHJ5/3Bzff9sb3n/dXiB/25wd/9ucHf/b3F1/25wd/9wcnn/bG51/3Byef9sbnX/bnB3/3Z4fP9tb3P/ -bG51/2psc/9qbXf/d3l//2xudf9kZ3H/am13/25xe/9qbXf/Z2px/2dqcf9maXP/bG95/2dqdP9ucXv/ -bnF7/25xe/9wc33/bG51/25xe/9tb3P/dnh8/2Zpc/9ucXv/am13/2ptd/93eX//bG95/2xvef9qbHP/ -bnB3/29xdf9zdXz/bG51/2ptd/9qbXf/cHN9/25wd/9wc33/bnF7/3N1fP9wcnn/bnB3/25xe/9qbXf/ -bG95/25xe/9nanT/am13/2ptd/9qbHP/Z2p0/2psc/9nanT/bG95/2Zpc/9sb3n/dnh8/21vc/9sbnX/ -bG51/2xudf9ucHf/bnB3/3Byef9wc33/bnB3/3V3ff9ucHf/bnB3/3V4gf91eIH/cHN9/25xe/91eIH/ -d3qD/3Byef91eIH/c3Z//25wd/92eHz/amxz/3Z4fP9wcnn/c3V8/3N1fP9zdXz/amxz/25wd/9wcnn/ -bG51/2ptd/9sbnX/c3V8/2psc/9vcXX/cHJ5/3V3ff9wcnn/cHJ5/25wd/9ucHf/bnB3/3V3ff9nanH/ -bG95/2xvef9qbXf/c3Z//3N2f/95e4H/dXiB/3Bzff9zdn//dXiB/3d6g/+Bg4r/d3l//35/g/97fYP/ -fn+D/3V3ff95fIb/c3Z//3l7gf9ucHf/dXiB/3V4gf9tcHr/fYCH/3V3fv9wc3v/dXeA/3Bzff97fYP/ -e32D/25xe/9ucHf/cnR7/21wev9tb3f/a254/2Zobv9maXP/Z2px/2dqcf91d33/amxz/2xvef9sbnX/ -Z2px/3Byef9sb3n/bG95/2xvef9sbnX/bnB3/29xdf9vcXX/bnF7/25xe/91eIH/bnF7/25wd/9ucXv/ -cHN9/3Byef95e4H/cHN9/3N2f/91eIH/c3Z//25xe/9sb3n/c3Z//3d6g/97fYP/d3qD/3l8hv95e4H/ -dXiB/3F0fv9ucHf/aGt0/2xvef9sbnX/bG95/2hrdf9rbXf/a254/3F0fP9ucXv/en2D/3l7gf9wc33/ -cHN9/3Bzff9wc33/bnB3/29xdf9vcXX/dXd9/2Zobv9tb3P/bnF7/25xe/9sbnX/dXd9/25wd/9wcnn/ -cHJ5/2dqdP9qbXf/bW9z/3Z4fP9sbnX/amxz/2dqdP9qbXf/bnF7/2Zpc/9maXP/cHN9/3N1fP9sb3n/ -dXd9/2psc/9maXP/bG95/2xudf9qbHP/Zmlz/2dqdP9maXP/bG51/2dqdP9ucXv/bnF7/2ptd/9qbXf/ -Zmlz/2dqcf9qbXf/Zmlz/3N1fP9nanT/amxz/2psc/9sbnX/am13/2dqdP9maXP/Zmlz/2psc/9zdXz/ -bG51/2xudf9iZW7/Z2p0/3N1fP9qbXf/Zmlz/2ptd/9sb3n/am13/2dqcf9kZ3H/Zmlz/25xe/9nanT/ -am13/2xvef9qbXf/cHN9/2Zpc/9nanT/Z2p0/25xe/9gY2z/Zmlz/2Rncf9iZW7/cHJ5/2xvef9nanT/ -Z2px/2ptd/9qbHP/am13/21vc/9sbnX/Zmlz/3Bzff9nanT/bnF7/2xvef9ucXv/bG95/2ptd/9ucXv/ -bG51/2xvef9sb3n/Zmlz/2dqdP9qbXf/Zmlz/2dqdP9maG7/Zmlz/2ptd/9nanH/am13/3Byef9kZ3H/ -Z2px/2Zobv9iZW7/Zmlz/2xudf9qbXf/am13/2xudf9ucXv/amxz/2psc/9ucXv/bG95/2dqdP9nanH/ -bG95/3Bzff9sbnX/Z2p0/2xvef9qbHP/c3V8/2dqdP91d33/bnB3/3Z4fP92eHz/bnF7/2psc/9sbnX/ -cHJ5/21vc/9wcnn/cHJ5/3V3ff9ucHf/bW9z/3V3ff93eX//bnF7/25xe/9sbnX/bG51/3Byef9wc33/ -Zmhu/25wd/9ucHf/Z2p0/2ptd/9wcnn/c3V8/2xudf9vcXX/bnB3/3Byef9zdXz/eXuB/2xudf91d33/ -dXd9/3V3ff9ucHf/c3V8/25wd/91d33/bnB3/3d6g/91eIH/bnB3/3t9hP9wc33/a212/3Bzff9wc33/ -dXiB/3l7gf9wc33/cHJ5/3N2f/9ucXv/b3F6/3V3ff9tb3P/dXd9/25wd/9ucHf/d3qD/25wd/9zdXz/ -bnB3/21vc/92eHz/bnB3/3Byef9wcnn/bnB3/3N1fP9ucHf/bnB3/25wd/9vcXX/dXd9/25wd/9tb3P/ -bG51/2ptd/9qbHP/cHN9/2xvef9qbXf/bnF7/2dqdP9qbHP/YmVu/2Zpc/9qbXf/Z2p0/2Zobv9qbXf/ -Z2pz/2dqc/9pbHP/a21y/2ttdP90dnz/bnB3/2xvef9tcHr/bnF7/2ptd/9maXH/ZWhy/2xvef9sb3n/ -YGNs/2Zobv9kZmz/d3l//3N2f/9ucXv/c3V8/3t+h/9sb3n/c3V8/3V4gf95fIb/eHl9/31+gf9zdXz/ -dXiB/3d6g/9ucXv/cHN9/3Bzff93eX//bnB3/2xvef9ucHf/bG95/3Z4fP9qbXf/bG95/3V3ff94eX3/ -cHJ5/3V3ff9wcnn/am13/3N1fP9tb3P/am13/2Zpc/9nanT/am13/21vc/9sbnX/c3V8/3V3ff9zdn// -c3Z//3Byef9zdXz/eXuB/3Bzff95fIb/c3V8/3N2f/9wc33/c3Z//3V4gf92eHz/e32D/3V3ff9zdn// -eXyG/3N2f/9zdn//bnF7/3V4gf93eoP/bnF7/2ptd/9zdXz/c3V8/3Byef9vcXX/bG51/2xvef91d33/ -bG51/3Byef9ucXv/am13/25xe/9qbHP/am13/2dqdP9ucXv/XWBq/2ptd/9nanT/Zmlz/3N1fP9sb3n/ -am13/2dqdP9sb3n/bG51/25wd/9tb3P/bW9z/2dqcf92eHz/cHJ5/3V3ff9zdXz/cHJ5/3Bzff9wc33/ -c3Z//3Bzff9zdn//c3Z//2xvef9qbHP/bnB3/25wd/9zdXz/bW9z/2xudf9zdXz/b3F1/3N1fP94eX3/ -bnB3/2xudf9vcXX/Z2px/2psc/9wcnn/bnB3/25wd/9ucHf/cHN9/2dqdP9sbnX/cHN9/3N1fP9sb3n/ -amxz/25xe/9ucXv/bG51/2ptd/9ucXv/bG51/3Z4fP9qbHP/dnh8/25xe/9zdn//c3Z//3Bzff9qbHP/ -bnB3/3N1fP9tb3P/bnF7/2ptd/91d33/bnB3/25wd/9wcnn/dnh8/3N1fP9wcnn/bnB3/25wd/9wc33/ -dXiB/2dqdP9wcnn/c3V8/2xvef9wc33/cHN9/3N2f/9ucHf/b3F1/29xdf9zdXz/cHJ5/3l8hv9sb3n/ -dXiB/3N1fP92eHz/bW9z/3Byef9ucHf/dXd9/25wd/95fIb/d3l//21vc/96e4H/b3F5/2Zpcv9sbnX/ -am13/3Byef94eX3/bnB3/25wd/9zdXz/cHJ3/3Fzev91d3v/bW9z/3N1fP9zdXz/b3F1/3t9g/9ucHf/ -cHJ5/25xe/9sbnX/c3V8/2ptd/9sb3n/am13/2ptd/9qbXf/bW9z/2xudf9sbnX/b3F1/3N2f/9ucXv/ -bnB3/2xvef9sb3n/bnB3/3Z4fP9wcnn/bnB3/3Byef9ucHf/bnB3/2psc/9wcnn/c3Z//3V4gf9wc33/ -e32D/3N2f/90d4D/bnF7/25xef9rbnf/c3Z//3Byef9wcnn/bnF7/3N2fv9xdHv/bG95/2hrdf9wc33/ -bG95/2Rncf9qbXf/bG51/3h5ff9zdXz/cHJ5/25wd/93eoP/am13/25xe/9ucXv/cHN9/2xvef9zdn// -bG95/25xe/9zdXz/bG51/25wd/9wcnn/d3l//2dqdP9iZW7/Zmlz/2ptd/9zdXz/am13/2xudf9wcnn/ -d3l//25wd/91d33/bnB3/2ptd/91d33/b3F1/2psc/9nanH/b3F1/2xudf9vcXX/b3F1/3Byef91d33/ -bnB3/25wd/9sbnX/bW9z/3N1fP9nanT/d3l//2xudf9qbXf/amxz/2psc/9nanH/Zmhu/2dqdP9kZ3H/ -YmVu/2xudf9gY2z/Zmhu/2BjbP9maXP/bG51/2Rncf9iZW7/Zmlz/2Rncf9maXP/Zmhu/2Rncf9nanT/ -bnF7/2dqdP9sb3n/bnF7/2xvef9ucXv/Z2p0/25xe/9ucXv/c3V8/2Zobv9wcnn/bnB3/2Zpc/91d33/ -bnF7/25wd/9qbHP/bnB3/2ptd/9sb3n/amxz/2dqdP9iZW7/bnF7/2dqdP9zdXz/bnF7/2xvef9wc33/ -bG95/2xvef9sbnX/am13/2ptd/9maXP/YmVu/2xvef9ucHf/c3V8/21vc/9sbnX/cHJ5/2ptd/9wc33/ -dXd9/25wd/9wcnn/bW9z/2Zobv9qbXf/dXiB/25xe/9sb3n/bG95/3N2f/9wcnn/cHN9/3V3ff91d33/ -bnF7/2xvef91d33/bnF7/2xudf9qbXf/am13/2xudf91d33/am13/3N1fP9ucXv/bG95/2xvef9qbXf/ -ZGdx/2dqcf9maXP/Z2p0/2xvef9qbXf/Z2p0/2dqcf9qbHP/bG95/3N1fP9wc33/bG95/2ptd/9tb3P/ -bnB3/3Bzff9maG7/bG51/2xudf9sbnX/bnF7/25xe/91eIH/cHJ5/3N1fP9ucHf/dXiB/3N2f/95e4H/ -c3Z//3d6g/9wc33/eXuB/25xe/9wcnn/c3Z//3Z4fP9ucHf/eXuB/3d5f/9wcnn/fH2C/3F0fP9wcnz/ -c3Z//3N2f/93eoP/eXyG/3Bzff91d33/eHuF/3N1e/9ydHn/cHN9/2tud/9qbXf/am13/2dqcf9zdn// -bG51/25xe/9ucXv/bG51/3N1fP9sb3n/bG95/2xudf9vcXX/bG95/25wd/9sb3n/bnF7/25wd/9zdn// -bG95/25wd/9ucHf/cHJ5/29xdf92eHz/bnF7/2xvef9ucXv/cHN9/25xe/9sb3n/c3Z//3N2f/91eIH/ -cHN9/3l7gf9zdn//c3Z//25weP9ucXn/bG51/3Byef9vcXX/bG95/25wd/9zdXz/cXN6/2lsdP9ucHf/ -dnh8/25xe/9nanT/bG51/25wd/92eHz/c3V8/3N1fP9sbnX/dnh8/2xudf9ucHf/bnF7/3N1fP9ucHf/ -dXd9/25wd/9wc33/dXiB/25xe/9sb3n/cHN9/3d6g/9ucHf/bG95/3Byef9wc33/eXuB/25xe/9wcnn/ -cHN9/3V4gf9ucHf/dXd9/25wd/9wcnn/dXiB/25xe/9sb3n/Z2p0/2xvef9qbXf/bnB3/29xdf9ucHf/ -dXd9/25wd/9ucHf/bnB3/25wd/9wc33/am13/3d5f/9ucHf/bnB3/25wd/9sb3n/cHJ5/3N1fP9wc33/ -bnB3/25wd/93eX//bnB3/25wd/9ucHf/dXd9/3h5ff9zdXz/bG51/3Byef9wcnn/cHN9/3Byef9ucHf/ -bnB3/3N1fP9sbnX/am13/2xvef9qbXf/c3V8/2Zpc/9ucXv/am13/2xvef9iZW7/am13/2dqdP9kZ3H/ -cHN9/2xvef9sbnX/amxz/3Bzff9sbnX/am13/3N2f/9zdXz/bnF7/3l8hv9zdn//eXyG/3V4gf9zdn// -c3Z//25xe/9wc33/bnB3/3Byef9zdXz/bG51/2dqcf9wcnn/c3V8/3N1fP9sbnX/bG51/2xvef9qbXf/ -c3V8/3V3ff9sb3n/bG95/2ptd/9iZW7/Zmlz/25xe/9qbXf/am13/2Zpc/9sb3n/amxz/2psc/9ucXv/ -bnF7/2dqdP9maXP/bG95/2Zpc/9maG7/ZGdx/2dqcf9kZ3H/bG95/2Jlbv9qbXf/am13/2Zpc/9nanT/ -Zmlz/2BjbP9kZmz/ZGdx/2Rncf9qbXf/Z2px/2Zpc/9kZ3H/Zmhu/2ptd/9wc33/c3V8/2xudf9nanT/ -bG51/3Bzff9sb3n/Zmhu/25wd/9ucHf/bG51/25xe/9wc33/dXd9/29xdf9ucHf/bnB3/3N2f/9ucHf/ -eHl9/3Byef91d33/b3F1/3V3ff9ucHf/bnB3/25wd/9zdXz/am13/3V4gf91d33/bG94/3d5gP9tcHj/ -aGt1/2ptd/9qbXf/bG95/3N1fP9sbnX/am13/25xe/9vcXf/cHJ5/3V3e/9wcnn/cHN9/3V4gf9ucXv/ -e36H/25xe/9wc33/cHN9/25xe/93eX//bnF7/3Byef9ucHf/cHJ5/25xe/9ucHf/bnB3/3Bzff9ucXv/ -c3Z//3Bzff9zdXz/bnF7/2xvef9ucHf/d3l//2xvef9wcnn/am13/2xudf9ucXv/bW9z/3V3ff9ucHf/ -bnF7/25wd/94eX3/cHJ5/3N1fP9qbXX/aGt1/2hrdP9ucXv/bG51/2ptd/9qbXf/bnF7/2tueP9kZ3D/ -ZWhx/3J1fP9ucXv/am13/2xudf9ucHf/c3V8/3N1fP9ucXv/bG95/3Z4fP9qbHP/cHJ5/25wd/9zdXz/ -bnB3/3d5f/9wcnn/bnF7/3Bzff9nanT/bnF7/25xe/93eoP/bnB3/2xvef9nanT/bnB3/3N1fP9qbHP/ -amxz/2ptd/91d33/bG95/25xe/9sbnX/bG51/25xe/9nanH/Z2px/2Zpc/9maXP/YmVu/2dqdP9qbHP/ -bG95/3N1fP9qbHP/am13/2dqdP9maXP/cHN9/2dqdP9zdXz/bG51/2xudf9wc33/bnB3/21vc/9tb3P/ -c3V8/2xvef9sb3n/e36H/25wd/9zdXz/bnB3/3V4gf97fYP/cHN9/3Byef9zdn//c3Z//3d6g/9wcnn/ -bnB3/3Byef95e4H/cHJ5/3V4gf95e4H/c3Z//3l7gf9zdXz/eXyG/3d6g/95fIb/bG95/3V4gf9zdXz/ -cHN9/3l8hv95e4H/dnh8/3N2f/9+gIb/dXiB/3V4gf9tb3P/bW9z/2dqcf92eHz/bnB3/3d6g/9zdXz/ -am13/2xvef9qbXf/Zmlz/2dqcf9nanH/am13/2dqdP9nanT/bG95/3Bzff9ucHf/bW9z/25wd/9tb3P/ -am13/3N1fP91d33/bG95/2ptd/9ucXv/ZWZq/2dqcf9wcnn/bnB3/25wd/9vcXX/c3V8/25wd/9ucXv/ -d3l//3V3ff9ucXv/bG95/3V3ff9wcnn/bnF7/2xvef9ucXv/cHJ5/3V3ff9sb3n/d3l//3d5f/91eIH/ -eXuB/3d6g/9ucXv/c3Z//3t9g/97fYP/fX6B/3Bzff9zdn//c3V8/3Bzff93eoP/dXiB/3V4gf9sb3n/ -Z2p0/25wd/9ucXv/cHJ5/2dqdP9ucXv/bnB3/25wd/9wcnn/cHN9/3Z4fP9sbnX/bG51/21vc/9wc33/ -bG95/3N1fP9ucXv/dXd9/2xudf92eHz/bnF7/3Byef91eIH/c3Z//29xdf95e4H/d3l//3N1fP97foX/ -dXd9/3J0e/9zdn//dXd9/31+gf97fof/dXiB/3V4gf91eIH/dHZ9/3J1f/92eH//bnF7/3N1fP9wcnn/ -bW9z/3l7gf9sbnX/bnB3/3Byef9ucHf/c3V8/25wd/9ucHf/bG51/2ptd/9qbHP/Z2p0/2psc/9qbXf/ -bG51/3N1fP9tb3P/amxz/2ptd/9sb3n/am13/3d5f/9sbnX/bG95/2ptd/9qbXf/cHN9/2ptd/9zdXz/ -cHJ5/25wd/9ucHf/c3V8/2xvef91d37/cHN4/3R2ff9ydX3/eHqA/3V4gf9zdn//b3J8/29yfP9vcnj/ -aGpy/2hrdP9zdXz/bG95/2Zpc/9sb3n/am13/3V3ff9wc33/cHN9/25xe/94eX3/am13/3Bzff91eIH/ -c3Z//2xvef91d33/b3F1/2xvef9ucXv/Z2p0/25xe/9wc33/eXyG/3Byef9ucHf/am13/3N2f/93eoP/ -bnF7/25wd/9wcnn/dnh8/25wd/9ucXv/bW9z/2xudf9zdXz/bG51/2psc/9qbXf/bG95/2ptd/9ucHf/ -bG51/25wd/93eX//am13/25wd/9sbnX/am13/25xe/9nanT/c3V8/2ptd/9sbnX/cHJ5/2xudf9sbnX/ -bG51/3N1fP9tb3P/bnB3/3V3ff9sbnX/am13/2dqdP9ucXv/dXd9/2xvef9nanT/am13/2xudf9wc33/ -amxz/2psc/9nanT/c3V8/2xudf9zdXz/dXd9/3Byef9zdn//bG95/3N2f/9ucXv/cHN9/2dqdP9ucXv/ -bnB3/2dqdP9wc33/bG95/25wd/9ucHf/d3l//3Byef9wcnn/Z2px/2xudf9iZW7/bnF7/2psc/91eIH/ -bG95/2psc/9maXP/Z2p0/2Zobv9maG7/ZGdx/2Zobv9iZW7/YGNs/2Rncf9nanT/ZGdx/2Rncf9kZ3H/ -YGNs/2Rncf9sb3n/bG95/2dqdP9maXP/Z2p0/11fZf9iZW7/bG95/2xvef9qbXf/bG51/2xvef9qbXf/ -bnF7/3Z4fP94eX3/cHJ5/2xudf9zdn//cHN9/3N1fP9ucHf/bnF7/3Bzff93eX//bnB3/3Z4fP92eHz/ -c3V8/3V3ff9wc33/b3F1/29xdf9zdXz/bnB3/3N1fP9tb3P/bG51/2xudf9sbnX/cHN9/2ptd/91d33/ -Z2p0/2Rncf9sbnX/bG95/2xvef9nanT/bG51/2xudf9sbnX/bnB3/3Bzff91d33/b3F1/25wd/9ucHf/ -c3V8/3Byef92eHz/cHJ5/3V3ff9qbHP/c3Z//3Bzff9wcnn/dXiB/3V3ff9sbnX/eHl9/3V3ff9wcnn/ -dXiB/3Byef9sb3j/b3F1/2xvef9zdn//eHl9/2xvef9wcnn/cHN8/21wev9tb3j/cHJ5/2dqcv9maXP/ -Zmlz/2Rncf9wc33/amxz/2psc/9sb3n/am13/2ptd/9qbXf/am13/2xudf9qbHP/bG51/2xudf9nanT/ -am13/2ptd/9ucXv/amxz/2xudf9qbXf/cHN9/2ptd/9zdn//am13/3Bzff9qbXf/bnB3/3V3ff9ucHf/ -dXd9/25wd/9wcnn/cHJ5/3Byef9tb3P/bnF7/21vd/9ucXn/bW93/3R2ff9sb3n/am13/2ptd/9ucXv/ -b3F4/2hrc/9sb3n/d3l//3N2f/9sb3n/bnF7/25wd/9ucXv/Z2p0/2dqdP9qbXf/bnF7/2Zpc/9nanT/ -Z2p0/2ptd/9nanT/bnF7/2xudf9qbXf/bG51/2psc/9tb3P/bnF7/3l7gf9tb3P/amxz/2psc/9ucXv/ -cHN9/25xe/9ucXv/c3Z//3l7gf9zdn//dXiB/25xe/9wc33/d3qD/3N1fP9zdXz/bnB3/25xe/9ucXv/ -c3Z//3N1fP9wc33/eXyG/3N2f/9wc33/c3V8/3N2f/93eoP/c3Z//3t9g/9zdn//cHJ5/3t9g/9zdn// -d3l//3V3ff93eoP/c3Z//3d6g/97fof/c3Z//3N1fP9zdn//eXuB/3l8hv9zdn//bG95/3N2f/9wcnn/ -d3l//3Byef9ucHf/bnB3/3h5ff9sbnX/cHJ5/3Z4fP9wcnn/bnB3/2ptd/9ucXv/bG51/2xvef9nanH/ -bnF7/2xudf9nanT/bnF7/2ptd/9qbXf/Z2p0/3N1fP9sbnX/Z2p0/2xudf9qbXf/Zmlz/3N1fP9qbXf/ -fn+D/3Z4fP9wcnn/c3V8/3N2f/9sb3n/bnF7/25wd/9wcnn/bnB3/2xvef9wc33/d3l//25xe/9wcnn/ -cHN9/25wd/9ucHf/d3l//3N2f/91d33/bnB3/3N1fP9lZmr/Zmlz/25xe/9sb3n/am13/2dqcf9qbXf/ -amxz/2dqdP9ucHf/cHJ5/2dqdP9kZ3H/bnF7/2ptd/9nanT/amxz/2ptd/9qbXf/cHJ5/2psc/9zdXz/ -c3V8/25wd/9zdXz/dXd9/29xdf9ucXv/dXiB/3Bzff91d33/bG95/25xe/9wcnn/bnF7/3Bzff9wcnn/ -eXuB/25wd/9qbXf/bnF7/3V4gf9wc33/bnF7/3V4gf9ucXv/cHN9/3Bzff93eoP/eXyG/3N2f/9zdn// -cHN9/3d6g/9zdn//e32D/3d6g/95fIb/cHN9/3l7gf91eIH/c3V8/3d6g/91eIH/c3Z//3t+h/97fob/ -d3qE/3p8g/90dn7/bXB6/25wd/9sb3n/cHN9/3d5f/9ucXv/bnB3/25xe/9xdH7/c3V9/3d5gP9wc33/ -bnF7/2xvef9ucHf/eXyG/25xe/9ucXv/cHN9/25xe/9wc33/cHJ5/25xe/9zdXz/cHJ5/25xe/9sb3n/ -bnB3/21vc/9ucHf/c3V8/25wd/9sb3n/bnF7/3d5f/9ucXv/d3qD/25xe/9zdn//cHN9/2xvef91d33/ -bG95/3Z4fP9ucHf/c3V8/25wd/9ucXv/bnB3/3Bzff9tb3f/bnB3/21vc/9ydHz/bnB3/25wd/9wcnn/ -cHJ5/3Fzef9oa3P/aGtx/3V3ff9wcnn/Z2px/2xvef9sbnX/dnh8/3N1fP91eIH/c3Z//3V4gf9sb3n/ -bG95/3Bzff9ucXv/bG95/3N2f/9sb3n/cHN9/25wd/9sb3n/bnB3/25xe/93eoP/bnB3/2xudf9qbHP/ -c3V8/3N1fP9ucHf/bnB3/3V3ff92eHz/c3V8/2xvef9qbXf/bnB3/3N1fP9sbnX/am13/2xudf9sbnX/ -amxz/25wd/9tb3P/bnB3/3V3ff9ucHf/bG95/2ptd/9tb3P/bnB3/2psc/9zdXz/bnB3/2ptd/91eIH/ -bnB3/25wd/9ucHf/bnF7/25wd/9zdXz/dXiB/25wd/9sb3n/bnB3/3N1fP91d33/bnB3/2psc/9tb3P/ -bG51/3V3ff9sbnX/bG51/25wd/91d33/bG51/3Byef9zdXz/am13/2ptd/9nanT/bG95/2psc/9qbXf/ -ZGdx/2ptd/9qbHP/Zmlz/2ptd/9qbXf/am13/2psc/9zdXz/bG51/2xudf9wcnn/bnF7/25xe/91eIH/ -cHN9/3+Bh/93eX//bG95/3Bzff9zdn//bG95/25xe/9ucHf/cHJ5/25wd/9qbXf/bnF7/3V4gf9ucXv/ -cHJ5/25xe/9ucHf/cHN9/3d5f/91eIH/c3V8/3Byef9ucXv/ZGdx/25wd/9wcnn/cHN9/2xvef9wcnn/ -bnF7/2xvef9wc33/d3l//3d5f/9zdXz/bG51/3Z4fP9zdXz/cHJ5/25wd/9wcnn/bG51/3V3ff9qbXf/ -cHN9/3N1fP9sb3n/bG95/2xvef9qbHP/Z2p0/25xe/9nanT/c3V8/2dqdP9qbXf/Z2px/2psc/9sb3n/ -amxz/3Byef9maG7/YmVu/2ptd/9sb3n/amxz/2Zpc/9ucHf/Z2px/2xudf9tb3P/bnB3/3Bzff9ucHf/ -dXiB/25wd/9zdXz/bnB3/3V3ff9zdXz/dXd9/2xudf91d33/bG95/25wd/9zdn//dXd9/29xdf92eHz/ -eHl9/3J0e/92eH7/bXB4/2hrdP9qbHP/Zmlz/3Byef91d33/am13/21vc/9sb3n/bm92/21weP92eH// -bnB3/2xvef9wc33/bnF7/3d6g/9zdn//d3qD/3t9g/93eX//fn+D/3d5f/93eX//e32D/3p7f/97fof/ -eXuB/3l7gf95e4H/e32D/3t9g/91eIH/d3l//31+gf9/gYf/d3l//3+CjP93eoP/d3qD/3Bzff9sb3n/ -dXd9/25wd/91d33/am13/2xvef9qbXf/bnF7/2psc/9rbnj/aGty/2hqc/9maG//am13/2dqcf9qbXf/ -bnF7/2xveP9tcHj/YmVu/19ibP9sb3n/Z2p0/2BjbP9maXP/bG95/3h5ff9wc33/c3Z//25wd/91d33/ -bG95/2xvef9sb3n/bnB3/25wd/92eHz/cHJ5/3Byef9sb3n/bnB3/25wd/9ucHf/dXd9/2xudf9qbHP/ -Z2px/3Byef9ucHf/am13/2xvef9wc33/c3V8/25xe/9ucXv/bG51/25xe/9wc33/bG51/25wd/9ucHf/ -bnB3/2ptd/9wcnn/b3F1/25wd/93eX//cHJ5/25wd/9vcXX/bG51/25wd/9sbnX/cHN9/2xvef9ucXv/ -eXuB/3Bzff9zdn//cHN9/3V4gf9ucXv/dXiB/3d6g/9ucHf/bG51/2xvef91d33/eHl9/3Bzff9sb3n/ -bnB3/25wd/95e4H/bG51/2xvef9ucHf/d3l//25xe/9wc33/dXd9/2xvef9zdXz/bnB3/25xe/9ucXv/ -bnF7/2dqdP9sb3n/bG95/2xudf9wc33/cHJ5/25wd/9sb3n/dXd9/25wd/9sb3n/bG51/2ptd/9nanT/ -bnF7/2xudf99foH/dXd9/21vc/9wcnn/c3Z//25wd/9ucHf/b3F1/2xudf9sbnX/Z2px/3N1fP9zdXz/ -bG51/21vc/9sb3n/am13/2xvef9zdXz/bG95/3Bzff91d33/cHJ5/2Rncf9ucHf/bnB3/3Bzff9ucHf/ -bnF7/25xe/9wcnn/cHN9/3d6g/93eoP/c3Z//2xvef91eIH/c3Z//3N2f/9ucXv/cHN9/3N1fP93eoP/ -bnF7/3d6g/91eIH/cHN9/3N2f/9wc33/bG95/2xvef91eIH/bnF7/3V3ff9sbnX/bG51/2xudf9sb3n/ -bnF7/2ptd/93eX//bW9z/2psc/9zdn//cHJ5/25wd/9sbnX/cHJ5/2psc/9vcXX/bnB3/25wd/9zdXz/ -bG51/3Byef9ucHf/dXd9/2xudf9zdXz/bnB3/3h5ff9sbnX/eHl9/25xe/9wcnn/c3Z//2xvef9qbHP/ -cHN9/3V3ff9sb3j/dHeB/25wef9sb3n/bnF7/25wd/9zdn//dXiB/2xvef9ucHf/bnF7/3R2fP9vcnn/ -dnh//25wd/9ucXv/bnF7/25wd/95e4H/bnF7/3N2f/91eIH/c3V8/3V4gf9wc33/cHJ5/25wd/9wcnn/ -dXiB/3Byef9ucHf/bG95/2xvef9wc33/bnB3/21vc/91d33/eHl9/3Byef95e4H/cHJ5/2xvef9ucXv/ -amxz/3N1fP9qbXf/cHN9/21vc/9wcnn/bnB3/3N1fP9vcXX/dHZ9/21wef9xc3z/bnB3/3N2f/9ucXv/ -c3Z//3V4gf9wc33/dXd+/2xvef9ydX7/e36H/3t9g/9ucXv/d3qD/3l8hv94eX3/cHJ5/3V3ff9tb3P/ -cHJ5/2xudf9ucHf/bG51/2ptd/9sbnX/dnh8/25wd/9qbXf/Z2p0/2dqdP9sbnX/bnF7/3V3ff9sbnX/ -bG51/2Zpc/9sb3n/am13/2ptd/9sb3n/c3V8/3Bzff9wc33/bG95/2ptd/9ucXv/cHN9/3Byef9ucHf/ -bG51/2xvef9nanT/bnB3/29xdf9zdXz/dnh8/25wd/9qbXf/amxz/2xudf9qbXf/Z2p0/2xvef9qbHP/ -Zmlz/3Bzff9sbnX/bG95/2ptd/9zdXz/bG51/25xe/91d33/bG51/2psc/9ucHf/dXd9/3h5ff9wcnn/ -Zmlz/2dqdP9sbnX/dnh8/2xudf9ucHf/b3F1/3d5f/9sbnX/cHJ5/3V3ff9qbXf/bG95/2xudf9sb3n/ -bnB3/3N1fP9qbHP/bnB3/2xudf9nanT/am13/2xvef9sbnX/bW9z/3N1fP9sbnX/bG95/2psc/9sb3n/ -Z2p0/25xe/9qbXf/eXuB/3d5f/9sbnX/bG51/3Bzff9sbnX/bW9z/2xudf9sbnX/bG51/2Zpc/9zdn// -cHN9/2xvef9vcXX/cHJ5/29xdf9wcnn/c3V8/25xe/92eHz/dnh8/3Byef9maG7/bnB3/3N1fP9zdXz/ -bnB3/3Byef9wc33/dXiB/3V4gf97fof/eXyG/3d6g/9qbXf/dXiB/3Bzff9wc33/bnB3/29xdf9sbnX/ -dXd9/25xe/9wc33/c3Z//3Byef9ucHf/bG51/25wd/9qbHP/dXd9/3Byef93eX//amxz/21vc/9sbnX/ -bnF7/2xvef9ucHf/dXd9/21vc/9ucHf/c3V8/3Byef9ucHf/bG51/3Byef9sbnX/bG51/2ptd/9sbnX/ -bnB3/2xudf9zdXz/bG51/3V3ff9qbXf/dXd9/25xe/91d33/Z2p0/3h5ff9ucHf/b3F1/3Byef93eoP/ -c3V8/3l7gf96fIP/c3Z//3Z5g/9ucXr/bG51/2xudf9qbXf/bnF7/3d5f/9tb3P/bW9z/2xudf9ucHf/ -b3F2/3d5gv9wcnn/bnF7/3Bzff9ucHf/d3qD/25wd/9ucHf/cHN9/25wd/92eHz/b3F1/25wd/9sb3n/ -bnB3/3Bzff9sb3n/bG95/25wd/9ucHf/c3V8/29xdf9vcXX/dXd9/3V3ff9ucHf/eXuB/3Byef9sb3n/ -bnF7/2dqdP9zdXz/am13/2xvef9qbHP/bG95/2xudf9wc33/amxz/3Bzff9qbXb/bG53/2hqdP9vcnz/ -am13/3Byef9wcnj/cXN6/3JzeP9oanP/Z2pz/3N1fP9ucXv/Zmhu/3N1fP9ucHf/dnh8/3Byef94eX3/ -bnB3/3V3ff9sbnX/bG51/25wd/9sbnX/bG51/3N1fP9wc33/am13/2dqdP9maXP/amxz/2ptd/9zdXz/ -Z2px/2Zpc/9iZW7/Zmlz/2RmbP9iZW7/Zmhu/2Zpc/9nanT/ZGdx/2Rncf9iZW7/Z2p0/2Zpc/9maG7/ -Zmlz/2Zpc/9qbXf/Zmlz/2xvef9sbnX/bnF7/3N1fP9qbXf/amxz/2psc/9qbXf/am13/2xudf91d33/ -b3F1/2xvef91d33/bG95/3Byef9sbnX/dXd9/2ptd/9wc33/dXd9/21vc/9nanH/cHJ5/3Z4fP92eHz/ -c3V8/2dqcf9sb3n/cHJ5/3t9g/9wc33/c3V8/25wd/93eoP/bnB3/3N1fP91d33/bG51/3Byef9sbnX/ -cHJ5/3Byef91d33/b3F1/3Byef9sbnX/bnB3/3N1fP9ucHf/bW9z/29xdf9zdXz/b3F1/2xvef9ucHf/ -cHN9/25wd/9wc33/bG95/3+Bh/93eX//bnB3/25xe/91eIH/cHN9/3N2f/9zdn//cHJ5/2ptd/9kZ3H/ -dXiB/3Bzff9sb3n/cHJ5/3Bzff9wcnn/c3Z//3l7gf9zdn//c3Z//3l7gf9wc33/Z2p0/25wd/91eIH/ -c3Z//3Byef9vcXX/bnB3/3Bzff9zdn//d3l//3h5ff9zdn//bG95/3d6g/9zdn//cHN9/25wd/9vcXX/ -cHJ5/3N1fP9ucHf/dXd9/3N1fP9ucHf/bnB3/3Byef9sbnX/Zmlz/25xe/9ucXv/d3l//2ptd/9qbHP/ -amxz/2ptd/9qbXf/am13/3N1fP9sbnX/Z2p0/2ptd/9sb3n/Z2px/2Zpc/9nanT/ZGdx/2Zpc/9kZ3H/ -amxz/2ptd/9nanT/cHN9/2xudf9wcnn/bG51/3Z4fP91d33/dXd9/2xvef95e4H/bnB3/25wd/9wcnn/ -c3Z//25wd/9zdn//dnh8/29yfP94eoH/bnB5/25wd/9ucXv/bnB3/3Byef93eX//bW9z/21vc/9sb3n/ -a252/2xudf92eYL/cHJ5/3Bzff9wc33/c3V8/3d6g/9zdn//dXiB/3V4gf9ucHf/eHl9/25wd/9vcXX/ -bG51/25wd/9wcnn/b3F1/2xudf9tb3P/bG51/3Byef9sbnX/bW9z/3Bzff9wc33/bG51/25wd/9qbXf/ -am13/2xvef9kZ3H/am13/2Rncf9sb3n/am13/3Bzff9qbXf/dXd9/2ptd/9xc3v/bG53/2ttc/9lZ3D/ -Z2p0/2Zpc/9maXP/ZGdx/2dqdP9tb3j/am13/21vdv90dn3/dXd9/2dqcf9zdXz/bnF7/3N1fP9qbXf/ -dXd9/2xvef9ucXv/bW9z/3Byef9wcnn/b3F1/2xvef9ucXv/dXd9/25wd/9ucHf/bG95/25xe/9zdXz/ -e32D/3Byef9vcXX/bnB3/25xe/9wcnn/b3F1/2xudf9wcnn/cHJ5/3Byef9wcnn/bG51/3Byef9ucXv/ -am13/2ptd/9sbnX/bnF7/2dqdP9qbXf/am13/2xvef91d33/cHJ5/29xdf9vcXX/bG95/3Byef9ucHf/ -c3V8/25wd/9sbnX/dnh8/3Byef9ucHf/bW9z/3V3ff9sb3n/d3l//3d6g/9zdXz/bG95/3d6g/97fYP/ -d3l//3Bzff9sb3n/cHJ5/2xvef92eHz/am13/2xvef9ucHf/eXyG/25xe/93eX//cHN9/25xe/9wcnn/ -bG95/2xvef9wc33/dXiB/25wd/9ucXv/am13/25wd/9wc33/bnF7/2xvef9sb3n/cHN9/25wd/9sb3n/ -Z2p0/25xe/9nanT/bnF7/21vc/+Agob/d3l//25wd/9ucHf/dXiB/3Bzff9zdn//c3Z//25xe/9ucXv/ -Zmlz/3N2f/9ucXv/bnB3/25wd/9ucXv/bW9z/25wd/91d33/bnB3/25xe/9zdXz/am13/2Rncf9qbXf/ -bG95/2ptd/9nanT/Z2px/2Zpc/9nanT/Z2p0/3Byef9ucHf/bnB3/2dqcf9zdXz/bG95/2ptd/9qbHP/ -bG51/2xvef9sb3n/bG51/3Bzff9ucXv/am13/2xudf9ucXv/bnB3/2dqdP91d33/c3V8/3d5f/9sbnX/ -b3F1/3Byef9wcnn/bG95/2ptd/91d33/bG51/2ptd/9sb3n/cHN9/2Zpc/9qbHP/bG95/2xudf9sb3n/ -Z2p0/2ptd/9qbXf/Z2p0/2ptd/9nanH/am13/2Zpc/9wcnn/c3V8/3V3ff9qbXf/cHN9/2dqdP9maXP/ -am13/3N1fP9tb3P/c3V8/3N1fP9sb3n/d3qC/25wef9ucHX/bnB3/25wd/9ucXv/d3qD/3Byef9ucHf/ -b3J8/29xef9sbnT/cHJ6/2dpb/9qbXf/Z2p0/2dqcf9wcnn/am13/2ptd/9ucXv/bG51/25xe/9qbXf/ -am13/2Zpc/9sbnX/cHN9/25wd/9sb3n/b3F1/29xdf9zdXz/bnB3/29xdf91d33/bnB3/2ptd/91d33/ -cHJ5/2xudf9ucXv/am13/2ptd/9maXP/bG95/2xvef9ucXv/am13/3Bzff9sb3n/cHN9/21wev9tcHr/ -bG95/3h6gP91eIH/foCG/3Z5gv93eoP/dXiA/25weP9pbHb/bnF7/3Bzff9maXP/bnB3/2xvef95fIb/ -dXiB/3t+h/93eoP/dXiB/3Byef9zdn//bG95/25xe/9sb3n/cHN9/3V4gf9wc33/bnB3/25wd/9wc33/ -c3Z//36Ahv91eIH/c3V8/25wd/9wc33/bnB3/2xudf9ucHf/c3V8/3V3ff9zdn//bnF7/2xvef9zdn// -cHN9/3Bzff9ucXv/c3V8/3Bzff9sbnX/bG95/25wd/9zdXz/dXd9/3Byef9sbnX/b3F1/2ptd/9ucHf/ -bG51/3N1fP9qbXf/bG51/3V3ff9ucXv/bnB3/2xudf9zdXz/bW9z/3Byef91d33/bG51/2ptd/9qbXf/ -cHN9/2xvef9qbXf/Zmlz/2xudf9qbXf/c3V8/2Zpc/9maXP/Z2px/3Bzff9nanH/bnF7/2xvef9qbHP/ -am13/2Zpc/9nanH/Zmhu/2Zpc/9kZ3H/Zmlz/2dqcf9kZ3H/Z2p0/2Zpc/9nanT/bG51/2xvef9sbnX/ -am13/2dqcf9sb3n/Zmlz/25xe/9sbnX/f4GH/3V3ff9sbnX/bG95/3Bzff9sbnX/bnF7/2xvef9qbHP/ -amxz/2RmbP9wc33/am13/2xudf9wcnn/cHJ5/2xudf9ucHf/c3V8/2ptd/9sb3n/bnF7/2xudf9iZW7/ -Z2p0/2xvef9sb3n/Z2p0/2ptd/9qbXf/bG95/3Bzff91d33/dXd9/3V3ff9vcXX/d3l//3V3ff9zdXz/ -bG51/2xudf9sb3n/bnF7/21vc/9zdXz/dXd9/25wd/9ucHf/bnB3/21vc/9nanH/c3V8/2xvef91d33/ -Z2p0/21vc/9zdXz/bnB3/2xudf9wcnn/d3l//2ptd/9nanT/am13/3V3ff9sbnX/bG51/2xvef9sbnX/ -am13/2Zpc/9sbnX/bG51/2xudf9ucHf/bW9z/3Byef9sb3n/dXd9/3V3ff93eX//bW9z/3V3ff9sbnX/ -bG51/2xudf91d33/cHJ5/3d5f/91eIH/cXR+/3Z5gv9wc3r/aGt1/25wd/9ucHf/bnF7/3d5f/9sbnX/ -bG95/2xvef9ydHv/bnF5/3V4gf9ucHf/cHN9/2xvef9ucHf/dnh8/3Byef9ucHf/bnB3/2xudf9wcnn/ -bnB3/3Byef9nanT/bG95/3N2f/9vcXX/bnB3/21vc/9sb3n/c3Z//3Bzff9wcnn/dXiB/25wd/9tb3P/ -eHl9/3V3ff9ucHf/c3V8/29xdf9ucHf/amxz/3N1fP9wcnn/c3Z//25xe/9zdXz/cHJ5/3V3ff9zdX3/ -bnF7/29xeP90d4D/cHN9/3Bzff9sb3n/cXN7/3Bze/9tb3f/aGp0/2xvef9ucXv/Z2p0/25xe/9sb3n/ -c3V8/25wd/94eX3/bnB3/3Bzff9wcnn/cHN9/25xe/9zdn//cHJ5/3N2f/91eIH/cHN9/3Byef9sb3n/ -c3V8/3N1fP97fYP/c3V8/29xdf9vcXX/dXd9/21vc/9ucHf/cHJ5/3Byef9wcnn/dXd9/2xvef9nanT/ -bG95/2ptd/9qbXf/amxz/2Zpc/9qbXf/Zmlz/2dqdP9sbnX/bG95/3N1fP9wc33/am13/2psc/9sbnX/ -bnF7/2xudf9zdXz/bG95/25wd/91d33/cHN9/25xe/9ucHf/dXd9/29xdf9zdXz/c3V8/25wd/9ucHf/ -bnF7/3V3ff9ucXv/d3qD/2xvef9ucHf/bG95/3d5f/9sb3n/bnB3/3Byef95fIb/bnB3/3N1fP9wcnn/ -bW9z/25wd/9wcnn/bG51/21vc/9wcnn/bG51/25wd/9ucHf/bG51/2xvef9sb3n/amxz/25wd/9ucXv/ -bW9z/2xudf9sb3n/bnF7/2xvef91eIH/bG95/4GDiv91d33/bW9z/3Byef9wc33/am13/25xe/9sb3n/ -amxz/2xudf9maXP/dnh8/2xvef9ucHf/cHJ5/25wd/9sbnX/b3F1/3Z4fP9zdXz/c3V8/3N1fP9ucHf/ -amxz/2xudf9wcnn/bnB3/29xdf9ucHf/bnB3/25xe/91eIH/d3l//3d6g/93eX//bG95/3d5f/9zdXz/ -cHN9/2psc/9ucHf/cHN9/3Bzff9ucXv/c3Z//3N2f/9wcnn/cHJ5/3Bzff9wcnn/cHJ5/3d6g/95fIb/ -eXyG/25xe/9zdn//c3Z//25xe/91eIH/e32D/3l8hv91eIH/c3V8/3d6g/97fYP/bnF7/25wd/9ucXv/ -cHJ5/3Bzff9sb3n/cHN9/3Byef9sb3n/cHJ5/25wd/9wc33/bnB3/25xe/9wcnn/eHl9/29xdf91d33/ -cHJ5/2xudf9vcXX/d3l//3Bzff97fYP/dXiB/29yfP91eIH/cHN9/21wev9wc33/cHJ5/2xvef93eX// -bnB3/2xvef9wcnn/cXR9/21weP91d33/bnB3/3N1fP9sbnX/b3F1/3Z4fP91d33/cHN9/25xe/91eIH/ -cHN9/25wd/9wc33/am13/3Byef91eIH/c3Z//3N2f/9zdXz/dXd9/3l7gf93eX//c3Z//3t9g/91eIH/ -c3V8/3l7gf9zdn//c3Z//3l8hv91d33/d3l//3Z4fP97fYP/e32D/3V4gf9wc33/dXiB/3N2f/92eYL/ -c3Z+/3Bye/9vcXj/c3V8/25wd/9ucXv/bG95/2xvef9xdHz/bG95/2ptd/9wc33/cHN9/2dqdP9zdXz/ -c3V8/25xe/9sb3n/c3V8/2xvef9qbXf/bG51/3V3ff9ucHf/c3V8/29xdf9wcnn/cHN9/2xvef9qbXf/ -bG51/3N1fP92eHz/eXuB/3N1fP9sbnX/bW9z/3Z4fP9sbnX/am13/2xvef9sb3n/cHJ5/3Byef9ucHf/ -amxz/3N1fP9ucXv/bG95/2ptd/9maXP/bnB3/2xudf9sb3n/bG51/2xvef9wc33/c3V8/2xvef9tb3P/ -bW9z/3Byef9qbHP/c3V8/25wd/9sb3n/dXd9/3V3ff9ucHf/bW9z/3Byef9ucHf/cHJ5/3Byef9sbnX/ -bG51/25xe/9wc33/am13/3Bzff9qbXf/bnB3/25wd/91d33/bG51/2psc/9ucHf/d3qD/2xvef9wc33/ -cHJ5/25wd/9ucXv/c3Z//25wd/9wcnn/cHN9/25wd/9wc33/bnF7/3Byef9zdn//d3qD/3Byef9zdn// -dXiB/25xe/9wc33/bnF7/3Bzff9wcnn/dXiB/2ptd/+BhI3/eXuB/25xe/91eIH/c3Z//2xvef9wc33/ -bnF7/2xudf9nanT/Z2p0/3V3ff9ucHf/bG95/3Byef9ucHf/bG51/25wd/91d33/c3V8/3V3ff9ucXv/ -cHJ5/2xvef9wcnn/c3Z//3N2f/9wc33/cHJ5/25xe/9ucXv/dXd9/3Z4fP93eX//eHl9/25wd/94eX3/ -cHJ5/3V3ff9qbHP/bW9z/25wd/9ucHf/bnB3/3N1fP9ucXv/bG51/2psc/9nanH/Z2px/2dqdP9sb3n/ -am13/3N1fP9maXP/amxz/2ptd/9qbXf/am13/3Bzff9zdXz/am13/2ptd/9zdXz/dnh8/2dqdP9wcnn/ -cHN9/2xvef9ucXv/Z2p0/25xe/9vcXX/amxz/3V3ff9vcXX/c3V8/2ptd/9wc33/cHN9/3l7gf9ucHf/ -c3Z//2xvef9sb3n/cHJ5/3Z4fP9wcnn/eHl9/3Z4fP9ydHv/dXd8/25wd/9qbHP/bG51/2xudf9sbnX/ -dnh8/2xudf9sbnX/bnB3/29xeP9tcHj/dHZ9/25xe/9zdn//bnB3/29xdf94eX3/cHN9/3N1fP9ucXv/ -cHN9/3N2f/9ucHf/bnB3/2xvef9ucHf/c3Z//3N1fP9ucXv/cHN9/3Bzff95fIb/c3Z//3Bzff93eoP/ -bnF7/25wd/97fYP/d3qD/3V4gf93eoP/cHN9/3N2f/9zdXz/cHN9/25xe/9wc33/cHJ5/3N2f/9zdn// -eHqA/3N2fv9vcnr/bnB3/3R2ff9wcnn/c3V8/3V3ff90dnz/c3Z9/29xef9tb3f/c3Z//3Byef9sbnX/ -cHN9/25xe/9zdn//cHN9/3d5f/9ucXv/cHJ5/29xdf9wcnn/cHJ5/3V4gf9ucHf/c3Z//3V3ff91d33/ -amxz/25wd/9wcnn/dnh8/3l7gf9zdXz/bW9z/2xudf9zdXz/bG51/2xudf9zdXz/bG95/3Byef9wcnn/ -c3V8/25wd/9zdXz/cHJ5/3N1fP9ucHf/Z2p0/2xvef9sbnX/bnB3/21vc/9ucHf/cHJ5/3V3ff9qbXf/ -bnB3/2ptd/9ucXv/Zmlz/3N1fP9vcXX/bnB3/3V3ff9wcnn/am13/2xudf9ucXv/am13/3Bzff9ucXv/ -bG51/21vc/9ucXv/cHN9/2xudf91d33/bW9z/2xudf9sbnX/dXd9/2psc/9qbHP/bW9z/3V3ff9tb3P/ -bG95/2xudf9qbXf/bG51/3V3ff9ucHf/bnB3/3Bzff9vcXX/bG95/2xvef9vcXX/cHN9/3V3ff9sb3n/ -dXd9/25wd/9ucXv/c3Z//2ptd/9sb3n/bG51/3N1fP9nanT/gIKG/3Z4fP9vcXX/dXiB/25xe/9qbXf/ -c3Z//3Bzff9sbnX/bG51/25wd/91eIH/c3V8/25xe/9sb3n/bnF7/2xvef9zdn//c3Z//3V4gf93eoP/ -cHN9/3Byef9ucHf/cHN9/3d6g/9wc33/cHN9/3N1fP9ucXv/bnF7/3l7gf93eX//eXuB/3l7gf9ucXv/ -dnh8/3Byef9zdXz/bnB3/25wd/9wcnn/bnF7/2xvef9wc33/bnF7/2xudf9ucHf/bnB3/25wd/9vcXX/ -cHJ5/3V3ff95e4H/bnB3/25wd/9wc33/bnF7/3Bzff95e4H/foCG/3d5f/92eHz/fn+D/36Ahv9zdXz/ -e32D/3+Bh/95fIb/e36H/3N2f/9+gIb/eHl9/3V3ff97fYP/d3l//3l7gf94eX3/e32D/3d6g/9+gIb/ -c3V8/3d6g/9ucXv/Z2p0/29xdf93eX//c3Z//3l7gf94eoD/dXiB/3R2fv9qbXf/aGty/2dqcf9qbHP/ -ZGdx/25wd/9nanH/Z2p0/2xvef9qbXT/aWty/3Fzev9qbHP/bnF7/21vc/9sbnX/dnh8/3N1fP9ucHf/ -cHJ5/3Byef9zdXz/bnB3/25wd/9ucHf/b3F1/25xe/9sb3n/bG95/25xe/9ucXv/c3Z//3N2f/9wc33/ -eXuB/3N2f/9wc33/fX6B/3l7gf9+gIb/e32D/3d5f/91d33/dXd9/3V4gf93eoP/d3qD/3N2f/93eoP/ -d3qD/3t+h/97fof/eHuC/3R3gP93eoL/eXuB/3l7gf93eX//dXh+/3R2fP9ucXv/bnB3/25xe/9wcnn/ -amxz/3Byef9sbnX/c3Z//3V4gf93eX//c3Z//3N2f/9ucXv/cHN9/25xe/93eX//bG95/3Byef9zdn// -dXiB/25xe/9wc33/dXiB/3t9g/9/gYf/d3qD/3Bzff91eIH/d3qD/3Bzff91eIH/d3qD/25xe/9sb3n/ -cHN9/3Bzff9ucHf/cHN9/3N2f/91eIH/c3Z//3N1fP9zdn//cHJ5/3Bzff9sb3n/bnB3/3N1fP9zdXz/ -b3F1/3Byef9wcnn/c3V8/2xudf91d33/cHJ5/25wd/93eX//c3V8/29xdf9ucHf/cHN9/2xvef91d33/ -c3V8/2ptd/9sbnX/bnF7/3V3ff9sbnX/bnF7/2xudf9qbXf/bG51/3N1fP9kZ3H/am13/2xudf93eX// -amxz/2xvef9qbXf/ZGdx/2xudf9sb3n/Z2p0/2psc/9qbXf/amxz/2ptd/9sbnX/amxz/2xvef9zdXz/ -amxz/25xe/9qbXf/am13/2xvef9wcnn/bnF7/25xe/93eX//cHJ5/4GEjf97fYP/d3qD/3l7gf91eIH/ -bG95/3l8hv97fYP/cHN9/25xe/9sb3n/d3qD/3N1fP9ucXv/dXiB/3N2f/9wc33/c3Z//3V4gf93eoP/ -eXuB/3Bzff9ucXv/bG95/2ptd/91d33/bnB3/3N1fP9ucHf/bG95/25xe/91eIH/d3l//3d5f/93eX// -bnF7/3d5f/9wc33/dXiB/2xvef9ucXv/dXiB/3N2f/91eIH/eXuB/3N2f/9ucXv/bnF7/3Bzff9zdXz/ -cHJ5/3N2f/95e4H/d3qD/25wd/9ucHf/bnF7/3Bzff9wc33/dXd9/3d5f/9wcnn/bnB3/25xe/9zdn// -bG95/2xvef9wc33/bG95/3Byef9nanT/bnF7/25wd/9sb3n/dXd9/3Bzff9wcnn/am13/3Bzff9zdXz/ -dnh8/29xdf9zdXz/am13/2Zpc/9qbXf/c3V8/3Byef9zdXz/dXd9/3J0e/92eH3/bW90/2xudv9tb3P/ -bG95/2xvef93eX//c3Z//3d6g/90d4D/bXB6/25wef90dn3/b3F2/3V3ff9sbnX/amxz/3V3ff9zdXz/ -cHJ5/3Bzff9sb3n/bnF7/25wd/9ucHf/b3F1/2xudf9sbnX/bG51/29xdf9sb3n/bnF7/3Bzff9ucXv/ -cHJ5/3V4gf9zdn//c3V8/3V4gf9zdn//d3qD/3V4gf9wc33/cHN9/3Byef9wc33/c3Z//3N2f/9sb3n/ -bnF7/3Bzff92eH7/c3Z//29yfP9ucXr/c3Z//3N2f/91d33/c3Z//3R2fP9zdoD/cHN9/3Bzff91eIH/ -c3Z//3Byef9wc33/cHJ5/3N1fP9wc33/c3V8/3V3ff9wcnn/bnB3/3Byef9ucHf/dXd9/2ptd/9ucXv/ -bG95/25xe/9maXP/amxz/2xvef9wc33/dXiB/2ptd/9sbnX/bG95/2xvef9sbnX/c3V8/3N1fP9sbnX/ -am13/2xvef9sbnX/Z2p0/25xe/9wc33/dXd9/25wd/9vcXX/bnB3/2xvef9ucXv/cHN9/25xe/9zdn// -dXiB/25wd/9wc33/cHN9/3N2f/9sb3n/d3qD/3Bzff9sb3n/eXyG/3Bzff9vcXX/b3F1/3N1fP9qbHP/ -cHN9/3Bzff9nanT/am13/2ptd/9wc33/amxz/2ptd/9nanH/Zmlz/2dqcf9maXP/YGNs/2Rncf9nanH/ -c3V8/2xudf9sb3n/amxz/2Zpc/9qbXf/bnF7/2xudf9tb3P/cHJ5/25wd/9ucXv/bnF7/3Byef9ucHf/ -cHN9/25wd/91eIH/bnF7/25xe/91eIH/dnh8/3N2f/91eIH/fn+D/3h5ff+Ji5H/fn+D/3l7gf9+f4P/ -e32D/3N1fP9+f4P/foCG/3d5f/91d33/cHN9/3l7gf91d33/cHN9/3N2f/9wc33/bnF7/3V4gf9zdn// -dXiB/3V4gf9zdn//c3Z//3Byef9ucXv/c3Z//25xe/9ucXv/bnB3/25wd/9qbXf/dXd9/3d5f/91d33/ -d3l//25wd/91d33/bnB3/3Z4fP9sbnX/c3V8/3V3ff9wcnn/cHJ5/3Z4fP9zdXz/b3F1/25wd/9wcnn/ -b3F1/21vc/9zdXz/dXd9/3d5f/9qbXf/bG51/25xe/9sbnX/dXd9/3V3ff93eX//am13/2psc/9ucXv/ -am13/2Jlbv9qbHP/am13/2dqcf9maXP/XWBq/2dqcf9kZ3H/Z2p0/3Bzff9qbXf/Z2px/2Rncf9sb3n/ -bG95/3Bzff9qbHP/c3V8/2xudf9maXP/Z2p0/3Bzff9sbnX/c3V8/3V3ff9xdH3/cnV+/2xudv9tb3b/ -bG51/2ptd/9ucHf/dnh8/25wd/9wcnn/bnB3/29xef9wcnn/dXh+/3Bzff95e4H/cHN9/2xvef95e4H/ -c3Z//3V4gf9zdn//cHN9/3N1fP9ucHf/cHJ5/3Byef9wcnn/cHN9/3Byef9sb3n/cHN9/25xe/9wcnn/ -bnB3/21vc/9wcnn/cHJ5/2xudf9zdXz/bG51/25xe/9wc33/bW9z/29xdf9ucHf/bnB3/3N1fP91d33/ -bG95/3Byef9sb3n/dHZ9/3R3f/9ucXn/bnB3/25xe/91d33/dXd9/3N2f/91eID/eHqA/3J0e/93eYD/ -foCG/3l8hv95e4H/e36H/3l7gf9zdn//c3Z//3V3ff93eX//bnF7/25xe/9wc33/dXiB/3V4gf9vcXX/ -cHN9/3Bzff9zdn//bG51/29xdf9wcnn/dnh8/3l7gf9wcnn/bnF7/3N2f/91eIH/cHJ5/3V4gf93eoP/ -bnF7/3N2f/9zdn//c3Z//3Bzff93eoP/eXyG/31+gf95e4H/c3Z//3V4gf9zdXz/c3Z//3N2f/9zdXz/ -dXiB/3t9g/92eHz/eXuB/3d5f/95e4H/dXd9/3t9g/93eoP/c3Z//36Biv91eIH/bnF7/3Byef93eoP/ -cHN9/3l7gf93eoP/bG95/2xvef9wc33/dXd9/2xvef9zdn//bG95/2xvef9zdXz/cHJ5/2dqcf9qbHP/ -bW9z/3V3ff9qbXf/c3V8/25wd/9sb3n/cHN9/3V4gf9sb3n/bnF7/2xvef9ucXv/bnF7/3Byef9ucXv/ -c3Z//3l7gf93eoP/eXyG/3d5f/93eX//fX6B/2ptd/9sbnX/am13/3Bzff9maXP/e32D/3Bzff9tb3P/ -c3V8/2xvef9nanT/bnF7/25xe/9qbHP/bW9z/2psc/9ucXv/bG51/2Zpc/9sb3n/am13/2Rncf9qbXf/ -am13/2dqdP9nanT/Z2px/2dqcf9nanH/ZGdx/2dqdP9maXP/Zmhu/2Jlbv9iZW7/ZGZs/25wd/9zdXz/ -cHN9/3N1fP9nanH/bnF7/2dqcf9wc33/Z2p0/2ptd/93eX//bnF7/3Byef91d33/bnB3/25wd/9vcXX/ -cHJ5/21vc/9ucHf/cHJ5/3Z4fP95e4H/bG51/25wd/9zdn//bG51/3h5ff91d33/d3l//3Byef9qbHP/ -c3V8/25xe/9kZ3H/am13/2xvef9nanH/Z2p0/2BjbP9nanH/YmVu/2Jlbv9nanT/am13/2dqcf9kZ3H/ -bnF7/3Byef94eX3/bW9z/3V3ff9ucHf/Zmlz/2Zpc/9zdn//cHJ5/3V4gf94eoD/c3Z//3J1f/9tcHj/ -bW92/2xudf9sbnX/bG51/3N1fP9wcnn/cHJ5/25wd/9vcnz/bnB3/3N1fP9sbnX/c3V8/21vc/9sbnX/ -eHl9/3N2f/91d33/bG95/2xvef9ucXv/b3F1/2xudf9vcXX/b3F1/21vc/9tb3P/b3F1/3N1fP9sbnX/ -bG95/21vc/9ucHf/cHN9/3Byef9vcXX/eHl9/25wd/9zdn//dXd9/21vc/9sbnX/am13/2xudf9ucXv/ -bnF7/21vc/9sbnX/bnB3/3V3ff9wc3v/bnB3/25wdP9sb3n/c3Z//3V4gf9ucXv/dHZ8/3V2ev9ucHf/ -a253/3N2f/9zdXz/dXd9/3V4gf9zdXz/c3Z//3d5f/91eIH/d3l//3N1fP9ucHf/cHJ5/3Bzff9sb3n/ -amxz/2ptd/9wcnn/bnF7/2Rncf9sbnX/bnF7/3Bzff91eIH/bG95/25xe/9wc33/bnF7/2ptd/9wc33/ -cHN9/2ptd/9sb3n/am13/2xudf9maXP/cHN9/25xe/9wc33/bG95/2xudf9sbnX/amxz/2xudf9sbnX/ -amxz/2ptd/9ucXv/Z2p0/2xudf9nanT/amxz/2BjbP9ucXv/am13/2xudf91d33/bnF7/2xudf9sbnX/ -cHN9/2xudf9zdXz/c3V8/25wd/9ucHf/dXd9/3Z4fP9wcnn/c3Z//2xvef9sb3n/cHN9/25xe/9sb3n/ -cHJ5/3N1fP97fYP/cHN9/3V4gf9wcnn/bG95/25xe/9zdXz/amxz/21vc/9ucHf/bnB3/2xudf9sbnX/ -bnF7/2xudf9wc33/bG95/3Byef9sbnX/cHJ5/3V3ff9ucHf/cHJ5/25xe/91d33/am13/3+Bh/91d33/ -bnB3/3Z4fP9ucHf/amxz/2xvef9wc33/Zmlz/2psc/9maXP/am13/2dqdP9nanT/am13/2Zobv9iZW7/ -Z2px/2ptd/9maXP/ZGdx/2Zobv9kZ3H/Zmhu/2Zobv9maXP/ZGZs/2Rncf9iZW7/ZGdx/2Zobv9ucHf/ -cHJ5/2Zpc/9wc33/Zmhu/25xe/9kZ3H/am13/2BjbP9kZ3H/bnB3/2ptd/9sb3n/bnF7/2ptd/9qbXf/ -am13/2xvef9qbHP/bG51/21vc/91d33/dXd9/25wd/9vcXX/c3Z//2xvef91eIH/d3qD/3l8hv9wc33/ -bnF7/3l7gf91eIH/bnF7/3N2f/97fYP/c3V8/3V4gf9sb3n/bnF7/2ptd/9ucHf/dXiB/3V4gf9ucXv/ -am13/3V4gf95e4H/e32D/3Bzff93eX//cHJ5/25wd/9ucHf/dXiB/3N2f/95fIb/e32D/3l7gf9ydX// -bnF7/25wd/9sb3n/bnB3/2xvef9wc33/bnF7/3Byef9vcXn/c3V9/29yev91eH7/bG95/3V4gf9ucXv/ -bG51/3Z4fP9wcnn/dXd9/2xudf9vcXX/bnB3/29xdf9qbHP/bG51/2xudf9tb3P/bG51/21vc/9wc33/ -cHJ5/3Byef9wcnn/cHJ5/3V4gf9ucXv/bG95/3l7gf9ucXv/c3Z//25xe/9ucHf/cHJ5/25xe/9ucHf/ -bnF7/3Bzff9ucHf/cHJ5/3Byef92eHz/c3V8/25wd/9sbnP/cHJ5/3Bzff9ucXv/am13/29yfP9xdHv/ -a211/2psdP9wcnn/bG51/2xudf9sbnX/bW9z/3Z4fP92eHz/bnB3/3Z4fP9wcnn/am13/25xe/9zdXz/ -bnF7/2xudf9qbXf/bnF7/3N1fP9nanH/cHJ5/3Byef91d33/e32D/3Byef91d33/c3V8/3Byef9tb3P/ -cHJ5/3N1fP9ucHf/bnB3/25wd/9vcXX/amxz/3Bzff9wc33/cHN9/2ptd/9sbnX/bG95/2dqcf9wcnn/ -bnB3/25xe/9wcnn/dXd9/2xudf9ucHf/c3Z//2xvef9sb3n/cHN9/25xe/9sb3n/d3qD/3Byef9ucHf/ -bW9z/3Byef9sbnX/c3V8/3Bzff9ucHf/bnF7/3V4gf95e4H/c3Z//3d6g/9ucXv/b3F1/3N1fP9ucHf/ -Zmhu/2ptd/9qbXf/d3l//2xudf9ucXv/bG51/2psc/9wcnn/c3V8/25wd/9ucHf/bG95/3Bzff9wcnn/ -bG95/3N1fP9ucHf/dXd9/25wd/9wcnn/am13/2xudf91d33/d3l//3t9g/9+f4P/fn+D/3l7gf+IipD/ -foGK/3l7gf9+gYr/foCG/3N1fP97fYP/e32D/3V3ff93eX//eHl9/3l7gf91d33/dXd9/3d6g/9zdXz/ -bG95/25wd/91d33/cHJ5/2xvef9sb3n/Z2p0/2psc/9qbHP/am13/2dqcf9qbXf/Zmlz/2Rncf9maG7/ -cHJ5/3V3ff9qbXf/c3V8/2Zobv9kZ3H/ZGdx/25wd/9kZ3H/Z2p0/3Bzff9ucXv/cHN9/3Bzff9ucHf/ -amxz/29xdf9wcnn/bnB3/2xudf9tb3P/dnh8/3V3ff9wcnn/b3F1/3Byef9wcnn/c3Z//3N1fP91eIH/ -bG95/2ptd/91d33/dXd9/2xudf9ucHf/dnh8/2xudf9wcnn/bG51/2xudf9maXP/am13/3N1fP9zdXz/ -bG51/2dqcf9wcnn/c3V8/3Z4fP9qbXf/dXd9/2ptd/9maXP/bG51/2Zpc/9maG7/Zmlz/2ptd/9sb3j/ -bW92/21vdv9tb3f/bnB3/2ptd/9nanT/cHN9/3Bzff9sb3n/b3F4/29yfP9rbnj/cXR9/2hrdf9ucXv/ -bG95/2ptd/9zdXz/bnF7/3Bzff9qbXf/am13/2xvef9vcXX/bG51/2xudf9sbnX/bW9z/2xudf9ucHf/ -cHJ5/21vc/9sb3n/am13/3Byef9zdXz/bG95/2ptd/9zdXz/bG95/3N1fP9sbnX/bnB3/25wd/9sb3n/ -bnB3/25xe/9zdn//bnB3/3Byef9wcnn/c3V8/3Fzev9ucXn/bG95/3Bzff9zdn//cHN9/25wd/9wc33/ -cXN6/2xud/9sbnX/cHN9/25wd/9wcnn/bnB3/25wd/91d33/c3V8/2xvef9zdXz/bnF7/25xe/9qbXf/ -bnF7/25xe/9qbHP/bG51/2ptd/9qbXf/Zmlz/2xvef9sb3n/bG95/3N2f/9sb3n/bnF7/25xe/9sb3n/ -bG95/25xe/9wc33/bG95/25xe/9sbnX/bG51/2dqdP9zdXz/dnh8/3Z4fP9wc33/bnB3/3Bzff9sb3n/ -bG95/29xdf9wcnn/dXiB/3d5f/9ucXv/c3V8/3N2f/9ucXv/bG95/3V4gf9zdn//cHN9/3l8hv91eIH/ -cHN9/3Byef93eoP/bnF7/3V4gf9zdn//cHJ5/3Byef91eIH/eXuB/3N2f/91eIH/c3Z//3Bzff92eHz/ -dXd9/2Zobv9ucHf/cHJ5/3V3ff9sbnX/bnF7/2xudf9nanT/cHJ5/3N1fP9sbnX/bnB3/25wd/9zdXz/ -bnB3/3Bzff9wc33/bnB3/3V4gf9wc33/dXiB/3N1fP91eIH/e32D/3l7gf95e4H/e32D/3t9g/91d33/ -g4WM/3d6g/9wcnn/dXiB/3V4gf9nanT/dXiB/3d6g/9wc33/c3V8/3N1fP9zdn//bG95/25wd/9ucXv/ -bG95/29xdf9sbnX/dXd9/3Bzff9sb3n/bnB3/25wd/9ucHf/b3F1/3N1fP9ucHf/dXd9/2ptd/9nanH/ -bW9z/3d5f/95e4H/cHJ5/3t9g/9ucHf/c3V8/21vc/91d33/bG51/3Byef93eX//bnF7/3N1fP9wcnn/ -bnB3/2dqcf9sbnX/bG95/2psc/9sbnX/Z2px/2xvef9zdXz/Z2px/2Zobv9qbXf/ZGdx/2xvef9sb3n/ -dXd9/2ptd/9qbHP/bnF7/25xe/9maXP/bG51/3N1fP9qbHP/cHJ5/2psc/9qbHP/ZGdx/2psc/9wc33/ -cHN9/2ptd/9nanT/bG95/25xe/91d33/bG51/3d5f/9ucHf/bG51/2psc/9wcnn/bG51/3Byef9wcnn/ -dHZ8/21vdv9tcHn/bG51/25wd/9sbnX/Zmlz/2xvef9sb3n/am13/25xe/9vcnn/bXB3/3V3fv9ucHf/ -cHN9/3Byef9sb3n/d3l//3N2f/93eX//bnF7/2xvef9wc33/bnF7/2xvef9ucXv/cHJ5/3N1fP91d33/ -c3Z//3d6g/9zdXz/cHJ5/25xe/91eIH/foCG/3V4gf9wc33/d3qD/3N2f/95fIb/c3Z//2xvef9sb3n/ -bnF7/3Byef9wc33/dXiB/25xe/9ucXv/cHJ5/3N2f/9ydX7/cHJ5/2xvef9ucXv/c3Z//3Bzff9wc33/ -cnV+/3J0ev9ucHn/a254/3Bzff9vcXX/b3F1/25xe/9wc33/dnh8/3N1fP9ucHf/d3l//3Byef92eHz/ -bnF7/3N2f/95e4H/cHJ5/25xe/9zdn//cHN9/25xe/91eIH/d3qD/3d6g/97fof/dXiB/3t9g/99foH/ -e32D/3d6g/93eoP/eXuB/3V4gf91eIH/dXiB/3V3ff92eHz/eXuB/3t9g/9+f4P/eXuB/3Bzff95e4H/ -cHN9/3Bzff9wcnn/bnF7/3V4gf95e4H/cHN9/3Bzff93eoP/bnB3/2ptd/9ucXv/bnB3/2xvef91eIH/ -cHN9/2xvef9vcXX/c3V8/25wd/9ucHf/c3V8/2xudf9sbnX/dXd9/3V3ff9wc33/dXiB/3V4gf9zdn// -eXuB/3N2f/9maXP/bnB3/3Bzff95e4H/dXiB/3l7gf9zdn//c3Z//3t9g/97fYP/c3V8/3Z4fP93eoP/ -eXyG/3d5f/97fYP/foCG/3h5ff9+f4P/e32D/35/g/91d33/eXuB/36Ahv9sb3n/am13/3Bzff92eHz/ -bnB3/3l8hv9wc33/bnB3/25xe/9ucXv/Zmlz/3V4gf97fYP/c3V8/3Byef9zdXz/d3qD/3V3ff93eX// -foCG/3Z4fP91d33/c3Z//3t9g/97fYP/d3qD/3V4gf91d33/dXd9/3N2f/95e4H/d3qD/3d6g/9sb3n/ -bG95/3Byef95e4H/e36H/3Bzff95fIb/cHJ5/3V4gf9zdXz/c3Z//29xdf9zdXz/dXiB/3Bzff93eX// -cHJ5/2xvef9qbHP/bnB3/25wd/9tb3P/bW9z/25wd/9zdXz/dXiB/2xvef9ucHf/c3Z//3Byef91d33/ -c3V8/3d5f/9wcnn/bW9z/3N1fP9zdXz/bG51/25wd/91d33/bW9z/3Bzff9sb3n/bnB3/2psc/9ucHf/ -dnh8/3N2f/9vcXX/amxz/2xvef9wc33/c3V8/2xudf93eX//bG51/2xudf9qbHP/dXiB/3N2f/9zdn// -cHN8/3N1fP9tb3b/cXN6/25wd/9ucHf/b3F1/25wd/9ucXv/c3Z//3Bzff92eYL/dHZ+/3Fzev93eX// -bW92/3V3ff9wcnn/bnB3/3N1fP9ucXv/cHN9/2xvef9sbnX/cHN9/2xudf9kZ3H/am13/2ptd/9nanT/ -Zmlz/2ptd/9wcnn/bG51/21vc/9ucHf/bnF7/3V3ff9sb3n/bG95/3N1fP9vcXX/dnh8/25wd/9sbnX/ -am13/25wd/9vcXX/b3F1/3Byef9vcXX/dXd9/3Byef90dn3/cXN9/25wd/9tcHn/bXB6/25xe/9ucHf/ -bnB3/3Byef9wc3r/bW94/2ptd/9zdXz/b3F1/21vc/9ucHf/bnF7/3V3ff9sb3n/bnB3/3V3ff9sb3n/ -c3V8/3Byef9zdXz/c3Z//25wd/9ucXv/bG95/25wd/9wcnn/cHN9/3N1fP9ucXv/d3l//25xe/9wc33/ -dXd9/3N2f/9wcnn/d3qD/3d5f/9zdn//c3Z//3Byef9wcnn/bnB3/25xe/9wc33/dXd9/2xudf9tb3P/ -c3V8/2dqdP9sbnX/bG51/21vc/9wcnn/c3V8/2Rncf9qbXf/bnF7/2xudf9tb3P/am13/2xudf9qbHP/ -dXd9/25xe/9qbXf/bG95/25xe/9sbnX/cHJ5/3V3ff9ucHf/cHJ5/3d5f/93eX//c3Z//3V4gf91eIH/ -bG95/3V3ff91d33/Zmhu/25wd/91d33/dnh8/3Byef9wcnn/b3F1/2xudf9wcnn/cHJ5/2Rncf9nanT/ -am13/2ptd/9nanT/bG51/2Zpc/9maG7/bG95/2dqdP9qbXf/Z2px/2dqcf9qbXf/c3V8/3Byef9wcnn/ -dnh8/2xudf93eoP/am13/21vc/9qbXf/bG51/2psc/9zdXz/d3l//25wd/9ucHf/b3F1/25wd/9qbXf/ -bG51/3V3ff9qbHP/amxz/29xdf9wcnn/c3V8/2xvef9ucHf/bG51/2ptd/9sbnX/c3V8/3N1fP9wcnn/ -amxz/2xudf9qbXf/c3V8/3V3ff9qbXf/d3l//2xudf9ucHf/bG51/2xvef9sbnX/cHJ5/3Z4fP9zdXz/ -c3V8/2ptd/9sbnX/amxz/2xudf9sbnX/bW9z/21vc/9sbnX/cHJ5/3V3ff9sbnX/bG51/3Z4fP9sb3n/ -dXd9/3Byef93eX//bnF7/29xdf91d33/cHN9/2xvef9wcnn/eHl9/3Byef95e4H/c3Z//25wd/9qbXf/ -bnB3/3d5f/91eIH/bnF7/25wd/9wc33/dXiB/3d5f/9ucHf/dXiB/25wd/9sb3n/Z2p0/2ptd/9sb3n/ -bnF7/25xe/9wc3z/bnB3/29yev9ucHf/b3F1/2xudf9qbXf/bnF7/3N2f/9wc33/bXB6/3F0ff9sbnf/ -cXR9/2ttdP9qbXf/Z2p0/2psc/9sb3n/bnF7/2xvef9ucHf/bG51/25wd/9sbnX/amxz/25wd/9vcXX/ -bnB3/2ptd/9ucHf/bnF7/2xvef9sb3n/cHN9/25xe/95e4H/cHN9/3Byef91eIH/cHN9/3l7gf9wc33/ -bG95/3Byef9ucHf/bnB3/21vc/9wcnn/bW9z/3Byef9ucHf/c3V8/2xudv9sbnX/a211/25xev9ucXv/ -bnB3/3Byef9ydHv/b3J7/25wef9ucHf/c3V8/25wd/9vcXX/b3F1/3Byef9zdXz/bG51/3N1fP94eX3/ -bnB3/3V3ff9ucHf/bnB3/3d5f/9wcnn/c3Z//3V4gf91eIH/bG95/3N2f/9wcnn/bnB3/3d5f/9sbnX/ -cHJ5/3V3ff91d33/b3F1/3N1fP92eHz/c3V8/3Byef9ucHf/bnB3/21vc/9sbnX/c3V8/3d5f/9ucHf/ -am13/25xe/9kZ3H/bG51/2ptd/9sbnX/bG95/3N1fP9maXP/bG51/2xvef9sb3n/bW9z/2xudf9ucHf/ -bnB3/3V4gf9ucXv/bnB3/25xe/9wcnn/bnB3/3Byef91d33/bG51/2xudf92eHz/d3l//3N1fP9zdXz/ -c3V8/25wd/91d33/c3Z//2dqcf9ucHf/dXiB/3t9g/91eIH/d3qD/3Bzff9ucHf/c3Z//3N2f/9sb3n/ -bnB3/3N1fP9ucHf/bnB3/3Bzff9ucXv/bnF7/3Z4fP91d33/c3V8/25wd/9tb3P/cHJ5/25wd/9sb3n/ -bnF7/3Z4fP9vcXX/e32D/25wd/9qbXf/am13/25wd/9nanH/cHJ5/3d6g/9sb3n/cHJ5/3Byef9wc33/ -bnB3/25xe/91eIH/am13/2xvef9ucHf/bnF7/3Bzff9sb3n/bnF7/29xdf9ucHf/bW9z/3N1fP9wcnn/ -c3V8/2xudf9ucHf/am13/3N1fP92eHz/am13/3V3ff9qbHP/am13/2xudf9qbXf/amxz/2xvef91d33/ -cHN9/3V3ff9sb3n/bG51/2dqdP9qbHP/bG51/2xudf9sbnX/bG51/2ptd/9wc33/amxz/2Rncf9ucXv/ -Z2p0/25xe/9sb3n/dXd9/2ptd/9qbXf/cHN9/25xe/9nanT/bG95/3V3ff9sbnX/cHN9/2ptd/9nanT/ -ZGdx/2xudf9zdXz/cHN9/25wd/9vcXX/bG95/3V3ff94eX3/bnB3/3l7gf9ucXv/bnB3/2dqdP91d33/ -bnB3/25wd/9wcnn/bnF7/21veP9wcnn/b3J8/3Byef9ucXv/am13/3Bzff9zdn//bG95/3Byef9ydH3/ -cHJ7/3V2e/9vcXf/cHJ5/25wd/9sbnX/cHJ5/3Bzff9wcnn/bnB3/25wd/9wcnn/bG51/2Rncf9sbnX/ -bG51/2dqdP9nanT/bG51/25wd/9ucHf/b3F1/3Bzff9wcnn/eHl9/3Byef9sb3n/cHN9/3Bzff93eX// -bG95/2xvef9ucXv/bG95/25wd/9vcXX/cHJ5/2xudf9ucHf/cHJ5/3N2f/9vcnz/b3J8/25xev9wc33/ -cHN9/3Byef9ucHf/bnB3/3Fzev9tb3b/bW91/25xe/9qbXf/bG51/2xudf9sb3n/c3V8/2ptd/9zdXz/ -dXd9/25wd/91d33/b3F1/25xe/93eX//bnB3/3Bzff9ucXv/c3Z//2xvef91eIH/bnF7/3Bzff95fIb/ -d3qD/3l8hv97fof/e32D/3V3ff95fIb/e32D/3N2f/9zdn//bnF7/3Bzff9wcnn/bG95/25xe/91eIH/ -bnB3/3Byef91d33/bG95/3Byef9sb3n/bnB3/3Bzff91d33/amxz/25wd/9wcnn/bnB3/25wd/9ucXv/ -bnF7/2ptd/95e4H/bnF7/25xe/9zdn//cHN9/3Byef9wc33/d3l//3N1fP9wcnn/dXd9/3V4gf9wcnn/ -cHN9/25xe/9ucXv/dXd9/3V4gf9maXP/am13/3Bzff94eX3/c3V8/3N1fP9vcXX/b3F1/3Byef91d33/ -bnB3/2ptd/9wcnn/cHJ5/21vc/9zdXz/bG95/2ptd/91d33/c3V8/3V3ff9qbXf/am13/2xudf91eIH/ -d3qD/3l8hv9+gIb/c3Z//4GDiv9zdn//c3Z//3Bzff9ucXv/am13/3N1fP95fIb/bnB3/25wd/9ucHf/ -cHJ5/2xudf9sbnX/c3V8/2dqcf9sbnX/bG95/25xe/9zdn//bG95/2xvef9ucHf/bnB3/25wd/9wc33/ -cHN9/3N2f/9ucHf/amxz/29xdf91d33/eHl9/2xudf92eHz/bW9z/25wd/9ucHf/bnF7/25wd/91d33/ -dXiB/3V3ff92eHz/bnB3/2xudf9nanH/bnB3/2xudf9vcXX/bG51/2xudf9qbXf/bnF7/2ptd/9qbXf/ -c3V8/2psc/92eHz/c3V8/3V3ff9wcnn/bnB3/3N2f/9wc33/am13/2xvef95e4H/bnB3/3Z4fP9ucHf/ -bG51/2psc/9vcXX/dXd9/3N1fP9sb3n/cHJ5/25xe/95e4H/eXuB/3Byef93eX//bnB3/29xdf9nanH/ -am13/2Rncf9maG7/Zmlz/2tueP9oa3P/am11/2ptd/9qbXf/bG51/2Rncf9qbXf/c3V8/2xudf9qbHP/ -b3F6/2xud/9zdXr/bnB3/3Byef9wcnn/bnB3/3N1fP91eIH/cHN9/3N1fP9sb3n/cHN9/25wd/9nanT/ -b3F1/29xdf9ucHf/bG51/2xvef9ucHf/bG51/2ptd/9ucXv/am13/3Z4fP9sbnX/bW9z/3Byef9wcnn/ -dXd9/2xudf9nanT/bG95/2ptd/9nanT/bG51/25xe/9ucHf/cHJ5/2ptd/9vcnz/bW92/2xvd/9sb3n/ -bG95/2dqdP9nanT/Z2p0/2ttdP9sb3n/bXB4/2xveP9zdn//bG95/2xvef9ucHf/cHN9/3N1fP9qbXf/ -dXd9/3d5f/9qbXf/c3V8/2xudf9tb3P/d3l//2ptd/9ucXv/bG95/3Bzff9qbXf/bnF7/2psc/9maXP/ -cHJ5/2ptd/9qbXf/cHN9/25xe/9sbnX/cHJ5/3N1fP9ucHf/bnB3/2xvef9wcnn/bG51/2xvef9wc33/ -dXiB/2xvef9ucXv/d3l//2xvef9ucXv/bnB3/3Bzff9zdn//dXiB/2xvef9wc33/c3Z//25wd/9ucHf/ -cHJ5/25wd/9nanH/dXd9/25wd/9tb3P/bG51/25wd/9tb3P/bG51/2xvef9sbnX/bW9z/3h5ff91d33/ -cHJ5/3N1fP9wcnn/cHJ5/3Z4fP9wcnn/Z2px/2xudf9zdn//dXd9/25xe/9zdn//cHN9/3Bzff91eIH/ -eXuB/3N1fP9ucXv/d3qD/3t9g/92eHz/fn+D/3l7gf97fYP/fX6B/3t9g/97fYP/c3V8/3Bzff91eIH/ -c3V8/3Byef9zdXz/dXd9/25wd/9+gYr/d3qD/3N1fP9zdXz/cHN9/2xvef95e4H/f4GH/3Bzff9zdXz/ -cHN9/3Bzff9ucHf/bG95/3N2f/9nanT/bnB3/3Byef91eIH/dXiB/3N2f/9zdn//c3V8/3Bzff9zdXz/ -c3Z//25xe/9zdn//bnB3/2xvef9ucXv/dnh8/3Z4fP9wcnn/dnh8/21vc/9zdXz/bG51/2xvef9tb3P/ -c3V8/3V3ff9ucXv/cHN9/2ptd/9nanT/XF9o/2Zpc/9qbXf/amxz/2dqcf9sbnX/bG51/3Bzff9nanH/ -Zmlz/25xe/9qbXf/c3V8/3V3ff91d33/bG51/2psc/9wc33/am13/2dqdP9qbXf/dXiB/25wd/92eHz/ -bnF7/25wd/9sb3n/b3F1/3N1fP9wcnn/bnB3/21vc/9sbnX/dXd9/3N1fP9tb3P/eHl9/29xdf9vcXX/ -Zmhu/3V3ff9ucHf/bG95/3Byef9xdH3/bnF7/3Fze/9ucHf/bnB3/29xdf9sbnX/c3V8/3N1fP9ucHf/ -b3F1/3J0ev9zdn//dnmD/3N2f/91eIH/bnF7/25xe/91eIH/eXyG/3d6g/91eIH/c3Z//3d6g/9wc33/ -bnF7/25wd/9sb3n/bG95/2xvef9zdn//dXiB/3Byef9sb3n/dXd9/3Bzff93eX//bnB3/2ptd/9wcnn/ -cHJ5/3Z4fP9ucHf/bG95/3N1fP9vcXX/am13/2xvef9zdXz/cHJ5/3N2f/9zdn//d3qD/3Bzff9xdH7/ -c3Z9/3J1fP9zdXz/bnB3/2xudf9sb3n/bnF6/21veP9tb3j/c3Z//2xvef9ucHf/bnB3/3N1fP94eX3/ -b3F1/3V3ff93eX//bnB3/3V3ff9ucHf/cHJ5/3V3ff9ucHf/bnF7/2xudf9ucXv/Z2p0/3Bzff9qbXf/ -am13/25xe/9sb3n/Z2p0/2xvef9qbXf/YmVu/2Rncf9maXP/Zmhu/2Zobv9maG7/Z2p0/2Rncf9maG7/ -Zmlz/25wd/9maG7/Zmhu/2xvef9gY2z/Zmlz/2Rncf9nanH/Zmlz/2Rncf9cX2j/Zmlz/2Zpc/9kZ3H/ -YmVu/2Zpc/9nanT/YmVu/3N1fP9nanH/Zmhu/2Zpc/9qbHP/Z2px/2xudf9sb3n/am13/2xudf9wc33/ -c3V8/25xe/9sb3n/am13/2ptd/9zdXz/bnB3/2Zobv9nanT/bnF7/3Bzff9sb3n/bG95/2ptd/9sbnX/ -bG95/2xvef9sbnX/Zmlz/2ptd/9ucXv/am13/3N1fP9sbnX/cHJ5/3Byef9zdXz/dXd9/2xudf9vcXX/ -c3V8/25xe/9wc33/bnF7/3Bzff9sbnX/e32D/3V3ff9ucHf/cHJ5/2xvef9nanT/dXd9/3l8hv9sb3n/ -b3F1/25wd/9ucHf/bnB3/25wd/9zdn//am13/25wd/9wcnn/c3Z//3N2f/9ucHf/cHN9/3Byef9wc33/ -bnF7/3V4gf9ucXv/dXd9/25wd/9qbHP/bnB3/3V3ff91d33/bnB3/3Z4fP9sbnX/c3V8/25wd/9sbnX/ -bG51/25xe/9zdXz/c3V8/3V3ff9zdXz/bG51/2RmbP9nanT/am13/2dqdP9sbnX/bG95/25wd/9ucXv/ -bG51/2dqdP9zdXz/bG95/3V3ff91d33/dXd9/2xudf9sbnX/dXd9/25wd/9vcXX/c3V8/3l7gf9sbnX/ -c3V8/2dqdP9nanT/Zmlz/2ptd/9ucXv/bG95/2xudf9qbXf/amxz/3Bzff9wc33/bG51/3N1fP9sbnX/ -bG51/2Jlbv93eoP/c3Z//3V4gf94e4X/eXuC/3V3ff9ydX3/a254/3Byef9tb3P/bnB3/3Byef9zdXz/ -bW9z/21vc/9xcnj/dHZ+/3l6f/94eoH/foCG/3d5f/95e4H/c3Z//3d6g/97fYP/dXiB/3V4gf9zdn// -c3V8/3N1fP9zdXz/cHN9/2xvef9zdXz/d3qD/3N2f/9zdXz/bG95/3Bzff9wc33/d3l//3Byef9qbXf/ -cHJ5/2xvef91d33/bG51/25wd/91d33/bnB3/2psc/9ucHf/c3V8/2xvef9ucHf/bG51/3Byef9ucHf/ -cnR6/3N1e/9wcnn/dXd9/2ptd/9sb3n/am13/2tudv9qbXf/am13/3Bzff9sbnX/cHJ5/2xudf9qbXf/ -dnh8/21vc/9sb3n/c3V8/2xudf9wcnn/bW9z/3Byef93eX//bnB3/2xvef9sbnX/cHN9/2xudf94eX3/ -bnB3/25wd/93eX//dXd9/25xe/91eIH/dnh8/25wd/9wc33/dXd9/3N1fP9ucHf/bnF7/3l7gf9wcnn/ -bnF7/3N2f/93eoP/bnF7/25xe/93eX//cHJ5/25xe/9ucHf/bnF7/2xvef9ucXv/bG51/2xvef9wc33/ -b3F1/25wd/9wc33/bnB3/2psc/94eX3/bnB3/29xdf9ucHf/bG51/25wd/9ucXv/cHN9/3Byef9ucXv/ -dXiB/3l7gf95e4H/cHN9/3Bzff9ucXv/eHl9/3V3ff9nanH/bG51/3Byef91d33/b3F1/25wd/9tb3P/ -bG51/25wd/9ucHf/bG51/2dqdP9sb3n/am13/2Rncf9qbXf/bG51/3Bzff9qbXf/bG95/2xvef9kZ3H/ -Z2p0/3Bzff9zdXz/c3V8/3N1fP91d33/bnB3/3t9g/9zdn//cHJ5/3N1fP9wcnn/am13/3d6g/95fIb/ -cHN9/3Bzff9zdn//cHN9/3Byef9wcnn/d3qD/2xvef9zdXz/cHJ5/3V4gf95e4H/c3V8/3Bzff91d33/ -d3qD/3d6g/91eIH/d3qD/3d6g/91eIH/dXd9/3t9g/97fYP/e32D/3l8hv97fof/cHN9/3d6g/9wc33/ -c3Z//3N2f/93eoP/eXuB/3V4gf95e4H/dXiB/2ptd/9qbXf/cHJ5/25wd/9sbnX/bG51/2xudf9ucHf/ -c3V8/21vc/9nanT/cHN9/25xe/93eX//dXd9/3Bzff9qbXf/bG51/3N1fP9sb3n/bG51/25xe/91eIH/ -am13/25xe/9kZ3H/amxz/2Rncf9nanT/cHJ5/2ptd/9nanH/Z2p0/2Rncf9maXP/Zmlz/2Zobv9nanT/ -YmVu/2Zobv9cX2j/bnF7/2ptd/9ucHf/b3F4/2tueP9tb3f/am12/2dpb/9maXP/Zmlz/2Rncf9maXP/ -Z2p0/2dqcf9sbnT/a254/2tueP9wc3r/a253/25xe/9tb3P/bnF7/2xudf9sb3n/bnF7/2xudf9qbHP/ -am13/2Rncf9maXP/Z2px/2xudf9iZW7/Z2p0/2xvef9qbXf/amxz/2dqdP9sb3n/bnF7/3V3ff9wcnn/ -bnB3/3Bzff9wc33/e32D/3Bzff9ucHf/d3qD/3Bzff9sb3n/dXd9/3l8hv9zdn//d3qD/3N2f/93eoP/ -cXR9/3Z4fv9ydHv/dHZ9/3Z4fP9ucHf/cHJ5/3Bydv9wcnr/b3F4/25wd/91eIH/bnB3/25xe/9sb3n/ -cHJ5/3Z4fP9tb3P/am13/3N1fP9qbXf/bnF7/2dqcf9ucXv/dXd9/2xvef9ucXv/bG51/2xvef9qbHP/ -dXd9/2ptd/9sbnX/dnh8/3N1fP9sb3n/dXd9/25xe/9nanT/Z2p0/25xe/9sb3n/amxz/2psc/9wc33/ -am13/2xudf9wc33/dXd9/2psc/9qbHP/bnF7/2dqcf9sbnX/bW9z/25wd/9sbnX/bnB3/2xudf9qbXf/ -bnF7/21vc/9vcXX/dXd9/21vc/9qbHP/eXuB/25xe/9wc33/cHN9/2xvef9ucHf/cHJ5/2xvef9ucHf/ -bG95/25xe/91d33/dnh8/25xe/9sbnX/am13/3N1fP9ucXv/YmVu/2ptd/9sb3n/bnF7/2psc/9qbHP/ -Z2px/2dqcf9nanH/Z2px/2dqdP9maXP/am13/2dqdP9kZ3H/bG95/2psc/9wc33/bG95/3Bzff9zdXz/ -Z2px/21vc/9zdn//cHN9/3Z4fP91d33/c3Z//25xe/95fIb/c3Z//25wd/9ucHf/bnB3/2ptd/9zdn// -e32D/25wd/9vcXX/cHN9/25xe/9ucHf/cHJ5/3V4gf9nanT/bnB3/25wd/93eoP/c3Z//2xvef9ucHf/ -bG95/3Bzff9wcnn/cHN9/2xvef9ucXv/bG51/2xudf9ucHf/bnF7/3N1fP9zdXz/dXd9/25wd/9wcnn/ -am13/2xvef9qbXf/cHN9/3Bzff9sb3n/cHN9/2xvef9iZW7/YGNs/2psc/9sb3n/Zmlz/2xudf9sbnX/ -bW9z/3N1fP9tb3P/amxz/3N1fP9ucHf/d3l//3V3ff9ucXv/am13/2ptd/9wc33/am13/2ptd/9ucHf/ -e32D/3Byef91d33/bG51/25wd/9ucHf/cHJ5/3V3ff9ucHf/amxz/25xe/9wcnn/bG95/25xe/9sbnX/ -cHN9/29xdf9sbnX/Z2px/2xvef9qbHP/am13/2xvef9tb3b/b3F5/29yev9tb3P/cHJ5/2xvef9sbnX/ -bG51/3N1fP9vcXX/a211/2xudv9vcXn/cnR7/25wd/9wcnn/bG51/2xvef9qbHP/am13/2xvef9sbnX/ -Z2p0/25xe/9nanT/am13/2xudf9qbXf/Zmlz/2ptd/9sb3n/bG95/2ptd/9qbXf/c3V8/3Byef92eHz/ -cHJ5/25wd/9sb3n/bG95/3N1fP9wcnn/bG51/3N1fP9qbHP/Z2px/2xudf9ucHf/bW9z/3Bzff9qbHP/ -bG51/25weP9xdHv/cXR8/25xe/91d33/b3F1/3N1fP9ucHX/bnB3/21vdf9rbXP/c3V8/2ptd/9sb3n/ -am13/2xudf91d33/bG51/2xvef91d33/bnB3/3Byef9sbnX/cHN9/3V4gf9wcnn/bG95/2ptd/9wcnn/ -b3F1/3h5ff9tb3P/bG51/3N1fP91d33/bnB3/3l7gf9zdn//bnF7/3Byef93eX//d3l//25xe/9wcnn/ -d3l//2xvef9sb3n/cHN9/3V3ff9ucHf/bnB3/3V3ff9ucHf/bG95/2xudf9wcnn/bnB3/3Byef9ucHf/ -bnB3/25xe/9qbXf/bW9z/3Bzff9qbHP/ZGdx/3N1fP9qbHP/am13/2xvef9nanT/amxz/2xudf9qbXf/ -bG51/2xudf9sb3n/dXd9/2xvef9ucXv/bG95/2xudf9zdXz/bG95/2BjbP9maXP/bG95/3Bzff9nanT/ -am13/2dqdP9qbHP/am13/2ptd/9qbXf/Z2p0/25xe/9sb3n/Zmlz/2xvef9sbnX/cHN9/2ptd/9zdXz/ -c3V8/2Rncf9sbnX/dXd9/3N2f/91d33/dXd9/3V4gf9ucXv/dXiB/3Bzff9ucHf/cHJ5/25wd/9sb3n/ -c3Z//3t9g/9sb3n/b3F1/25wd/9ucHf/b3F1/29xdf9zdXz/Zmhu/25wd/9sbnX/c3V8/3Bzff9qbXf/ -bnB3/2psc/9wcnn/am13/3Byef9sbnX/cHJ5/2xudf9tb3P/bG51/3Byef91d33/bnF7/3d5f/9ucHf/ -cHJ5/3Byef9ucHf/cHN9/3V3ff95e4H/dXd9/3V3ff9wc33/bG95/2ptd/9vcXX/bnB3/2ptd/9sb3n/ -bnB3/21vc/9zdXz/bW9z/2psc/91d33/am13/3V4gf94eX3/cHJ5/25wd/9ucHf/cHJ5/2xudf9qbXf/ -bG95/3N2f/9qbXf/bG95/2Rncf9nanT/Zmlz/3Bzff9wc33/am13/2dqdP9sb3n/bnF7/2xudf9ucXv/ -amxz/2xvef9sbnX/bnF7/2Rncf9zdXz/bG51/21vc/9sbnX/b3F4/3FzfP9vcnv/bnB3/3N2f/9zdn// -bnF7/3Byef9wc33/bnB3/25xe/9xc3v/cXR9/3d5gP9wc33/dXiB/3Bzff9ucXv/bnB3/25xe/9wc33/ -bnF7/25wd/93eX//bG95/25xe/9wc33/cHN9/2xvef9wcnn/c3Z//3Bzff9wc33/c3V8/3d6g/91eIH/ -e32D/3Byef9zdn//cHN9/3N2f/93eX//c3Z//3Byef91eIH/cHN9/3Bzff9zdn//d3qD/3V4gf97fYP/ -c3V8/3Bzff9xdH3/cnR7/3F0fv9wc3r/cHJ5/2xudf9wc33/am13/25xev9tb3b/a210/3N1fv9wc33/ -c3Z//2xvef9wcnn/dXd9/2xudf9zdXz/eHl9/3Bzff9zdXz/bnB3/3V3ff93eoP/c3Z//3N2f/91d33/ -eXuB/3N1fP97fof/c3Z//3N2f/9+gIb/e32D/3l8hv9/gYf/d3qD/3N1fP9zdXz/foCG/3t9g/93eoP/ -dXiB/36Ahv91d33/c3V8/3t9g/9+gIb/dXd9/3N1fP93eX//bG95/25wd/9vcXX/c3Z//25xe/91eIH/ -bnB3/3Byef9zdXz/bnF7/3Byef91eIH/cHN9/3V3ff95fIb/cHN9/3V4gf95fIb/dXd9/3N1fP9zdn// -cHN9/3Byef9ucXv/cHN9/3d6g/91eIH/c3Z//3V4gf9ucXv/dXiB/3V4gf9nanT/bG51/3N2f/93eX// -cHN9/25wd/9sbnX/bG51/25wd/9sbnX/c3V8/2xudf91d33/bnB3/2psc/9zdXz/bG51/3V3ff9ucHf/ -c3Z//3h5ff9qbHP/bnB3/3N2f/9wc33/c3V8/3N1fP9zdXz/cHN9/3h5ff9ucHf/bnB3/25wd/9nanT/ -bG95/3V4gf9/gYf/cHN9/3Byef9ucXv/cHN9/3Byef9zdXz/dXiB/2dqdP9wc33/bnB3/3Bzff93eoP/ -c3V8/3N2f/9ucXv/dXiB/3Bzff91eIH/c3V8/3t9g/91eIH/c3Z//3d6g/91eIH/e32D/3l8hv9+gYr/ -eXuB/3l7gf95fIb/dXiB/3t9g/97fof/e36H/3l7gf95e4H/d3qD/25xe/9qbXf/cHJ5/3N1fP9sb3n/ -bnF7/3Byef9wcnn/dXd9/29xdf9qbHP/dnh8/3N1fP93eX//dnh8/2xvef9qbXf/bG95/25xe/9sbnX/ -bG95/2xvef93eX//bG95/25xe/9qbXf/am13/2dqdP9zdXz/bG95/2psc/9nanT/bG95/2xvef9qbHP/ -Z2p0/2dqcf9sb3n/Zmhu/2Rncf9dYGr/cHJ5/2xudf9sb3n/a210/2ttdf9rbnj/aGpx/2Rncf9maXP/ -Zmlz/2Zobv9iZW7/ZGdx/2Jlbv9maXP/aGpw/2xvd/9xc3r/bG51/3N1fP9qbXf/bnF7/2ptd/9sb3n/ -bnF7/25wd/9sbnX/dXd9/2psc/9sbnX/bnB3/29xdf9nanH/bnB3/25wd/9ucXv/bnB3/2xvef9zdXz/ -dnh8/3V3ff9sb3n/cHN9/3Byef9ucXv/c3Z//3Bzff9wcnn/dXiB/25xe/9ucXv/bG95/3V4gf91eIH/ -foCG/3V3ff91eIH/dHeA/3R3fv90d4D/dHeA/3Bzff9ucXv/cHJ5/2xudf9vcXj/bW94/21vdv9zdn7/ -cHN9/3Z4fP9ucHf/c3V8/3V3ff9ucHf/dXiB/3d5f/91d33/cHJ5/2xudf9sb3n/dXd9/25xe/9sb3n/ -Zmlz/25xe/9qbHP/bnF7/2ptd/9qbHP/cHN9/2xvef9ucXv/dXiB/2xvef9tb3P/am13/3N1fP9ucXv/ -Z2p0/2psc/9wcnn/Zmlz/2Zpc/9sb3n/bnF7/2dqdP9sbnX/c3V8/2ptd/9qbXf/amxz/25xe/9sb3n/ -bG95/2dqdP9sbnX/bnB3/25wd/9tb3P/cHJ5/2xudf9qbXf/dXd9/3Byef9ucHf/bnB3/25wd/9ucHf/ -bnF7/3Bzff9ucHf/bnF7/2xvef95fIb/bnF7/25xe/9wc33/bG95/3V4gf9zdXz/ZGdx/2Zpc/9wc33/ -bnF7/2ptd/9sb3n/am13/2xvef9qbXf/amxz/2ptd/9maXP/bnF7/2Zpc/9gY2z/am13/2psc/91d33/ -bG95/2xvef91d33/ZGdx/2psc/9ucXv/dXiB/3Z4fP91eIH/d3l//3d6g/97fYP/d3qD/3N2f/9zdn// -cHN9/3V3ff97fYP/g4WM/3Bzff9ucXv/cHN9/3Byef9ucHf/cHJ5/3V4gf9qbHP/dXiB/25wd/9ucXv/ -dXiB/25wd/9wcnn/am13/3Bzff9ucXv/cHJ5/21vc/9zdXz/bnB3/21vc/9zdXz/bnB3/3h5ff9ucHf/ -dXd9/25wd/9ucHf/c3V8/2xudf9wc33/d3l//3d5f/91eIH/cHN9/3N2f/9nanT/Z2p0/25xe/9sb3n/ -bG95/2xvef9ucHf/bnF7/3V4gf9wcnn/Zmlz/3V3ff9wc33/d3l//3h5ff91d33/b3F1/25wd/9zdXz/ -bnB3/3Byef9ucHf/d3l//25xe/9sb3n/bG51/2xudf9sbnX/cHN9/3V3ff9ucHf/bG51/3N1fP91d33/ -bW9z/25wd/9tb3P/bnF7/2ptd/9sbnX/Zmhu/2xvef9qbHP/bnF7/2xudf9vcXb/cXN7/29xev9sb3n/ -c3Z//25xe/9ucHf/bG95/2xvef9ucHf/cHJ5/21vdv9wcnj/dXd7/29xe/9wc33/bnF7/3Byef9ucHf/ -cHJ5/3Bzff9ucHf/bnB3/3Z4fP9nanT/am13/2xudf9tb3P/ZGZs/29xdf9ucHf/c3V8/25wd/9ucHf/ -bnB3/3N1fP91d33/bnB3/3N2f/9ucHf/bnB3/3N1fP9wc33/cHJ5/3N2f/9sb3n/Z2p0/2ptd/9zdn// -bnF7/3d5f/9wc33/cXN9/3R3f/91eH//dXiB/3V4gf9wc33/bnF7/3Bzff9ucXr/cnR9/3Bzff9ucXv/ -dHZ9/3N2f/91d33/bG95/3Byef91d33/bG95/3Bzff91eIH/c3V8/2xvef9ucHf/c3V8/3V3ff9wcnn/ -bnB3/25wd/92eHz/bG95/3d5f/9ucXv/bnB3/3l7gf9zdXz/c3V8/3l7gf9ucHf/bW9z/2xudf92eHz/ -cHJ5/3Byef9sbnX/dnh8/2ptd/9qbXf/dXd9/3Z4fP9sbnX/bnB3/3d5f/9ucHf/amxz/2xudf9zdXz/ -bnF7/3Bzff9qbXf/bG51/21vc/9wcnn/bnB3/3N2f/9ucHf/bG51/3Bzff9ucHf/bnB3/3Bzff9ucHf/ -b3F1/29xdf9wc33/cHJ5/3N2f/91eIH/foGK/3V4gf95fIb/eXyG/3N2f/9+gYr/d3qD/3Bzff9wc33/ -e32D/3d6g/91eIH/eXyG/3N2f/95fIb/dXiB/3V4gf95fIb/cHN9/3t9g/95fIb/cHN9/3V4gf9wcnn/ -d3l//3V3ff92eHz/eXuB/2dqdP9ucHf/dXiB/2ptd/9ucXv/bG95/3Bzff9sb3n/dXd9/2xudf9qbXf/ -am13/2dqdP9nanT/bnF7/3l7gf9sbnX/bG51/25wd/9sbnX/am13/2xudf9ucXv/ZGZs/2ptd/9maXP/ -bG95/3N1fP9nanT/amxz/2Zpc/9qbXf/bG51/25wd/9tb3P/dXd9/3Byef9sbnX/dXd9/3Byef92eHz/ -c3V8/3h5ff9ucHf/bG51/3V3ff9ucXv/dXiB/3l8hv95fIb/d3qD/3N2f/91eIH/bnF7/25xe/91eIH/ -cHJ5/3Byef9zdn//bnB3/25wd/9wc33/bnF7/2dqdP91eIH/dXiB/3l7gf95fIb/dXiB/3N1fP9wc33/ -c3Z//2xvef9zdn//bnF7/3l7gf9zdn//bnF7/25wd/9vcXX/b3F1/3N1fP9zdXz/bnB3/2psc/9zdn// -dXd9/2xudf9wcnn/bG95/2xvef9sbnX/bG51/1xfaP9ucXv/bG95/3N1fP9tcHr/bW91/3ByeP9tb3j/ -aGp0/2xvef9qbXf/bG95/2dqdP9sbnX/bnB3/29xef9oa3X/bG93/3Byev9rbnj/bnF7/2xudf9sb3n/ -bG95/2xvef9sb3n/bnB3/2ptd/9wc33/Z2p0/2ptd/9qbXf/bG51/2Jlbv9qbHP/Z2p0/2xvef9qbHP/ -amxz/2ptd/9ucXv/bG95/2psc/9ucXv/am13/2xudf9ucXv/bG95/2xudf9sbnX/ZGdx/2dqdP9kZ3H/ -bG95/3Byef9zdXz/bG95/21vdP9ucHf/cnR6/3Fzev9vcXj/bG95/2xudf9ucHf/bG51/2ptd/9rbnj/ -a254/3J1fv91d33/dXd9/29xdf9wcnn/c3Z//25xe/91eIH/d3qD/3N2f/9ucHf/bnB3/3N1fP93eX// -bnF7/25xe/9qbXf/c3Z//3Bzff91d33/bnF7/2xudf94eX3/cHJ5/3V3ff91eIH/bnF7/25wd/9sb3n/ -dXd9/25wd/91d33/bG51/3Z4fP9qbHP/Z2p0/3Bzff92eHz/bG51/3Byef92eHz/bW9z/2xudf9vcXX/ -dnh8/3N1fP9zdXz/bnB3/29xdf9ucHf/cHJ5/29xdf91d33/bG51/2ptd/9ucXv/am13/2psc/9wc33/ -Zmlz/2ptd/9maXP/am13/2dqcf9maXP/Z2px/25wd/9kZ3H/Zmhu/2Zpc/9nanH/cHJ5/2Zpc/9gY2z/ -YmVu/2Zpc/9qbXf/Zmhu/2dqdP9iZW7/Z2p0/2Zobv9maG7/am13/2Rncf9maXP/Zmhu/2BjbP9maXP/ -ZGdx/2ptd/9nanT/bG95/3Byef9kZ3H/ZGdx/2ptd/91d33/dXd9/3V3ff94eX3/cHJ5/3N2f/9ucXv/ -c3V8/3V4gf9zdXz/bnB3/3N2f/9+gIb/bnB3/29xdf9ucHf/bG51/2xudf9ucHf/dXd9/2ZobP9ucHf/ -bG51/25wd/92eHz/bG51/2xudf9qbHP/bnB3/29xdf9ucHf/bG51/3Bzff9qbXf/bG51/25xe/9wc33/ -bG95/3Bzff9zdXz/am13/2xudf91d33/bG51/3Byef91d33/d3l//3N2f/9ucXv/cHN9/2xvef9sbnX/ -cHJ5/29xdf9sbnX/bG95/2ptd/9vcXX/c3V8/3Byef9maG7/c3V8/3N1fP92eHz/d3l//3V4gf9ucHf/ -cHN9/3Bzff9wcnn/d3qD/3Bzff95e4H/cHN9/2xvef9sb3n/bnB3/29xdf91d33/dXd9/3Bzff9sb3n/ -dXiB/3V3ff9ucHf/cHJ5/3Byef9wcnn/bnB3/3Byef9maG7/cHJ5/25wd/9wc33/bnB3/25weP9wcnn/ -bXB5/25wd/9wcnn/b3F1/3N1fP9sbnX/bnB3/3Byef9vcXj/bG52/2xvef9vcnv/bXB5/2xvef9sbnX/ -bG95/2Zpc/9nanT/Z2p0/2psc/9nanH/cHN9/2Zpc/9qbXf/am13/2ptd/9iZW7/bG51/2xvef91d33/ -bnB3/25wd/9zdn//d3qD/3N2f/9wcnn/dXiB/3N2f/9zdXz/eXyG/3V4gf91d33/dXiB/3N1fP9zdn// -bnF7/3l8hv99foH/foCG/3V4gf91d33/dXiB/3V3fv90d4D/cXR+/25xe/9wcnn/c3Z//3Byef9wcnr/ -cHJ5/2tueP90d4D/d3l//3V3ff9ucHf/cHN9/3V3ff9wc33/c3Z//3d6g/91d33/bG95/2xvef9zdn// -eXyG/25xe/9ucHf/bnB3/3Z4fP9wcnn/c3V8/2xudf9nanH/cHN9/2ptd/9ucXv/d3l//21vc/9tb3P/ -b3F1/3Z4fP9ucHf/cHJ5/2ptd/94eX3/bnB3/2dqcf9ucHf/c3V8/2psc/9wcnn/dnh8/29xdf9qbHP/ -bW9z/3N1fP9zdXz/cHJ5/2xudf9qbXf/am13/2xvef9qbHP/am13/2dqcf9kZ3H/am13/2psc/9maG7/ -Z2p0/1xfaP9gY2z/YmVu/2dqdP9kZ3H/ZGdx/2Zobv9ucHf/Zmlz/2Rncf9nanT/Z2px/25xe/9qbXf/ -ZGdx/2Zpc/9wc33/c3V8/2xudf9zdXz/bG51/2xvef9qbXf/am13/3N1fP9ucHf/cHJ5/25xe/9maXP/ -cHN9/25wd/92eHz/cHJ5/25xe/9zdXz/amxz/2xudf91d33/dXd9/3N1fP92eHz/d3l//3N1fP91d33/ -bG95/29xdf9wcnn/amxz/2xudf9wcnn/eXuB/3Byef9tb3P/bG51/2Zpc/9nanT/am13/3N1fP9gY2z/ -am13/2dqdP9qbXf/bnF7/2dqcf9ucHf/bnB3/29xdf9ucHf/cHJ5/29xdf91d33/cHJ5/21vc/9wcnn/ -dXd9/3Byef92eHz/dnh8/25xe/9ucXv/eXuB/3N1fP91eIH/e36H/3t+h/93eX//cHN9/3N2f/9ucHf/ -am13/3V3ff9ucHf/bG95/3Byef9sb3n/bnF7/3N2f/9ucXv/am13/3N1fP9ucXv/dXd9/3d5f/91eIH/ -bG95/25wd/9ucXv/bnB3/3N2f/9sb3n/d3l//3Bzff9ucXv/bG95/25wd/9ucHf/d3l//3Z4fP9sb3n/ -am13/3V3ff9zdXz/bnB3/3N2f/9wc33/cHN9/3N2f/91eIH/Z2p0/25xe/9ucHf/dXd9/3R3gP9wcnv/ -cnR8/3Bzff9ucXv/c3Z//25xe/9zdn//bG95/3Bzff9zdn//bnF7/3F0ff9zdn//cXR+/3F0ff9wcnn/ -bW9z/3N1fP9ucHf/bG95/2ptd/9qbHP/amxz/2xvef9maXP/Z2p0/2ptd/9qbXf/ZGdx/2psc/9qbXf/ -dXd9/2xudf9tb3P/cHJ5/3N1fP9wc33/Z2px/25xe/9sbnX/bW9z/3Byef9sbnX/am13/2xudf9ucHf/ -bG51/2Zpc/9ucXv/dXd9/3N1fP9sbnX/bG92/29xef9wc3v/dHd//3F0ff9wcnn/cHJ5/3Byef9ydHz/ -bnB4/21weP9tb3f/cHN9/3Bzff9wc33/amxz/2xvef95e4H/dXiB/3N2f/9+gYr/eXyG/3d5f/93eX// -foCG/4OFjP97fYP/dXiB/25xe/95fIb/c3Z//3t9g/9wc33/cHN9/3d5f/9wc33/c3Z//3d6g/9ucXv/ -cHN9/29xdf93eX//bnB3/3N1fP9ucHf/eHl9/2psc/9maXP/bG95/25xe/9maXP/bG51/3N1fP9sbnX/ -Zmlz/2xudf9zdXz/cHN9/25xe/9qbXf/am13/2Zpc/9ucXv/amxz/2dqdP9maXP/Zmlz/25xe/9qbHP/ -Z2px/2dqdP9iZW7/Zmhu/2Jlbv9nanT/Zmhu/2Zpc/9maG7/bnB3/2dqdP9kZ3H/Z2p0/2Rncf9nanT/ -ZGdx/11gav9gY2z/am13/2ptd/9maG7/am13/2dqcf9ucXv/bnF7/2ptd/9zdXz/am13/2ptd/9qbXf/ -Z2px/3N1fP9ucHf/eHl9/3Bzff9wc33/d3l//2xudf9ucHf/c3Z//3l7gf91eIH/eXuB/3l8hv91eIH/ -dXiB/3V4gf9wc33/dXiB/25xe/9ucHf/bnF7/3l8hv9zdn//cHJ5/3Bzff9ucXv/cHN9/3V4gf9+gIb/ -bG95/3V4gf9zdXz/dXiB/3d6g/9qbXf/cHJ5/2xvef9wcnn/bG95/2xvef9sb3n/c3V8/3N1fP9ucHf/ -c3V8/3N1fP9wc33/dXd9/3d5f/9sb3n/cHJ5/3N1fP9qbXf/bG95/3V3ff91d33/dnh8/3V3ff9ucXv/ -bnB3/2xvef91eIH/c3V8/2xvef9wc33/am13/3Byef93eoP/cHN9/2dqdP9wc33/cHN9/3V3ff94eX3/ -dXd9/2xudf9vcXX/bnB3/2dqcf9wcnn/bG51/3V3ff9wcnn/bG51/2ptd/9nanT/bG51/25xe/9qbXf/ -Z2px/2Rncf9ucXv/Zmlz/2Jlbv9kZ3H/Z2px/2Zpc/9qbXf/Z2p0/11gav9nanT/amxz/25xe/9qbXf/ -a211/2lrdP9oa3X/aWtz/2xvef9sb3n/cHN9/2psc/9wcnn/bnB3/2xuc/9sb3n/amx1/2hrdP9oam// -ZGdx/2Zobv9nanT/Zmlz/2Zpc/9nanH/ZGdx/2dqcf9ucXv/am13/2ptd/9sb3n/bG95/2Zpc/9qbXf/ -bnB3/3V3ff9wcnn/bnB3/25xe/9zdn//c3V8/25wd/9wc33/bnF7/25wd/91d33/bnB3/25wd/9ucHf/ -bnB3/2ptd/9maG7/c3V8/3N1fP9wcnn/bG51/21vc/9ucHT/bnB3/3Byef9wcnr/bG95/2xvef9ucHf/ -cnR7/2xudv9rbXb/aWx2/25xe/9zdXz/dXd9/25wd/91d33/c3V8/2xvef9qbXf/d3l//2xvef9qbHP/ -bG51/25xe/91eIH/bnF7/25wd/9kZ3H/dXd9/2ptd/9ucXv/am13/2xvef9sb3n/bG51/2xvef91d33/ -am13/2ptd/9sbnX/dXd9/25wd/91d33/bG51/3Z4fP9nanT/am13/25wd/9zdXz/bG51/29xdf9zdXz/ -b3F1/2psc/9ucHf/dXd9/3N1fP9ucXv/am13/2ptd/9qbXf/cHN9/2xudf9ucXv/bG51/25wd/92eHz/ -bG51/21vc/9zdXz/bG51/29xdf9qbXf/cHN9/25xe/9zdXz/bnB3/3h5ff9zdXz/bnB3/25wd/9vcXX/ -c3Z//25xe/9sb3n/bG95/3d5f/9zdn//cHN9/3d6g/9wcnn/dXiB/3V4gf9wcnn/e32D/3Bzff9zdn// -cHN9/2ptd/9ucXv/bG95/3d5f/9wc33/c3Z//3d6g/9sb3n/cHN9/3l7gf95e4H/cHN9/3V4gf91eIH/ -c3V8/25wd/9wc33/bG95/3V4gf9qbXf/cHJ5/25xe/93eoP/cHN9/29xdf9zdXz/bnB3/21vc/9qbXf/ -cHN9/2Rncf9ucXv/Z2p0/25wd/91d33/amxz/21vc/9tb3P/am13/25wd/9ucXv/bG95/3d5f/91eIH/ -dXiB/3V4gf9zdn//dXiB/3V4gf95e4H/c3Z//3d6g/97fYP/dXiB/3d6g/97fof/e36H/3d6g/93eoP/ -cHN9/25xe/9sb3n/dXd9/2xvef9ucXv/cHN9/2xudf9sb3n/bnF7/2dqdP9gY2z/Z2p0/2ptd/9wcnn/ -cHN9/2ptd/9nanT/bG51/2xvef9kZ3H/bnF7/2ptd/93eX//bnB3/21vc/9qbXf/am13/2xvef93eX// -cHN9/2ptd/9maXP/dXd9/3Bzff9qbXf/bnF7/2xvef9wcnn/c3V8/3V3ff9maG7/amxz/2ptd/9wc33/ -bnF7/25wd/9ucHb/bW93/3J0e/9zdn//cHN9/3V4gf9sb3n/dXiB/25xe/9sb3n/b3J8/21wev9tcHr/ -b3J7/2xvef9sbnX/bnF7/2dqdP9sbnX/amxz/2ptd/9sbnX/cHJ5/2xudf9sbnX/cHJ5/2xvef9kZ3H/ -bG51/25wd/91d33/cHJ5/29xdf9ucXv/dXiB/3N2f/9ucHf/cHN9/3Bzff9wcnn/c3Z//25xe/9qbXf/ -bnF7/2xvef9ucHf/ZGdx/25xe/9ucXv/bG95/2dqdP9qbXf/bW92/2tudv9sb3n/bG95/2dqdP9maXP/ -Zmlz/2xudf9laHH/Y2Zw/2Zpc/9ydHv/bnF7/2ptd/9sbnX/cHN9/25xe/9qbXf/am13/3Byef9qbXf/ -Z2p0/2xudf9zdXz/d3l//3V3ff9ucHf/amxz/3l7gf9wc33/cHN9/25wd/9ucHf/cHN9/3Byef91eIH/ -eXuB/3Byef9wc33/bnB3/3d6g/9wc33/dXiB/3N1fP95fIb/dXd9/3N1fP9zdn//c3Z//3Bzff9zdn// -d3qD/3Bzff9sb3n/c3Z//3l8hv97fYP/dXiB/3N2f/9zdn//c3V8/3t9g/9zdn//dXiB/25wd/9wcnn/ -c3Z//25wd/9ucHf/dXd9/2psc/9ucHf/Z2p0/3Bzff9ucXv/cHN9/2xvef93eX//c3Z//3Bzff9wc33/ -bnB3/3N2f/9wc33/cHJ5/2xvef95e4H/cHN9/3Byef93eX//cHJ5/3V4gf9zdn//bG95/3d5f/9zdXz/ -cHN9/2xvef9sb3n/bnB3/3Byef93eX//c3V8/25xe/95e4H/bG95/2xvef95e4H/dnh8/25wd/93eX// -d3l//25xe/9sb3n/cHN9/25wd/9zdn//bG95/25wd/9ucXv/eXyG/3N1fP9tb3P/c3V8/25wd/9vcXX/ -bG51/3Byef9maG7/cHJ5/25wd/9wc33/dXd9/2xudf9ucHf/bnB3/2xudf9ucHf/cHJ5/3Byef92eHz/ -cHJ5/3N1fP9wc33/bnF7/2xvef9sb3n/bnF7/2ptd/9ucXv/cHN9/25wd/9ucHf/dXd9/3d5f/9zdn// -dXd9/25xe/9sb3n/bG95/3V3ff9ucHf/bnB3/3N1fP9sbnX/bnB3/3Z4fP9ucHf/Z2px/2xvef91eIH/ -d3qD/3d6g/91eIH/am13/2xvef9ucXv/bnB3/3Byef9sbnX/dXd9/2xvef9sbnX/bG51/2xudf9qbXf/ -dXd9/25xe/9nanT/Z2p0/3Bzff9zdXz/amxz/2xvef9qbXf/am13/25xe/9wc33/YmVu/2dqdP9sbnX/ -bnF7/2xvef9pbHb/a254/2xuc/9rbnX/cHJ5/25wd/91d33/am13/3Bzff9wcnn/cHJ5/29xef9ucHn/ -bnF5/29ye/9sb3n/amxz/25xe/9ucXv/am13/2dqdP9tb3P/bG51/25xe/9tb3P/bnB3/3Bzff9wcnn/ -Zmhu/25wd/9wcnn/c3Z//3N2f/9sb3n/bG95/3Bzff9zdn//bnB3/3Bzff9zdXz/bnB3/3V4gf9wc33/ -am13/3Bzff9ucHf/bnB3/2Zpc/91eIH/d3qD/3Bzff9sb3n/cHJ5/2xvef9rbnj/cHJ3/2xudv9qbXf/ -Zmlz/2xudf9qbXf/aGp0/2dqdP9tb3X/dXd8/3V3ff9wcnn/bW9z/3d5f/9zdXz/bnF7/25wd/91d33/ -c3V8/2xudf9vcXX/d3l//3l7gf92eHz/bnB3/2dqdP93eX//cHN9/25xe/9wcnn/cHJ5/3N2f/9wcnn/ -d3qD/3l8hv9zdXz/cHN9/2xvef93eX//cHJ5/3N1fP9ucHf/dXd9/2xudf9tb3P/b3F1/25wd/9maG7/ -bG51/3Byef9qbHP/YmVu/25wd/93eX//dXd9/25wd/9sbnX/cHJ5/29xdf91d33/b3F1/3Byef9ucHf/ -b3F1/3N2f/9ucHf/bnB3/3V4gf9qbXf/c3Z//3Bzff95e4H/eXuB/3d6g/9zdn//foCG/31+gf97fYP/ -d3l//3h5ff97fYP/d3qD/3N2f/9wc33/e32D/3d6g/9wc33/e32D/3N2f/95fIb/d3qD/25xe/95e4H/ -dXiB/3V4gf9ucXv/bG95/25wd/9wcnn/d3qD/25xe/9wcnn/dnh8/2xudf9sbnX/dXd9/3N1fP9wcnn/ -eHl9/3Z4fP9ucHf/am13/2xvef9nanT/bG95/2dqdP9sbnX/bG51/3N2f/9wc33/amxz/2ptd/9nanT/ -am13/2xvef9sb3n/ZGdx/3Bzff9ucHf/c3V8/3N1fP9nanH/bG51/2ptd/9qbXf/am13/3N1fP9ucHf/ -dXd9/3N1fP91d33/c3V8/25wd/9wcnn/bG95/2ptd/9nanT/bnF7/3Z4fP9sbnX/bnB3/3V3ff93eX// -c3V8/25xe/9qbXf/am13/2xudf9zdXz/am13/2xvef9ucXv/Zmlz/2xudf9zdXz/bnB3/2Vmav9ucHf/ -c3V8/3l7gf9wc33/c3Z//2dqdP9wcnn/bG51/2psc/9zdXz/bG51/3V3ff9wcnn/bW9z/2ptd/9sbnX/ -cHN9/3V3ff9ucXv/am13/29xdf92eHz/c3Z//29xdf9wcnn/cHN9/25xe/9wc33/dXd9/2dqcf9qbXf/ -bnB3/3Bzff90d4D/cnR7/29yfP9sb3n/bnF7/3N2f/9zdn//eXuB/3N1fP91eIH/dXiB/3V4gP9ucXv/ -b3J8/3BzfP9vcnv/bnF7/25wd/9zdn//bG95/29xdf9sb3n/b3F1/25wd/9zdn//bnB3/25wd/9wc33/ -cHN9/2Zpc/9wcnn/c3V8/3V4gf91eIH/bnB3/2xvef9zdn//dXd9/2xvef9zdn//dXiB/25xe/93eX// -bnF7/2ptd/9wc33/bnB3/25wd/9qbXf/d3l//3V4gf9zdn//bG95/3Byef9tb3b/bW94/29ye/9wcnn/ -bnB3/2xvef9sb3n/c3V8/2xvef9qbXf/b3F5/3V3ff94eX3/c3V8/25wd/94eX3/d3l//3V3ff9ucHf/ -d3l//3V3ff9tb3P/bW9z/3V3ff95e4H/cHJ5/2ptd/9maXP/c3V8/2dqdP9nanT/Z2p0/2dqdP9qbXf/ -Zmlz/2xvef91d33/Z2p0/2xudf9nanT/dXd9/2ptd/9ucXv/am13/3d5f/9ucHf/bnB3/3Byef9ucXv/ -ZGdx/2xvef9wc33/bnB3/2psc/9wcnn/e32D/3V3ff9ucHf/bG95/25wd/9ucHf/eXuB/25wd/9ucXv/ -bG95/2xvef93eX//bnB3/25xe/91eIH/bG95/3Byef9sbnX/dXd9/3Byef9ucHf/bG51/3Z4fP9zdXz/ -am13/2xudf9sbnX/bnB3/25xe/9qbHP/Zmlz/3V3ff9ucXv/bG51/3V3ff9tb3P/am13/2ptd/9kZ3H/ -dXd9/2xvef9ucHf/am13/2ptd/9qbXf/bG51/3V4gf9sb3n/bnB3/3V3ff9sbnX/bG95/3V3ff9zdn// -bnF7/3d5f/95e4H/cHN9/3Bzff91eIH/bnB3/3Bzff9ucHf/bnF7/29xdf95e4H/c3Z//2xvef9wcnn/ -bG51/2xvef9ucXv/bnF7/2Zpc/9zdn//bnB3/3N1fP9zdXz/Zmhu/29xdf9ucHf/cHJ5/29xdf94eX3/ -c3V8/3N1fP9ucXv/bnF7/3Bzff9sb3n/bnF7/2xvef9sb3n/Z2px/25xe/9zdXz/amxz/2ptd/9ucXv/ -dXd9/2xvef9qbXf/Z2px/2psc/9kZ3H/am13/2psc/9qbXf/bG95/2Rncf9sbnX/cHJ5/2xudf9lZmr/ -bnB3/3V3ff93eoP/cHN9/3d5f/9qbXf/cHJ5/29xdf9qbHP/dXd9/2psc/93eX//cHN9/2xvef9sb3n/ -bG95/3V4gf93eoP/cHJ5/25wd/9tb3P/dXd9/3V3ff9qbHP/bG95/2xvef9wcnn/am13/25xe/9maG7/ -bG95/2xvef9zdn//b3J8/3Fzev9vcnr/a253/2xudf9ucXv/am13/3N1fP9sbnX/cHN9/25xe/9qbXf/ -bnF6/25xef9tcHr/bXB6/2ptd/9qbXf/bG95/2psc/9qbHP/Z2p0/2dqcf9sbnX/bnF7/2psc/9maXP/ -bG95/2xvef9gY2z/Z2p0/21vc/9ucHf/bnB3/2psc/9sbnX/bG95/3N1fP9qbXf/bnF7/3Z4fP9wcnn/ -d3l//3Bzff9qbXf/c3V8/2xudf9sbnX/amxz/3V3ff9zdXz/c3V8/2psc/9ucHf/b3F4/25wd/9xc3n/ -bnB3/2ptd/9sbnX/bnB3/2xvef9qbXf/aWx2/29xeP91d33/dnh8/3N1fP9sbnX/dnh8/3d5f/9zdXz/ -bnB3/3V3ff9zdXz/bW9z/2xudf92eHz/d3l//3Bzff9sb3n/Z2p0/3Bzff9ucXv/bG95/2ptd/9qbXf/ -am13/21vc/91d33/eHl9/29xdf9ucHf/bG51/3Z4fP9sbnX/dXd9/2xudf93eX//bnB3/21vc/9tb3P/ -c3V8/2Rncf9wcnn/dXiB/3Bzff9ucXv/dXiB/4GDiv91eIH/bnF7/25wd/9ucHf/bG95/3Z4fP9ucHf/ -bG95/25wd/9qbXf/d3l//25wd/9sb3n/c3Z//25wd/9wc33/Zmlz/3N2f/9zdn//bnF7/2xvef93eX// -dXd9/3Bzff9ucHf/am13/3Bzff9wc33/bnB3/2ptd/92eHz/cHN9/29xdf91d33/bnF7/25xe/9wcnn/ -Z2p0/3d6g/9zdn//c3Z//3Bzff9ucXv/cHJ5/3Byef91eIH/bnF7/2xvef91d33/bnB3/3N2f/95e4H/ -bnB3/2xvef91d33/cHN9/2ptd/9nanT/bG95/2Zpc/9nanT/Zmhu/2dqcf9kZ3H/c3V8/25xe/9maXP/ -am13/2Zpc/9qbHP/am13/2ptd/9kZ3H/cHN9/2dqdP9wcnn/bG95/2BjbP9qbHP/amxz/2ptd/9sbnX/ -cHN9/25xe/9wc33/bnF7/25xe/9ucXv/am13/3N1fP9zdXz/c3V8/2xudf9zdXz/dnh8/3Byef9ucHf/ -dXd9/3N1fP9ucXv/cHJ5/2ptd/9ucXv/am13/3Bzff9sb3n/bG95/25wd/9ucHf/bG95/3Bzff9ucXv/ -Z2p0/3Bzff9wc33/eXuB/3V3ff92eHz/Z2px/2xvef9wcnn/Z2p0/3N2f/9nanT/d3l//3Bzff9tb3P/ -bnB3/29xdf9zdn//d3l//3Bzff9sb3n/bG95/3V4gf94eX3/bnB3/3N1fP9zdXz/cHJ5/2xvef9zdn// -amxz/2psc/9nanT/bnF7/2hqdP9ucHb/bXB4/2xvdv9ucHf/dXd9/29xdf92eHz/b3F1/3Z4fP9zdXz/ -bnB3/3Byef9wcnn/cXN6/3N1fP9wcnn/cHJ5/3Z4fP9ucXv/bG95/2xvef9sb3n/bG95/3V4gf9zdXz/ -cHJ5/3V4gf9wc33/am13/25xe/9ucHf/bG95/25wd/9vcXX/bG51/3N1fP91d33/bG51/3Bzff9zdXz/ -bnB3/3N1fP9sbnX/Z2px/2xvef9vcXX/bnB3/2Rncf9zdXz/bG95/2xvef9maXP/bG95/2hrdf9wcnn/ -cHJ7/3J0fP9ucHf/Z2p0/25xe/9zdXz/b3J7/2ptdf9sb3n/c3V8/3V3ff9sb3n/bG51/3V3ff91eIH/ -bnF7/3Byef92eHz/dXd9/2xudf9sbnX/dnh8/3d6g/91d33/cHN9/2ptd/91eIH/d3qD/3d6g/9ucHf/ -bG95/25wd/9ucHf/dXiB/3l7gf9wc33/c3V8/3N2f/9+gYr/eXuB/35/g/92eHz/f4GH/3V3ff91eIH/ -dXd9/35/g/9wcnn/eHl9/31+gf93eX//eHl9/3d5f/+Fh43/fn+D/3l7gf92eHz/dXd9/3Bzff9+gYr/ -c3Z//3Bzff9sb3n/cHN9/3l7gf9wcnn/c3V8/3V4gf9zdXz/dXiB/2dqdP9zdn//c3Z//3Bzff9sb3n/ -dXd9/3Z4fP9wc33/bG51/2Zpc/9wc33/cHJ5/29xdf9ucHf/dXd9/3Byef9ucHf/eHl9/2xvef9ucHf/ -cHJ5/25wd/93eX//dXd9/3Byef9ucHf/bnB3/2xudf9vcXX/dXd9/2xudf9sbnX/c3V8/2ptd/9wcnn/ -eHl9/3Bzff91eIH/dXiB/3V3ff9wcnn/bnB3/3V3ff9qbHP/cHN9/3Byef9ucXv/bG95/3V4gf93eX// -Z2p0/25xe/9sb3n/bnB3/3N1fP9ucHf/bG51/3Bzff9nanT/am13/25xe/9maXP/am13/2xudf9sbnX/ -bG51/3V3ff9ucHf/cHJ5/3N1fP9ucXv/c3V8/25wd/9ucHf/cHJ5/3N1fP9vcXX/dXd9/3h5ff9wcnn/ -cHJ5/3V3ff9zdXz/cHJ5/25wd/9qbHP/bnF7/2xudf9sb3n/bG95/2dqdP9nanT/Zmhu/2Rncf9nanT/ -Z2px/1xfaP9maG7/ZGdx/3Byef9maXP/bnB3/1lcZf9iZW7/Zmhu/2Jlbv9nanT/XWBq/2xvef9nanT/ -amxz/2xudf9qbHP/bnF7/3d5f/9qbXf/Zmlz/2xudf91eIH/d3l//2xudf9zdXz/cHJ5/3N1fP9sb3n/ -dXd9/2Zpc/9maG7/Z2px/2ptd/9oanT/bnB5/29xeP9ucHj/bG51/3Z4fP9vcXX/dnh8/29xdf91d33/ -bnF7/3Bzff91eIH/dHZ+/3N1ff9zdn3/bnF7/25xe/91d33/cHJ5/25wd/9ucHf/bnB3/25wd/9wc33/ -b3F1/29xdf9ucHf/bG51/2Zobv9tb3P/bW9z/2xudf9sbnX/am13/2psc/9wc33/c3V8/2xudf9wc33/ -cHN9/25xe/9wc33/bW9z/2xudf9zdXz/b3F1/25wd/9maG7/dnh8/3Byef9zdXz/Z2px/3Byef9ucHj/ -cHJ6/25xef9tb3b/bG51/2RmbP9sbnX/bnF4/25wd/9sb3j/dHZ+/3V4gf95e4H/bnF7/3Byef91eIH/ -dnh8/3Byef9ucXv/c3V8/3N1fP9ucHf/b3F1/3d5f/97fYP/dXd9/3Bzff9sb3n/d3l//3Z4fP9zdXz/ -amxz/2xudf9qbXf/am13/2xvef9zdXz/amxz/2psc/9kZ3H/c3V8/2Zpc/9qbXf/ZGdx/3Byef9iZW7/ -ZGZs/2Rncf9maXP/XV9l/2Rncf9nanT/ZGZs/2BjbP9iZW7/cHN9/2ptd/9maG7/YmVu/2Jlbv9iZW7/ -cHJ5/2dqcf9kZ3H/YGNs/2Rncf9kZ3H/YmVu/2dqcf9qbXf/bG51/2ptd/9iZW7/bnF7/25xe/9qbXf/ -bG51/3N1fP91d33/c3V8/25wd/9qbHP/cHN9/3Bzff9wcnn/cHJ5/3d6g/91eIH/cHJ5/3t9g/9wc33/ -c3Z//3N2f/9wcnn/eXyG/3l7gf9ucXv/cHJ5/2xvef9wcnn/bnB3/3d6g/9ucXv/cHJ5/3t9g/9wc33/ -d3qD/3d6g/9wc33/d3qD/3t9g/9zdn//cHN9/3Byef91d33/Z2p0/2xvef9ucHf/c3Z//25xe/93eoP/ -eXuB/2xvef9zdn//cHJ5/25xe/9wc33/b3F1/2xudf9zdXz/am13/25wd/9wcnn/Zmlz/2ptd/9sbnX/ -bG95/2ptd/9zdXz/bW9z/25xe/9zdXz/c3V8/3Bzff9sbnX/bnB3/3Bzff9sb3n/bG51/3V3ff93eX// -bnB3/3Byef9wcnn/cHJ5/3Byef91d33/bG51/3Byef9tb3P/bnF7/25xe/9sb3n/am13/2xudf9nanT/ -am13/2dqdP9iZW7/am13/25xe/9zdn//bG95/3V3ff9kZmz/bW9z/21vc/9ucHf/dXd9/2dqdP95e4H/ -cHN9/2xvef9sb3n/bnF7/3Bzff93eX//bnF7/2xvef9ucXv/e36H/3d6g/9ucHf/dXd9/3Byef9wcnn/ -bnB3/3N1fP9qbHP/bG51/2xudf91d33/bW93/29xeP9tcHj/aGt1/2Vocf9ucXv/amxz/3d5f/9sbnX/ -bnF7/3Byef9wcnn/cXN6/3F0ev9wc33/c3Z//3Byef9wc33/eXuB/3Bzff9wc33/bnF7/3Bzff9ucXv/ -cHN9/25wd/9ucHf/cHJ5/21vc/9nanH/b3F1/25wd/9ucHf/bG51/2ptd/9sbnX/dXd9/3N1fP9qbXf/ -cHN9/3Byef9wcnn/c3Z//2xudf9sbnX/c3Z//2ptd/9ucHf/ZGdx/3N2f/9zdn//c3Z//2ptd/9zdn// -cXN7/3N2gP91eIH/cnV//3N1fP9qbXf/cHJ5/29xeP9ucHj/bW94/3J0e/90d3//eXyG/3Bzff9ucXv/ -d3l//3d5f/9ucXv/c3V8/25xe/9wcnn/bnB3/25wd/91d33/e36H/3Z4fP9wcnn/bnB3/3V4gf91d33/ -dnh8/25wd/9wcnn/c3V8/3Byef9zdn//e32D/2xvef9sb3n/Z2p0/3d6g/9zdn//dXiB/25wd/93eX// -Z2p0/2xvef9ucHf/c3V8/2ZobP9sbnX/c3V8/2psc/9nanT/amxz/3l7gf9ucXv/Zmlz/2Zobv9sbnX/ -ZGdx/3Bzff9maG7/amxz/2Zpc/9qbHP/bnB3/2xudf9ucHf/cHJ5/2xvef9wc33/Z2p0/3Bzff9wc33/ -dXiB/3N2f/93eoP/d3qD/3l7gf91d33/c3Z//3V4gf95fIb/cHN9/3N1fP95fIb/d3qD/3V3ff95fIb/ -cHN9/3V4gf9wc33/bnB3/3d5f/91d33/bnB3/2xudf9sbnX/bW9z/25wd/94eX3/bG95/2xvef93eX// -bnB3/3N1fP9zdn//bnF7/3d6g/93eX//cHN9/3Bzff9zdn//dXd9/2psc/9ucHf/bW9z/2xvef9qbXf/ -c3V8/3V3ff9kZ3H/bG51/2dqcf9maG7/Z2p0/2Rncf9kZ3H/bG95/2dqcf9qbHP/Z2p0/2Rncf9qbHP/ -Z2px/2psc/9qbHP/cHN9/2ptd/9zdXz/c3V8/3N1fP91d33/cHN9/3Bzff91eIH/bnF7/25wd/9zdn// -d3qD/3Bzff9zdn//c3Z//3N2f/91eIH/dXiB/3Byef93eoP/cHN9/3d6g/95fIb/d3qD/3d6g/9wc33/ -c3Z//3V4gf9wc33/am13/3N1fP93eoP/e32D/3l7gf95fIb/am13/3N2f/9zdXz/c3V8/3l7gf9sb3n/ -eXuB/3V4gf9ucHf/bnB3/25xe/9zdXz/d3l//25xe/9nanT/bnF7/3d6g/93eoP/bnF7/3Bzff91d33/ -cHN9/25xe/93eX//Zmlz/2xvef9zdXz/e32D/3Bzff9zdXv/dHZ//3F0fv9sb3n/d3qD/3N1fP93eoP/ -cHJ5/3N2f/9zdn//c3Z//3Bzff9zdX3/dHeA/3V4gf9zdn//cHN9/3d6g/9wc33/bnB3/2dqdP9ucHf/ -cHJ5/3Byef9ucHf/b3F1/3Bzff9vcXX/Z2px/2xudf9sbnX/amxz/2ptd/9nanT/Z2p0/25xe/9sb3n/ -amxz/2ptd/9ucXv/am13/3N1fP9qbXf/Z2p0/25xe/9nanT/bG51/2RmbP9wcnn/bnF7/2xvef9kZ3H/ -bG95/2lsc/9ucXr/b3F5/2xvef9ucHf/Z2p0/2xvef9ucHf/bG52/2dqdP9tcHf/bG94/3Byef9nanH/ -Zmlz/3Byef94eX3/bnB3/3N1fP9wcnn/c3V8/2xudf9ucHf/c3V8/3l7gf9zdXz/bG95/21vc/92eHz/ -c3V8/3Bzff9sbnX/bG51/21vc/9sbnX/bnB3/3V3ff9tb3P/bG51/2dqdP91eIH/c3V8/3Byef9tb3P/ -eHl9/2ptd/9sb3n/bnF7/3Bzff9kZ3H/am13/3V3ff9ucHf/bG51/25wd/9+gIb/cHN9/3Byef9tb3P/ -bG51/2psc/97fYP/bG51/2ptd/9qbXf/b3F1/3N1fP9ucHf/bG51/3N1fP9ucHf/cHN9/2Zpc/9qbXf/ -am13/2ptd/9qbHP/cHN9/2xvef9wc33/bG51/2Rncf9qbHP/am13/2ptd/9sbnX/c3V8/2ptd/9nanT/ -d3l//2xudf9sb3n/bG51/2xudf94eX3/dXd9/3Byef9vcXX/bG95/25wd/9sb3n/eXuB/3Bzff9wcnn/ -eXuB/3Byef9zdn//eXuB/3Bzff9ucXv/dXd9/3V3ff9wc33/c3Z//3N2f/9sb3n/cHJ5/3Byef9wc33/ -cHJ5/3d5f/97fYP/cHJ5/25xe/9ucHf/b3F1/3Byef9sbnX/am13/3N1fP9tb3P/am13/25xe/9kZ3H/ -am13/2ptd/9ucXv/bG51/3N1fP9ucHf/c3V8/3N1fP9ucHf/dXd9/25xe/9qbXf/cHN9/2xudf9sbnX/ -c3V8/3V3ff9ucHf/dXd9/3Byef9wcnn/cHJ5/3Byef9tb3P/cHN9/2ptd/9sb3n/am13/25xe/9sb3n/ -am13/2dqdP9qbXf/am13/2BjbP9qbHP/cHN9/3V3ff91d33/dnh8/2Vmav9ucHf/bnB3/2xvef91eIH/ -Z2p0/3N2f/9zdn//bnF7/2xvef9ucXv/c3Z//3d6g/9ucXv/am13/25xe/95e4H/eXuB/21vc/9zdXz/ -c3V8/2xudf9sbnX/c3V8/2Zobv9qbXf/bG51/3V3ff9rbXX/bG52/25vdf9sb3j/Zmlz/3Bzff9sbnX/ -d3l//21vc/9sbnX/c3V8/3V3ff9vcnv/bnB3/29xef9zdn//bnF7/3N1fP91eIH/bnF7/25xe/9ucHf/ -cHN9/3N2f/9zdn//cHJ5/3N1fP91eIH/cHJ5/2Zpc/9ucXv/bnB3/29xdf9ucHf/bG95/3Bzff91eIH/ -cHN9/25xe/9ucXv/c3Z//29xdf92eHz/bW9z/2psc/9wcnn/amxz/25wd/9nanH/c3Z//3Bzff9ucXv/ -Z2px/3N1fP9ucHf/cHJ7/3R2f/9xdH7/cHJ5/2dqdP9sb3n/cHJ5/29xeP9tb3j/cnR6/3R2ff93eX// -bnB3/3Byef93eX//dnh8/2ptd/9wcnn/cHJ5/3Byef9qbHP/cHJ5/3h5ff93eX//dXd9/25xe/9vcXX/ -eHl9/3d5f/91eIH/c3V8/3N1fP9wc33/cHJ5/2xvef9zdn//bG95/2xvef9sb3n/d3qD/25xe/9wc33/ -bG95/3d5f/9sbnX/b3F1/25wd/9ucHf/ZGZs/2Zpc/9wc33/amxz/2dqdP9sbnX/d3l//2dqdP9sb3n/ -Z2px/2Zobv9gY2z/eXuB/2Zpc/9sbnX/amxz/2xudf9zdXz/bW9z/2xvef91d33/bG95/3V4gf9sb3n/ -c3Z//3d6g/91eIH/cHN9/3l7gf93eoP/foCG/3N2f/9ucXv/c3V8/3N2f/91eIH/dXd9/36Ahv9zdn// -c3V8/36Biv9zdXz/cHN9/29xdf9vcXX/dnh8/3V3ff9wcnn/bW9z/25wd/9ucHf/am13/3d5f/9ucXv/ -am13/3h5ff9sb3n/c3Z//3t+h/9sbnX/bG95/3N1fP9ucXv/cHN9/25xe/9ucXv/Z2p0/2ptd/9sbnX/ -cHJ5/25wd/9zdn//dXd9/2xvef9vcXX/bW9z/2xudf9ucXv/am13/21vc/91d33/bnB3/25wd/91d33/ -Z2px/25wd/9wcnn/c3Z//25wd/95e4H/d3qD/3d6g/93eX//cHN9/3Z4fP9wcnn/bnB3/3N1fP9sbnX/ -bnB3/3V3ff93eX//cHJ5/3N1fP9wcnn/c3V8/3Byef91d33/bW9z/3V3ff9ucHf/cHJ5/3N1fP9ucXv/ -am13/2xudf9qbXf/bG95/2xudf9iZW7/am13/3N1fP9zdXz/c3V8/3d5f/9lZmr/bW9z/2xudf9ucHf/ -c3Z//2dqdP9wc33/c3Z//3Byef9sbnX/cHJ5/3N1fP93eoP/bG51/2psc/9ucHf/d3l//3d5f/9ucHf/ -dXd9/3V3ff9ucHf/bnF7/3d5f/9qbXf/cHJ5/29xdf91eIH/bnF7/3Fze/9ydHz/bnF7/2ptd/91d33/ -bnB3/3V3ff9vcXX/bnF7/3N2f/93eoP/cnV8/25wd/9tb3j/dnh8/25wd/9vcXX/bnB3/2xvef9qbXf/ -Zmlz/25xe/9qbXf/am13/2dqcf9kZ3H/Z2p0/2Zobv9gY2z/Z2p0/2Zpc/9maXP/amxz/2Rncf9qbXf/ -am13/2dqdP9sb3n/am13/3Bzff9sbnX/dnh8/29xdf9qbHP/cHN9/3Byef9zdn//Zmlz/3Bzff9wc33/ -cHN9/2ptd/9zdn//bnB3/3FzfP9wcnr/a211/25wd/9sbnX/bG95/25weP9xc3r/cHN7/3J1fv94eoP/ -fYCJ/3N2f/93eoP/eXyG/3d6g/9zdXz/dXiB/3d6g/9wc33/am13/25wd/93eoP/eXuB/3d5f/9zdn// -bnF7/3t9g/95e4H/c3Z//3Byef9wcnn/cHN9/2xvef9ucHf/dXd9/3Byef9qbHP/b3F1/3d6g/9wc33/ -c3Z//2xvef91d33/am13/25wd/9sb3n/bnF7/2dqcf9sbnX/dnh8/29xdf9qbXf/bG51/3t9g/9qbXf/ -bnF7/2xudf9sbnX/Z2px/3t9g/9qbHP/bnB3/2xudf9tb3P/bnF7/25wd/9ucHf/dXd9/3Byef91d33/ -amxz/25wd/91d33/dXd9/25wd/9zdXz/bG51/3N1fP9sbnX/ZGZs/2dqdP9qbXf/am13/2dqdP9sb3n/ -amxz/2Rncf9zdXz/Zmlz/2dqdP9kZ3H/ZGZs/2ptd/9sb3n/Z2p0/2Jlbv9kZmz/XWBq/2BjbP9qbXf/ -Zmlz/2Jlbv9sb3n/am13/2xvef9zdXz/Z2p0/2xudf9ucXv/bnF7/3Byef9zdXz/c3V8/2psc/9ucHf/ -bG95/2xvef9tb3P/c3V8/3h5ff9sbnX/bnB3/25wd/9wc33/cHN9/2xvef9ucHf/dXd9/3Bzff9ucHf/ -cHN9/2dqdP9sb3n/c3Z//3Z4fP9qbXf/c3V8/2ptd/9sbnX/cHN9/2xvef9zdXz/bnF7/2xudf9sb3n/ -amxz/2psc/9sb3n/bG95/2Zpc/9qbXf/Z2p0/25xe/9qbXf/am13/2xudf9wc33/bG51/2xvef9sb3n/ -bnF7/3Byef9ucHf/bnB3/3N1fP9tb3P/Zmhu/29xdf91d33/dXd9/3d5f/93eoP/amxz/25wd/9ucXv/ -c3Z//3d5f/9sb3n/c3Z//3l7gf9zdXz/am13/3N2f/93eoP/eXyG/3Byef9sb3n/cHN9/3l8hv97fof/ -cHN9/3t9g/97fYP/dXd9/3Bzff97fYP/am13/25xe/9ucHf/eXuB/21wef90dnz/dXd//3R3gP9zdXz/ -eXuB/3Bzff95fIb/c3Z//3Bzff91eIH/eXuB/3Z5gv9ydHz/c3aA/3p9g/9zdn//cHN9/3Bzff9ucXv/ -c3Z//3Bzff93eoP/d3qD/3V4gf9zdXz/cHN9/3N2f/9sb3n/Zmlz/3Bzff9ucHf/c3V8/3N2f/9sb3n/ -bG95/3Byef9ucXv/cHN9/25wd/9wc33/bnB3/3h5ff9vcXX/amxz/25xe/9vcXX/c3V8/2Zpc/9wc33/ -c3V8/3Byef9sb3n/d3qD/3Byef9vcnv/cHJ6/29xef9ucHf/amxz/21vc/9sbnX/b3F1/25wd/9wcnr/ -cXR9/3V3ff9sb3n/c3V8/3h5ff93eoP/cHN9/25xe/9zdn//cHN9/2dqdP9wc33/e32D/3l8hv93eoP/ -c3Z//3Bzff93eX//dXd9/3Byef9ucHf/b3F1/3Bzff9ucXv/bnF7/3N2f/9ucHf/Z2p0/2ptd/93eX// -bnB3/25wd/9qbHP/dXd9/2xudf9vcXX/bnB3/2xvef9maXP/bG95/3Z4fP9vcXX/bG51/25xe/9/goz/ -dXiB/3N2f/9ucHf/b3F1/2psc/9+f4P/bG51/29xdf9ucHf/b3F1/3Byef9sbnX/bnB3/3V3ff9wc33/ -c3Z//2psc/9vcXX/dXd9/3N1fP9qbXf/bnF7/2xudf9wc33/amxz/2BjbP9kZ3H/amxz/2ptd/9maXP/ -cHN9/2xudf9maXP/d3l//2xudf91d33/bG51/2ptd/91d33/bnF7/2ptd/9nanH/Zmlz/2Rncf9kZ3H/ -cHN9/2xvef9nanT/dXd9/25xe/9ucXv/c3V8/25wd/9sb3n/dnh8/3Byef9ucXv/c3V8/3Bzff9maXP/ -bnB3/3Byef9wcnn/bnB3/3N2f/95e4H/cHN9/3Byef9wc33/dXiB/3N2f/9wc33/cHN9/3t9g/93eoP/ -dXiB/3t9g/9zdn//d3qD/3l8hv95fIb/cHN9/3l8hv9zdn//cHN9/3l7gf9ucXv/c3Z//3V3ff9vcXX/ -c3V8/25wd/9wcnn/dXd9/3Z4fP9zdXz/cHJ5/2xvef9ucXv/bnF7/2ptd/9qbHP/bnF7/2ptd/9qbHP/ -am13/3Bzff9wc33/am13/2xudf9ucXv/bG51/2Rncf9sbnX/c3V8/3V3ff9zdXz/c3V8/2BjbP9maXP/ -am13/2xudf9wc33/Zmlz/25xe/91d33/bG51/2Zpc/9sb3n/bnF7/3V3ff9maXP/YGNs/2dqcf9wcnn/ -cHJ5/2dqcf9ucXv/bG95/2psc/9maG7/am13/2BjbP9nanH/Z2px/3V3ff9qbHP/bnB3/29xd/9sbnX/ -amxz/2xvef9maXP/cHJ5/2psc/9nanH/bG95/3Bzff9ucXr/aGtz/2ptd/9zdXz/bW9z/2xudf9sb3n/ -bG95/2ptd/9maXP/bnF7/2ptd/9qbHP/ZGdx/2dqcf9qbXf/Z2p0/2Zpc/9qbXf/bG51/2xudf9tb3P/ -bG51/25wd/9sb3n/cHJ5/3N1fP9sb3n/d3l//3Bzff93eX//bG95/2ptd/9ucXv/cHJ5/3N2f/9qbXf/ -d3qD/3N2f/9zdn//bnB3/3N2f/9ucHf/bnB4/2ptdv9rbnf/bG51/2Rncf9sbnX/am13/2psc/9pbHT/ -bXB4/2xueP9wc33/bG51/3Byef94eX3/cHN9/3Bzff9sb3n/c3Z//25xe/9nanT/bnF7/3d5f/91eIH/ -c3Z//25xe/9zdn//eXuB/3Z4fP91d33/bG51/21vc/9ucHf/bG51/2xudf9zdXz/bG51/2Rncf9maXP/ -cHJ5/2dqcf9maXP/YmVu/25xe/9nanT/bG51/2xudf9qbXf/Zmhu/21vc/9zdXz/bW9z/2ptd/9sb3n/ -f4GH/25xe/9sb3n/bG51/2xudf9qbHP/fX6B/2psc/9sbnX/b3F1/29xdf9zdXz/bG95/2xvef9wc33/ -cHN9/3Bzff9qbHP/cHJ5/3V3ff9zdn//bnF7/3V3ff9ucHf/dXiB/3Byef9nanH/bnF7/3Bzff93eoP/ -bG95/3l7gf93eoP/d3l//3+Bh/9zdXz/d3qD/3Bzff9wc33/eXyG/3d6g/9ucXv/bnB3/2xvef9sbnX/ -am13/3V3ff9wc33/Z2p0/3h5ff9zdXz/c3V8/3d5f/9sb3n/bG95/3h5ff9ucHf/c3V8/3V3ff91d33/ -Z2px/25wd/9wc33/bG95/2xudf9sbnX/c3V8/2ptd/9maXP/amxz/2ptd/9ucXv/am13/2ptd/9zdXz/ -cHN9/2ptd/9ucXv/ZGdx/2ptd/9nanT/cHJ5/2Rncf9zdXz/am13/2ptd/9ucXv/am13/3Bzff9wc33/ -bG95/3V3ff9qbXf/bnB3/3N2f/91eIH/cHN9/3V3ff91d33/dXd9/3Bzff9wc33/cHN9/3Z4fP9wc33/ -cHN9/3N2f/93eoP/d3qD/25xe/9zdXz/dXiB/3Byef9sb3n/cHN9/3l7gf91eIH/dXd9/3d5f/9kZ3H/ -bnB3/2xudf9zdXz/eHl9/25wd/91d33/dnh8/2ptd/9maXP/c3V8/3N1fP93eX//bG51/2psc/9sbnX/ -dXiB/3V3ff9vcXX/c3Z//3N2f/9sb3n/bnB3/3N2f/9sb3n/bG95/21vc/95e4H/b3F2/3J0ev90dn7/ -dnmC/3V3ff95fIb/dXd9/3t+h/9wc33/c3V8/3V4gf93eoP/dnmB/3Fzev9vcXf/dXh+/29xdf9tb3P/ -bG51/25wd/9ucHf/bnB3/3N1fP9ucHf/bnB3/25wd/9vcXX/dXd9/29xdf9maG7/cHJ5/2ptd/9nanT/ -amxz/2Zpc/9sbnX/bG95/2xvef9qbXf/amxz/3Byef9maXP/bG95/2Zobv9dYGr/YmVu/2Zobv9maXP/ -XWBq/2ptd/9nanT/Zmhu/2Jlbv9nanT/Zmhy/2hqcf9oa3P/aWtz/2ptd/9qbHP/bG51/25wd/9rbXL/ -aGty/2ttc/9pbHX/Z2p0/2Vocv9maXP/bnF7/3Bzff9ucHf/bG51/3N1fP9sbnX/Zmlz/2xvef9zdXz/ -c3V8/3N1fP9qbHP/bnF7/3N1fP9wc33/bnF7/2Zpc/9nanH/Zmlz/2Rncf9sbnX/cHN9/2psc/9kZ3H/ -ZGdx/25wd/9iZW7/ZGdx/11gav9nanT/ZGdx/2Zobv9qbHP/Z2px/2Jlbv9nanT/cHN9/2dqdP9qbXf/ -bG95/36Biv9ucXv/bG95/21vc/9tb3P/b3F1/4CChv9ucHf/cHJ5/3Byef9zdXz/c3Z//3Byef9wc33/ -cHN9/3N2f/9wc33/am13/25wd/9wc33/dXd9/25wd/9ucHf/bG51/3Bzff9nanT/YmRq/2dqdP9qbXf/ -bG95/2Zpc/9ucXv/Z2p0/2Jlbv9ucHf/YmVu/2dqdP9nanH/Z2px/3Byef9zdXz/amxz/2dqcf9nanT/ -Zmlz/2dqdP9sb3n/am13/2Zpc/91d33/bG95/3Byef93eX//dXiB/3V4gf97fof/d3qD/3t9g/93eoP/ -c3Z//2Zpc/9zdXz/c3V8/3V4gf9sb3n/cHJ5/3d5f/9ucXv/bG51/25xe/9wc33/dXiB/3N1fP91d33/ -eXuB/3t9g/91eIH/foCG/3V3ff93eoP/dXiB/3V4gf9sb3n/d3qD/3N2f/9wcnn/dXiB/3V4gf95e4H/ -dXiB/3Bzff93eX//c3Z//3Byef9wc33/dXiB/3N2f/91d33/c3V8/3N1fP9wcnn/bnB3/3Byef92eHz/ -cHJ5/25wd/9ucHf/c3V8/3N1fP9sbnX/bW9z/3N2f/9wcnn/amxz/25xe/93eX//dXiB/3N2f/9zdn// -Z2p0/2ptd/9ucXv/cHN9/3V4gf9wcnn/c3Z//3d5f/9sb3n/Z2p0/3N2f/91d33/d3l//25wd/9sbnX/ -b3F1/3h5ff95e4H/b3F1/3N1fP91d33/bG95/2ptd/91d33/amxz/2ttdP9sbnX/c3Z//2ptd/9vcXj/ -cHJ3/25wd/9tb3P/cHJ5/2xudf93eX//am13/21vc/9zdXz/dXd9/3J0e/9sb3n/bXB6/3Bzff9sbnb/ -amxz/2ptd/9rbnj/bG51/2tud/9wcnn/bG95/25wd/9ucHf/cHJ5/3V3ff9ucHf/Zmlz/3R3gP9tcHf/ -bnB3/3Fzef9ucHf/cnR7/3Bzff9ydX7/cHJ8/3Bzff93eoP/cHN9/3h6gP9zdn7/bnF7/3Byef9vcXj/ -bnF7/2hrdf91d33/bW92/25wd/9vcXj/eHl9/29xef9wcnn/cHN8/3Z3fP95e4H/dXd9/3d5f/96fIP/ -cnV+/3F0e/91d37/dniA/3V3ff9wcnn/c3Z//3Z4f/93eoP/dXiB/3Bzff91eIH/bnF7/2ptd/91eIH/ -e32D/3d5f/93eX//c3V8/3d6g/9zdn//dnh8/3N1fP9ucHf/bnF7/25xe/9vcXX/bG95/3V3ff9vcXX/ -amxz/2xudf92eHz/bnB3/3Byef9nanT/cHN9/2ptd/9ucHf/c3Z//3Byef9qbHP/b3F1/3Z4fP9qbHP/ -bG51/25wd/9/gYf/cHJ5/2ptd/9tb3P/bnB3/2ptd/9/gYf/bnB3/29xdf9ucHf/bG95/3Byef9tb3P/ -am13/2ptd/9wc33/bnF7/2dqdP9sbnX/c3V8/3h5ff9wcnn/bnF7/2xvef9wcnn/am13/2Vmav9sbnX/ -bnF7/3Byef9sbnX/dnh8/3Bzff9ucHf/eXuB/3V3ff93eoP/cHN9/3N2f/97fof/e36H/3V4gf91d33/ -dXd9/25xe/9zdXz/dXiB/3V4gf9wc33/e32D/3d6g/95fIb/e36H/2xvef9ucXv/d3l//25xe/9zdn// -c3Z//3N2f/9maG7/bnB3/3N1fP9wcnn/b3F1/21vc/9zdXz/bG51/2dqcf9wcnn/bnF7/3N1fP9ucHf/ -bG95/3V3ff9zdXz/bG51/3Byef9ucHf/c3V8/25wd/91d33/am13/3V4gf9ucXv/amxz/2xvef9ucXv/ -cHN9/3Bzff9wcnn/c3V8/3Byef9wcnn/cHN9/3Bzff9zdn//c3Z//3Bzff9wcnn/dXd9/3Byef9ucHf/ -d3l//25wd/9wcnn/bnB3/3V3ff91d33/bnF7/3Byef91eIH/bnF7/2ptd/9sb3n/c3Z//3Z4fP9wcnn/ -c3V8/2Zobv9nanT/bnF7/2xvef91d33/bG51/2ptd/9zdXz/Z2p0/2Rncf9ucXv/c3V8/3N1fP9qbXf/ -am13/2psc/93eX//d3qD/2xudf9ucXv/bG95/2ptd/9qbXf/c3V8/2ptd/9xc3r/bnB3/3d5f/9ucHf/ -cHJ5/29xd/9ucXv/amxz/25wd/9ucHf/d3l//25wd/9vcXX/dXd9/3d5f/9wcnn/bG52/25xe/9xdHz/ -am13/2ttdf9qbXf/bG51/2xudf9rbnf/bXB6/2xudf9qbXf/bG51/3Byef90dnz/cHJ5/2hrc/9ydX7/ -aGt1/25wd/9wcnn/bnB4/25weP9ydHv/b3J7/29ye/9vcXj/dXiB/3F0ff9zdn//bG95/2xvef9ucHf/ -cXN3/3Byef9oa3P/cnR8/2xveP9qbXf/aWx1/3R2ff9pbHP/am13/2dqc/9pbHb/bG51/2Rncf9maG7/ -bG95/2psc/9maXP/bG94/29xef9sb3f/am12/2ttdv9ydHr/c3V8/3Bzff9vcXX/cHJ5/2xvef9qbXf/ -cHN9/3d5f/93eX//d3l//3Byef91eIH/c3Z//3d6g/93eoP/cHN9/3N2f/9wc33/bG95/29xdf91d33/ -b3F1/2psc/9sbnX/dnh8/25wd/9sbnX/bG51/25wd/9qbHP/bG51/2xvef9wcnn/amxz/2xudf92eHz/ -Z2px/25wd/9ucHf/f4GH/3Z4fP9zdXz/cHJ5/25wd/9qbXf/gYOK/2xvef9ucXv/bnB3/3V4gf9zdn// -c3Z//3N2f/91eIH/e32D/3t9g/92eHz/eXuB/31+gf9/gYf/eXuB/3V4gf9zdn//dXiB/3Bzff9qbXf/ -c3V8/3d6g/93eoP/c3Z//3t9g/93eoP/bnF7/3t9g/9ucXv/dXiB/25xe/9vcXX/eXuB/3d6g/9sb3n/ -bnB3/25wd/9nanH/bW9z/25wd/9sbnX/Z2px/3N2f/9ucXv/c3Z//3V3ff91d33/d3qD/36Ahv91eIH/ -eXuB/3d6g/93eoP/bG95/3t9g/97fYP/d3qD/3V3ff91d33/dXiB/3V4gf9ucXv/d3qD/3V4gf9zdn// -bnB3/3Byef95e4H/dXiB/3Byef9zdn//bnB3/3N1fP9zdXz/bnB3/21vc/95e4H/dnh8/21vc/9sb3n/ -bnF7/3Bzff9wc33/c3V8/25xe/9ucXv/bG95/2xvef9sb3n/cHN9/3Bzff9ucXv/cHN9/25xe/9qbHP/ -bG51/3N1fP9nanT/amxz/2psc/9ucXv/cHJ5/2Zobv9kZ3H/Zmlz/2Zpc/9dYGr/Zmlz/2dqdP9sb3n/ -ZGdx/2dqdP9cX2j/YGNs/2Zpc/9maXP/bG95/2Rncf9kZ3H/cHJ5/2Zobv9kZ3H/am13/2xvef9zdXz/ -bG95/2xudf9sbnX/d3l//3l8hv9sbnX/c3V8/3N1fP9zdXz/b3F1/3V3ff9sb3n/cnR6/3Fzev90dn7/ -bnF5/3J0e/9wcnf/cHJ5/2xudf9ucHf/bnB3/3d5f/9sbnX/b3F1/3V3ff91d33/cnR7/2xudv9sbnb/ -cXN7/2ttc/9qbHX/bG93/3Fzef9rbXb/bG53/29yev9tcHj/a254/2xvef9ucXn/c3V7/29yev9rbXb/ -cnV//25xef9wcnn/c3V8/3V3ff9ydHn/eXuA/3V3fv90dn3/c3V9/3h7hf91eID/dXd+/3N1fP90dnz/ -cHJ5/3R2fv9xdH3/b3J8/3J1fP9wc3v/a252/29xeP9ydX//bW94/2xveP9nanT/a253/2xudf9qbXf/ -bW9z/3Bzff9qbXf/aGt0/2xvef9zdn3/am11/21veP9sbnb/bW94/2xvef9qbXf/am13/3Bzff9sbnX/ -Z2p0/2xvef9ucXv/c3V8/2xvef9sbnX/c3V8/3N1fP9zdXz/cHJ5/21vc/9qbXf/bnF7/21vc/9ucHf/ -dnh8/21vc/9qbHP/cHJ5/3l7gf9wcnn/bG95/2xvef9ucXv/bnB3/2xvef9zdn//cHN9/2xvef9qbXf/ -eHl9/2dqdP9nanT/bG51/3t9g/9sb3n/cHN9/2xvef9qbXf/Z2p0/3t9g/9qbHP/Z2px/2dqcf9maXP/ -Z2px/2dqcf9qbHP/am13/25xe/9qbXf/Z2p0/2xudf9wc33/c3V8/2xvef9qbXf/bW9z/25wd/9ucHf/ -Zmhu/2xudf9sbnX/c3V8/2dqdP9zdn//c3Z//25wd/95e4H/am13/3V4gf9zdn//cHJ5/3l7gf97fYP/ -cHJ5/3N2f/9wcnn/bG95/3Byef9zdn//dXiB/2xvef91eIH/c3Z//3d6g/91eIH/c3V8/3N2f/97fYP/ -bnF7/3N2f/9zdn//c3Z//2dqdP95e4H/c3Z//25xe/9ucHf/bG95/25xe/9zdXz/Zmlz/3N1fP9zdXz/ -c3V8/25wd/9wcnn/dnh8/3Z4fP9ucHf/cHN9/25wd/9wcnn/dXiB/3Bzff9wcnn/eXyG/3l8hv9zdXz/ -bnF7/3V3ff9zdn//c3Z//3d5f/9wc33/cHN9/25xe/9wc33/cHN9/3h5ff91d33/c3V8/3N1fP9wcnn/ -am13/2psc/91d33/am13/2xudf9maXP/bG95/3N1fP9nanH/Z2px/2ptd/9qbXf/Zmlz/2xudf9zdXz/ -dnh8/3Byef9zdXz/Zmlz/2xvef9wc33/dXiB/3d5f/9wc33/cHN9/36Biv9wcnn/c3V8/3t9g/9+gIb/ -e32D/3d6g/9wc33/cHN9/3l8hv+Bg4r/dXiB/3t9g/93eoP/eXuB/3N2f/91d33/b3F1/3R2fP9vcXn/ -cnR8/21vdv90dnv/bnB3/3Byef9qbXf/bG95/2xvef93eX//bG51/25wd/93eX//e36H/3Z5gv9tcHr/ -b3J7/3Z3ff9rbnf/bG94/2xveP90dn//bW92/3J1ff9wc33/bW92/21wev9ydX//cHN9/3F0ff9tcHn/ -aWty/21vdv9qbHP/bG94/3V3fv9tcHn/a210/3Z4fv9tb3b/bW92/21veP9ucXr/b3F6/21wef9tb3b/ -cXN6/2xudP9ydHv/b3F5/2xvd/9ydHz/bW93/2tueP90dnz/cXN6/29xeP9sbnX/amxz/2xudf9qbHP/ -bG51/2xudf9wc33/bG51/2ptd/9wc3z/c3V8/21vdv9zdXz/bnB3/25xev9ucHf/cHJ5/25xe/9zdn// -cHJ5/2ptd/9zdXz/cHN9/3V3ff93eX//cHJ5/3V4gf9zdn//dXd9/3Bzff9ucHf/c3V8/3Bzff9zdXz/ -cHN9/3l7gf9wc33/am13/3Byef93eX//am13/2xvef9sb3n/bG95/2ptd/9sbnX/dXd9/3Byef9qbXf/ -Z2p0/3V3ff9nanT/bG51/29xdf9+gIb/dXd9/3V3ff9ucHf/bnB3/25wd/+Bg4r/bnB3/29xdf9vcXX/ -bG51/2xudf9ucHf/bnB3/21vc/91d33/bnB3/25wd/9vcXX/dnh8/3l7gf9zdn//cHN9/25wd/9ucXv/ -bnB3/2dqcf9vcXX/bG51/3N1fP9qbXf/dXiB/3N2f/9ucHf/d3l//2dqdP91eIH/c3Z//3N1fP9zdn// -eXyG/3N1fP93eoP/cHN9/3Bzff9zdXz/bnF7/3V4gf9wc33/eXyG/3V4gf95e4H/d3qD/2xudf9sbnX/ -dnh8/3Byef9zdXz/bnB3/25xe/9gY2z/bnF7/25xe/9ucHf/bG51/2xudf9sb3n/bG95/2dqcf9zdXz/ -bG95/3N2f/9ucHf/bnB3/3N1fP92eHz/b3F1/3Byef9ucHf/cHJ5/3N1fP9sb3n/bG51/3d5f/91d33/ -am13/2xudf9ucXv/bG95/25xe/9wc33/bG51/2xvef9sbnX/Z2p0/2xvef9wcnn/bG95/2dqdP9wc33/ -bG95/2xvef9qbXf/dXd9/2ptd/9qbXf/am13/3Z4fP92eHz/bnB3/25xe/95e4H/cHN9/3Byef9zdn// -d3qD/3l7gf93eoP/e32D/3Bzff9zdn//d3qD/36Ahv97fof/dXiB/3d5f/+DhYz/dXiB/3V3ff97fYP/ -foCG/3t9g/9zdn//cHJ5/3N1fP93eX//d3qD/2xvef93eX//c3Z//3N2f/9ucXv/dXd9/25wd/94eoD/ -dHeA/3N2f/9ucXv/dnh//2xvef9wcnn/bG51/2xudf9qbHP/eHl9/2xvef9sb3n/d3l//3d6g/91d33/ -bnF7/3Bzff96fIP/bnB3/29xdf9ucXr/d3h8/2xudf9ydHv/bnB3/2ptd/9vcXj/bnF7/2xudf9wcnn/ -b3F4/2Zpc/9rbnX/am13/29yfP93eoD/b3J8/2xvef95e4H/b3F1/2xvef9ucXv/b3J8/3F0ff9vcnv/ -bnF7/3Z4fv9wcnn/dnh+/3J0fP9ydHv/dXd9/2xudv9nanT/dnh+/25xe/9ucXv/am13/2ptdP9qbHP/ -bW9z/2xudf9qbHP/cHN9/2xudf9sb3n/dXd9/3d5f/9wc33/eHqA/3N2f/9sb3n/c3Z//3d6g/91eIH/ -e32D/3N2f/9wc33/e32D/3l8hv9+gIb/e32D/3Bzff95e4H/d3l//3d5f/9ucXv/bnB3/25wd/9ucXv/ -bG95/2xudf9wc33/amxz/2BjbP9nanH/bG95/2Zpc/9nanH/Zmlz/2ptd/9nanT/am13/3V3ff9ucXv/ -am13/2ptd/9zdXz/bG51/2xudf9qbXf/e32D/25xe/9wc33/am13/2ptd/9qbXf/f4GH/2ptd/9qbXf/ -bG95/2ptd/9wcnn/bnB3/25wd/9sbnX/dnh8/25wd/9sb3n/bG95/3V3ff93eX//cHN9/3N2f/9wcnn/ -cHN9/3Byef9nanT/cHJ5/3Byef9wc33/am13/3N2f/9zdn//cHJ5/3l8hv9ucXv/dXiB/3Bzff9vcXX/ -bnB3/3h5ff9tb3P/bG95/2psc/9qbHP/Z2p0/2ptd/9ucXv/Zmlz/2xvef9sbnX/am13/25xe/9sbnX/ -bW9z/3h5ff9wc33/c3V8/3N1fP9wc33/amxz/3Byef9ucHf/bnB3/29xdf9sbnX/bnB3/3Byef9maXP/ -bnF7/2xudf9ucXv/am13/2xvef9zdXz/cHN9/2xudf9wcnn/bG51/3Byef9ucXv/bG95/2ptd/93eX// -dXd9/3Byef9ucHf/c3V8/3N1fP91d33/c3V8/25wd/9wcnn/bnB3/3Bzff9zdn//eXuB/3N2f/9wc33/ -eXuB/3Bzff9wc33/cHJ5/3Z4fP9zdXz/bG51/2xvef91d33/c3V8/2xudf9qbHP/bG95/2ptd/9qbHP/ -bG95/2xvef9wcnn/am13/3Bzff9nanT/Z2p0/25xe/9zdXz/dXd9/2xudf9sbnX/c3V8/2xudf9qbXf/ -cHN9/3Z4fP9wcnn/bnB3/2xudf9tb3P/dXd9/3V4gf9sbnX/dXd9/3V3ff91d33/c3V8/3Z4fP9vcXX/ -c3Z//3V3ff9sbnX/Z2p0/3V3ff9qbXf/bnF7/2dqdP9qbHP/Z2p0/3V3ff9ucHf/bnB3/3N1fP92eHz/ -dXd9/3Byef9wcnn/eXuB/25wd/9sb3n/c3V8/3Z4fP9ucHf/cHJ5/21vc/9sbnX/cHJ5/3N2f/9wcnn/ -c3Z//3N2f/9qbXf/c3V8/3N1fP93eoP/eXyG/25xe/9qbXf/fX6B/21vc/9nanT/bnF7/2xvef9sb3n/ -bG95/2xvef9wc33/amxz/2xvef9sb3n/bG95/25xe/9nanT/ZGdx/3V3ff9wcnn/bnB3/21vc/9vcXX/ -am13/29xdf9ucHf/bG95/3N2f/9sb3n/bG95/3N2f/93eX//bnF7/3d5f/9wc33/cHJ5/3N2f/91eIH/ -c3Z//3l7gf9sb3n/bnB3/3N1fP91d33/dXd9/3N1fP9sbnX/dnh8/3Z4fP91d33/bnB3/21vc/9qbHP/ -am13/2xudf9tb3P/cHJ5/2xudf9kZmz/bnB3/3V3ff9sbnX/b3F1/2psc/9wcnn/bG51/2xvef91d33/ -c3Z//3Byef9ucHf/e32D/3N1fP9zdXz/c3V8/4OFjP91eIH/fX6B/3d5f/97fYP/dXd9/4mLkf93eX// -dXiB/3d6g/9zdn//dXiB/3Bzff9zdn//dXd9/3t+h/97fYP/dXd9/3Bzff95e4H/f4GH/3d6g/9ucXv/ -bnB3/3Byef9wcnn/Z2p0/25wd/9vcXX/cHJ5/2psc/9ucHf/bnB3/2xudf93eX//am13/3N2f/9sb3n/ -bnB3/25xe/91eIH/am13/3Bzff9ucHf/bG95/3Byef9wcnn/c3V8/2xudf9wcnn/bnB3/25wd/9zdXz/ -cHN9/3N1fP91eIH/c3Z//3N2f/95e4H/dXiB/25wd/9ucXv/bnF7/25xe/9vcXX/amxz/3V3ff9zdXz/ -amxz/3N1fP9tb3P/cHN9/2ptd/9ucHf/c3V8/3d5f/9qbXf/cHJ5/21vc/9sb3n/c3V8/25wd/9qbXf/ -dXd9/3V4gf9wc33/bG95/3N2f/91eIH/d3l//3N2f/9zdXz/dXiB/3V4gf95fIb/dXiB/3t+h/93eoP/ -dXiB/3t+h/9zdn//dXiB/25xe/97fYP/c3Z//2xvef9wc33/c3Z//3d5f/9vcXX/b3F1/3Bzff9wc33/ -bnB3/3Bzff9zdn//c3V8/3Byef91d33/bG51/21vc/91d33/dXd9/3d5f/9sb3n/bnF7/3l7gf9wcnn/ -cHJ5/3V4gf93eoP/c3Z//3N2f/9zdn//cHJ5/3d5f/95fIb/bnB3/3N2f/91d33/dXd9/25xe/95e4H/ -am13/3V4gf9wc33/bnB3/25wd/94eX3/b3F1/3V3ff9vcXX/b3F1/2xudf9ucXv/bG51/25wd/91d33/ -dnh8/3N1fP9sb3n/bnB3/3Z4fP9tb3P/bG51/25xe/91d33/amxz/2xvef9qbXf/bW9z/3Byef91d33/ -bW9z/25xe/9ucXv/Z2px/21vc/9sbnX/c3Z//36Ahv9sb3n/ZGdx/3d6g/9kZ3H/YGNs/2Zpc/9kZ3H/ -ZGdx/2Zpc/9nanT/bG95/2psc/9qbXf/bnF7/25xe/9ucXv/Z2p0/2Zpc/91d33/cHN9/25xe/9sbnX/ -amxz/2psc/9ucHf/bnB3/2xudf91eIH/bnF7/3Bzff93eoP/eXuB/3Bzff91eIH/cHN9/2ptd/9ucXv/ -cHN9/25wd/91d33/bW9z/2xudf9ucHf/cHN9/3N1fP9wc33/bG95/3V3ff9ucXv/cHN9/2ptd/9nanH/ -ZGdx/2Zpc/9iZW7/ZGdx/2Zpc/9nanH/XWBq/2psc/9ucXv/ZGdx/2xudf9kZ3H/bG95/2Zpc/9qbXf/ -cHN9/3Bzff9sbnX/bW9z/3N2f/9sb3n/bnB3/29xdf9+gIb/cHJ5/3Byef9ucHf/cHJ5/21vc/9+gIb/ -bG95/2xudf9wcnn/bG51/25xe/9qbHP/amxz/2dqdP93eX//cHN9/2ptd/9sbnX/c3V8/3N2f/9ucXv/ -Z2px/2dqcf9nanT/Z2px/2BjbP9nanT/bG51/2xvef9qbHP/am13/2ptd/9qbXf/dXiB/2psc/9ucXv/ -bW9z/2xvef9ucXv/d3qD/25wd/9wcnn/bnB3/2ptd/9wcnn/c3Z//3V3ff9sb3n/cHN9/3N1fP9wc33/ -eXuB/3d5f/91d33/e32D/3t9g/97fYP/f4GH/36Ahv9zdXz/d3l//3t9g/93eX//d3l//3d5f/9+f4P/ -e32D/3Bzff93eoP/c3Z//36Ahv9zdn//dXiB/3t9g/97fof/c3Z//3V4gf9zdXz/cHN9/3l7gf9wc33/ -bnF7/3V3ff91eIH/bnF7/25xe/91d33/bnF7/3N1fP9ucXv/am13/3Byef9ucHf/dnh8/29xdf94eX3/ -bnB3/25wd/93eX//cHJ5/3Byef9ucHf/eHl9/3Byef9ucHf/dXd9/3N1fP95e4H/b3F1/21vc/9wcnn/ -bG95/2xudf9ucXv/cHJ5/3N1fP9ucHf/c3V8/2dqdP9maXP/bnF7/25xe/9ucXv/ZGdx/2dqcf9ucHf/ -Zmhu/2Jlbv9qbXf/cHJ5/2xvef9ucXv/bG95/2dqdP9wc33/c3Z//2xudf9wc33/cHN9/3Byef9sbnX/ -cHN9/2dqdP9qbXf/bG95/2xvef9qbXf/c3V8/2xudf9wc33/am13/2ptd/9qbXf/cHJ5/25wd/9ucHf/ -dXd9/3V3ff9zdXz/bnB3/25wd/92eHz/bG95/2dqdP91d33/dXd9/2xudf9qbXf/bG51/2xudf9qbXf/ -c3V8/25wd/9sb3n/cHN9/2ptd/9wcnn/bnB3/3Bzff9+gIb/bnB3/2psc/9/gYf/b3F1/2psc/9zdXz/ -bnB3/3Byef9wcnn/bnF7/3Z4fP9wcnn/c3V8/3Byef91d33/cHJ5/2xudf9maG7/d3l//3l7gf9zdn// -bnB3/2xudf9nanT/bnB3/25wd/9qbXf/c3Z//2ptd/9sb3n/c3Z//3d5f/9ucXv/dHeA/3N2f/9rbnf/ -bnF7/25xe/9ucHf/eXuB/2xvef9sb3n/cHN9/3d5f/95e4H/dXd9/3Bzff91d33/cHN9/3Z4fP9ucHf/ -bG51/29xdf9ucHf/bnB3/2xvef9zdn//c3Z//2Zpc/9zdn//d3qD/25wd/9wc33/am13/3V4gf9wc33/ -dXiB/36Ahv9+f4P/dXd9/3V3ff97fYP/c3Z//3N1fP9wc33/foGK/3V4gf91eIH/eXuB/3t9g/91d33/ -g4WM/3t9g/9zdn//eXuB/3Bzff91eIH/cHJ5/25xe/9ucHf/eXyG/3l7gf9wc33/cHN9/3N2f/93eX// -c3Z//25wd/9sb3n/bnF7/25wd/9nanT/b3F1/25wd/9wcnn/bW9z/2xudf9ucHf/am13/3l7gf9nanT/ -bnF7/25xe/9wc33/cHN9/3t+h/9qbXf/bnF7/3Byef9ucHf/bnF7/3V4gf91eIH/dXd9/3l8hv91d33/ -d3l//36Ahv95e4H/d3l//3l8hv95e4H/d3l//36Ahv97fYP/cHN9/3V4gf91eIH/cHN9/3Byef9qbXf/ -dnh8/3Byef9nanT/bnF7/2psc/9zdXz/bG51/2ptd/9ucXv/c3V8/2dqdP9qbXf/Z2px/2Zobv9ucXv/ -am13/2Rncf9qbXf/am13/2Zpc/9nanH/am13/2dqdP9sb3n/cHN9/2ptd/9ucXv/bW9z/3Byef9ucHf/ -eHl9/25wd/9sbnX/dnh8/3N1fP9wcnn/cHJ5/3d5f/9wcnn/bnB3/3N2f/9wcnn/d3qD/25wd/9sb3n/ -bnF7/25wd/9vcXX/c3V8/3Byef9ucXv/bnB3/3N1fP9qbXf/Z2p0/3Bzff92eHz/dXd9/2psc/9wcnn/ -dXd9/21vc/9sbnX/c3V8/3V3ff9wc33/bG95/3Byef9sb3n/c3V8/3l7gf9sb3n/cHN9/3V3ff9zdXz/ -cHN9/3V4gf9sb3n/bnB3/29yfP9wc33/bG95/3d5ff9sb3n/dXd9/2ptd/9sb3n/am13/25xe/9wcnn/ -c3Z//3V4gf95e4H/d3l//25xe/9ucXv/d3l//25xev9qbXf/cHJ5/3J0e/9sbnX/bG52/2xudf9sbnX/ -bnB3/3N1fP9tb3P/a254/2tueP9oa3T/a253/2xudf9vcXn/eXuC/29xeP9qbHP/fH6F/25wdf9nanL/ -cnR7/29xeP9xc3r/cHJ5/21vd/9zdXz/b3F4/25xev9ucXv/b3J8/25xe/9sbnX/Zmlz/3N2fP9xdH7/ -cnR7/21vc/9nanT/ZGdx/2xudf9sbnX/amxz/25xe/9qbXf/am13/25xev90dnz/a211/2ptd/9sb3n/ -Z2pz/2xvef9sbnX/amxz/3N1fP9nanT/Z2p0/2xvef9zdXz/c3V8/3Bzff9sb3n/cHN9/2xvef9zdXz/ -bG95/2xudf9qbXf/bG95/2xudf9qbXf/cHJ5/25wd/9nanH/cHN9/3N2f/9sb3n/cHJ5/2Zpc/9wcnn/ -bG51/3Bzff93eX//d3qD/3Byef9qbXf/dXiB/25xe/9zdXz/cHN9/36Biv9zdn//c3Z//25xe/9zdn// -c3Z//4GDiv9zdn//cHJ5/3l7gf9wcnn/c3Z//3N1fP9wc33/bG95/3d6g/91eIH/b3F1/29xdf9zdXz/ -eHl9/3h5ff9tb3P/bG51/2xudf9qbHP/Z2p0/21vc/9wcnn/cHJ5/25wd/9wcnn/cHJ5/25wd/95fIb/ -Z2p0/25xe/9wc33/bnF7/25xe/97fof/c3Z//3d5f/91d33/eHl9/3d5f/95e4H/e32D/3l7gf9+gYr/ -eXyG/3l8hv+Agob/cHJ5/25wd/9wc33/bG95/2xvef92eHz/dXd9/2xudf9tb3P/bG95/25xe/9ucHf/ -amxz/3V3ff9wcnn/bnB3/3Byef9vcXX/d3l//25xe/9zdn//eXuB/3l8hv9zdn//dXiB/3Bzff9wc33/ -dXd9/25xe/9sb3n/eHl9/3d5f/9ucHf/bnB3/3V4gf9sb3n/c3Z//3V3ff9vcXX/c3V8/25wd/9zdXz/ -bG51/3l7gf9ucHf/bnB3/3Z4fP9ucXv/bnF7/2ptd/91d33/bG95/2psc/92eHz/cHJ5/3h5ff9vcXX/ -b3F1/3Byef9sbnX/bG51/25xe/9sbnX/cHJ5/25wd/9zdXz/bW9z/2psc/9wc33/dXd9/3N1fP9nanT/ -bnF7/3Z4fP9vcXX/b3F1/3N1fP91d33/cHN9/25xe/9wc33/bG95/3Bzff93eoP/bG51/3Byef9ucXv/ -bnF7/3Byef91d33/bG51/21vd/9tcHr/c3V9/2xvdv92eH3/b3F4/3Byef9sbnX/bG51/2xudf9qbXf/ -bW9z/3N1fP91d33/dXiB/3V3ff9ucHf/bXB6/3J1fv9vcXj/a212/25xe/9ucXv/bnB4/29yd/9ucXr/ -cnR7/3F0ff92eH7/b3F4/3N1fv9xdH3/bnB2/3BzfP9vcXj/cnV8/3x+hP9tb3b/a210/3p8gv9vcXb/ -aGp0/2xveP9vcXf/bnF5/25xef9tb3b/bXB6/25weP9tb3f/bnB4/3Bzev9ucHj/bW91/2dqc/9ydXr/ -eHl//3N1fP9tb3b/bnB3/2xudf9vcXX/b3F1/2xudf9wcnn/bG51/2xudf9xc3r/d3mA/29xd/9ucXv/ -c3V+/3BzfP9sb3n/amxz/2psc/9ucHf/YmVu/2Zpc/9nanT/Z2p0/2dqdP9maXP/Zmlz/25wd/9maXP/ -Z2p0/2Zobv9kZ3H/YmVu/2Rncf9kZ3H/Zmhu/2ptd/9sbnX/ZGdx/2xudf9wc33/am13/2ptd/9iZW7/ -bG51/2Zpc/9ucXv/dXd9/3N1fP9ucHf/bnB3/3N2f/9sb3n/bnB3/25wd/95e4H/bnB3/2xvef9qbXf/ -bnB3/2xudf99foH/cHJ5/25wd/9zdXz/bnB3/3Byef9ucHf/cHN9/3Byef97fof/eXuB/25xe/9wcnn/ -eHl9/3Z4fP94eX3/bW9z/2xudf9sbnX/b3F1/25wd/9vcXX/cHJ5/3Byef9sbnX/cHJ5/25wd/9tb3P/ -d3l//2dqcf9ucHf/c3V8/2ptd/9sbnX/dXd9/2ptd/9sb3n/bG51/2dqdP9qbXf/am13/2ptd/9maXP/ -bnF7/2xudf9sbnX/cHJ5/25xe/9sb3n/c3V8/25wd/9ucXv/eXuB/3V4gf9ucXv/c3V8/3V4gf91eIH/ -bnF7/2ptd/9wc33/cHN9/3Byef9wc33/bnB3/3d5f/9wcnn/cHN9/3d6g/95e4H/c3Z//3V4gf9ucXv/ -cHN9/3V3ff9wc33/b3F1/3V3ff91eIH/bnF7/25wd/91d33/bG95/25xe/91eIH/bnB3/3N2f/9sb3n/ -c3V8/2xudf95e4H/bnB3/3N1fP93eX//dXd9/3Byef9wcnn/dnh8/2xvef9qbXf/cHN9/2xvef91d33/ -am13/2Zpc/9nanT/bG51/2psc/9sb3n/bG51/2xvef9qbXf/bG95/2dqcf9maXP/bnF7/3Byef9sb3n/ -Zmlz/2ptd/9ucXv/am13/2xudf9wcnn/dXd9/3N1fP9zdXz/dXd9/25xe/9zdn//e36H/2xvef9zdXz/ -cHJ5/3V3ff91d33/dXd9/25wd/9sbnf/b3J6/3N2f/9sb3f/dniA/3F0ff90dnz/bnB3/21vc/9sbnX/ -am13/2psc/9ucXv/bnF7/3V3ff9wc33/Z2p0/3Byef9ucXv/a252/2lsdv9sb3n/a254/2tueP9tcHj/ -bG95/2hrdf9maXP/bnF5/2lrcf9tcHj/am13/2dqcv9pbHb/aWt0/2psdP9wcnv/ZWhy/2Zpc/9vcnr/ -a252/2dqc/9nanT/cXR8/25wef9ucHj/ZWhx/2Vocv9kZ3H/Zmlx/2dpcP9nanT/aWx0/2Vocf9gY2z/ -Z2p0/3N1ff9qbXf/Zmly/2Zocf9jZm7/ZWhy/2dqcf9kZ3H/Z2p0/2Rncf9nanP/b3J7/3R3f/9rbnb/ -a211/3R2fP9ydHv/bnF7/21vc/9ucHf/d3l//2psc/9ucHf/cHN9/3N1fP9zdXz/c3Z//2xvef91eIH/ -c3V8/3Z4fP9zdXz/cHJ5/25wd/9ucXv/b3F1/25wd/9ucHf/bnB3/2xudf9sbnX/c3V8/2xudf9sbnX/ -Zmlz/2psc/9qbXf/bnF7/3N1fP9wc33/am13/2ptd/9ucXv/bG51/25wd/9ucHf/foCG/25xe/9wcnn/ -b3F1/2xudf9zdXz/e32D/3N1fP9ucHf/c3V8/25wd/9zdXz/bnF7/3N2f/9wcnn/eXyG/3d6g/9zdn// -c3Z//3d5f/93eX//eXuB/25xe/9ucXv/bnB3/2xvef9sb3n/bnB3/25xe/9zdn//bnB3/2xvef9ucXv/ -cHJ5/3d5f/9kZ3H/bnF7/3Bzff9sb3n/bnF7/3V4gf9ucHf/bG95/25xe/9ucHf/cHN9/25wd/9ucXv/ -bG95/3N1fP9ucHf/bnB3/25xe/91eIH/dXiB/3N2f/9sb3n/bnB3/3h5ff9ucHf/bG51/21vc/9wcnn/ -c3V8/3Byef9nanT/bnF7/3N2f/9sb3n/cHJ5/2xvef95e4H/cHN9/3Bzff91eIH/dXiB/3Z4fP9zdn// -bG95/25xe/91eIH/cHN9/25wd/95fIb/d3qD/3Bzff9wc33/d3qD/25xe/9wc33/eHl9/2xudf9ucHf/ -bG95/25wd/9qbHP/d3qD/2ptd/9sb3n/d3l//25xe/9qbXf/bnB3/3V3ff9ucHf/amxz/3Bzff9sbnX/ -dnh8/2xvef9qbXf/am13/2xudf9qbXf/c3V8/2xudf9wcnn/bnB3/3N1fP9vcXX/bG51/3V3ff91d33/ -dXd9/2ptd/9sb3n/am13/2ptd/9maXP/bnF7/3V3ff9sb3n/cHN9/25xe/9qbXf/cHN9/3V4gf9sbnX/ -cHJ5/2xudf92eHz/cHN9/3d5f/9wc33/bnB4/29xef95e4L/bnB2/3N2fv9ucXr/c3V+/2xvef9ucHf/ -cHJ5/25xe/9ucHf/dXd9/3Byef91d33/c3V8/21vc/9ydHz/b3F6/2ttdv9rbXX/am13/2Zpc/9rbnf/ -bG94/2tueP9naXD/Zmlz/2xveP9oa3X/cnR7/2ptd/9oa3T/cnR7/2xudf9sb3b/dHZ+/3Bydv9sb3n/ -cHN8/3J1ff9tcHn/b3F1/3l7gf92eH7/dXd9/25wd/9tb3f/aGt1/25wd/9ucHf/bG95/3R2f/9ucHf/ -bW92/25wd/97fIH/cHJ5/21wef9ucHf/am13/21wev9ucXv/bnB3/3N2f/9ucHf/b3F4/3F0fv90d4H/ -a254/2lsdv9xdH7/c3V8/3N2f/9wc33/d3qD/3t+h/9ucXv/cHN9/3d6g/91eIH/dXiB/25xe/9ucHf/ -e36H/3Bzff95fIb/d3qD/3Bzff9nanT/bnB3/2xvef9sb3n/c3V8/2ptd/9nanH/cHJ5/3Byef9vcXX/ -bG95/2xudf9ucHf/bG95/3Bzff94eX3/dXd9/3Byef9wcnn/eXuB/3N2f/9zdXz/c3Z//3l8hv9ucXv/ -bnF7/25wd/9ucXv/cHN9/3l8hv9wc33/bG95/3V3ff9wcnn/cHJ5/3Byef9wcnn/bG51/3N1fP9sb3n/ -bG51/2xudf9wc33/bG95/25wd/9qbHP/Z2px/2dqcf9kZ3H/Z2p0/2xudf9sb3n/bnB3/2xudf9vcXX/ -bnB3/25xe/93eX//ZGdx/25xe/9wc33/c3Z//3N2f/95fIb/cHJ5/3V4gf93eoP/c3Z//3t9g/91d33/ -dXiB/3Bzff93eoP/c3Z//3N2f/93eoP/eXuB/3l7gf93eoP/dXiB/3d5f/9/gYf/foCG/3d5f/92eHz/ -e32D/36Ahv99foH/d3l//3t9g/9+f4P/eXuB/3d6g/9wc33/foGK/3N2f/9zdn//eXyG/3l8hv97fYP/ -d3qD/3V4gf9wc33/e32D/3V4gf9ucXv/e36H/3d5f/9ucXv/bG95/3Bzff9vcXX/bnF7/3Z4fP9sbnX/ -am13/25wd/9wcnn/bG51/3l7gf9ucHf/c3V8/3h5ff9zdn//bG51/25wd/94eX3/bnB3/2psc/9zdXz/ -bnB3/3Z4fP9ucHf/bnB3/21vc/9tb3P/bG95/3Bzff9sbnX/cHJ5/3Byef9ucHf/am13/2psc/91d33/ -dXd9/3Byef9maXP/am13/2dqdP9nanH/YmVu/2Zpc/9ucHf/am13/25xe/9ucXv/am13/25xe/91d33/ -amxz/25xe/9qbXf/bnF7/25wd/9zdXz/am13/25xe/9zdn//fH+I/3Byev90d4D/b3J6/3Bzff9nanT/ -bG51/2ptd/9qbXf/bnB3/3N1fP9wcnn/dXd9/3N1fP9sbnb/dXd+/3R3f/9vcnr/bnF6/3Bzff9vcXv/ -dnmC/3p8gv94eoD/cnV//3Byef9zdn//cHJ5/3h6gP9wc33/bnB3/3Z5gv9zdXz/c3V8/3l8hv91d33/ -dHZ8/3R2ff92eYL/dHeA/3N1fP95fIX/d3qD/3Z4f/9wc33/bG95/2dpc/9ucHf/bG51/29xdf9wcnn/ -bnB3/25wd/9sb3n/e32D/29ye/9ucXr/bnB3/21vdv9tcHr/bnB3/29xdf9ucXv/cHJ5/25wd/9tcHr/ -dnmC/2tueP9sb3n/d3qD/3N2f/9ucXv/bnB3/25xe/93eX//bG95/25wd/9wc33/cHN9/3N2f/9wc33/ -bnB3/3t+h/9ucHf/dXiB/3N1fP9wcnn/Z2px/3Byef9sbnX/bnB3/25xe/9ucXv/bnF7/3N2f/9wc33/ -c3V8/2ptd/9sb3n/cHJ5/3N1fP93eoP/eXyG/36Ahv91d33/dnh8/36Ahv95fIb/cHN9/3N1fP9/gYf/ -c3Z//3V4gf93eoP/d3l//3d5f/+Cg4f/e32D/3Z4fP95fIb/c3Z//3V4gf9zdn//c3Z//25wd/95e4H/ -d3qD/3N2f/9zdn//d3qD/3N2f/93eX//bnB3/2xvef9sb3n/bG95/25wd/9ucHf/dnh8/3Byef9vcXX/ -bG51/25wd/9wcnn/dXd9/2Zobv9sb3n/bnF7/3Bzff91eIH/e32D/25wd/9ucXv/bG95/3Byef9zdn// -bnB3/3V4gf9wc33/eXyG/3V3ff93eX//e32D/2Zpc/9nanT/Z2p0/2xudf9sbnX/c3V8/2ptd/9sbnX/ -am13/3N1fP9sb3n/cHN9/2xudf9zdXz/dXd9/25wd/9wcnn/bnF7/36Biv9zdXz/c3V8/3t9g/95fIb/ -d3l//3Bzff9ucXv/bnF7/3N2f/9sb3n/bG51/3d5f/92eHz/bnB3/2ptd/9qbXf/amxz/25xe/93eX// -amxz/2ptd/9sbnX/Z2p0/2Jlbv9wc33/ZGdx/2ptd/9ucHf/am13/2psc/9qbHP/bnF7/2psc/9kZ3H/ -bG95/2xudf9wc33/am13/2Zpc/9sb3n/am13/25wd/9zdn//bnB3/25xe/9wcnn/c3V8/25wd/9ucHf/ -d3l//3Z4fP92eHz/am13/25xe/9wcnn/bW9z/2dqdP9sb3n/cHN9/2xvef9zdXz/c3V8/2xvef9wc33/ -dXd9/2xudf9sb3n/bG51/2xvef9qbXf/bnF7/2ptd/9wc33/bnF7/3h7hf9sb3b/cHJ7/25wdv9ucXv/ -am13/2xudf9sbnX/bG95/2xudf9ucXv/dXiB/3V4gf9zdXz/b3F1/3R2fP9xc3v/bnB1/25wd/9ucHf/ -am13/3Bzff91d33/dnh8/3Byef9sbnX/cHN9/3Byef95e4H/cHN9/25xe/91d33/bW9z/25wd/9wcnn/ -bnB3/29xdf9ucHf/c3V8/3Byef9vcXX/eXuB/3V4gf95e4H/bnB3/25wd/9kZmz/bG51/2dqdP9qbHP/ -bG51/2ptd/9maXP/amxz/3N2f/9qbXf/am13/2ttdv9rbnX/cHJ6/2xvef9wcnn/cHN9/3Byef9vcnn/ -bXB6/3N2gP9oa3X/Z2p0/2xvef9qbXf/dXiB/3N1fP93eoP/eXyG/3N2f/93eX//fn+D/3l8hv95fIb/ -dXiB/3d6g/9+gYr/cHN9/3d6g/91eIH/bnF7/2dqdP9sb3n/bnF7/25wd/9wc33/bG95/2ptd/9wc33/ -bnF7/3Byef9sb3n/bnF7/2xvef9sb3n/c3V8/3V3ff9zdXz/bnB3/25wd/93eX//bnF7/3Byef9ucHf/ -e32D/25wd/9wc33/c3V8/25xe/9ucHf/eXyG/3N1fP9ucHf/dnh8/21vc/9sb3n/cHJ5/25xe/9sbnX/ -dXd9/3V3ff9ucXv/bG51/3N1fP9ucXv/dnh8/2xudf9qbXf/bG51/21vc/9tb3P/bW9z/3N1fP9sbnX/ -amxz/2dqdP9sbnX/bnF7/3N1fP9kZ3H/bG51/2xvef9nanT/am13/2xvef9maG7/bG51/2xudf9qbHP/ -Z2p0/2Rncf9maXP/Zmhu/2Zpc/9iZW7/ZGdx/2dqdP9qbXf/am13/2xvef9qbXf/amxz/3N1fP9maXP/ -Z2px/2Zpc/9sb3n/am13/25xe/9kZ3H/cHN9/25xe/9sbnX/bG95/2xvef91eIH/bnB3/29xdf93eX// -eXyG/3d6g/9wc33/cHN9/3N2f/95e4H/c3Z//3V3ff9/goz/foCG/3d6g/9zdn//d3qD/3Bzff95fIb/ -f4GH/3d5f/93eoP/c3Z//3d6g/91d33/foGK/3Bzff91eIH/d3qD/3N2f/9ucHf/bG95/3N2f/9zdn// -am13/25xe/9ucXv/c3Z//3Bzff9qbXf/c3V8/3Bzff9ucXv/dXd9/29xdf9ucHf/bnB3/3V3ff9ucHf/ -am13/3V4gf95e4H/eXuB/2xvef9wc33/cHN9/3N1fP9ucHf/cHJ5/3V3ff91d33/d3l//3Z4fP9sbnX/ -cHN9/3d5f/9qbXf/bnB3/21vc/9wcnn/bnF7/3V3ff9ucXv/bG51/25wd/94eoH/bnB4/3J0fP9vcXn/ -dHZ9/2xudf9qbXf/Z2p0/2ptd/9nanP/bG95/2xvef93eX//bnF7/2psc/9tcHn/bnB5/21vdP9rbXT/ -bnB3/2dqcf9sb3n/cHN9/25xe/9sb3n/amxz/2xvef9maG7/bG95/2dqcf9nanH/am13/2dqdP9maXP/ -bG95/2ptd/9qbXf/am13/2xudf91d33/bG95/3l8hv95e4H/eXuB/3Bzff9ucHf/am13/3N2f/9zdXz/ -c3V8/3V4gf91d33/dXiB/3d5f/+DhYz/e32D/3h6gP9zdn7/b3F5/2xvef9rbnj/Z2px/2dqdP9qbHP/ -a210/2xvef93eX//c3V8/25xev91eIH/cHN9/2xudf9sbnX/cHJ5/3Bzff9kZ3H/bnF7/3N1fP9sb3n/ -bG95/2xvef9ucXv/dXiB/2xvef91d33/bnF7/3N1fP9sbnX/bnB3/2xudf9ucHf/bG51/25wd/9qbXf/ -c3Z//25wd/9sb3n/bnF7/2ptd/9sb3n/bnB3/3Bzff93eoP/c3Z//25xe/9sb3n/dXiB/25xe/9wc33/ -cHJ5/3t+h/9ucXv/bG95/29xdf9sbnX/cHJ5/3t9g/9ucXv/amxz/3V3ff9qbHP/am13/2ptd/9sb3n/ -Z2p0/3V3ff9sb3n/am13/2psc/9zdXz/cHJ5/3d5f/9tb3P/bW9z/2xudf9nanH/bG51/2xudf91d33/ -bG51/21vc/9sbnX/bG51/3Z4fP92eHz/Z2p0/2xvef91d33/c3V8/25xe/9zdXz/b3F1/25wd/9ucHf/ -bnB3/25wd/9nanT/bG95/2ptd/9ucXv/am13/2xudf9sbnX/bG95/25wd/9wcnn/bG95/2xudf9zdXz/ -Z2p0/2dqcf9nanT/bG95/2ptd/9ucXv/ZGdx/25xe/9zdXz/bG51/2xvef9qbXf/cHJ5/2dqcf9nanH/ -bG95/3Bzff9ucXv/Z2p0/2dqdP9nanT/bG95/2Zpc/9kZ3H/dXd9/3Byef9qbXf/bG51/2xudf9qbHP/ -cHN9/3N2f/9qbHP/Z2p0/2dqcf9nanT/Zmlz/3V3ff9qbXf/bnF7/2xvef9sb3n/bG51/2xudf9sb3n/ -c3V8/2dqcf9ucHf/bnB3/25xe/9ucHf/Z2px/2xudf9ucHf/c3V8/3Z4fP9vcXX/cHJ5/25wd/91d33/ -bnB3/2xvef91eIH/dnh8/3V3ff9ucHf/cHN9/3N1fP9vcXX/b3F1/2xvef9zdXz/c3V8/3d5f/92eHz/ -bnB3/3Z4fP93eX//bG51/3N1fP9sbnX/cHJ5/3V3ff93eX//c3Z//25xe/9ucXv/d3qD/29yfP9zdn// -c3V9/3l7gf9qbXf/bnF7/3Byef9zdn//a254/3N2f/91eIH/e32D/3d6g/9wcnn/cXR+/3J1fv9ucXn/ -bnB3/3Byef9qbHT/c3Z//3h6gP9zdn//bnF7/2xvef9zdXz/b3F1/3N1e/9sbnX/bG51/3R2fP9ucXv/ -bnB3/3F0ff9vcXj/b3F4/25xe/9zdXz/dXiB/25xe/95fIb/eXuB/3l7gf9ucXv/am13/2Zpc/9wcnn/ -bnB3/2ptd/9wc33/bG95/3Bzff9ucHf/d3qD/3N2f/9wcnn/bnB3/29xdv9ucHf/cHJ5/25wd/9ucXv/ -bG95/25wd/9sb3j/dXd8/29xd/9sbnX/cHN9/2xvef9ucHf/bG95/3d5f/91eIH/Zmlz/3V4gf95e4H/ -cHN9/3N1fP91eIH/d3qD/4GDiv95e4H/eXyG/3V4gf93eoP/bnF7/3N1fP9ucXv/bG95/2xvef9ucHf/ -bnB3/3N2f/9wcnn/bnB3/2ptd/9ucHf/bG51/25wd/9ucXv/d3l//25xe/9ucHf/amxz/3d5f/9ucXv/ -am13/2ptd/91d33/bG51/3Byef9ucHf/cHN9/3V4gf9+gYr/d3qD/3Bzff97fof/cHN9/3N2f/93eoP/ -dXiB/3N2f/97fof/e32D/3d6g/91d33/e32D/3d6g/9+gYr/cHN9/3N1fP9zdXz/cHJ5/2xvef9ucHf/ -dXd9/25wd/9tb3P/bnB3/25wd/9zdn//dXd9/25wd/9tb3P/c3V8/2xvef9sb3n/cHN9/2dqcf9qbHP/ -amxz/2ptd/9qbXf/Z2p0/2ptd/9sb3n/cHN9/2xudf9nanT/am13/2dqdP9maXP/Z2p0/2dqdP9kZ3H/ -am13/2Rncf9maG7/YmVu/2Zpc/9kZ3H/am13/1xfaP9qbXf/bG95/2BjbP9kZ3H/Z2px/2xvef9maG7/ -Zmhu/25wd/9zdXz/bnF7/2dqdP9maXP/Z2p0/25wd/9qbHP/Zmlz/3N1fP91d33/am13/25wd/9qbXf/ -bG51/2xvef9zdn//amxz/2xudf9qbHP/bnB3/21vc/93eX//am13/3N1fP9wc33/bG95/2ptd/9qbXf/ -bG95/25xe/9maXP/bG51/2xudf9ucXv/bG95/2psc/9sbnX/bnB3/3Byef91d33/bnB3/25wd/9zdXz/ -cHJ5/29xdf9sbnX/dXd9/3V4gf95e4H/cHN9/3V4gf9zdn//cHJ5/3N1fP9wc33/e32D/3t9g/9+gYr/ -eXuB/3Bzff95e4H/eXuB/25wd/9zdn//bG95/3N2f/91eIH/eXyG/3d5f/9wcnb/b3F2/3Z4ff9vcXj/ -cHN7/21veP90dn3/am13/3Byef9wcnn/cHN8/2psc/9ucHf/bnB3/3V3ff9wcnn/bW9z/29xeP9sb3n/ -amxy/2Zpcv9oa3T/X2Js/2hrdf9xc3v/bG95/2xudf9pbHb/bXB6/2ttdf9rbnf/a252/2lsdv9tb3j/ -bW93/2psdP9vcnz/amx0/2dqdP9tb3b/bG51/3N1fP9qbXf/d3qD/3Bzff9wc33/bG95/2ptd/9qbHP/ -bnB3/21vc/9sbnX/bnB3/2xudf9wcnn/bW9z/3d5f/9wc33/bG95/29xef9sbnX/aWx2/2ptd/9nanT/ -am13/2xudf9nanT/a210/3N1ff9vcXn/bW93/3V4gf91eIH/am13/2ptd/9wc33/cHN9/2Jlbv9ucXv/ -dXd9/25wd/9sbnX/bG51/25wd/91d33/cHJ5/3V3ff9sbnX/cHN9/2dqdP9vcXX/bG51/2xudf9qbXf/ -am13/2xudf9zdXz/bnB3/29xdf9maXP/bG95/2xvef9sb3n/c3Z//3V4gf9wcnn/c3V8/2psc/91d33/ -cHN9/25xe/9sb3n/d3l//2xvef9ucXv/bnB3/2xudf9zdXz/foCG/3N2f/9sb3n/d3qD/2xvef9sb3n/ -c3Z//3N1fP9ucHf/dnh8/3Byef9ucHf/bG95/3V3ff9wcnn/e32D/29xdf9tb3P/bG51/29xdf9ucHf/ -b3F1/3Z4fP9ucHf/bnB3/3Byef9zdXz/dXd9/3V3ff9nanH/bG51/3d5f/9sb3n/am13/2xvef9sbnX/ -bnF7/2xvef9nanT/am13/2Rncf9maXP/Zmlz/2dqdP9iZW7/XF9o/2Rncf9ucXv/am13/3Byef9zdXz/ -bG51/3V3ff9ucHf/bG51/2psc/9zdXz/cHJ5/3N1fP9maG7/cHJ5/3N1fP9nanT/dXd9/2xudf92eHz/ -b3F1/2xvef91eIH/d3qD/3V4gf9sb3n/bnF7/3N2f/91d33/bnB3/2xvef93eX//dXiB/25wd/9sbnX/ -bG51/25wd/9zdXz/d3l//2ptd/9qbXf/bnB3/3Byef9vcXX/dnh8/21vc/9zdXz/cHN9/2xvef9qbXf/ -bG51/2xudf9qbXf/Zmlz/2xudf9qbXf/bG95/2xudf9maXP/bG51/2ptd/9ucHf/d3l//2ptd/9sbnX/ -bnF7/2ptd/9sbnX/am13/3d5f/93eX//eHl9/25wd/91d33/cHN9/25wd/9ucXv/cHJ5/3l7gf93eX// -e36H/3d5f/9ucHf/dXiB/3d5f/9wcnn/c3Z//2xvef9ucXv/c3Z//3l7gf92eHz/Z2pz/2Zpcv9ucHj/ -Zmlz/2hrc/9pbHb/bXB6/2dqdP9maXP/Zmlz/2dqdP9hZGz/Z2px/2dqcf9zdXz/am13/2dqdP9oa3X/ -a254/2hrdP9oa3P/am13/2hqcf9tcHj/cHJ5/3Byef90dnz/bnB5/3V4gf9ydHz/cXR+/29ye/9vcnv/ -b3J8/3N2f/9xc3r/eXyF/29ye/9tb3f/cnR+/3N1fP93eX//bnF7/3l8hv95e4H/dXiB/3N2f/9ucHf/ -am13/3N1fP9wc33/cHN9/3N2f/9ucHf/bnF7/2xvef95e4H/dXd9/25wd/9wc3r/cHN6/29ye/9ydX7/ -c3Z//3V4gf9zdXz/c3Z//3J1fv94eoL/cXN6/25weP9zdXz/c3V8/3V4gf91d33/foCG/3t9g/9wc33/ -d3qD/3l7gf93eoP/c3Z//3N2f/9zdn//d3qD/3N2f/93eX//bnB3/3V4gf9nanT/cHJ5/3Byef9wcnn/ -cHJ5/2xvef9wcnn/d3qD/3N2f/91d33/am13/3N1fP9wc33/cHN9/3l8hv97fYP/d3qD/3N2f/9ucHf/ -eXuB/3N2f/9ucXv/cHN9/3l7gf9wc33/c3Z//25wd/9wcnn/dXiB/36Ahv9zdn//bnB3/3d6g/9vcXX/ -bnB3/3N1fP9wcnn/bG51/3h5ff9wcnn/cHJ5/2xudf9zdXz/cHJ5/3d5f/9tb3P/bG51/2dqdP9ucHf/ -bnB3/3Byef93eX//bnF7/25wd/9ucXv/c3Z//3V3ff91d33/Z2p0/25xe/95e4H/c3Z//3N2f/9wc33/ -bnB3/3N2f/9ucHf/bnB3/3V3ff9sbnX/cHJ5/3V3ff91d33/b3F1/2dqcf9wcnn/c3Z//3Byef9zdn// -dXiB/3Bzff95e4H/c3Z//25xe/9qbXf/c3Z//3V3ff91d33/amxz/3Byef94eX3/bG95/3N2f/9ucXv/ -dXd9/25wd/9ucXv/d3qD/3V4gf93eoP/b3F1/3Byef91d33/dXd9/2xvef9nanT/cHJ5/3V3ff9sb3n/ -am13/2ptd/9wcnn/cHJ5/3l7gf9wcnn/bG51/21vc/9sb3n/b3F1/3h5ff9sbnX/c3V8/3V3ff9wcnn/ -bnB3/25wd/9ucHf/bnB3/2xudf9tb3P/bG51/25wd/9sbnX/Z2p0/2xudf9qbHP/am13/3N1fP9qbXf/ -Z2px/2dqdP9qbHP/Zmlz/2Jlbv9qbXf/am13/2xvef9maG7/Z2p0/2Rncf9gY2z/ZGdx/2Rncf9sb3n/ -Zmlz/3Bzff9zdXz/amxz/2ptd/9zdXz/bG51/25xe/9qbXf/am13/2xvef91d33/c3V8/21wev9vcXb/ -dHZ8/25wd/9vcnz/bXB5/3N2f/9sbnX/bG51/25wd/9ucXv/Zmlz/21vc/9sbnX/dXd9/25wd/9ucHf/ -cXN6/29xeP9ucHj/bnF6/3Bzff9vcnz/dHeA/3J1f/9wc33/dnmC/3J0fP93eYD/dHZ9/29xeP9wcnr/ -bnB4/3Byef9ydHv/b3F5/3h7gv9vcnz/bG93/3Fzev9sb3n/dnh8/29xdf95e4H/d3l//3N1fP9zdn// -bnB3/2dqcf9tb3P/bG51/2xudf9sb3n/amxz/2ptd/9nanH/c3Z//2xvef9qbHP/bG94/21vdv9rbnb/ -bG95/2ptd/9qbXf/Z2p0/2xudf9sbnX/cnR7/29xeP9oa3T/bG95/2xvef9ucXv/bG95/3V4gf9zdn// -amxz/25xe/91d33/bnB3/21vc/9qbXf/cHJ5/3d5f/9wcnn/d3l//2xvef91d33/Z2p0/25xe/9sb3n/ -bG95/3Byef9tb3P/bW9z/3Bzff9sbnX/Z2p0/2BjbP9nanT/Z2p0/2Zpc/9sb3n/bnF7/2dqdP9nanT/ -YmVu/25wd/9maXP/ZGZs/2Rncf9sb3n/Zmhu/2ptd/9kZ3H/YmVu/2Zpc/9ucHf/Z2p0/2BjbP9sb3n/ -YmVu/2Rncf9qbXf/Zmlz/2psc/9qbXf/Zmlz/2Rncf9iZW7/am13/2dqdP9zdn//amxz/2psc/9nanT/ -am13/2xudf9nanH/dXd9/2xudf9tb3P/bnB3/3Byef94eX3/d3l//2ptd/9ucXv/eXuB/3V4gf93eoP/ -dXiB/3N1fP95e4H/cHN9/3Bzff93eoP/cHJ5/3V4gf91eIH/c3Z//25wd/9qbXf/cHN9/3V3ff9vcXX/ -c3Z//3V4gf9ucHf/c3Z//25wd/9wc33/Z2p0/3N2f/9wc33/cHN9/2ptd/9wc33/dXiB/2ptd/9wc33/ -bnF7/3Z4fP9wcnn/cHJ5/3l7gf93eX//e32D/29xdf91d33/dXd9/3N1fP9sb3n/Z2p0/3V3ff91d33/ -bnB3/2xvef9sbnX/bnB3/25wd/91d33/bW9z/2xudf9tb3P/bW9z/2ptd/91d33/bG51/3N1fP91d33/ -bnB3/25wd/9ucHf/bnF7/3Bzff9ucHf/bnB3/2xvef9wc33/bnB3/2dqdP9sb3n/bnB3/3N1fP91d33/ -bnB3/21vc/9wcnn/bG51/2xvef9qbXf/dnh8/3h5ff91d33/bG51/25wd/9ucHf/am13/2xudf9nanT/ -c3V8/2xvef91d33/dXd9/2xudf9sb3n/c3V8/2dqdP9ucXv/Zmlz/2xvef9wcnn/d3l//3Bzff9wc3v/ -bXB5/3J1fv9qbXf/bnF7/2ptd/9zdXz/bG51/25wd/9zdXz/bnF7/2ptd/9ucXv/cHJ5/3d5f/9ucXv/ -cHN9/3V4gf9ucXv/bnF7/25wd/9vcnz/bXB6/21wev9oa3X/bXB6/3R2fP9ucHX/eHqA/29xef9sb3n/ -bG95/2dqdP9qbXf/Z2p0/2Zpc/9ydHz/bXB4/2lsc/9tb3j/a253/3V3ff9ucHf/d3qD/3V4gf91d33/ -dXd9/29xdf9maG7/bnB3/21vc/9sbnX/bnF7/2xudf9wcnn/bW9z/3V4gf9wc33/amxz/2ptd/9qbXb/ -bnB3/29xeP9qbXf/bnB3/2dqcf9sbnX/bG51/21wev9rbnf/Z2p0/2psc/9sb3n/cHJ5/2psc/91d33/ -dXd9/2psc/9sb3n/c3V8/3Byef9sb3n/bnB3/3V3ff94eX3/bnF7/3l8hv9zdXz/e32D/2xvef9zdn// -d3qD/3N2f/93eoP/dXd9/3N2f/9+gIb/cHN9/3N1fP9sb3n/cHN9/3N2f/9zdn//d3qD/3t9g/95fIb/ -d3qD/3Bzff97fof/eXyG/3V4gf9zdXz/dXiB/25wd/9wcnn/bnB3/3Byef91d33/d3qD/3d5f/9sb3n/ -d3l//25wd/9ucXv/d3qD/3V4gf91eIH/d3qD/3V4gf91eIH/dXd9/3t9g/93eoP/foGK/3Byef9ucXv/ -bnB3/25xe/9wcnn/c3V8/3t+h/9wc33/cHJ5/25xe/9wc33/d3l//3h5ff9qbXf/cHJ5/3d6g/9wcnn/ -dnh8/3N1fP9sbnX/dnh8/29xdf9ucHf/cHJ5/21vc/9zdXz/c3V8/3N1fP9tb3P/bG51/3N2f/9ucXv/ -bG51/2xvef9wc33/Zmlz/2xvef9nanH/Zmlz/2BjbP9qbXf/Z2p0/2ptd/9iZW7/am13/25xe/9qbXf/ -bnF7/25wd/91d33/bnF7/2xvef93eoP/eXuB/36Ahv9wcnn/c3Z//3l7gf93eoP/c3Z//25xe/9+gIb/ -foGK/3l7gf97fYP/d3l//3t9g/93eoP/foGK/3V4gf93eoP/c3Z//3V4gf9zdn//eXyG/3N2f/95e4H/ -e32D/3N1fP9wcnn/cHJ5/25xe/9zdn//c3V8/25wd/9ucHf/c3Z//3Byef9qbXf/b3F1/29xdf9wc33/ -dXiB/3Bzff9wcnn/bG95/25wd/9zdXz/bG51/3V3ff92eHz/dXd9/25wd/9sb3n/bnF7/2xvef9ucHf/ -cHJ5/3h5ff9wcnn/foCG/3t9g/9tb3P/cHJ5/3Z4fP9ucHf/dXd9/2ptd/9ucHf/c3Z//3V4gf92eHz/ -c3V7/21wd/9wcnr/am13/3N1fP9sbnX/bnF7/2ptd/9sbnX/cHN9/25xe/9qbHP/bnB3/29xdf91d33/ -bG95/25xe/9wcnn/bG95/21vc/9ucHf/bG95/25wd/91d33/amxz/25xe/9zdn//c3V8/36Biv93eoP/ -c3Z//3d6g/91d33/cHN9/3d6g/91d33/foCJ/2Zpcv9jZnD/bnB3/2ptdv9vcnz/amxz/3d5f/93eX// -c3V8/3V3ff9ucHf/ZGZs/2xvef9sb3n/cHN9/3N2f/9vcXX/cHN9/25wd/93eoP/dXiB/25xe/9ucXv/ -bXB6/3Byef9vcXr/bnB3/2xvef9nanT/cHJ5/25weP90d37/c3V6/25weP9ucXr/c3Z//25xe/9maXP/ -c3V8/3V3ff9nanH/bnB3/3N1fP9zdXz/bnB3/21vc/9zdXz/d3l//25xe/9zdn//bG51/3Bzff9kZmz/ -bG51/2xvef9sbnX/c3V8/29xdf9sb3n/c3Z//25wd/9qbXf/Z2p0/3Byef9ucHf/bG51/3Bzff9zdn// -cHN9/2xvef9sb3n/dXd9/3V4gf9zdn//cHJ5/3V4gf9ucXv/cHN9/3Bzff9ucHf/c3Z//3d5f/91d33/ -Z2px/3Z4fP9sbnX/bG51/3Bzff9ucHf/bW9z/25wd/9sbnX/bnF7/2xudf9wc33/cHJ5/3V3ff9nanT/ -bG51/2dqdP9nanT/am13/2xudf93eoP/bG51/2xudf9wcnn/cHJ5/3d6g/93eX//bnB3/25wd/93eoP/ -cHN9/3d5f/9zdn//am13/3V3ff9ucHf/c3V8/3V3ff9tb3P/cHJ5/3N1fP91d33/bG51/2xudf9ucHf/ -dnh8/2xvef91eIH/cHN9/25wd/9zdXz/bnB3/2xvef9qbXf/dXiB/3N1fP9zdn//bnB3/3N2f/9zdn// -cHJ5/3V4gf93eoP/c3Z//3N2f/9zdn//e36H/3l7gf9/gYf/bnB3/25xe/91d33/c3V8/21vc/9ucHf/ -dXd9/3d5f/9ucHf/bnB3/2xudf9sb3n/bnB3/3V4gf9qbXf/bnF7/25wd/9sbnX/bnB3/3V3ff9vcXX/ -dXd9/3V3ff9ucHf/bnB3/2xvef9wc33/cHN9/3Byef9wcnn/cHN9/3V4gf9zdn//bnF7/3N2f/91d33/ -eXyG/36Biv91eIH/dXiB/3N1fP9wc33/dXiB/25xe/9zdn//dXd9/3Bzff9ucHf/cHJ5/3Byef9qbXf/ -cHJ5/2ptd/91d33/bG95/36Ahv97fYP/bW9z/3Byef91d33/b3F1/3Bzff9sb3n/bG95/3V4gf95e4H/ -d3l//3d5gv9ucXv/cHN9/25wd/9zdn//c3V8/3Bzff9sb3n/bnB3/3Z4fP9zdn//am13/25xe/9ucHf/ -dXiB/25wd/9wc33/cHN9/3Byef9vcXX/bG51/25wd/9zdXz/dXd9/2psc/9wcnn/bnF7/2xudf91d33/ -c3V8/25wd/9ucXv/am13/2psc/9sbnX/bW9z/3V3ff9ucHf/aWxz/3Fzef9sbnX/c3V+/25wd/93eX// -d3l//3Bzff93eoP/bnF7/2Zpc/9wcnn/bnB3/3Bzff9zdn//bG95/3N2f/9ucXv/dXiB/3V4gf9wc33/ -cnV+/25weP9rbXX/bXB4/2hqcf9maXP/YGNs/2ptd/9qbXf/b3J7/25wd/9pa3P/amxz/2ptd/9wc33/ -Zmlz/3V3ff91d33/amxz/3Byef9zdXz/cHN9/3N2f/9wc33/eXyG/3l8hv91eIH/d3qD/25xe/9zdn// -ZGdx/25wd/9ucXv/bW9z/3Byef9sbnX/bG51/3N1fP9qbHP/Zmlz/2dqdP9sbnX/amxz/2Rncf9ucXv/ -am13/2xvef9nanH/YmVu/2ptd/9qbXf/Z2px/2Zpc/9nanT/amxz/2psc/9sb3n/Z2p0/25xe/9wc33/ -cHN9/2Zpc/93eX//Z2p0/2xudf9zdn//c3Z//2ptd/9wcnn/b3F1/3Byef9vcXX/cHJ5/25wd/91d33/ -Z2p0/2ptd/9qbHP/bG51/2xvef9sbnX/d3qD/2dqdP9sbnX/bnF7/2xvef93eX//bnF7/2xudf9nanT/ -c3V8/2ptd/9qbXf/bG95/2Zpc/9wcnn/am13/2xvef9wc33/amxz/2ptd/9sb3n/cHN9/2ptd/9tb3P/ -bG95/3Z4fP9ucHf/c3V8/25xe/9qbHP/bnF7/2xudf9sbnX/YGNs/2xvef9sb3n/bG95/2psc/9sbnX/ -am13/2xudf9zdXz/cHJ5/3Byef9wcnn/am13/3N1fP9wc33/eXyG/21vc/9ucHf/dXd9/2xvef9qbXf/ -bG51/3V3ff93eX//bG95/3Byef9ucHf/bG95/25wd/97fYP/b3F1/3Byef9wcnn/bG51/2xudf93eX// -am13/3Bzff9wc33/bW9z/2ptd/9nanT/am13/2xvef9sbnX/Z2p0/2xudf9nanT/amxz/11gav9sbnX/ -Z2px/2ptd/9zdXz/bG95/2xvef9qbHP/bG51/25xe/9nanT/dnh8/3N1fP9wc33/bnF7/3N2f/9zdn// -am13/3Bzff9zdXz/e32D/3V4gf+Fh43/f4KM/3N2f/93eoP/foCG/3N1fP95fIb/dnh8/3l7gf9+gIb/ -e36H/36Ahv95fIb/c3Z//3N2f/9sb3n/dXiB/2xvef9ucXv/bG95/3Byef91eIH/eXuB/2ptd/9ucXv/ -bnB3/3Bzff9wcnn/c3Z//3V4gf9sb3n/bG95/2xudf9sbnX/cHJ5/3V3ff9nanH/bnF7/3Bzff9ucXv/ -d3qD/3N2f/9ucXv/dXiB/3Byef9qbXf/b3F4/25wd/92eHz/cXR9/25wd/9vcnv/bG95/3N2f/9wcnn/ -d3qD/3d6g/9zdn//dXiB/3Bzff9nanT/bnB3/25xe/9zdn//cHN9/25wd/9zdn//cHJ5/3h5ff91d33/ -bG51/2xvef9tb3f/bnB4/29xev9rbnj/bnB3/2psc/9ucHf/b3F5/3J0ev9ucHb/Zmhv/2ptdP9sb3n/ -cHJ5/2dqcf93eX//c3V8/2dqcf9qbXf/cHJ5/25xe/9ucXv/cHN9/3t9g/95fIb/c3Z//3d6g/9zdn// -d3qD/2ptd/9zdXz/dXiB/3Bzff95fIb/dXd9/3V4gf9+gIb/cHN9/25xe/9qbXf/cHJ5/25wd/9sbnX/ -c3Z//3Bzff9wc33/bW9z/2ptd/9ucXv/bG95/2psc/9nanH/Z2px/2psc/9sbnX/bG95/2xudf9zdXz/ -dXd9/3N1fP9qbXf/dXiB/2dqdP9wcnn/c3V8/3N1fP9sbnX/am13/2xudf9sb3n/am13/2xvef9sb3n/ -dXd9/2ptd/9qbXf/Z2p0/2xudf9wcnn/b3F1/31+gf9vcXX/bW9z/3N2f/9wc33/dXiB/3N1fP9ucHf/ -cHN9/3d6g/9zdn//c3Z//3N2f/9sb3n/eXuB/25wd/9zdn//dXd9/25wd/9ucXv/dXiB/3l7gf9sb3n/ -bnB3/3N1fP9wcnn/Z2p0/2xvef9sb3n/bG51/25xe/9qbXf/bG95/2BjbP9sb3n/cHN9/2xvef9tb3P/ -bnB3/2xvef9qbXf/cHN9/25xe/9ucXv/bG95/25xe/91d33/c3V8/3t9g/9qbXf/bG95/3Z4fP9ucHf/ -bnB3/2psc/92eHz/dXd9/25xe/9ucXv/bnF7/3Byef9ucXv/f4GH/3Byef9wc33/c3Z//25xe/9ucXv/ -d3qD/2xvef9wc33/cHN9/25wd/9ucXv/bnF7/3V4gf91eIH/bnF7/25wd/9ucHf/cHJ5/21vc/9iZW7/ -amxz/2psc/9qbXf/cHN9/2dqdP9ucXv/amxz/2ptd/9qbXf/Z2p0/3Bzff9ucHf/cHJ5/21vc/9ucHf/ -bnB3/2Zpc/9nanT/Z2p0/3V3ff9ucHf/fX6B/3d5f/9sbnX/bG95/3h5ff9ucHf/cHN9/2xvef9ucHf/ -dnh8/3V3ff91d33/dXd9/29xdf9ucHf/bG51/3Byef9sbnX/bG95/2ptd/9sbnX/cHN9/3V3ff9maXP/ -bG95/2xudf9qbXf/amxz/2ptd/9sb3n/Zmhu/2psc/9maXP/amx0/2ptd/9sb3n/YmVu/2xvef9tcHn/ -bW92/3V3ff9xdH3/bXB6/3V3ff9vcXj/bXB5/3Fzev9ydHr/dXh//3J0fP9vcXn/b3J7/29xdv9wcnn/ -bW9z/3V3ff93eX//bnB3/3Byef9wcnn/ZGdx/2ptd/9maXP/bG95/25xe/9qbXf/c3V8/2xudf91d33/ -c3V8/25wd/9zdXz/bXB6/21wev9ucXn/bG95/2xvef9sbnX/bnB3/25xe/92eH3/c3V8/2ptdf9vcXb/ -c3V8/3N2f/9maXP/e36H/3N2f/9sb3n/bG95/25xe/9zdn//cHN9/3N2f/93eX//eXuB/3Bzff93eoP/ -cHN9/3d6g/9nanT/bnB3/3N2f/9wcnn/c3Z//25wd/9ucXv/d3l//25wd/9sbnX/Z2p0/3Byef9ucHf/ -am13/3V4gf91eIH/c3Z//25wd/9sb3n/c3V8/3N2f/9ucHf/bnB3/25xe/9ucHf/bnB3/3V4gf9wc33/ -c3Z//3V3ff91d33/bnB3/3l7gf9nanT/bnF7/3Bzff9zdXz/bG51/2xudf9sbnX/bnB3/2xudf9sbnX/ -bG95/3Z4fP9qbXf/bG95/2xvef9wcnn/d3qD/3N1fP9+gIb/c3V8/3N1fP93eoP/dXiB/3t+h/93eoP/ -c3Z//3N2f/9+gYr/eXyG/3N2f/91eIH/bG95/3V4gf9ucHf/dXd9/3V3ff9wcnn/bG95/3N1fP9wc33/ -Zmlz/2dqcf9qbXf/eHl9/2xvef9wc33/c3Z//25xe/9zdn//cHN9/3V4gf9sb3n/dXiB/3t9g/91eIH/ -dXd9/3l7gf95e4H/d3l//35/g/95e4H/d3qD/3d6g/95e4H/eXyG/3d6g/+DhYz/dXiB/3d6g/97fYP/ -d3qD/3Bzff9wcnn/eXyG/3t+h/9wc33/bnF7/25wd/9wc33/cHN9/3l8hv9vcXX/c3V8/25wd/9tb3P/ -bG51/3V3ff9sbnX/cHN9/3N2f/9ucHf/bnF7/2ptd/9wc33/cHN9/3Bzff9sb3n/bnF7/3Bzff9vcXX/ -ZGZs/29xdf9ucHf/cHJ5/3V3ff9ucHf/dXd9/2xudf9ucHf/bG95/2xudf9zdXz/bnF7/3Byef9sbnX/ -bG51/21vc/9sbnX/cHJ5/2dqcf94eX3/bG95/3t9g/91d33/am13/25xe/91d33/am13/2ptd/9sbnX/ -bW9z/3V3ff94eX3/dXd9/29yfP9ucHf/bnB3/2ptd/9ydHz/b3F1/3V3ff9ucHf/bnB3/3V3ff9zdXz/ -Z2px/3Byef9ucXv/dXiB/3Byef9zdn//dXiB/3Byef9sb3n/a254/3Byd/9vcXn/cHJ5/2ttc/9tb3j/ -bnF7/25xev91d37/cHN8/25weP90dn//cXN5/29yev9ydH3/bnB3/3V3fv9ydX7/b3J8/3F0fv9zdn// -dXiB/25xe/93eX//d3l//25xe/9zdXz/bW9z/2dqcf9ucHf/bG51/3V3ff9ucHf/am13/3N1fP9sbnX/ -cHN9/3N1fP9qbXf/cHJ5/2xudf9rbnf/amx0/2ttc/9kZ3H/Zmlz/2psc/9qbXf/bnF6/3F0fP9rbnf/ -bXB4/3R2fP9wc33/YGNs/3d6g/9ucXv/Zmlz/2psc/9qbHP/Z2p0/2dqdP9nanT/c3V8/25wd/9sb3n/ -cHJ5/2dqcf9wc33/Zmlz/2xudf9qbXf/amxz/2ptd/9qbXf/bG95/3N1fP9sbnX/bG51/2Zpc/9qbXf/ -bG51/2psc/91d33/cHN9/25xe/9qbXf/am13/3Bzff9zdXz/amxz/2psc/9nanH/Z2px/2Zpc/9ucXv/ -am13/3Bzff9zdXz/cHJ5/2psc/91d33/bnB3/25xe/91d33/dXd9/2xvef9sb3n/bG95/25xe/9qbXf/ -cHN9/3N2f/95e4H/bG95/3N2f/9wcnn/cHJ5/3d6g/9wc33/foCG/25wd/9vcXX/c3V8/2xudf92eHz/ -cHJ5/29xdf9sbnX/dXd9/25wd/9wcnn/bG95/2Zpc/9zdXz/bW9z/3Z4fP91d33/bW9z/25wd/91d33/ -dXd9/2xudf9ucHf/cHJ5/25wd/9qbHP/bG95/25xe/9sbnX/bnF7/2dqcf9nanT/YGNs/2xudf9sb3n/ -amxz/2psc/9qbXf/amxz/2psc/9sb3n/am13/2xvef9qbHP/cHN9/3N1fP9sb3n/eXuB/2dqcf9nanT/ -am13/2dqdP9maG7/Zmlz/3Byef9zdXz/bG95/2xvef9tb3P/am13/2ptd/9zdn//am13/2xvef9sb3n/ -bG51/21vc/91d33/am13/2xvef9zdXz/bG51/2xvef9maXP/bnF7/25xe/9ucXv/am13/2xudf9nanT/ -Zmhu/2BjbP9qbHP/am13/2ptd/9ucXv/bnB3/3V3ff9sbnX/bG51/25wd/9qbXf/c3V8/25wd/9ucXv/ -am13/2xvef9sb3n/am13/25xe/9qbXf/dXiB/3N2f/9/gYf/eXyG/3Bzff91eIH/d3l//25wd/9zdXz/ -bnB3/29xdf9zdXz/dnh8/3V3ff9wcnr/b3F4/3J0ev9tb3f/cXN6/2ttdP9ucXv/bG51/25wd/94eX3/ -cHJ5/2dqcf9zdXz/c3V8/3N1fP9ucHf/bnB3/3Z4fP9vcXb/bXB6/2xvef9wc3z/cXN7/3Fze/9xdHv/ -cHJ5/3R2fv92eH7/dHeB/3R3f/9xdHz/eXuA/3d5f/9ydX3/eXyF/3BzfP93eYD/dHd//3Bzff90dn3/ -cHJ5/25xe/9tcHn/dnh8/3V3gP9ucXr/bnF6/2xvef9rbnj/aWx2/2tueP90dnz/b3F4/25wdP90dnv/ -bW93/3J0fP9zdXz/bW92/3J0fP9qbXf/bG51/25wdf9ucHb/bG51/2psc/9sbnX/am13/2ptd/9ydHr/ -Z2pz/2ptd/9xc3n/bG95/2Jlbv99foH/c3V8/2xudf9tb3P/bG51/25wd/9ucHf/bnB3/3V3ff91d33/ -cHN9/3Byef9maG7/bG95/2Rncf9iZW7/Z2p0/2xudf9qbXf/Z2p0/2xudf9ucXv/amxz/2dqdP9nanT/ -am13/2dqcf9nanH/cHJ5/25xe/9sb3n/am13/2xudf9ucXv/c3V8/2xvef9qbXf/bnB3/29xdf9ucHf/ -c3V8/3Byef91d33/bG95/2xvef9nanT/dXd9/29xdf9wcnn/dXd9/3Bzff9qbXf/bG51/2xudf9sb3n/ -Zmlz/2ptd/9qbXf/cHJ5/2Rncf9qbHP/Z2p0/2ptd/9sb3n/bG95/3d6g/9nanH/Z2px/25xe/9qbHP/ -d3l//2xvef9qbHP/bG51/3N1fP9sb3n/bG95/25xe/9maXP/bG95/2dqcf9ucXv/bG95/2dqcf9nanT/ -bnF7/25xe/9maXP/bG51/2ptd/95e4H/cHJ5/3V4gf93eoP/cHJ5/3l7gf9wc33/bnF7/2dqdP9sb3n/ -c3V8/3Byef9ucHf/c3Z//25xe/9ucXv/cHN9/25xe/9ucXv/bG95/3h5ff94eX3/cHJ5/4CChv9sbnX/ -bG51/3N1fP9wcnn/bnB3/2xvef91d33/dnh8/3V3ff9wcnn/bG95/3Bzff9zdn//eXyG/3Byef9ucHf/ -bnB3/25wd/9vcXX/dnh8/25wd/9zdXz/cHJ5/2xudf9wcnn/amxz/3Bzff9zdn//dXd9/25wd/9ucHf/ -cHJ5/2psc/9kZ3H/bG51/2xvef9nanT/cHN9/2dqdP9sb3n/Z2p0/2xudf9qbHP/Z2p0/25xe/9qbXf/ -bnF7/2dqcf9qbXf/am13/2Zpc/9qbHP/ZGdx/2xvef9qbXf/c3Z//3N1fP9qbXf/am13/3N1fP9qbXf/ -bnF7/2ptd/9sbnX/bnF7/3Bzff9ucXv/am11/2xudf9xc3j/a211/3Fzev9tb3T/cHN9/2Zpc/9ucHf/ -dnh8/3Byef9rbXT/dHZ7/3Bzff90d4D/cHN9/2xvef9zdn//bnB3/25wd/9tcHr/cnV8/29xef9wcnr/ -cnR6/21vdv9wc3v/c3V7/3V3ff9wc33/bXB6/3N2fv90dnr/bnB1/3V3ff9tb3b/cXN6/3Byef9vcXn/ -cHJ5/3Byef9xc33/cHN8/3d5f/93eoL/cnV+/3BzfP9ucXr/bXB5/2tueP9tcHn/dnh+/3J0ff9vcnn/ -dHZ+/21wef9vcXr/b3J8/21vdv9ydX7/bG95/25wd/9tcHn/bW92/2dqdP9nanT/bnB3/25wd/9ucXv/ -dXd9/2ptdv9rbnf/bnF5/2xvef9iZW7/d3qD/2ptd/9qbXf/am13/2ptd/9qbXf/bG95/2ptd/9wcnn/ -bG95/2xvef9ucHf/Zmhu/2xvef9iZW7/ZGdx/2psc/9nanH/Zmlz/2Rncf9qbHP/bG95/2psc/9qbHP/ -Zmlz/2ptd/9qbHP/amxz/3Byef9qbHP/Z2p0/2psc/9iZW7/bG95/3Bzff9qbHP/amxz/2ptd/9sbnX/ -amxz/25xe/9ucHf/dXd9/29xdf9wcnn/Zmlz/3V3ff9sbnX/bnB3/3N1fP91d33/bnB3/3Byef9vcXX/ -bnB3/2psc/9sb3n/bnB3/3V4gf9qbHP/bG51/29xdf9sb3n/cHJ5/3Byef+Agob/bG51/2xudf9zdXz/ -bW9z/3Z4fP9zdXz/bnB3/25wd/94eX3/dXd9/3Byef9zdXz/bnB3/3V3ff9ucHf/dXd9/3Z4fP9vcXX/ -bG95/3V4gf93eoP/bnF7/2xvef91eIH/eXyG/25xe/93eoP/d3qD/3N1fP97fof/dXiB/3V4gf9ucXv/ -c3Z//3d6g/9zdn//cHN9/3N2f/9ucXv/bnF7/25xe/9sb3n/cHN9/25wd/94eX3/eHl9/3V3ff9/gYf/ -bG95/2xvef9wc33/bnF7/25wd/9sbnX/bnF7/25xe/9zdXz/cHJ5/25wd/9wcnn/bnB3/3t+h/9sb3n/ -bnF7/3V4gf9sb3n/bnB3/3d5f/9ucHf/dXiB/3N2f/9ucXv/cHN9/2ptd/9ucXv/c3V8/3V3ff9ucHf/ -cHJ5/25wd/9ucHf/bG51/2ptd/9ucXv/cHJ5/3V3ff9sb3n/bG95/2dqdP9qbHP/Zmhu/2Rncf9nanT/ -amxz/2Zpc/9cX2j/ZGZs/2Zobv9gY2z/amxz/2BjbP9nanT/am13/3V3ff9zdXz/am13/2xudf9sb3n/ -bG51/2xvef9sbnX/am13/3N1fP9zdXz/c3V8/3Byef94eoD/eHuC/3N1fP93eX7/cnR5/3R2ff9sbnX/ -dXd9/3d6g/9zdXz/bnB2/3N1ff91d33/dXd9/3N1fP9sbnX/cHJ5/21wev9wc33/b3J7/3R3fv9ucXr/ -b3J3/3N1ef9rbnf/bnF7/3J0fP9ydX7/bnF6/2tueP9wc3z/b3F6/2lsdP9wcnn/aWx2/21veP9rbnj/ -bG95/21veP9pa3T/amxz/25wdv9ucHf/b3F2/2hqc/9tb3b/bG92/29xef9nanT/bnB3/3J1ff9vcXr/ -b3F4/3J0fP9ydHv/c3V7/3N1fP9tb3T/dHZ8/2ttdv9tb3X/a253/2xudf9laHL/ZGdx/2xudf9qbXf/ -bG95/3V3ff9qbHP/a213/2xudP9ucXv/ZGdx/3t9g/9ucXv/Z2p0/2xudf9qbHP/bnF7/2ptd/9ucXv/ -d3l//3N1fP91d33/dnh8/2xudf9wcnn/Zmlz/2dqdP9sbnX/bnB3/3Byef9vcXX/cHJ5/3Z4fP9vcXX/ -bnB3/2xudf9ucHf/am13/2ptd/9zdXz/bG51/2ptd/9qbXf/Z2p0/3Byef94eX3/b3F1/2xudf9sbnX/ -bW9z/2xudf9wcnn/bnF7/3V3ff9sb3n/cHJ5/2psc/93eX//bW9z/25wd/9wcnn/dXd9/25wd/9wc33/ -bnF7/25xe/9qbXf/c3V8/3N2f/95fIb/bG95/3Bzff9zdXz/bnF7/3N2f/9zdn//gYSN/3N1fP9ucHf/ -c3Z//25wd/91eIH/cHN9/25xe/9ucHf/d3l//3d6g/93eoP/eXuB/3Byef9zdn//c3V8/3l7gf95e4H/ -c3Z//3Bzff95e4H/eXuB/25wd/9ucXv/d3l//3t+h/9zdXz/e32D/3N2f/9sb3n/dnh8/25wd/9zdXz/ -Zmhu/2xudf9wcnn/cHJ5/25wd/9wcnn/bG51/2xudf9qbXf/bG51/3Byef9ucHf/dXd9/3V3ff9zdXz/ -f4GH/29xdf9zdXz/cHJ5/25wd/9vcXX/bnB3/3Bzff9wc33/c3Z//3N2f/9ucXv/c3Z//3N2f/9+gYr/ -c3Z//3N2f/93eoP/d3l//3V3ff9/gYf/dXd9/36Ahv99foH/dXiB/36Ahv9ucXv/d3qD/3l7gf95e4H/ -dXiB/3d6g/9zdn//dXiB/25xe/9wc33/dXiB/3V4gf9zdn//bG95/3N1fP9ucHf/bnF7/2xvef9ucHf/ -cHJ5/2xudf9wcnn/Z2px/25wd/9tb3P/Z2p0/25wd/9nanT/cHN9/3N2f/91eIH/d3l//25xe/9sb3n/ -c3Z//25xe/91d33/bG51/29xdf91d33/dXd9/3N1fP9oa3T/cXR8/3N1ev9tcHn/b3J8/29xd/9zdXz/ -am13/3V3ff91d33/cHJ5/2xudv9ydHv/cXN6/3J0e/9wcnn/am13/25xe/9rbXP/bW92/21veP9vcnr/ -bXB6/21weP9ucHX/bG93/3Fze/9zdn7/dnmA/3N2f/9xdH7/d3l//3FzfP9tb3b/c3V6/25wef9xc3j/ -b3J3/25xef9zdn3/bG94/29xef91d3z/cXN4/3Bydv9qbXb/bXB6/21vd/9ydHv/Z2p0/2ttdP9ucHb/ -bG51/2hrc/9qbXb/a253/3J1ff9wc33/a210/3R2ff9nanT/aGty/2psc/9sbnX/ZGdx/2Zpc/9sbnX/ -Z2p0/2xvef9wc33/Zmlz/2xvef9qbXf/bnF7/2Jlbv93eoP/bnF7/2Zpc/9nanH/amxz/3Bzff9sbnX/ -bnF7/3V3ff9ucXv/bG95/3Byef9qbHP/am13/2Zpc/9kZ3H/Z2px/2dqcf9qbHP/bG51/2dqdP9ucXv/ -Z2px/2dqcf9maXP/Z2p0/2psc/9nanT/c3V8/2dqdP9qbXf/am13/2Zpc/9qbHP/am13/2dqcf9nanT/ -Z2p0/2Zobv9maXP/Z2p0/2ptd/9wc33/am13/2xudf9iZW7/c3V8/2Zpc/9ucXv/bnF7/3Bzff9sbnX/ -cHJ5/2xvef9qbXf/am13/2xudf9sbnX/d3l//2dqdP9sbnX/bG51/2dqdP9qbXf/am13/3t9g/9kZ3H/ -Zmlz/3Byef9qbHP/c3Z//2xvef9ucHf/bG51/3Z4fP9zdXz/dXd9/3V3ff9vcXX/cHJ5/2xvef9zdn// -c3Z//2xvef9qbXf/dXiB/3d5f/9ucHf/cHJ5/3l7gf91eIH/amxz/2xvef9sb3n/amxz/3Bzff9qbHP/ -bG95/2BjbP9sbnX/cHJ5/2xudf9ucHf/cHJ5/2ptd/9qbHP/am13/2ptd/9ucHf/bnB3/3N1fP9wc33/ -cHN9/4GDiv9ucHf/c3Z//25xe/9vcXX/b3F1/2ptd/9wcnn/cHJ5/3V3ff91d33/b3F1/2xudf9qbXf/ -d3qD/2ptd/9sb3n/bnF7/21vc/9sbnX/bnF7/2psc/9sb3n/bnF7/2xudf9wc33/XWBq/2xvef9ucXv/ -bnF7/2Zpc/9qbXf/bG51/2xvef9kZ3H/amxz/2ptd/9sb3n/bnF7/25wd/91d33/bnB3/25xe/9wc33/ -bnB3/3Bzff9zdn//d3qD/2xvef95fIb/dXd9/25xe/9zdn//cHN9/3l8hv93eoP/f4KM/3+Bh/97fYP/ -dXiB/3l8hv93eoP/eXyG/3N2f/9wcnn/dXiB/3l7gf9wc33/bnB3/3R2fv93eYH/c3V+/3R2fv9vcnn/ -cHN9/2ptd/91eIH/d3qD/3V4gf9wcnn/b3J8/29yfP9wcnn/cHJ5/21vc/9zdXz/b3F1/2xvef9tb3n/ -cHN7/3J0ff9wc3z/Z2p0/29xef9zdn//bnF7/3d4ff9zdn//cHJ5/3Z4fv9xc3f/am10/2xvef9ucHf/ -a254/21wev9wcnb/dXd9/25xev9vcnz/dnh//3Fzev9zdX3/Z2p0/25xe/9sb3n/dnh+/2hrdP9ucHf/ -bXB5/25xe/9sb3n/cHN9/3N2f/94e4X/c3Z//29xdf91d33/c3V8/2xudf9qbXf/bG95/2Zpc/9maXP/ -bG51/25wd/9wcnn/dXd9/2psc/9ucHf/bG95/3V3ff9maXP/f4GH/3V4gf9wcnn/cHN9/3Bzff93eX// -c3Z//3V4gf97fof/eXuB/3t9g/97fYP/d3qD/3l8hv9zdn//cHN9/3N1fP9zdXz/bnF7/25xe/9ucXv/ -dnh8/25wd/9wcnn/bG95/3N1fP9sbnX/Z2p0/3N1fP9kZ3H/Z2p0/2psc/9kZ3H/am13/2xvef9sbnX/ -bnF7/3Bzff9sbnX/Z2p0/2ptd/9ucXv/c3V8/25wd/9qbXf/ZGdx/3N1fP9nanT/bG95/25xe/9wc33/ -bG95/25xe/9qbXf/bnF7/2ptd/9ucHf/b3F1/3d5f/9maG7/b3F1/2xudf9nanT/bnB3/2xvef9/gYf/ -bG95/25xe/93eoP/cHJ5/3t+h/9wc33/cHN9/25wd/91eIH/dXd9/3N2f/9wc33/cHJ5/3V4gf9zdn// -d3l//3V3ff9vcXX/bG51/3V3ff9zdXz/bG51/2psc/9wc33/foGK/3N1fP93eoP/c3Z//25wd/91d33/ -bnB3/25wd/9kZ3H/bnB3/3N2f/9sb3n/bnB3/3Byef9ucHf/bG95/25wd/9sb3n/bnB3/25wd/9sb3n/ -cHN9/2xvef9/gYf/cHJ5/3Byef9ucHf/bnB3/3Byef9sb3n/dXiB/3N2f/93eoP/eXuB/3Bzff91eIH/ -c3Z//3+Bh/9zdn//d3qD/31+gf9zdn//c3Z//3l8hv9zdn//e32D/3V4gf9zdXz/eXuB/2Zpc/93eX// -c3Z//3Z4fP9ucHf/bnB3/25wd/9wcnn/am13/25wd/9wcnn/bG51/25xe/9qbXf/bnF7/2xudf9qbXf/ -amxz/2Zpc/9sb3n/am13/25xe/9maXP/bG95/2xudf9iZW7/bG51/2dqdP9sb3n/cHJ5/3d5f/93eX// -am13/2ptd/9qbXf/am13/25xe/9sbnX/Z2p0/25xe/9wc33/cHN9/25vdf9qbHX/bG51/2ptdv9rbnj/ -Z2pz/2dqdP9kZ3H/am13/3N1fP9sb3n/Zmlz/2psc/9maXP/am13/2Zpc/9qbHP/am13/2psc/9sbnX/ -Z2p0/21vdv9tcHr/bG95/15ha/9nanH/a210/2ttdP9wcnn/dHZ9/2ptd/9sb3n/aGty/2dqdP9oa3T/ -amxz/2ptd/9wcnn/bW9z/3Z4fP9qbXf/bnB3/3Z4fP9sbnX/am13/2Rncf9qbXf/am13/3d5f/9nanH/ -bG51/2xudf9ucHf/bG95/25wd/9ucHf/dXiB/25xe/9sbnX/dXd9/25xe/9tb3P/cHJ5/25wd/9nanH/ -amxz/29xdf9ucHf/cHJ5/3N1fP9qbXf/am13/2ptd/9sb3n/YmVu/36Ahv9sb3n/Z2p0/2dqdP9qbXf/ -cHN9/2ptd/9sb3n/dXd9/3V3ff9wcnn/c3V8/3Byef9ucXv/bG95/2ptd/9ucHf/bG95/25xe/9sb3n/ -bG95/3V3ff9ucHf/bG95/25wd/93eX//bnB3/25wd/97fYP/amxz/25wd/9ucHf/bG51/25wd/9sb3n/ -bW9z/2xvef9ucXv/Z2p0/2Jlbv9nanH/am13/3Bzff9qbXf/am13/2Rncf9wc33/amxz/2xudf9ucHf/ -c3V8/2xvef9ucXv/am13/3Bzff9nanT/bG51/21vc/92eHz/Zmhu/2xudf9tb3P/bG51/29xdf9zdXz/ -f4KM/25xe/9nanT/d3qD/2xvef93eX//cHJ5/2xvef9ucHf/dXiB/3h5ff9zdn//c3Z//3Byef9zdn// -dXiB/3t9g/95fIb/cHJ5/3Bzff97fYP/fn+D/3Z4fP9wc33/e32D/3t+h/9wc33/dXiB/3Bzff9ucXv/ -dXiB/25wd/9wc33/Z2p0/25wd/9wc33/bnB3/2xvef9sb3n/bnB3/2ptd/9qbXf/bnF7/25wd/9sbnX/ -bG51/3N1fP9wcnn/f4GH/3Byef9wcnn/bnB3/2ptd/9qbXf/Zmlz/2xvef9ucXv/am13/3N1fP9qbHP/ -Z2p0/2dqcf91eIH/am13/2ptd/9wcnn/bW9z/21vc/9wcnn/bW9z/3Byef9sbnX/bG51/3N1fP9iZW7/ -c3V8/25xe/9zdXz/bG51/2xvef9sbnX/cHJ5/2xudf9ucHf/c3V8/25wd/9wcnn/cHJ5/3N1fP9tb3P/ -bnB3/2ptd/9qbXf/c3V8/25xe/9ucXv/am13/2xvef9ucHf/ZGZs/25wd/9sbnX/cHJ5/3V3ff97fYP/ -eHl9/25wd/9ucHf/bnB3/3Byef9wc33/bW9z/2psc/9zdXz/dXd9/3N1fP9ydHr/Zmlz/2ptd/9oa3X/ -b3J8/2xvef9ucHf/bnB3/3V3ff93eX//dXd9/25wd/9ucHf/bnF7/3N2f/9ucXv/bnF7/3N2f/9ucHf/ -bG95/2xvef9vcXX/dXd9/3Byef9kZmz/bW9z/25wd/9ucXv/d3l//3d6g/9wc33/dXiB/3N1fP9wcnn/ -bG95/3Byef9sbnX/cHJ5/25wd/9zdn//bnB3/25xe/95e4H/bG95/25wd/9qbXf/b3F1/29xdf94eX3/ -bnB3/25wd/9ucHf/b3F1/3Byef9sb3n/cHJ5/3d5f/9zdXz/bG51/3N1fP9ucXv/bG51/3N1fP9sbnX/ -Z2p0/2dqdP9sb3n/bnB3/25xe/9wc33/amxz/29xdf9wcnn/c3V8/2Jlbv9/gYf/bnB3/21vc/9sbnX/ -bG95/3d5f/9wc33/dXiB/3l7gf93eX//c3Z//3V4gf9ucXv/bnF7/25wd/9maXP/bnB3/25xe/9ucXv/ -cHJ5/2xvef91d33/b3F1/2xudf9ucHf/dnh8/25wd/9sbnX/dXiB/2psc/9sb3n/bG51/2dqdP9qbXf/ -am13/2psc/9sb3n/bnF7/2ptd/9qbXf/bnF7/25xe/91d33/am13/2ptd/9kZ3H/c3V8/2ptd/9qbHP/ -am13/25xe/9qbXf/am13/2psc/9sb3n/ZGdx/2xudf9nanT/cHN9/2Rncf9nanT/bG51/2dqdP9qbXf/ -bnF7/36Ahv9qbXf/Z2p0/3N2f/9sbnX/dXd9/2xvef9qbXf/bW9z/3d5f/93eX//dXd9/3Byef9ucHf/ -cHN9/3N2f/93eX//dXd9/2xvef9qbXf/dXd9/3V3ff9sb3n/b3F1/3Z4fP93eX//bnB3/3N2f/9ucXv/ -bnB3/3Bzff9sb3n/bnF7/2Zpc/9sb3n/cHN9/25wd/9wc33/bnB3/2xudf9ucHf/bnB3/3V3ff9wcnn/ -bW9z/25wd/9zdXz/c3V8/3+Bh/91d33/cHJ5/3N2f/9vcXX/bW9z/2psc/9wcnn/c3V8/3Byef92eHz/ -bnB3/2ptd/9sbnX/c3Z//2ptd/9sb3n/bnF7/2ptd/9qbHP/c3V8/21vc/9zdXz/bnB3/3Bzff91d33/ -Zmhu/3Bzff9wc33/eHl9/25wd/9wcnn/b3F1/3Byef9sbnX/bnB3/3Byef9ucHf/bnF7/25xe/95e4H/ -c3V8/3Bzff9wc33/Z2p0/3Bzff9zdXz/cHJ5/2xudf9wcnn/am13/2Jlbv9qbXf/Z2p0/2xvef9wc33/ -c3Z//3N1fP9sbnX/bG95/21vc/9ucXv/bnF7/2dqdP9kZ3H/bnF7/3Bzff9ucXv/cnR7/2Rncf9qbHP/ -am13/3Bzff9sb3n/bnB3/2psc/9zdXz/dXd9/3N1fP9qbXf/bG51/25wd/92eHz/cHJ5/3Byef9zdXz/ -b3F1/25wd/9nanT/bW9z/25wd/9sb3n/ZGdx/2ptd/9qbXf/am13/25xe/93eX//cHJ5/3N1fP9wcnn/ -bW9z/21vc/9ucHf/bG51/2Zpc/9nanH/bG95/2dqcf9maXP/bnF7/2psc/9maXP/am13/2xudf9sbnX/ -c3V8/2psc/9nanT/a253/2xudf9wc33/a254/3Byef91eID/bG95/2xvef91d33/cHJ5/2ptd/9ucXv/ -bG95/2hrdf9qbXf/bG51/2xudf9qbXf/Z2p0/2Rncf9nanH/a254/2xvef9gY2z/gIKG/2xudf9tb3P/ -bG51/29xdf91d33/cHJ5/3V3ff91d33/c3Z//3Bzff91d33/cHN9/3Bzff9wcnn/am13/25wd/9zdn// -cHN9/3V4gf93eoP/d3l//2ptd/9ucHf/bnB3/3Z4fP9qbHP/bW9z/3Z4fP9sbnX/bnB3/3Byef9qbHP/ -bnB3/2ptd/9sbnX/bnB3/3N1fP9ucHf/bG51/3N1fP9wcnn/dnh8/3Byef9ucHf/bG51/3N1fP9ucHf/ -bnB3/25xe/9zdn//c3Z//3Bzff9wc33/d3qD/25xe/91eIH/cHN9/3l8hv9zdXz/dXd9/3l7gf92eHz/ -eXuB/3t9g/+FiJH/d3qD/3Bzff9/gYf/dXiB/3t+h/91eIH/d3qD/3V4gf9+gYr/e32D/3d6g/9zdn// -c3V8/3N2f/9zdn//dnh8/3V4gf9sb3n/bG95/3Z4fP91d33/bG51/21vc/9wcnn/d3l//25xe/91d33/ -cHJ5/25wd/9ucXv/bnB3/3Byef9nanH/cHN9/3V4gf9wcnn/bnF7/25xe/9ucHf/cHJ5/25xe/91eIH/ -cHN9/3Byef9ucXv/c3Z//3N2f/9+gIb/dnh8/3Bzff9wc33/b3F1/25wd/9qbXf/c3V8/3V3ff9wcnn/ -eHl9/25wd/9ucHf/bW9z/3V4gf9ucXv/cHJ5/3N2f/9wcnn/c3V8/3V4gf9wcnn/c3Z//25xe/9wc33/ -dnh8/2ZobP9zdXz/c3V8/3Z4fP9vcXX/c3V8/2xudf9ucHf/bW9z/2xudf9wcnn/bG51/2xvef9qbXf/ -c3V8/2Zobv9sb3n/bG51/2Zpc/9qbXf/am13/2ptd/9nanT/am13/2xvef9kZ3H/bG95/2dqdP9ucXv/ -bnF7/3V3ff94eX3/bG95/3N2f/9sb3n/cHN9/3Bzff9ucHf/Z2p0/3V3ff91d33/dXd9/3h5ff9sbnX/ -bnB3/2xvef91d33/c3Z//2xvef9qbXf/c3Z//3l7gf91eIH/bnB3/3Byef9wc33/d3l//3Byef9wcnn/ -cHJ5/21vc/9sbnX/amxz/2xudf9sbnX/bG51/2Zobv9wcnn/bG51/25xe/9ucXv/c3V8/3J0e/9sb3n/ -bnB3/2xudf9ucHT/bG51/2Zpc/9vcXj/bG51/21vdv9tb3b/bW93/3R2ff9rbnf/aGt1/2dqdP9sbnX/ -am13/3Fzev9qbHP/a253/2xveP9qbHP/bG95/2xveP9wcnj/dHZ7/21vdf9ydXz/dXd9/3J0ff9sb3n/ -b3J8/3N1fP9vcXj/b3F4/21vc/9qbXf/bG95/3Byef9ucHf/b3F1/29xeP9zdXz/Z2px/4GDiv9sb3n/ -bnF7/3Byef9wcnn/dXiB/3N2f/93eoP/e32D/3V4gf9wc33/c3Z//3V3ff9ucHf/b3F1/2psc/9ucHf/ -bnF7/25wd/9zdn//c3V8/3Z4fP9qbHP/bG51/21vc/92eHz/bG51/29xdf92eHz/amxz/2xudf9wc33/ -Zmlz/3Byef9qbXf/bnB3/25wd/92eHz/b3F1/25wd/9zdXz/c3V8/3V3ff9wc33/am13/2dqcf9wcnn/ -bW9z/29xdf9sbnX/cHJ5/2xvef9wcnn/bG51/2xvef9maXP/cHJ5/25wd/94eX3/Zmhu/2xudf9sb3n/ -Z2p0/2ptd/9sb3n/foCG/25xe/9sbnX/eXuB/2xvef93eX//bG51/25wd/9tb3P/dXd9/3N1fP91d33/ -bG51/2psc/9zdXz/c3V8/3N1fP9sb3n/amxz/2ptd/92eHz/c3V8/29xdf9ucHf/cHN9/3d6g/9ucXv/ -d3l//3Bzff9zdXz/cHN9/3Byef9wc33/am13/3Bzff95e4H/dXd9/3V4gf9wc33/cHN9/3V3ff91eIH/ -eXuB/3N1fP9zdXz/cHN9/3d6g/95e4H/g4WM/3l8hv91eIH/d3qD/3Bzff9zdn//c3V8/3N2f/91eIH/ -bnB3/3d5f/9sb3n/bnB3/25wd/93eX//bG95/25wd/9wc33/bnB3/25wd/9wc33/bnB3/3Bzff9ucXv/ -dXiB/3V4gf9nanH/cHN9/3N2f/95e4H/cHJ5/3N2f/9wcnn/cHN9/3N1fP9wcnn/dXiB/25xe/93eoP/ -bnF7/3V4gf9ucHf/c3Z//3Bzff9qbXf/c3V8/3Bzff91eIH/bG95/2xvef9zdn//bG95/2xvef9qbXf/ -cHN9/3Byef91eIH/d3l//2xvef9zdn//bnB3/3N2f/9wc33/cHJ5/2ptd/9zdXz/cHJ5/3V3ff92eHz/ -Z2p0/2ptd/9qbXf/cHN9/2ptd/9sbnX/amxz/3Byef91d33/c3V8/2dqdP9tb3P/bnF7/3V4gf9wc33/ -cHN9/3d6g/9zdXz/bnF7/25xe/9xc3r/dXiA/3N1fP9tcHr/c3Z//3Z4fv94e4T/enyC/31/hv94eoD/ -dHeA/3Bzff9ucXv/cHN6/29xef9tcHn/cnR7/25wd/9vcXX/aWx1/2ttdv9wcnn/b3F3/21vdv9sbnb/ -bW92/21wdv9xc3n/bG50/21vdP9wcnj/bW91/25xef9xdHz/cXR9/3Fzev9vcXj/b3F4/3Z4gP9wc3v/ -bG95/29yfP9ydHz/cXN7/21wev9ucHf/bnF7/3Byef9wc33/bnB3/25wd/9xc3r/cHJ5/2Zobv+Agob/ -bG51/2xudf9sbnX/bG51/3N1fP9wcnn/eHl9/3V3ff91d33/c3V8/3Bzff9zdXz/amxz/2psc/9nanT/ -Z2px/2xudf9sbnX/cHN9/2xudf9wc33/Z2p0/2psc/9sbnX/dXd9/2ptd/9qbHP/c3V8/2ptd/9qbXf/ -cHN9/2dqdP9ucXv/bnB3/3N1fP9ucHf/dXd9/25wd/9sb3n/c3Z//3N2f/93eX//dXiB/25xe/9sb3n/ -c3Z//25wd/9wcnn/c3V8/3N2f/9ucXv/c3Z//2xvef9zdXz/Z2px/3Byef9sbnX/cHN9/2Rncf9qbHP/ -bnF7/2dqcf9qbXf/am13/3V4gf9maXP/ZGdx/3N1fP9nanT/cHJ5/2psc/9nanT/Z2px/3V3ff9zdXz/ -bnF7/2ptd/9qbXf/cHN9/3N1fP9zdXz/c3V8/25wd/9ucHf/d3qD/3N2f/9ucHf/bG95/3Bzff95e4H/ -bG95/3V3ff9sb3n/bnB3/25xe/9sb3n/bnB3/2dqcf9vcXX/c3V8/2ptd/9ucHf/bG51/2ptd/9nanT/ -bG51/3N1fP9sbnX/bW9z/2xudf9zdXz/dXd9/31+gf9zdXz/bG95/2xvef9sbnX/bG51/2ptd/9ucHf/ -c3V8/2xvef91d33/bnB3/3Byef9sb3n/dXiB/2xvef9sb3n/bnF7/25xe/9ucHf/cHJ5/25wd/9ucXv/ -bnF7/3V3ff93eoP/ZGdx/3N2f/93eoP/d3qD/25wd/9zdn//bnF7/25xe/9wcnn/bnB3/3Bzff9sbnX/ -c3V8/25wd/91d33/am13/3Bzff9sbnX/amxz/25wd/9sb3n/bnF7/2ptd/9qbXf/dXd9/2xudf9sbnX/ -Zmlz/2xvef9sb3n/dXd9/3N1fP9qbXf/bnF7/21vc/9zdXz/cHJ5/25xe/9sb3n/c3Z//3Bzff93eX// -eHqA/2hrdf9ucHf/a254/3N2f/9ucHf/bnB3/25wd/9wcnn/eXuB/3V3ff9sbnX/bG51/21vdv91d3z/ -am13/2psc/9ucXv/amxz/2dqcf9nanT/Z2pz/2dqc/9maHL/YmRt/2Zobv9pbHb/bG53/25wef9wcnr/ -cHJ5/2tueP9tb3f/bG51/3Fzev9sb3f/bG95/21wev9vcnr/bG53/2xudf9rbnX/b3J6/25wef9ucXn/ -am13/2tueP9ydHv/cHJ6/25wd/9ucXn/dHZ9/29xdv9wcnr/dHZ9/3BzeP9ucHf/bnB4/29xef93eYD/ -bnF2/25wd/9xc3v/cXN4/3N1e/9xc3r/cXN6/3N2f/9wc33/d3qD/3Byef9wcnn/cXR9/3Bzff9nanT/ -f4KM/3Bzff9ucHf/b3F1/21vc/9zdXz/bnB3/3V3ff93eX//cHN9/25xe/9wc33/dXd9/29xdf9ucHf/ -bnB3/25wd/9vcXX/cHN9/3N2f/9ucXv/dXiB/2xvef9ucXv/bnF7/3l7gf91d33/d3l//35/g/94eX3/ -eXuB/36Ahv96e3//f4GH/3l8hv9+gYr/eXyG/4CChv97fYP/dXd9/3l8hv99foH/fn+D/35/g/93eX// -cHN9/3t9g/9wc33/c3V8/3Byef9wc33/b3F1/3Z4fP9qbXf/bG95/2Jlbv9qbXf/am13/2ptd/9gY2z/ -Zmlz/2xvef9kZ3H/Zmlz/2xvef93eoP/am13/2Rncf9wc33/ZGdx/2ptd/9maG7/Z2px/2Zobv9zdXz/ -d3qD/3Bzff9sb3n/amxz/3Byef9zdXz/dnh8/3N1fP9sbnX/bG51/3h5ff9wcnn/bnB3/25wd/9zdXz/ -d3l//25wd/91d33/bnB3/21vc/9wcnn/bnB3/2xvef9maXP/bnB3/3Byef9sbnX/bnB3/25wd/9wcnn/ -amxz/25wd/92eHz/bnB3/29xdf9wcnn/cHJ5/3Z4fP9+gIb/c3V8/3Byef9sb3n/bG51/2ptd/9maXP/ -am13/2xvef9ucXv/cHJ5/2dqcf9nanT/Z2px/3Byef9kZ3H/YGNs/2Zobv9kZ3H/Zmhu/2Zpc/9maG7/ -Zmlz/2Zobv9sb3n/c3V8/1lcZf9maXP/Zmlz/25wd/9kZ3H/am13/2dqcf9nanH/YmVu/2Jlbv9nanT/ -Zmhu/2Zpc/9kZ3H/cHJ5/2Zpc/9qbXf/am13/2Rncf9maXP/Z2p0/2xvef9maXP/bG51/3Bzff9maXP/ -bW9z/2ptd/9sb3n/am13/3Bzff9ucXv/amxz/25xe/9sbnX/cHJ5/2xvef9qbXf/ZGdx/2ptd/9qbXf/ -c3V8/3F0e/9laHH/bG51/2dqc/9tcHr/amxz/2ptd/9nanT/cHJ5/3l7gf91d33/amxz/2xudf9vcXj/ -d3h8/3Byef9vcXX/dXd9/21vc/9sbnX/bG95/29yfP9wc3v/bW92/2ptd/9sb3j/c3V7/3V4f/90dnr/ -c3V8/3Byev9xc3v/c3Z9/29xeP91d4D/bnB4/21wev91d37/dnh//3Fze/9tb3b/bW93/3J0e/9zdn3/ -cnV+/25xe/9vcnn/cnV//25xe/9wcnr/cHN8/3Z4gf9wcnn/cHJ6/3d6hP9zdXz/cXN9/3Bzff9zdXz/ -fYCJ/25wd/9sb3n/bG95/29xeP90dnv/b3J7/25wd/9ucHf/bW92/3N1fP9ucHf/bnB3/29yef9wcnn/ -Z2px/35/g/9ucHf/bG51/21vc/9qbXf/bnF7/2xvef93eX//d3l//3N1fP9ucXv/bnF7/25xe/9nanT/ -amxz/2Zpc/9nanT/ZGdx/2dqdP9nanT/ZGdx/3Byef9kZ3H/bG51/2xudf9sb3n/Zmlz/2psc/9wc33/ -amxz/2xudf9zdXz/amxz/2xvef9qbXf/bnF7/2ptd/9sb3n/am13/2xudf9ucXv/cHN9/3Bzff9wc33/ -am13/2ptd/91d33/bnB3/2xudf9sbnX/bnB3/2xudf92eHz/bG51/25wd/9kZ3H/bG95/3N1fP9sb3n/ -ZGZs/2ptd/9ucXv/bG51/2ptd/9zdXz/fn+D/2xvef9sb3n/foCG/25xe/91eIH/bnF7/25wd/9vcXX/ -dXd9/3d5f/9wc33/c3Z//25wd/9zdn//bnF7/3V3ff9ucXv/bG51/29xdf94eX3/c3Z//25wd/9ucXv/ -c3Z//3l7gf9wcnn/d3l//25xe/9wcnn/cHN9/3N2f/9zdXz/am13/2xvef91d33/bG51/3N1fP9sb3n/ -bG51/2dqcf9sb3n/dXd9/2psc/9qbXf/bG95/2xvef9wcnn/d3qD/3V3ff91d33/am13/3Byef9wcnn/ -Z2p0/2xvef9wc33/c3V8/3V4gf9tb3P/bnB3/21vc/92eHz/bW9z/29xdf9sbnX/bnB3/25wd/9qbXf/ -am13/2ptd/9nanT/c3V8/3d6g/9kZ3H/bG95/2xvef93eoP/Z2p0/25xe/9qbXf/am13/2xudf9sbnX/ -cHJ5/29xdf9wc33/bnF7/3l8hv9sb3n/cHN9/3N2f/9sb3n/bG95/3N2f/9wc33/bG95/3Bzff93eX// -am13/25wd/9vcXX/cHJ5/25wd/9zdXz/c3V8/2xudf9sb3n/bnB3/2xvef9sbnX/amxz/1xfaP9nanH/ -Z2px/3Bzff9ucXv/a253/2xud/9tb3j/cXR7/21vc/9ucHf/amxz/25xe/93eX//c3V8/2hqdP9rbnf/ -bXB5/3R2ev9sbnX/bW9z/25wd/9qbHP/cHJ5/29xef9zdX3/cHJ7/21weP9sb3n/bnB3/3N2f/94eoD/ -b3J7/3N2f/9zdn//eHuF/3l7gf92eH7/fX+F/3R2ff91eH7/enyC/3p8gv94eoH/d3h9/31/hv97fYP/ -e32D/3x9gf94eoD/dnh8/31/hf94eX7/d3l//3d5f/97fYP/cHN9/3V3ff97fof/cHN9/2xvef9wc33/ -cHN9/3t+h/9zdXz/c3Z//3d6g/9wc33/d3mA/3J1f/9ucHb/bXB5/21vdv9ucHf/bnB3/25wd/9vcnv/ -cHJ5/2dqcf9+gIb/bnF7/3N1fP9vcXX/bnF7/3d6g/9wc33/e36H/3l8hv9zdn//cHN9/25xe/91d33/ -bnB3/25xe/9sb3n/bnF7/2xvef9ucXv/cHN9/3Byef93eX//bG51/2xudf9sbnX/bG95/2dqdP9qbHP/ -bnF7/2psc/9nanH/am13/2Zpc/9nanT/Z2px/2ptd/9sbnX/bnF7/2xudf9tb3P/cHJ5/3V3ff91d33/ -dXd9/2xvef9sb3n/dXiB/25wd/9wc33/c3V8/3V4gf9zdn//d3qD/3N2f/95fIb/cHN9/3l8hv97fYP/ -eXuB/2dqdP9zdn//eXyG/3Bzff91eIH/eXuB/3+Bh/9ucXv/bnB3/35/g/9tb3P/dXd9/3Byef9wcnn/ -b3F1/3d5f/93eX//bnF7/3Bzff9sb3n/cHJ5/25xe/93eX//c3Z//3Byef9ucHf/dXd9/3N1fP9sb3n/ -bG95/3N2f/93eX//bnB3/3V3ff9vcXX/bnF7/3Bzff9ucXv/bnB3/2dqdP9ucXv/cHN9/2ptd/91eIH/ -bG95/2xvef9qbHP/bG95/3V3ff9vcXX/bG51/2xvef9qbXf/cHJ5/3l7gf91d33/bnF7/25wd/9ucHf/ -cHJ5/2psc/9sbnX/cHN9/3Bzff9zdn//bG51/25xe/9nanH/cHN9/2Zpc/9nanH/Z2px/2xudf9sb3n/ -am13/2xudf9ucHf/bG51/3V3ff99foH/Zmhu/3N1fP9wcnn/eXuB/2ptd/91d33/bnF7/2ptd/9qbXf/ -am13/25xe/9ucHf/c3V8/3V3ff95e4H/bnB3/3V3ff92eHz/amxz/2xudf92eHz/bnF7/2xudf9ucHf/ -c3V8/2dqdP9qbXf/bG51/3N1fP9ucHf/c3V8/3V3ff9ucHf/cHJ5/3Byef9zdXz/bW9z/21vc/9kZmz/ -bG51/2xvef91d33/bG50/3Byef9vcXb/cXN5/3Fzef9qbXf/bG95/2Zpc/9sb3n/d3l//3N1fP9rbXT/ -bXB4/29yev9zdXz/bnB3/25wd/9zdn//am13/25xe/9ucHr/cHN7/2xudv9oa3X/a254/2xudf9wc33/ -dXd9/2xudf9ucHf/bnB3/3Byef91d33/bnB3/3d5f/9ucHf/bG95/3N2f/92eHz/cHJ5/25wd/9wcnn/ -cHJ5/3Byef9wcnn/bnB3/25wd/9sb3n/bnB3/25wd/91eIH/c3Z//3Byef9ucHf/d3l//29xdf9nanH/ -bG51/21vc/93eoP/bG51/2ptd/9ucXv/amxz/3N1fP9qbXb/aWt0/29xeP9sb3j/bG51/2xvef9ucHf/ -bG95/2xvef9nanH/fn+D/25wd/9ucHf/am13/2xudf91d33/bG51/3l7gf91eIH/cHN9/3N2f/9wc33/ -d3l//2xvef9wc33/bnB3/2xvef9sb3n/bnF7/3Bzff9ucXv/d3l//2ptd/9ucHf/bG95/3Byef9vcXX/ -b3F1/3N1fP9vcXX/b3F1/3Bzff9nanT/bG51/2ptd/9ucXv/bG51/2xvef9sb3n/bG51/2xudf9sb3n/ -dXd9/3Bzff9qbXf/am13/3Byef9qbXf/am13/2Zpc/9ucXv/bG95/2xvef9nanT/bnF7/2Rncf9sb3n/ -bnF7/25xe/9gY2z/Z2p0/2xvef9qbXf/am13/3Bzff93eoP/am13/2ptd/97fYP/bG51/2xvef9ucXv/ -bG95/2psc/91d33/dXd9/2ptd/9zdXz/bnB3/3Bzff9ucHf/dnh8/25xe/9wcnn/cHJ5/3d6g/9ucXv/ -cHN9/2xvef9wc33/AA0BAAADAAAAAQEAAAABAQADAAAAAQEAAAABAgADAAAABAAEAKoBAwADAAAAAQAB -AAABBgADAAAAAQACAAABEQAEAAAAAgAEALIBEgADAAAAAQABAAABFQADAAAAAQAEAAABFgADAAAAAQCA -AAABFwAEAAAAAgAEALoBHAADAAAAAQABAAABUgADAAAAAQABAAABUwADAAAABAAEAMIAAAAAAAgACAAI -AAgAAAAIAAIACAACAAAAAgAAAAEAAQABAAE - - - - - - 3 - MCAwAA - - - scrollViewTexturedBackgroundColor - - 0.80000001192092896 - IBIPadFramework - - YES - - 1 - Ticks - - NSImage - ticks_tab.png - - IBIPadFramework - - - - 2 - Title - - NSImage - title_tab.png - - IBIPadFramework - - - - 3 - Labels - - NSImage - label_tab.png - - IBIPadFramework - - - - - - {250, 400} - - - _NS:195 - - IBIPadFramework - - - - - YES - - - view - - - - 7 - - - - tabBar - - - - 18 - - - - delegate - - - - 19 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - 14 - - - YES - - - - - - - - 15 - - - - - 16 - - - - - 17 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 14.IBPluginDependency - 15.IBPluginDependency - 16.IBPluginDependency - 17.IBPluginDependency - 4.IBPluginDependency - - - YES - AxisInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 19 - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - label_tab.png - ticks_tab.png - title_tab.png - - - YES - {30, 30} - {30, 30} - {30, 30} - - - 534 - - diff --git a/test/ios/RootBrowser/AxisLabelsInspector.h b/test/ios/RootBrowser/AxisLabelsInspector.h deleted file mode 100644 index 083e7fd5f89d3..0000000000000 --- a/test/ios/RootBrowser/AxisLabelsInspector.h +++ /dev/null @@ -1,33 +0,0 @@ -#import "ObjectInspectorComponent.h" - -@class ROOTObjectController; - - -class TObject; -class TAxis; - -@interface AxisLabelsInspector : UIViewController { -@private - __weak IBOutlet UIButton *plusSize; - __weak IBOutlet UIButton *minusSize; - __weak IBOutlet UILabel *sizeLabel; - - __weak IBOutlet UIButton *plusOffset; - __weak IBOutlet UIButton *minusOffset; - __weak IBOutlet UILabel *offsetLabel; - - __weak IBOutlet UISwitch *noExp; -} - -+ (CGRect) inspectorFrame; - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; - -- (IBAction) showLabelFontInspector; - -- (IBAction) plusBtn : (UIButton *)sender; -- (IBAction) minusBtn : (UIButton *)sender; -- (IBAction) noExpPressed; - -@end diff --git a/test/ios/RootBrowser/AxisLabelsInspector.mm b/test/ios/RootBrowser/AxisLabelsInspector.mm deleted file mode 100644 index 00a3d31bd0094..0000000000000 --- a/test/ios/RootBrowser/AxisLabelsInspector.mm +++ /dev/null @@ -1,153 +0,0 @@ -#import "ROOTObjectController.h" -#import "AxisLabelsInspector.h" -#import "AxisFontInspector.h" - -#import "TObject.h" -#import "TAxis.h" - -//It's mm file == C++, consts have internal linkage. -const float sizeStep = 0.01f; -const float minSize = 0.f; -const float maxSize = 1.f; - -const float offsetStep = 0.001f; -const float minOffset = -1.f; -const float maxOffset = 1.f; - -const float totalHeight = 400.f; -const float tabBarHeight = 49.f; -const CGRect componentFrame = CGRectMake(0.f, tabBarHeight, 250.f, totalHeight - tabBarHeight); - -@implementation AxisLabelsInspector { - __weak ROOTObjectController *controller; - TAxis *object; -} - -//____________________________________________________________________________________________________ -+ (CGRect) inspectorFrame -{ - return componentFrame; -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - - [self view]; - - if (self) - [self view]; - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - object = dynamic_cast(o); - - sizeLabel.text = [NSString stringWithFormat : @"%.2f", object->GetLabelSize()]; - offsetLabel.text = [NSString stringWithFormat : @"%.3f", object->GetLabelOffset()]; - - noExp.on = object->GetNoExponent(); -} - -//____________________________________________________________________________________________________ -- (void) showLabelFontInspector -{ - AxisFontInspector *fontInspector = [[AxisFontInspector alloc] initWithNibName : @"AxisFontInspector" mode : ROOT_IOSObjectInspector::afimLabelFont]; - - [fontInspector setROOTObjectController : controller]; - [fontInspector setROOTObject : object]; - - [self.navigationController pushViewController : fontInspector animated : YES]; -} - -//____________________________________________________________________________________________________ -- (IBAction) plusBtn : (UIButton *)sender -{ - if (sender == plusSize) { - if (object->GetLabelSize() + sizeStep > maxSize) - return; - - sizeLabel.text = [NSString stringWithFormat : @"%.2f", object->GetLabelSize() + sizeStep]; - object->SetLabelSize(object->GetLabelSize() + sizeStep); - } else if (sender == plusOffset) { - if (object->GetLabelOffset() + offsetStep > maxOffset) - return; - - offsetLabel.text = [NSString stringWithFormat : @"%.3f", object->GetLabelOffset() + offsetStep]; - object->SetLabelOffset(object->GetLabelOffset() + offsetStep); - } - - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) minusBtn : (UIButton *)sender -{ - if (sender == minusSize) { - if (object->GetLabelSize() - sizeStep < minSize) - return; - - sizeLabel.text = [NSString stringWithFormat : @"%.2f", object->GetLabelSize() - sizeStep]; - object->SetLabelSize(object->GetLabelSize() - sizeStep); - } else if (sender == minusOffset) { - if (object->GetLabelOffset() - offsetStep < minOffset) - return; - - offsetLabel.text = [NSString stringWithFormat : @"%.3f", object->GetLabelOffset() - offsetStep]; - object->SetLabelOffset(object->GetLabelOffset() - offsetStep); - } - - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) noExpPressed -{ - object->SetNoExponent(noExp.on); - [controller objectWasModifiedUpdateSelection : NO]; -} - -@end diff --git a/test/ios/RootBrowser/AxisLabelsInspector.xib b/test/ios/RootBrowser/AxisLabelsInspector.xib deleted file mode 100644 index cfdc32a77a6ca..0000000000000 --- a/test/ios/RootBrowser/AxisLabelsInspector.xib +++ /dev/null @@ -1,789 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - YES - IBUISwitch - IBUIButton - IBUIImageView - IBUIView - IBUILabel - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 292 - {{10, 270}, {230, 3}} - - - - _NS:544 - NO - IBIPadFramework - - - - 292 - {{35, 281}, {180, 50}} - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - 1 - Label font - - 3 - MQA - - - - 3 - MC41AA - - - NSImage - forward_btn.png - - - Helvetica-Bold - Helvetica - 2 - 15 - - - Helvetica-Bold - 15 - 16 - - - - - 292 - {{20, 44}, {90, 21}} - - - - _NS:327 - - 3 - MCAwAA - - NO - YES - 7 - NO - IBIPadFramework - Label size: - - 1 - MCAwIDAAA - - - 1 - 10 - - Helvetica - Helvetica - 0 - 15 - - - Helvetica - 15 - 16 - - - - - 292 - {{20, 136}, {100, 21}} - - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Label offset: - - - 1 - 10 - - - - - - 292 - {{20, 225}, {113, 21}} - - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - No exponent: - - - 1 - 10 - - - - - - 292 - {{146, 222}, {94, 27}} - - - - _NS:592 - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{113, 44}, {42, 21}} - - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Label - - - 1 - 10 - - 1 - 17 - - - Helvetica - 17 - 16 - - - - - 292 - {{163, 36}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - NSImage - plus_btn.png - - - - - - - 292 - {{200, 36}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - NSImage - minus_btn.png - - - - - - - 292 - {{113, 136}, {42, 21}} - - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - Label - - - 1 - 10 - - - - - - 292 - {{163, 128}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - - 292 - {{200, 128}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - {250, 351} - - - - _NS:195 - - IBIPadFramework - - - - - YES - - - view - - - - 20 - - - - sizeLabel - - - - 21 - - - - offsetLabel - - - - 22 - - - - plusSize - - - - 23 - - - - minusSize - - - - 24 - - - - plusOffset - - - - 25 - - - - minusOffset - - - - 26 - - - - noExp - - - - 38 - - - - showLabelFontInspector - - - 7 - - 33 - - - - noExpPressed - - - 13 - - 37 - - - - plusBtn: - - - 7 - - 29 - - - - minusBtn: - - - 7 - - 30 - - - - plusBtn: - - - 7 - - 31 - - - - minusBtn: - - - 7 - - 32 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - - - - - - - - - - - 8 - - - - - 9 - - - - - 10 - - - - - 11 - - - - - 12 - - - - - 13 - - - - - 14 - - - - - 15 - - - - - 16 - - - - - 17 - - - - - 18 - - - - - 19 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 10.IBPluginDependency - 11.IBPluginDependency - 12.IBPluginDependency - 13.IBPluginDependency - 14.IBPluginDependency - 15.IBPluginDependency - 16.IBPluginDependency - 17.IBPluginDependency - 18.IBPluginDependency - 19.IBPluginDependency - 4.IBPluginDependency - 8.IBPluginDependency - 9.IBPluginDependency - - - YES - AxisLabelsInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 38 - - - - YES - - AxisLabelsInspector - UIViewController - - YES - - YES - back - minusBtn: - noExpPressed - plusBtn: - showLabelColorInspector - showLabelFontInspector - - - YES - id - UIButton - id - UIButton - id - id - - - - YES - - YES - back - minusBtn: - noExpPressed - plusBtn: - showLabelColorInspector - showLabelFontInspector - - - YES - - back - id - - - minusBtn: - UIButton - - - noExpPressed - id - - - plusBtn: - UIButton - - - showLabelColorInspector - id - - - showLabelFontInspector - id - - - - - YES - - YES - minusOffset - minusSize - noExp - offsetLabel - plusOffset - plusSize - sizeLabel - - - YES - UIButton - UIButton - UISwitch - UILabel - UIButton - UIButton - UILabel - - - - YES - - YES - minusOffset - minusSize - noExp - offsetLabel - plusOffset - plusSize - sizeLabel - - - YES - - minusOffset - UIButton - - - minusSize - UIButton - - - noExp - UISwitch - - - offsetLabel - UILabel - - - plusOffset - UIButton - - - plusSize - UIButton - - - sizeLabel - UILabel - - - - - IBProjectSource - ./Classes/AxisLabelsInspector.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - forward_btn.png - minus_btn.png - plus_btn.png - - - YES - {180, 50} - {40, 40} - {40, 40} - - - 933 - - diff --git a/test/ios/RootBrowser/AxisTicksInspector.h b/test/ios/RootBrowser/AxisTicksInspector.h deleted file mode 100644 index ef8c79822696b..0000000000000 --- a/test/ios/RootBrowser/AxisTicksInspector.h +++ /dev/null @@ -1,33 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" - -@interface AxisTicksInspector : UIViewController { -@private - __weak IBOutlet UILabel *tickLengthLabel; - __weak IBOutlet UIButton *plusLengthBtn; - __weak IBOutlet UIButton *minusLengthBtn; - - __weak IBOutlet UIButton *plusPrim; - __weak IBOutlet UIButton *minusPrim; - __weak IBOutlet UILabel *primLabel; - - __weak IBOutlet UIButton *plusSec; - __weak IBOutlet UIButton *minusSec; - __weak IBOutlet UILabel *secLabel; - - __weak IBOutlet UIButton *plusTer; - __weak IBOutlet UIButton *minusTer; - __weak IBOutlet UILabel *terLabel; - - __weak IBOutlet UISegmentedControl *ticksNegPos; -} - -- (void) setROOTObject : (TObject *)object; -- (void) setROOTObjectController : (ROOTObjectController *)c; - -- (IBAction) plusTick : (UIButton *)sender; -- (IBAction) minusTick :(UIButton *)sender; -- (IBAction) ticksNegPosPressed; - -@end diff --git a/test/ios/RootBrowser/AxisTicksInspector.mm b/test/ios/RootBrowser/AxisTicksInspector.mm deleted file mode 100644 index b29ec9e5c55b4..0000000000000 --- a/test/ios/RootBrowser/AxisTicksInspector.mm +++ /dev/null @@ -1,229 +0,0 @@ -#import - -#import "ROOTObjectController.h" -#import "AxisTicksInspector.h" - -#import "TObject.h" -#import "TAxis.h" - - -//It's mm file == C++, consts have internal linkage. -const float tickLengthStep = 0.01f; -const float maxTickLength = 1.f; -const float minTickLength = -1.f; - -const CGFloat tabBarHeight = 49.f; -const CGFloat totalHeight = 400.f; -const CGRect componentFrame = CGRectMake(0.f, tabBarHeight, 250.f, totalHeight - tabBarHeight); - -@implementation AxisTicksInspector { - float tickLength; - unsigned primaryTicks; - unsigned secondaryTicks; - unsigned tertiaryTicks; - - __weak ROOTObjectController *controller; - - TAxis *object; -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - - [self view]; - - if (self) { - // Custom initialization - self.view.frame = componentFrame; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -#pragma mark - Inspector's protocol. - -//____________________________________________________________________________________________________ -- (void) setTicksWidgets -{ -// object->SetNdivisions(int(primaryTicks.value), int(secondaryTicks.value), int(tertiaryTicks.value), 1); -// [controller objectWasModifiedByEditor]; - - const int nDivisions = object->GetNdivisions(); - //Hardcoded constants from TAttAxis, never defined as named values in ROOT. - //"Formulas" from TAxisEditor. - primaryTicks = nDivisions % 100; - secondaryTicks = (nDivisions / 100) % 100; - tertiaryTicks = (nDivisions / 10000) % 100; - - primLabel.text = [NSString stringWithFormat : @"%u", primaryTicks]; - secLabel.text = [NSString stringWithFormat : @"%u", secondaryTicks]; - terLabel.text = [NSString stringWithFormat : @"%u", tertiaryTicks]; - - tickLength = object->GetTickLength(); - tickLengthLabel.text = [NSString stringWithFormat : @"%.2f", object->GetTickLength()]; -} - -//____________________________________________________________________________________________________ -- (void) setupInspector -{ - const char *option = object->GetTicks(); - - if (!strcmp("+-", option)) - [ticksNegPos setSelectedSegmentIndex : 1]; - else - [ticksNegPos setSelectedSegmentIndex : 0]; - - [self setTicksWidgets]; -} - - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - //The result of a cast is not checked here, it's done on top level. - object = dynamic_cast(o); - - [self setupInspector]; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController:(ROOTObjectController *)c -{ - controller = c; -} - -//____________________________________________________________________________________________________ -- (IBAction) ticksNegPosPressed -{ - if (ticksNegPos.selectedSegmentIndex == 0) - object->SetTicks(""); - else - object->SetTicks("+-"); - - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (void) setTicks -{ - object->SetNdivisions(primaryTicks, secondaryTicks, tertiaryTicks); -} - -//____________________________________________________________________________________________________ -- (IBAction) plusTick : (UIButton *)sender -{ - if (sender == plusLengthBtn) { - if (tickLength + tickLengthStep < maxTickLength) { - tickLength += tickLengthStep; - tickLengthLabel.text = [NSString stringWithFormat:@"%.2f", tickLength]; - object->SetTickLength(tickLength); - [controller objectWasModifiedUpdateSelection : NO]; - } - return; - } - - UILabel *labelToModify = 0; - unsigned n = 0; - - if (sender == plusPrim) { - labelToModify = primLabel; - if (primaryTicks < 99) - n = ++primaryTicks; - else - return; - } else if (sender == plusSec) { - labelToModify = secLabel; - if (secondaryTicks < 99) - n = ++secondaryTicks; - else - return; - } else { - labelToModify = terLabel; - if (tertiaryTicks < 99) - n = ++tertiaryTicks; - else - return; - } - - labelToModify.text = [NSString stringWithFormat : @"%u", n]; - [self setTicks]; - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) minusTick :(UIButton *)sender -{ - if (sender == minusLengthBtn) { - if (tickLength - tickLengthStep > minTickLength) { - tickLength -= tickLengthStep; - tickLengthLabel.text = [NSString stringWithFormat:@"%.2g", tickLength]; - object->SetTickLength(tickLength); - [controller objectWasModifiedUpdateSelection : NO]; - } - return; - } - - UILabel *labelToModify = 0; - unsigned n = 0; - - if (sender == minusPrim) { - labelToModify = primLabel; - if (primaryTicks > 0) - n = --primaryTicks; - else - return; - } else if (sender == minusSec) { - labelToModify = secLabel; - if (secondaryTicks > 0) - n = --secondaryTicks; - else - return; - } else { - labelToModify = terLabel; - if (tertiaryTicks > 0) - n = --tertiaryTicks; - else - return; - } - - labelToModify.text = [NSString stringWithFormat : @"%u", n]; - [self setTicks]; - [controller objectWasModifiedUpdateSelection : NO]; -} - - -@end diff --git a/test/ios/RootBrowser/AxisTicksInspector.xib b/test/ios/RootBrowser/AxisTicksInspector.xib deleted file mode 100644 index 0a39d1140c6e7..0000000000000 --- a/test/ios/RootBrowser/AxisTicksInspector.xib +++ /dev/null @@ -1,1127 +0,0 @@ - - - - 1056 - 11B26 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBUIImageView - IBUIButton - IBUISegmentedControl - IBUIView - IBUILabel - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 292 - {{10, 102}, {230, 3}} - - - - _NS:544 - NO - IBIPadFramework - - NSImage - separator.png - - - - - 292 - {{10, 167}, {230, 3}} - - - - _NS:544 - NO - IBIPadFramework - - - - - 292 - {{20, 43}, {210, 44}} - - - - _NS:277 - NO - IBIPadFramework - 2 - 0 - - YES - + - -+ - - - YES - - - - - YES - - - - - YES - {0, 0} - {0, 0} - - - YES - - - - - - - 292 - {{71, 15}, {107, 20}} - - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - Ticks on both sides: - - Helvetica - 17 - 16 - - - 1 - MCAwIDAAA - - - 1 - 10 - - - - 292 - {{148, 178}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - Helvetica-Bold - 15 - 16 - - - 3 - MQA - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - 3 - MC41AA - - - NSImage - plus_btn.png - - - - - 292 - {{185, 178}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - NSImage - minus_btn.png - - - - - 292 - {{148, 226}, {40, 40}} - - - - _NS:237 - - 3 - MCAwAA - - NO - IBIPadFramework - 0 - 0 - - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - 292 - {{185, 226}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - 292 - {{148, 274}, {40, 40}} - - - - _NS:237 - - NO - IBIPadFramework - 0 - 0 - - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - 292 - {{185, 274}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - 292 - {{17, 189}, {73, 21}} - - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - N of primary: - - - 1 - 10 - - - - 292 - {{17, 235}, {90, 21}} - - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - N of secondary: - - - 1 - 10 - - - - 292 - {{17, 283}, {73, 21}} - - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - N of tertiary: - - - 1 - 10 - - - - 292 - {{109, 189}, {31, 21}} - - - - _NS:327 - - 3 - MC42NjY2NjY2NjY3AA - - NO - YES - 7 - NO - IBIPadFramework - Label - - - 1 - 10 - 1 - - - - 292 - {{109, 235}, {31, 21}} - - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Label - - - 1 - 10 - 1 - - - - 292 - {{109, 283}, {31, 21}} - - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Label - - - 1 - 10 - 1 - - - - 292 - {{17, 126}, {65, 21}} - - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - Tick length: - - - 1 - 10 - - - - 292 - {{90, 126}, {50, 21}} - - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Label - - - - 1 - 10 - 1 - - - - 292 - {{148, 117}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - 1 - - - - - - - - 292 - {{185, 117}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - 1 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - {250, 351} - - - - _NS:195 - - IBIPadFramework - - - - - YES - - - view - - - - 26 - - - - plusPrim - - - - 50 - - - - minusPrim - - - - 51 - - - - plusSec - - - - 52 - - - - minusSec - - - - 53 - - - - plusTer - - - - 54 - - - - minusTer - - - - 55 - - - - primLabel - - - - 62 - - - - secLabel - - - - 63 - - - - terLabel - - - - 64 - - - - plusTick: - - - 7 - - 65 - - - - plusTick: - - - 7 - - 66 - - - - plusTick: - - - 7 - - 67 - - - - minusTick: - - - 7 - - 68 - - - - minusTick: - - - 7 - - 69 - - - - minusTick: - - - 7 - - 70 - - - - tickLengthLabel - - - - 75 - - - - plusLengthBtn - - - - 77 - - - - minusLengthBtn - - - - 79 - - - - plusTick: - - - 7 - - 80 - - - - minusTick: - - - 7 - - 81 - - - - ticksNegPosPressed - - - 13 - - 82 - - - - ticksNegPos - - - - 83 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - - - - - - - - - - - - - - - - - - - 37 - - - - - 42 - - - - - 44 - - - - - 45 - - - - - 46 - - - - - 47 - - - - - 48 - - - - - 49 - - - - - 56 - - - - - 57 - - - - - 58 - - - - - 59 - - - - - 60 - - - - - 61 - - - - - 71 - - - - - 72 - - - - - 73 - - - - - 74 - - - - - 76 - - - - - 78 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 37.IBPluginDependency - 37.IUISegmentedControlInspectorSelectedSegmentMetadataKey - 4.IBPluginDependency - 42.IBPluginDependency - 44.IBPluginDependency - 45.IBPluginDependency - 46.IBPluginDependency - 47.IBPluginDependency - 48.IBPluginDependency - 49.IBPluginDependency - 56.IBPluginDependency - 57.IBPluginDependency - 58.IBPluginDependency - 59.IBPluginDependency - 60.IBPluginDependency - 61.IBPluginDependency - 71.IBPluginDependency - 72.IBPluginDependency - 73.IBPluginDependency - 74.IBPluginDependency - 76.IBPluginDependency - 78.IBPluginDependency - - - YES - AxisTicksInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 83 - - - - YES - - AxisTicksInspector - UIViewController - - YES - - YES - back - minusTick: - plusTick: - ticksNegPos - ticksNegPosPressed - - - YES - id - UIButton - UIButton - id - id - - - - YES - - YES - back - minusTick: - plusTick: - ticksNegPos - ticksNegPosPressed - - - YES - - back - id - - - minusTick: - UIButton - - - plusTick: - UIButton - - - ticksNegPos - id - - - ticksNegPosPressed - id - - - - - YES - - YES - minusLengthBtn - minusPrim - minusSec - minusTer - plusLengthBtn - plusPrim - plusSec - plusTer - primLabel - secLabel - terLabel - tickLengthLabel - ticksNegPos - - - YES - UIButton - UIButton - UIButton - UIButton - UIButton - UIButton - UIButton - UIButton - UILabel - UILabel - UILabel - UILabel - UISegmentedControl - - - - YES - - YES - minusLengthBtn - minusPrim - minusSec - minusTer - plusLengthBtn - plusPrim - plusSec - plusTer - primLabel - secLabel - terLabel - tickLengthLabel - ticksNegPos - - - YES - - minusLengthBtn - UIButton - - - minusPrim - UIButton - - - minusSec - UIButton - - - minusTer - UIButton - - - plusLengthBtn - UIButton - - - plusPrim - UIButton - - - plusSec - UIButton - - - plusTer - UIButton - - - primLabel - UILabel - - - secLabel - UILabel - - - terLabel - UILabel - - - tickLengthLabel - UILabel - - - ticksNegPos - UISegmentedControl - - - - - IBProjectSource - ./Classes/AxisTicksInspector.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - minus_btn.png - plus_btn.png - separator.png - - - YES - {40, 40} - {40, 40} - {230, 3} - - - 534 - - diff --git a/test/ios/RootBrowser/AxisTitleInspector.h b/test/ios/RootBrowser/AxisTitleInspector.h deleted file mode 100644 index 1afc7f7874818..0000000000000 --- a/test/ios/RootBrowser/AxisTitleInspector.h +++ /dev/null @@ -1,31 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" - -@interface AxisTitleInspector : UIViewController { -@private - __weak IBOutlet UITextField *titleField; - __weak IBOutlet UISwitch *centered; - __weak IBOutlet UISwitch *rotated; - __weak IBOutlet UILabel *offsetLabel; - __weak IBOutlet UILabel *sizeLabel; - __weak IBOutlet UIButton *plusSizeBtn; - __weak IBOutlet UIButton *minusSizeBtn; -} - -+ (CGRect) inspectorFrame; - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; - -- (IBAction) showTitleFontInspector; -- (IBAction) textFieldDidEndOnExit : (id) sender; -- (IBAction) textFieldEditingDidEnd : (id) sender; -- (IBAction) centerTitle; -- (IBAction) rotateTitle; -- (IBAction) plusOffset; -- (IBAction) minusOffset; -- (IBAction) plusSize; -- (IBAction) minusSize; - -@end diff --git a/test/ios/RootBrowser/AxisTitleInspector.mm b/test/ios/RootBrowser/AxisTitleInspector.mm deleted file mode 100644 index de621565cc01b..0000000000000 --- a/test/ios/RootBrowser/AxisTitleInspector.mm +++ /dev/null @@ -1,205 +0,0 @@ -#import "ROOTObjectController.h" -#import "AxisTitleInspector.h" -#import "AxisFontInspector.h" - -//C++ (ROOT) imports. -#import "TObject.h" -#import "TAxis.h" - -//It's mm file == C++, consts have internal linkage. -const float minTitleOffset = 0.1f; -const float maxTitleOffset = 10.f; -const float titleOffsetStep = 0.01f; - -const float minTitleSize = 0.01f; -const float maxTitleSize = 1.f; -const float titleSizeStep = 0.01f; - -const float totalHeight = 400.f; -const float tabBarHeight = 49.f; - -@implementation AxisTitleInspector { - - ROOTObjectController *controller; - TAxis *object; - float offset; - float titleSize; - -} - -//____________________________________________________________________________________________________ -+ (CGRect) inspectorFrame -{ - return CGRectMake(0.f, tabBarHeight, 250.f, totalHeight - tabBarHeight); -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - - if (self) - [self view]; - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - object = dynamic_cast(o); - - const char *axisTitle = object->GetTitle(); - if (!axisTitle || !*axisTitle) - titleField.text = @""; - else - titleField.text = [NSString stringWithFormat : @"%s", axisTitle]; - - centered.on = object->GetCenterTitle(); - rotated.on = object->GetRotateTitle(); - - offset = object->GetTitleOffset(); - offsetLabel.text = [NSString stringWithFormat:@"%.2f", offset]; - - titleSize = object->GetTitleSize(); - if (titleSize > maxTitleSize || titleSize < minTitleSize) {//this is baaad - titleSize = minTitleSize; - object->SetTitleSize(titleSize); - [controller objectWasModifiedUpdateSelection : NO]; - } - - sizeLabel.text = [NSString stringWithFormat:@"%.2f", titleSize]; -} - -//____________________________________________________________________________________________________ -- (IBAction) showTitleFontInspector -{ - AxisFontInspector *fontInspector = [[AxisFontInspector alloc] initWithNibName : @"AxisFontInspector" mode : ROOT_IOSObjectInspector::afimTitleFont]; - - [fontInspector setROOTObjectController : controller]; - [fontInspector setROOTObject : object]; - - [self.navigationController pushViewController : fontInspector animated : YES]; -} - -//____________________________________________________________________________________________________ -- (IBAction) textFieldDidEndOnExit : (id) sender -{ - object->SetTitle([titleField.text cStringUsingEncoding : [NSString defaultCStringEncoding]]); - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) textFieldEditingDidEnd : (id) sender -{ - [sender resignFirstResponder]; -} - -//____________________________________________________________________________________________________ -- (IBAction) centerTitle -{ - object->CenterTitle(centered.on); - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) rotateTitle -{ - object->RotateTitle(rotated.on); - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) plusOffset -{ - if (offset + titleOffsetStep > maxTitleOffset) - return; - - offset += titleOffsetStep; - offsetLabel.text = [NSString stringWithFormat:@"%.2f", offset]; - object->SetTitleOffset(offset); - - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) minusOffset -{ - if (offset - titleOffsetStep < minTitleOffset) - return; - - offset -= titleOffsetStep; - offsetLabel.text = [NSString stringWithFormat:@"%.2f", offset]; - object->SetTitleOffset(offset); - - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) plusSize -{ - if (titleSize + titleSizeStep > maxTitleSize) - return; - - titleSize += titleSizeStep; - sizeLabel.text = [NSString stringWithFormat:@"%.2f", titleSize]; - object->SetTitleSize(titleSize); - - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) minusSize -{ - if (titleSize - titleSizeStep < minTitleSize) - return; - - titleSize -= titleSizeStep; - sizeLabel.text = [NSString stringWithFormat:@"%.2f", titleSize]; - object->SetTitleSize(titleSize); - - [controller objectWasModifiedUpdateSelection : NO]; -} - - -@end diff --git a/test/ios/RootBrowser/AxisTitleInspector.xib b/test/ios/RootBrowser/AxisTitleInspector.xib deleted file mode 100644 index b448f4c72b5d3..0000000000000 --- a/test/ios/RootBrowser/AxisTitleInspector.xib +++ /dev/null @@ -1,797 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - YES - IBUIView - IBProxyObject - IBUILabel - IBUISwitch - IBUIImageView - IBUITextField - IBUIButton - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 292 - {{10, 270}, {230, 3}} - - - _NS:544 - NO - IBIPadFramework - - NSImage - separator.png - - - - - 292 - {{84, 38}, {156, 31}} - - - _NS:310 - NO - YES - IBIPadFramework - 0 - - 3 - - 3 - MAA - - 2 - - - 1 - YES - 17 - - 1 - 1 - 9 - IBCocoaTouchFramework - - 1 - - 1 - 12 - - - Helvetica - 12 - 16 - - - - - 292 - {{10, 43}, {42, 21}} - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - Title: - - 1 - MCAwIDAAA - - - 1 - 10 - 1 - - Helvetica - Helvetica - 0 - 15 - - - Helvetica - 15 - 16 - - - - - 292 - {{10, 203}, {96, 21}} - - - _NS:327 - - 3 - MCAwAA - - NO - YES - 7 - NO - IBIPadFramework - Centered: - - - 1 - 10 - - - - - - 292 - {{136, 200}, {94, 27}} - - - _NS:592 - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{10, 238}, {87, 21}} - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Rotated: - - - 1 - 10 - - - - - - 292 - {{136, 235}, {94, 27}} - - - _NS:592 - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{35, 281}, {180, 50}} - - _NS:237 - NO - IBIPadFramework - 0 - 0 - 1 - Title font - - 3 - MQA - - - - 3 - MC41AA - - - NSImage - forward_btn.png - - - Helvetica-Bold - Helvetica - 2 - 15 - - - Helvetica-Bold - 15 - 16 - - - - - 292 - {{152, 153}, {40, 40}} - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - NSImage - plus_btn.png - - - - - - - 292 - {{190, 153}, {40, 40}} - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - NSImage - minus_btn.png - - - - - - - 292 - {{10, 161}, {66, 21}} - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - Offset: - - - 1 - 10 - - - - - - 292 - {{92, 161}, {42, 21}} - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - Label - - - 1 - 10 - - 1 - 17 - - - Helvetica - 17 - 16 - - - - - 292 - {{10, 112}, {73, 21}} - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - Title size: - - - 1 - 10 - - - - - - 292 - {{92, 112}, {42, 21}} - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - Label - - - 1 - 10 - - - - - - 292 - {{152, 103}, {40, 40}} - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - 1 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - - 292 - {{190, 103}, {40, 40}} - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - 1 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - {250, 351} - - - _NS:195 - - IBIPadFramework - - - - - YES - - - view - - - - 14 - - - - centered - - - - 15 - - - - rotated - - - - 16 - - - - titleField - - - - 23 - - - - offsetLabel - - - - 34 - - - - sizeLabel - - - - 41 - - - - plusSizeBtn - - - - 42 - - - - minusSizeBtn - - - - 43 - - - - textFieldDidEndOnExit: - - - 20 - - 26 - - - - textFieldEditingDidEnd: - - - 19 - - 27 - - - - centerTitle - - - 13 - - 28 - - - - rotateTitle - - - 13 - - 29 - - - - showTitleFontInspector - - - 7 - - 17 - - - - plusOffset - - - 7 - - 35 - - - - minusOffset - - - 7 - - 36 - - - - plusSize - - - 7 - - 44 - - - - minusSize - - - 7 - - 45 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - - - - - - - - - - - - - - - 5 - - - - - 6 - - - - - 7 - - - - - 8 - - - - - 9 - - - - - 10 - - - - - 11 - - - - - 25 - - - - - 30 - - - - - 31 - - - - - 32 - - - - - 33 - - - - - 37 - - - - - 38 - - - - - 39 - - - - - 40 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 10.IBPluginDependency - 11.IBPluginDependency - 25.IBPluginDependency - 30.IBPluginDependency - 31.IBPluginDependency - 32.IBPluginDependency - 33.IBPluginDependency - 37.IBPluginDependency - 38.IBPluginDependency - 39.IBPluginDependency - 4.IBPluginDependency - 40.IBPluginDependency - 5.IBPluginDependency - 6.IBPluginDependency - 7.IBPluginDependency - 8.IBPluginDependency - 9.IBPluginDependency - - - YES - AxisTitleInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 45 - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - forward_btn.png - minus_btn.png - plus_btn.png - separator.png - - - YES - {180, 50} - {40, 40} - {40, 40} - {230, 3} - - - 933 - - diff --git a/test/ios/RootBrowser/ColorCell.h b/test/ios/RootBrowser/ColorCell.h deleted file mode 100644 index 1ebe9b20866d4..0000000000000 --- a/test/ios/RootBrowser/ColorCell.h +++ /dev/null @@ -1,7 +0,0 @@ -#import - -@interface ColorCell : UIView - -- (void) setRGB : (const double *) rgb; - -@end diff --git a/test/ios/RootBrowser/ColorCell.mm b/test/ios/RootBrowser/ColorCell.mm deleted file mode 100644 index 21bb41b1e99ae..0000000000000 --- a/test/ios/RootBrowser/ColorCell.mm +++ /dev/null @@ -1,53 +0,0 @@ -#import - -#import "ColorCell.h" - -@implementation ColorCell { - double rgb[3]; -} - -//____________________________________________________________________________________________________ -- (id)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - - if (self) { - self.backgroundColor = [UIColor clearColor]; - self.layer.shadowColor = [UIColor darkGrayColor].CGColor; - self.layer.shadowOffset = CGSizeMake(4.f, 4.f); - self.layer.shadowOpacity = 0.4f; - - //Here important optimization. - self.layer.shadowPath = [UIBezierPath bezierPathWithRect:CGRectMake(10.f, 10.f, frame.size.width - 20.f, frame.size.height - 20)].CGPath; - // - - self.opaque = NO; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) setRGB : (const double *) newRgb -{ - rgb[0] = newRgb[0]; - rgb[1] = newRgb[1]; - rgb[2] = newRgb[2]; -} - -//____________________________________________________________________________________________________ -- (void)drawRect:(CGRect)rect -{ - CGContextRef ctx = UIGraphicsGetCurrentContext(); - if (!ctx) { - //Log error: ctx is nil. - return; - } - - CGContextSetRGBFillColor(ctx, CGFloat(rgb[0]), CGFloat(rgb[1]), CGFloat(rgb[2]), 1.f); - - const CGRect colorCellRect = CGRectMake(10.f, 10.f, rect.size.width - 20.f, rect.size.height - 20.f); - CGContextFillRect(ctx, colorCellRect); -} - -@end diff --git a/test/ios/RootBrowser/Constants.cxx b/test/ios/RootBrowser/Constants.cxx deleted file mode 100644 index 2cc5b70922790..0000000000000 --- a/test/ios/RootBrowser/Constants.cxx +++ /dev/null @@ -1,90 +0,0 @@ -#include "Constants.h" - -namespace ROOT { -namespace iOS { -namespace Browser { - -/////////////Geometric constants for ROOTObjectController. -//'L' postfix is for landscape, 'P' is for portrait. -////Main view (self.view): - -//X and Y are the same for portrait and landscape orientation. -const float viewX = 0.f; -const float viewY = 0.f; - -//portrait - 768 x 1004 (20 Y pixels are taken by iOS). -const float viewWP = 768.f; -const float viewHP = 1004.f; - -//landscape - 1024 x 748 (20 Y pixels are taken by iOS). -const float viewWL = 1024.f; -const float viewHL = 748.f; - -////Scroll view: - -//X and Y are the same for landscape and portrait. -const float scrollX = 0.f; -const float scrollY = 44.f;//Navigation bar height. - -//portrait - 768 x 960 (44 Y pixels from parent are taken by navigation bar). -const float scrollWP = 768.f; -const float scrollHP = 960.f; - -//landscape - 1024 x 704 (44 Y pixels from parent are taken by navigation bar). -const float scrollWL = 1024.f; -const float scrollHL = 704.f; - -//Default pad's width and height, -//when not zoomed, without editor -//or with editor in landscape orientation. -const float padW = 600.f; -const float padH = 600.f; - -//This is pad's width and height, when -//pad is not zoomed and editor is visible, -//device orientation is portrait. -const float padWSmall = 600.f;//30.08 : I decided to make the sizes equal for all possible orientations and states. -const float padHSmall = 600.f; - -const float padXNoEditorP = scrollWP / 2 - padW / 2; -const float padYNoEditorP = scrollHP / 2 - padH / 2; -const float padXNoEditorL = scrollWL / 2 - padW / 2; -const float padYNoEditorL = scrollHL / 2 - padH / 2; - -//X and Y for pad (no zoom) with editor in portrait orientation: -const float padXWithEditorP = 20.f; -const float padYWithEditorP = scrollHP / 2 - padHSmall / 2; - -//X and Y for pad (no zoom) with editor in landscape orientation: -const float padXWithEditorL = 100.f; -const float padYWithEditorL = scrollHL / 2 - padH / 2; - -const double predefinedFillColors[nROOTDefaultColors][3] = -{ -{1., 1., 1.}, -{0., 0., 0.}, -{251 / 255., 0., 24 / 255.}, -{40 / 255., 253 / 255., 44 / 255.}, -{31 / 255., 29 / 255., 251 / 255.}, -{253 / 255., 254 / 255., 52 / 255.}, -{253 / 255., 29 / 255., 252 / 255.}, -{53 / 255., 1., 254 / 255.}, -{94 / 255., 211 / 255., 90 / 255.}, -{92 / 255., 87 / 255., 214 / 255.}, -{135 / 255., 194 / 255., 164 / 255.}, -{127 / 255., 154 / 255., 207 / 255.}, -{211 / 255., 206 / 255., 138 / 255.}, -{220 / 255., 185 / 255., 138 / 255.}, -{209 / 255., 89 / 255., 86 / 255.}, -{147 / 255., 29 / 255., 251 / 255.} -}; - -const unsigned colorIndices[nROOTDefaultColors] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 30, 38, 41, 42, 50, 51}; - -const unsigned stippleBase = 3000; - -bool deviceIsiPad3 = false; - -}//namespace Browser -}//namespace iOS -}//namespace ROOT diff --git a/test/ios/RootBrowser/Constants.h b/test/ios/RootBrowser/Constants.h deleted file mode 100644 index f59873a69a598..0000000000000 --- a/test/ios/RootBrowser/Constants.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef CONSTANTS_INCLUDED -#define CONSTANTS_INCLUDED - -namespace ROOT { -namespace iOS { -namespace Browser { - -/////////////////////////////////////////////////////////////////////// -//Pad's geometry: sizes, positioins. -//'L' postfix is for landscape, 'P' is for portrait -//device orientation. - -////Main view (self.view for ROOTObjectController): - -//X and Y are the same for portrait and landscape orientation. -extern const float viewX; -extern const float viewY; - -//portrait - 768 x 1004 (20 Y pixels are taken by iOS). -extern const float viewWP; -extern const float viewHP; - -//landscape - 1024 x 748 (20 Y pixels are taken by iOS). -extern const float viewWL; -extern const float viewHL; - -////Scroll view: - -//X and Y are the same for landscape and portrait. -extern const float scrollX; -extern const float scrollY; - -//portrait - 768 x 960 (44 Y pixels from parent are taken by navigation bar). -extern const float scrollWP; -extern const float scrollHP; - -//landscape - 1024 x 704 (44 Y pixels from parent are taken by navigation bar). -extern const float scrollWL; -extern const float scrollHL; - -//Default pad's width and height, -//when not zoomed, without editor -//or with editor in landscape orientation. -extern const float padW; -extern const float padH; - -//This is pad's width and height, when -//pad is not zoomed and editor is visible, -//device orientation is portrait. -extern const float padWSmall; -extern const float padHSmall; - -extern const float padXNoEditorP; -extern const float padYNoEditorP; -extern const float padXNoEditorL; -extern const float padYNoEditorL; - -//X and Y for pad (no zoom) with editor in portrait orientation: -extern const float padXWithEditorP; -extern const float padYWithEditorP; - -//X and Y for pad (no zoom) with editor in landscape orientation: -extern const float padXWithEditorL; -extern const float padYWithEditorL; - -/////////////////////////////////////////////////////////////////////// -//Editor's constants; -enum { - -nROOTDefaultColors = 16 - -}; - -extern const double predefinedFillColors[nROOTDefaultColors][3]; -//Color indices in a standard ROOT's color selection control. -extern const unsigned colorIndices[nROOTDefaultColors]; - - -//Constant for TAttFill, never defined in ROOT, I have to define it here. -extern const unsigned stippleBase; - -//This does not have const qualifier, but set only once during startup (by application delegate). -extern bool deviceIsiPad3; - -}//namespace Browser -}//namespace iOS -}//namespace ROOT - -#endif diff --git a/test/ios/RootBrowser/Default-Landscape.png b/test/ios/RootBrowser/Default-Landscape.png deleted file mode 100644 index 1f214c3f6ba4d..0000000000000 Binary files a/test/ios/RootBrowser/Default-Landscape.png and /dev/null differ diff --git a/test/ios/RootBrowser/Default-LandscapeLeft.png b/test/ios/RootBrowser/Default-LandscapeLeft.png deleted file mode 100644 index 1f214c3f6ba4d..0000000000000 Binary files a/test/ios/RootBrowser/Default-LandscapeLeft.png and /dev/null differ diff --git a/test/ios/RootBrowser/Default-LandscapeRight.png b/test/ios/RootBrowser/Default-LandscapeRight.png deleted file mode 100644 index 1f214c3f6ba4d..0000000000000 Binary files a/test/ios/RootBrowser/Default-LandscapeRight.png and /dev/null differ diff --git a/test/ios/RootBrowser/Default-Portrait.png b/test/ios/RootBrowser/Default-Portrait.png deleted file mode 100644 index 1582424813876..0000000000000 Binary files a/test/ios/RootBrowser/Default-Portrait.png and /dev/null differ diff --git a/test/ios/RootBrowser/Default-PortraitUpsideDown.png b/test/ios/RootBrowser/Default-PortraitUpsideDown.png deleted file mode 100644 index 1582424813876..0000000000000 Binary files a/test/ios/RootBrowser/Default-PortraitUpsideDown.png and /dev/null differ diff --git a/test/ios/RootBrowser/EditorPlateView.h b/test/ios/RootBrowser/EditorPlateView.h deleted file mode 100644 index 6d288e9ae714e..0000000000000 --- a/test/ios/RootBrowser/EditorPlateView.h +++ /dev/null @@ -1,13 +0,0 @@ -#import - -@class EditorView; - -@interface EditorPlateView : UIView - -@property (nonatomic, retain) NSString *editorName; -@property (nonatomic, retain) UIImageView *arrowImageView; - -+ (CGFloat) plateHeight; -- (id) initWithFrame : (CGRect)frame editorName : (NSString *) name topView : (EditorView *) tv; - -@end diff --git a/test/ios/RootBrowser/EditorPlateView.mm b/test/ios/RootBrowser/EditorPlateView.mm deleted file mode 100644 index f42ad72a7e8d3..0000000000000 --- a/test/ios/RootBrowser/EditorPlateView.mm +++ /dev/null @@ -1,81 +0,0 @@ -#import - -#import -#import - -#import "EditorPlateView.h" -#import "EditorView.h" - - -@implementation EditorPlateView { - UIImage *plateImage; - UILabel *editorLabel; - - UIImage *arrowImage; - - EditorView *topView; -} - -@synthesize editorName; -@synthesize arrowImageView; - -//____________________________________________________________________________________________________ -+ (CGFloat) plateHeight -{ - return 50.f; -} - -//____________________________________________________________________________________________________ -- (id)initWithFrame:(CGRect)frame editorName : (NSString *)name topView : (EditorView *) tv -{ - self = [super initWithFrame:frame]; - - if (self) { - editorLabel = [[UILabel alloc] initWithFrame : CGRectMake(frame.size.width / 2 - 60.f, 10.f, 120.f, 30.f)]; - editorLabel.backgroundColor = [UIColor clearColor]; - editorLabel.font = [UIFont systemFontOfSize : 14]; - -#ifdef __IPHONE_6_0 - editorLabel.textAlignment = NSTextAlignmentCenter; -#else - editorLabel.textAlignment = UITextAlignmentCenter; -#endif - - editorLabel.textColor = [UIColor whiteColor]; - [self addSubview : editorLabel]; - editorLabel.text = name; - topView = tv; - - plateImage = [UIImage imageNamed:@"editor_plate.png"]; - - arrowImage = [UIImage imageNamed:@"editor_state_arrow.png"]; - arrowImageView = [[UIImageView alloc] initWithImage : arrowImage]; - CGRect arrowFrame = arrowImageView.frame; - arrowFrame.origin.x = frame.size.height / 2 - arrowFrame.size.width / 2 + 3; - arrowFrame.origin.y = frame.size.height / 2 - arrowFrame.size.height / 2; - arrowImageView.frame = arrowFrame; - [self addSubview : arrowImageView]; - - UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector(handleTap:)]; - [self addGestureRecognizer:tap]; - self.editorName = name; - self.opaque = NO; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)drawRect : (CGRect)rect -{ - [plateImage drawAtPoint : CGPointZero]; - //Draw the triangle. -} - -//____________________________________________________________________________________________________ -- (void) handleTap : (UITapGestureRecognizer *) tap -{ - [topView plateTapped : self]; -} - -@end diff --git a/test/ios/RootBrowser/EditorView.h b/test/ios/RootBrowser/EditorView.h deleted file mode 100644 index c8fc4741c9bfe..0000000000000 --- a/test/ios/RootBrowser/EditorView.h +++ /dev/null @@ -1,30 +0,0 @@ -#import - - -// -//EditorView is a small panel to the right of -//pad, contains widgets to modify pad's contents. -//To make it possible to include more staff, -//every sub-editor (like line attributes editor, -//or filled area editor) is placed into -//the collapsing panel. -// - -@class EditorPlateView; - -@interface EditorView : UIView - -+ (CGFloat) editorAlpha; -+ (CGFloat) editorWidth; -+ (CGFloat) editorHeight; -+ (CGFloat) scrollWidth; -+ (CGFloat) scrollHeight; - -- (void) removeAllEditors; -- (void) propertyUpdated; -- (void) addSubEditor : (UIView *)element withName : (NSString *)editorName; -- (void) correctFrames; -- (void) plateTapped : (EditorPlateView *) plate; -- (void) setEditorTitle : (const char*)title; - -@end diff --git a/test/ios/RootBrowser/EditorView.mm b/test/ios/RootBrowser/EditorView.mm deleted file mode 100644 index 4b4ef105c51b9..0000000000000 --- a/test/ios/RootBrowser/EditorView.mm +++ /dev/null @@ -1,425 +0,0 @@ -#import - -#import -#import - -#import "ScrollViewWithPickers.h" -#import "EditorPlateView.h" -#import "EditorView.h" - - -//Hoho! As soon as I use Objective-C++, I can use namespaces! "Yeaaahhh, that's good!" (c) Duke Nukem. - -namespace { - -enum { - evMaxComponents = 5, - evMaxStates = 1 << evMaxComponents -}; - -} - -@implementation EditorView { - UILabel *editorTitle; - - ScrollViewWithPickers *scrollView; - - CGFloat plateYs[evMaxStates * evMaxComponents]; - CGFloat viewYs[evMaxStates * evMaxComponents]; - - UIView *plates[evMaxComponents]; - UIView *views[evMaxComponents]; - UIView *containers[evMaxComponents]; - - unsigned nStates; - unsigned nEditors; - unsigned currentState; - - int newOpened; - - BOOL animation; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) editorAlpha -{ - return 0.85f; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) editorWidth -{ - return 270.f; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) editorHeight -{ - return 650.f; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) scrollWidth -{ - return [EditorView editorWidth] - 20.f; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) scrollHeight -{ - return [EditorView editorHeight] - 20.f; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) ncWidth -{ - return 20.f; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) ncHeight -{ - return 20.f; -} - -//____________________________________________________________________________________________________ -- (id)initWithFrame : (CGRect)frame -{ - self = [super initWithFrame : frame]; - - if (self) { - //Scroll view is a container for all sub-editors. - //It's completely transparent. - const CGRect titleRect = CGRectMake(10.f, 10.f, 250.f, 35.f); - editorTitle = [[UILabel alloc] initWithFrame : titleRect]; - -#ifdef __IPHONE_6_0 - editorTitle.textAlignment = NSTextAlignmentCenter; -#else - editorTitle.textAlignment = UITextAlignmentCenter; -#endif - - editorTitle.textColor = [UIColor blackColor]; - editorTitle.backgroundColor = [UIColor clearColor]; - [self addSubview : editorTitle]; - - const CGRect scrollFrame = CGRectMake(10.f, 45.f, [EditorView scrollWidth], frame.size.height - 55.f); - scrollView = [[ScrollViewWithPickers alloc] initWithFrame : scrollFrame]; - scrollView.backgroundColor = [UIColor clearColor]; - scrollView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; - scrollView.bounces = NO; - [self addSubview : scrollView]; - self.opaque = NO; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) drawRect : (CGRect)rect -{ - //Draw main editor's view as a semi-transparent - //gray view with rounded corners. - - CGContextRef ctx = UIGraphicsGetCurrentContext(); - if (!ctx) { - NSLog(@"[EditorView drawRect:], ctx is nil"); - return; - } - - UIColor *background = [[UIColor scrollViewTexturedBackgroundColor] colorWithAlphaComponent : [EditorView editorAlpha]]; -// UIColor *background = [[UIColor colorWithPatternImage:[UIImage imageNamed:@"inspector_bkn.png"]] colorWithAlphaComponent : [EditorView editorAlpha]]; - CGContextSetFillColorWithColor(ctx, background.CGColor); - CGContextSetPatternPhase(ctx, CGSizeMake(-8.f, 0.f)); - - //Draw the rect with rounded corners now. - CGContextFillRect(ctx, CGRectMake(0.f, [EditorView ncHeight] / 2, [EditorView ncWidth] / 2, rect.size.height - [EditorView ncHeight])); - CGContextFillRect(ctx, CGRectMake([EditorView ncWidth] / 2, 0.f, rect.size.width - [EditorView ncWidth] / 2, rect.size.height)); - - //Draw arcs. - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, [EditorView ncWidth] / 2, [EditorView ncHeight] / 2); - CGContextAddArc(ctx, [EditorView ncWidth] / 2, [EditorView ncHeight] / 2, [EditorView ncWidth] / 2, M_PI, 3 * M_PI / 2, 0); - CGContextFillPath(ctx); - // - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, [EditorView ncWidth] / 2, rect.size.height - [EditorView ncHeight] / 2); - CGContextAddArc(ctx, [EditorView ncWidth] / 2, rect.size.height - [EditorView ncHeight] / 2, [EditorView ncWidth] / 2, M_PI / 2, M_PI, 0); - CGContextFillPath(ctx); -} - -//____________________________________________________________________________________________________ -- (void) removeAllEditors -{ - //Remove all sub-editors. - for (unsigned i = 0; i < nEditors; ++i) { - [plates[i] removeFromSuperview]; - [containers[i] removeFromSuperview]; - } - - nEditors = 0; - currentState = 0; - nStates = 0; - animation = NO; -} - -//____________________________________________________________________________________________________ -- (void) propertyUpdated -{ -} - -//____________________________________________________________________________________________________ -- (CGFloat) recalculateEditorGeometry -{ - const CGFloat dY = 3.f;//space between controls. - for (unsigned i = 0; i < nStates; ++i) { - CGFloat currentY = 0.f; - for (unsigned j = 0; j < nEditors; ++j) { - plateYs[nEditors * i + j] = currentY; - currentY += plates[j].frame.size.height + dY; - - const unsigned editorBit = 1 << j; - if (i & editorBit) {//In this state, j-th editor is visible. - viewYs[nEditors * i + j] = currentY; - currentY += views[j].frame.size.height + dY; - } else - viewYs[nEditors * i + j] = 0.f;//coordinate is not used, currentY does not need update. - } - } - - //Now, the total container height. - CGFloat totalHeight = 0.f; - for (unsigned i = 0; i < nEditors; ++i) - totalHeight += plates[i].frame.size.height + dY + views[i].frame.size.height + dY; - - return totalHeight; -} - -//____________________________________________________________________________________________________ -- (void) correctFrames -{ - CGRect frame = self.frame; - frame.origin.x = 10.f; - frame.origin.y = 45.f; - frame.size.height -= 55.f; - frame.size.width = 250.f; - scrollView.frame = frame; - - const CGFloat totalHeight = [self recalculateEditorGeometry]; - scrollView.contentSize = CGSizeMake([EditorView scrollWidth], totalHeight); - scrollView.contentOffset = CGPointZero; -} - -//____________________________________________________________________________________________________ -- (void) setPlatesYs -{ - //Plates positions for the current state. - for (unsigned i = 0; i < nEditors; ++i) { - CGRect frame = plates[i].frame; - frame.origin.y = plateYs[nEditors * currentState + i]; - plates[i].frame = frame; - } -} - -//____________________________________________________________________________________________________ -- (void) addSubEditor:(UIView *)element withName : (NSString *)name -{ - if (nEditors == evMaxComponents) { - NSLog(@"Could not add more editors"); - return; - } - - //Add this new editor. - views[nEditors] = element; - //1. Plate with editor's name and triangle, showing the editor's state. - //topView is 'self' - the view, which will be informed, that user tapped on editor's plate. - plates[nEditors] = [[EditorPlateView alloc] initWithFrame : CGRectMake(0.f, 0.f, [EditorView scrollWidth], [EditorPlateView plateHeight]) editorName : name topView : self]; - [scrollView addSubview : plates[nEditors]]; - - //Create a container view for sub-editor. - CGRect elementFrame = element.frame; - elementFrame.origin = CGPointZero; - containers[nEditors] = [[UIView alloc] initWithFrame : elementFrame]; - element.frame = elementFrame; - //Place sub-editor into the container view. - [containers[nEditors] addSubview : element]; - //Clip to bounds: when we animate sub-editor (appear/disappera) - //it moves from/to negative coordinates and this negative part - //should not be visible. - containers[nEditors].clipsToBounds = YES; - //Initially, container with sub-editor is hidden. - containers[nEditors].hidden = YES; - //Add container. - [scrollView addSubview : containers[nEditors]]; - - //New number of sub-editors and possible editor states. - ++nEditors; - nStates = 1 << nEditors; - - //Recalculate possible positions of all plates and containers. - const CGFloat totalHeight = [self recalculateEditorGeometry]; - //Set scrollView.contentSize to include all sub-editors in opened state. - scrollView.contentSize = CGSizeMake([EditorView scrollWidth], totalHeight); - scrollView.contentOffset = CGPointZero; - - //No sub-editor is visible. - currentState = 0; - //Also, make new sub-editor transparent. - element.alpha = 0.f; - - //Place all plates. - [self setPlatesYs]; -} - -//____________________________________________________________________________________________________ -- (void) presetViewsYs -{ - //These are sub-views positions before animation. - for (unsigned i = 0; i < nEditors; ++i) { - //If view must appear now: - if (containers[i].hidden && (currentState & (1 << i))) { - CGRect frame = views[i].frame; - frame.origin.y = viewYs[currentState * nEditors + i]; - //Place the container in a correct position. - containers[i].frame = frame; - //Contained view is shifted in a container (it will appear from nowhere). - frame.origin.y = -frame.size.height; - views[i].frame = frame; - } - } -} - -//____________________________________________________________________________________________________ -- (void) setViewsYs -{ - //These are new sub-views positions at the end of animation. - for (unsigned i = 0; i < nEditors; ++i) { - CGRect frame = views[i].frame; - if (currentState & (1 << i)) {//View will become visible now (and could be visible before). - frame.origin.y = viewYs[currentState * nEditors + i]; - containers[i].frame = frame; - frame.origin.y = 0.; - views[i].frame = frame; - } else if (!views[i].hidden) {//View will hide now - it moves outside of container. - frame.origin.y = -frame.size.height; - views[i].frame = frame; - } - } -} - -//____________________________________________________________________________________________________ -- (void) setViewsAlphaAndVisibility -{ - //During animation, if view will appear it's alpha changes from 0 to 1, - //and if it's going to disappear - from 1 to 0. - //Also, I have to animate small triangle, which - //shows editor's state (hidden/visible). - for (unsigned i = 0; i < nEditors; ++i) { - EditorPlateView *p = (EditorPlateView *)plates[i]; - UIView *v = views[i]; - const BOOL nowVisible = currentState & (1 << i); - if (containers[i].hidden) { - if (nowVisible) { - containers[i].hidden = NO; - v.alpha = 1.f; - p.arrowImageView.transform = CGAffineTransformMakeRotation(M_PI / 2);//rotate the triangle. - } - } else { - if (!nowVisible) { - p.arrowImageView.transform = CGAffineTransformMakeRotation(0.f);//rotate the triangle. - v.alpha = 0.f; - } - } - } -} - -//____________________________________________________________________________________________________ -- (void) hideViews -{ - for (unsigned i = 0; i < nEditors; ++i) { - if (!(currentState & (1 << i))) - containers[i].hidden = YES; - } -} - -//____________________________________________________________________________________________________ -- (void) showEditorFrame -{ - CGRect frameToShow = CGRectMake(0.f, 0.f, 250.f, 90.f); - - if (newOpened != -1) { - frameToShow = containers[newOpened].frame; - frameToShow.origin.y = viewYs[currentState * nEditors + newOpened] - 70.f; - frameToShow.size.height += 70.f; - } - - [scrollView scrollRectToVisible : frameToShow animated : YES]; - animation = NO; -} - -//____________________________________________________________________________________________________ -- (void) animateEditor -{ - animation = YES; - - [self presetViewsYs]; - - [UIView beginAnimations : nil context : nil]; - [UIView setAnimationDuration : 0.25]; - [UIView setAnimationCurve : UIViewAnimationCurveEaseOut]; - - [self setPlatesYs]; - [self setViewsYs]; - [self setViewsAlphaAndVisibility]; - - [UIView commitAnimations]; - - //Do not hide the views immediately, so user can see animation. - [NSTimer scheduledTimerWithTimeInterval : 0.15 target : self selector : @selector(hideViews) userInfo : nil repeats : NO]; - [NSTimer scheduledTimerWithTimeInterval : 0.3 target : self selector : @selector(showEditorFrame) userInfo : nil repeats : NO]; -} - -//____________________________________________________________________________________________________ -- (void) plateTapped : (EditorPlateView *) plate -{ - if (animation) - return; - //User has tapped on editor's plate. - //Depending on the current editor's state, - //we open or close it with animation. - newOpened = -1; - - for (unsigned i = 0; i < nEditors; ++i) { - if (plate != plates[i]) { - if (currentState & (1 << i)) - newOpened = i;//Remember the index of opened editor above our plate. - } else { - currentState ^= (1 << i);//reset the bit for the editor. - - if (currentState & (1 << i))//plate's editor was opened. - newOpened = i; - else if (currentState) {//Is any editor opened at all? - //plate's editor was closed, find the next which we can be made visible. - if (newOpened == -1) {//we did not find any opened editor above the plate yet. - for (unsigned j = i + 1; j < nEditors; ++j) { - if (currentState & (1 << j)) { - newOpened = j; - break; - } - } - } - } - - [self animateEditor]; - break; - } - } -} - -//____________________________________________________________________________________________________ -- (void) setEditorTitle : (const char*) title -{ - editorTitle.text = [NSString stringWithFormat : @"%s", title]; -} - -@end diff --git a/test/ios/RootBrowser/FileContainerElement.h b/test/ios/RootBrowser/FileContainerElement.h deleted file mode 100644 index 311abb71885c9..0000000000000 --- a/test/ios/RootBrowser/FileContainerElement.h +++ /dev/null @@ -1,6 +0,0 @@ -@interface FileContainerElement : NSObject - -@property (nonatomic, retain) NSString *elementName; -@property (nonatomic, assign) unsigned elementIndex; - -@end diff --git a/test/ios/RootBrowser/FileContainerElement.mm b/test/ios/RootBrowser/FileContainerElement.mm deleted file mode 100644 index ab47a8fd2ae96..0000000000000 --- a/test/ios/RootBrowser/FileContainerElement.mm +++ /dev/null @@ -1,8 +0,0 @@ -#import "FileContainerElement.h" - -@implementation FileContainerElement - -@synthesize elementName; -@synthesize elementIndex; - -@end diff --git a/test/ios/RootBrowser/FileContentController.h b/test/ios/RootBrowser/FileContentController.h deleted file mode 100644 index 2e65cf761860f..0000000000000 --- a/test/ios/RootBrowser/FileContentController.h +++ /dev/null @@ -1,32 +0,0 @@ -#import - -#import "SearchController.h" - -@class FileContainerElement; -@class ObjectShortcut; - -namespace ROOT { -namespace iOS { -namespace Browser { - -class FileContainer; - -} -} -} - -@interface FileContentController : UIViewController { -@private - ROOT::iOS::Browser::FileContainer *fileContainer; - __weak IBOutlet UIScrollView *scrollView; -} - -//@property (nonatomic, assign) id * -@property (nonatomic, readonly) ROOT::iOS::Browser::FileContainer *fileContainer; - -- (void) activateForFile : (ROOT::iOS::Browser::FileContainer *)container; -- (void) selectObjectFromFile : (ObjectShortcut *)obj; - -- (void) searchesController : (SearchController *)controller didSelectKey:(FileContainerElement *)key; - -@end diff --git a/test/ios/RootBrowser/FileContentController.mm b/test/ios/RootBrowser/FileContentController.mm deleted file mode 100644 index b265b321cdca1..0000000000000 --- a/test/ios/RootBrowser/FileContentController.mm +++ /dev/null @@ -1,468 +0,0 @@ -#import - -#import -#import - -#import "FileContentController.h" -#import "ROOTObjectController.h" -#import "FileContainerElement.h" -#import "SlideshowController.h" -#import "TransparentToolbar.h" -#import "SearchController.h" -#import "ObjectShortcut.h" -#import "Shortcuts.h" -#import "SpotView.h" - - -//C++ imports. -#import "IOSPad.h" - -#import "FileUtils.h" - -@interface FileContentController () { - NSMutableArray *objectShortcuts; - UISearchBar *searchBar; - UIPopoverController *searchPopover; - SearchController *searchController; - UIBarButtonItem *slideShowBtn; - - BOOL animateDirAfterLoad; - BOOL animateObjAfterLoad; - unsigned spotElement; -} - -- (void) highlightDirectory : (unsigned)tag; -- (void) highlightObject : (unsigned)tag; - -@end - - -@implementation FileContentController - -@synthesize fileContainer; - - -//____________________________________________________________________________________________________ -- (void) initToolbarItems -{ - UIToolbar *toolbar = [[TransparentToolbar alloc] initWithFrame : CGRectMake(0.f, 0.f, 250.f, 44.f)]; - toolbar.barStyle = UIBarStyleBlackTranslucent; - - NSMutableArray *items = [[NSMutableArray alloc] initWithCapacity : 2]; - - searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.f, 0.f, 150.f, 44.f)]; - searchBar.delegate = self; - - UIBarButtonItem *searchItem = [[UIBarButtonItem alloc] initWithCustomView : searchBar]; - [items addObject : searchItem]; - - slideShowBtn = [[UIBarButtonItem alloc] initWithTitle : @"Slide show" style : UIBarButtonItemStyleBordered target : self action : @selector(startSlideshow)]; - [items addObject : slideShowBtn]; - - [toolbar setItems : items animated : NO]; - - UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithCustomView : toolbar]; - rightItem.style = UIBarButtonItemStylePlain; - self.navigationItem.rightBarButtonItem = rightItem; - - -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - - if (self) { - [self view]; - [self initToolbarItems]; - searchController = [[SearchController alloc] initWithStyle : UITableViewStylePlain]; - searchController.delegate = self; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - - -//____________________________________________________________________________________________________ -- (void) correctFramesForOrientation : (UIInterfaceOrientation) orientation -{ - //TODO: all this staff with manual geometry management should be deleted, as soon as I switch to - //ThumbnailView class. - CGRect mainFrame; - CGRect scrollFrame; - - if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) { - mainFrame = CGRectMake(0.f, 0.f, 768.f, 1004.f); - scrollFrame = CGRectMake(0.f, 44.f, 768.f, 960.f); - } else { - mainFrame = CGRectMake(0.f, 0.f, 1024.f, 748.f); - scrollFrame = CGRectMake(0.f, 44.f, 1024.f, 704.f); - } - - self.view.frame = mainFrame; - scrollView.frame = scrollFrame; - - if ([[scrollView subviews] count]) - [ShorcutUtil placeShortcuts : objectShortcuts inScrollView : scrollView withSize : CGSizeMake([ObjectShortcut iconWidth], [ObjectShortcut iconHeight] + [ObjectShortcut textHeight]) andSpace : 100.f]; -} - -//____________________________________________________________________________________________________ -- (void) viewWillAppear:(BOOL)animated -{ - //TODO: all this staff with manual geometry management should be deleted, as soon as I switch to - //ThumbnailView class. - //self.interfaceOrientation ? - [self correctFramesForOrientation : [UIApplication sharedApplication].statusBarOrientation]; -} - -//____________________________________________________________________________________________________ -- (void) viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void) viewDidAppear:(BOOL)animated -{ - [super viewDidAppear : animated]; - if (animateDirAfterLoad) { - [self highlightDirectory : spotElement]; - animateDirAfterLoad = NO; - } else if (animateObjAfterLoad) { - [self highlightObject : spotElement]; - animateObjAfterLoad = NO; - } -} - -//____________________________________________________________________________________________________ -- (void) viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void) willAnimateRotationToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration -{ - //TODO: all this staff with manual geometry management should be deleted, as soon as I switch to - //ThumbnailView class. - - [self correctFramesForOrientation : interfaceOrientation]; -} - -//____________________________________________________________________________________________________ -- (void) didRotateFromInterfaceOrientation : (UIInterfaceOrientation)fromInterfaceOrientation -{ - //Bring back the popover after rotating. - if (searchPopover) { - [searchPopover presentPopoverFromRect : searchBar.bounds inView : searchBar - permittedArrowDirections : UIPopoverArrowDirectionAny animated : NO]; - } -} - -//____________________________________________________________________________________________________ -- (void) clearScrollview -{ - NSArray *viewsToRemove = [scrollView subviews]; - for (UIView *v in viewsToRemove) - [v removeFromSuperview]; - -} - -//____________________________________________________________________________________________________ -- (void) addShortcutForObjectAtIndex : (unsigned) objIndex -{ - const CGRect rect = CGRectMake(0.f, 0.f, [ObjectShortcut iconWidth], [ObjectShortcut iconHeight]); - UIGraphicsBeginImageContext(rect.size); - CGContextRef ctx = UIGraphicsGetCurrentContext(); - if (!ctx) { - UIGraphicsEndImageContext(); - return; - } - - //Now draw into this context. - CGContextTranslateCTM(ctx, 0.f, rect.size.height); - CGContextScaleCTM(ctx, 1.f, -1.f); - - //Fill bitmap with white first. - CGContextSetRGBFillColor(ctx, 1.f, 1.f, 1.f, 1.f); - CGContextFillRect(ctx, rect); - //Set context and paint pad's contents. - ROOT::iOS::Pad *pad = fileContainer->GetPadAttached(objIndex); - pad->cd(); - pad->SetViewWH(rect.size.width, rect.size.height); - pad->SetContext(ctx); - pad->PaintThumbnail(); - - UIImage *thumbnailImage = UIGraphicsGetImageFromCurrentImageContext();//autoreleased UIImage. - UIGraphicsEndImageContext(); - - ObjectShortcut *shortcut = [[ObjectShortcut alloc] initWithFrame : [ObjectShortcut defaultRect] controller : self forObjectAtIndex:objIndex withThumbnail : thumbnailImage]; - shortcut.layer.shadowColor = [UIColor blackColor].CGColor; - shortcut.layer.shadowOffset = CGSizeMake(20.f, 20.f); - shortcut.layer.shadowOpacity = 0.3f; - - [scrollView addSubview : shortcut]; - [objectShortcuts addObject : shortcut]; - - UIBezierPath *path = [UIBezierPath bezierPathWithRect : rect]; - shortcut.layer.shadowPath = path.CGPath; -} - -//____________________________________________________________________________________________________ -- (void) addShortcutForFolderAtIndex : (unsigned) index -{ - ObjectShortcut *shortcut = [[ObjectShortcut alloc] initWithFrame : [ObjectShortcut defaultRect] controller : self forFolderAtIndex : index]; - [scrollView addSubview : shortcut]; - [objectShortcuts addObject : shortcut]; -} - -//____________________________________________________________________________________________________ -- (void) addObjectsIntoScrollview -{ - using namespace ROOT::iOS::Browser; - - [self clearScrollview]; - - objectShortcuts = [[NSMutableArray alloc] init]; - - //Add directories first. - for (FileContainer::size_type i = 0; i < fileContainer->GetNumberOfDirectories(); ++i) - [self addShortcutForFolderAtIndex : i]; - //Now add objects. - for (FileContainer::size_type i = 0; i < fileContainer->GetNumberOfObjects(); ++i) - [self addShortcutForObjectAtIndex : i]; -} - -//____________________________________________________________________________________________________ -- (void) activateForFile : (ROOT::iOS::Browser::FileContainer *)container -{ - fileContainer = container; - self.navigationItem.title = [NSString stringWithFormat : @"Contents of %s", container->GetFileName()]; - slideShowBtn.enabled = fileContainer->GetNumberOfObjects() > 1 ? YES : NO; - - //Prepare objects' thymbnails. - [self addObjectsIntoScrollview]; - [self correctFramesForOrientation : [UIApplication sharedApplication].statusBarOrientation]; -} - -//____________________________________________________________________________________________________ -- (void) startSlideshow -{ - SlideshowController *slideshowController = [[SlideshowController alloc] initWithNibName : @"SlideshowController" bundle : nil fileContainer : fileContainer]; - [self.navigationController pushViewController : slideshowController animated : YES]; -} - -//____________________________________________________________________________________________________ -- (void) doTest -{ - const unsigned testIndex = 1 + rand() % (fileContainer->GetNumberOfObjects() - 1); - ROOTObjectController *objectController = [[ROOTObjectController alloc] initWithNibName:@"ROOTObjectController" bundle : nil]; - [objectController setNavigationForObjectWithIndex : testIndex fromContainer : fileContainer]; - [self.navigationController pushViewController : objectController animated : YES]; -} - -//____________________________________________________________________________________________________ -- (void) selectObjectFromFile : (ObjectShortcut *) shortcut -{ - if (shortcut.isDirectory) { - //Create another FileContentController and push it on stack. - FileContentController *contentController = [[FileContentController alloc] initWithNibName : @"FileContentController" bundle : nil]; - [contentController activateForFile : fileContainer->GetDirectory(shortcut.objectIndex)]; - [self.navigationController pushViewController : contentController animated : YES]; - } else { - ROOTObjectController *objectController = [[ROOTObjectController alloc] initWithNibName : @"ROOTObjectController" bundle : nil]; - [objectController setNavigationForObjectWithIndex : shortcut.objectIndex fromContainer : fileContainer]; - [self.navigationController pushViewController : objectController animated : YES]; - } -} - -#pragma mark - Search delegate. - -//____________________________________________________________________________________________________ -- (void) searchBarTextDidBeginEditing : (UISearchBar *)aSearchBar -{ - typedef ROOT::iOS::Browser::FileContainer::size_type size_type; - - if (auto nEntities = fileContainer->GetNumberOfDescriptors()) { - if (!searchPopover) { - UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController : searchController]; - searchPopover = [[UIPopoverController alloc] initWithContentViewController : navController]; - searchPopover.delegate = self; - searchPopover.passthroughViews = [NSArray arrayWithObject : searchBar]; - } - - NSMutableArray *keys = [[NSMutableArray alloc] init]; - for (size_type i = 0; i < nEntities; ++i) { - const auto &descriptor = fileContainer->GetElementDescriptor(i); - NSString *formatString = descriptor.fIsDir ? @"%s (directory)" : @"%s"; - FileContainerElement *newKey = [[FileContainerElement alloc] init]; - newKey.elementName = [NSString stringWithFormat : formatString, descriptor.fName.c_str()]; - newKey.elementIndex = i; - [keys addObject : newKey]; - } - - searchController.keys = keys; - [searchPopover presentPopoverFromRect : [searchBar bounds] inView : searchBar permittedArrowDirections : UIPopoverArrowDirectionAny animated : YES]; - } -} - -//____________________________________________________________________________________________________ -- (void) searchBarTextDidEndEditing : (UISearchBar *)aSearchBar -{ - if (searchPopover) { - [searchPopover dismissPopoverAnimated:YES]; - searchPopover = nil; - } - - [aSearchBar resignFirstResponder]; -} - -//____________________________________________________________________________________________________ -- (void) searchBar : (UISearchBar *)searchBar textDidChange : (NSString *)searchText -{ - // When the search string changes, filter the recents list accordingly. - [searchController filterResultsUsingString : searchText]; -} - -//____________________________________________________________________________________________________ -- (void) searchBarSearchButtonClicked : (UISearchBar *)aSearchBar -{ - //NSLog(@"search clicked"); - [searchPopover dismissPopoverAnimated : YES]; - [searchBar resignFirstResponder]; -} - -#pragma mark - Popover controller delegate. - -//____________________________________________________________________________________________________ -- (void) popoverControllerDidDismissPopover : (UIPopoverController *)popoverController -{ - //NSLog(@"popover dismiss"); - [searchBar resignFirstResponder]; -} - -#pragma mark - Search delegate. - -//____________________________________________________________________________________________________ -- (void) searchesController : (SearchController *)controller didSelectKey : (FileContainerElement *)key -{ - //NSLog(@"selected %@ with index %d", key.elementName, key.elementIndex); - assert(key.elementIndex < fileContainer->GetNumberOfDescriptors()); - - [searchPopover dismissPopoverAnimated : YES]; - searchPopover = nil; - [searchBar resignFirstResponder]; - - const auto &descriptor = fileContainer->GetElementDescriptor(key.elementIndex); - if (descriptor.fOwner == fileContainer) { - descriptor.fIsDir ? [self highlightDirectory : descriptor.fIndex] : [self highlightObject : descriptor.fIndex]; - } else { - //Create another FileContentController and push it on stack. - FileContentController *contentController = [[FileContentController alloc] initWithNibName : @"FileContentController" bundle : nil]; - [contentController activateForFile : descriptor.fOwner]; - - if (descriptor.fIsDir) - contentController->animateDirAfterLoad = YES; - else - contentController->animateObjAfterLoad = YES; - - contentController->spotElement = descriptor.fIndex; - - [self.navigationController pushViewController : contentController animated : YES]; - } -} - -#pragma mark - adjust file container to show search result - -//____________________________________________________________________________________________________ -- (void) animateShortcut : (ObjectShortcut *) sh -{ - CGAffineTransform originalTransform = sh.transform; - CGAffineTransform newTransform = CGAffineTransformScale(originalTransform, 1.2f, 1.2f); - - [UIView beginAnimations : @"hide_object" context : nil]; - [UIView setAnimationDuration : 1.5f]; - [UIView setAnimationCurve : UIViewAnimationCurveLinear]; - [UIView setAnimationTransition : UIViewAnimationTransitionNone forView : sh cache : YES]; - sh.transform = newTransform; - sh.spot.alpha = 0.8f; - [UIView commitAnimations]; - - [UIView beginAnimations : @"show_object" context : nil]; - [UIView setAnimationDuration : 1.f]; - [UIView setAnimationCurve : UIViewAnimationCurveLinear]; - [UIView setAnimationTransition : UIViewAnimationTransitionNone forView : sh cache : YES]; - sh.transform = originalTransform; - sh.spot.alpha = 0.f; - [UIView commitAnimations]; -} - -//____________________________________________________________________________________________________ -- (void) highlightDirectory : (unsigned)tag -{ - for (ObjectShortcut *sh in objectShortcuts) { - if (sh.objectIndex == tag && sh.isDirectory) { - const CGRect thumbFrame = sh.frame; - const CGRect scrollBounds = scrollView.bounds; - if (CGRectGetMaxY(thumbFrame) > CGRectGetMaxY(scrollBounds)) { - //We have to scroll view to show object's or directory's shortcut. - //Find new Y for bounds. - const CGFloat newY = CGRectGetMaxY(thumbFrame) - scrollBounds.size.height; - CGRect newBounds = scrollBounds; - newBounds.origin.y = newY; - [scrollView scrollRectToVisible : newBounds animated : YES]; - } - - [self animateShortcut : sh]; - - break; - } - } -} - -//____________________________________________________________________________________________________ -- (void) highlightObject : (unsigned)tag -{ - for (ObjectShortcut *sh in objectShortcuts) { - if (sh.objectIndex == tag && !sh.isDirectory) { - CGRect thumbFrame = sh.frame; - const CGRect scrollBounds = scrollView.bounds; - if (CGRectGetMaxY(thumbFrame) > CGRectGetMaxY(scrollBounds)) { - //We have to scroll view to show object's or directory's shortcut. - //Find new Y for bounds. - const CGFloat newY = CGRectGetMaxY(thumbFrame) - scrollBounds.size.height; - CGRect newBounds = scrollBounds; - newBounds.origin.y = newY; - [scrollView scrollRectToVisible : newBounds animated : YES]; - } - - [self animateShortcut : sh]; - - break; - } - } -} - -@end diff --git a/test/ios/RootBrowser/FileContentController.xib b/test/ios/RootBrowser/FileContentController.xib deleted file mode 100644 index e618ec66a6edd..0000000000000 --- a/test/ios/RootBrowser/FileContentController.xib +++ /dev/null @@ -1,201 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - YES - IBProxyObject - IBUIView - IBUIScrollView - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 274 - {1024, 748} - - - - - 3 - MCAwAA - - YES - YES - IBIPadFramework - - - {{0, 20}, {1024, 748}} - - - - - NO - - 2 - - - 3 - 3 - - IBIPadFramework - - - - - YES - - - view - - - - 7 - - - - scrollView - - - - 8 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - YES - - - - - - 5 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 2.IBPluginDependency - 5.IBPluginDependency - - - YES - FileContentController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 10 - - - - YES - - FileContentController - UIViewController - - scrollView - UIScrollView - - - scrollView - - scrollView - UIScrollView - - - - IBProjectSource - ./Classes/FileContentController.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 933 - - diff --git a/test/ios/RootBrowser/FileShortcut.h b/test/ios/RootBrowser/FileShortcut.h deleted file mode 100644 index 410a6a031a253..0000000000000 --- a/test/ios/RootBrowser/FileShortcut.h +++ /dev/null @@ -1,24 +0,0 @@ -#import - - -namespace ROOT { -namespace iOS { -namespace Browser { - -class FileContainer; - -} -} -} - -@interface FileShortcut : UIView - -@property (nonatomic, retain) NSString *fileName; - -+ (CGFloat) iconWidth; -+ (CGFloat) iconHeight; - -- (id) initWithFrame : (CGRect)frame controller : (UIViewController *)controller fileContainer : (ROOT::iOS::Browser::FileContainer *)container; -- (ROOT::iOS::Browser::FileContainer *) getFileContainer; - -@end diff --git a/test/ios/RootBrowser/FileShortcut.mm b/test/ios/RootBrowser/FileShortcut.mm deleted file mode 100644 index 2aa677f2bfb0c..0000000000000 --- a/test/ios/RootBrowser/FileShortcut.mm +++ /dev/null @@ -1,112 +0,0 @@ -#import -#import -#import - -#import "RootFileController.h" -#import "FileShortcut.h" - -//C++ imports. -#import "FileUtils.h" - -@implementation FileShortcut { - __weak UIViewController *controller; - - UIImage *filePictogram; - - ROOT::iOS::Browser::FileContainer *fileContainer; -} - -@synthesize fileName; - -//____________________________________________________________________________________________________ -+ (CGFloat) iconWidth -{ - return 150.f; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) textHeight -{ - return 50.f; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) iconHeight -{ - return [FileShortcut iconWidth] + [FileShortcut textHeight]; -} - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame controller : (UIViewController *)viewController fileContainer : (ROOT::iOS::Browser::FileContainer *)container; -{ - self = [super initWithFrame : frame]; - - if (self) { - controller = viewController; - fileContainer = container; - - self.fileName = [NSString stringWithFormat : @"%s", fileContainer->GetFileName()]; - filePictogram = [UIImage imageNamed : @"file_icon.png"]; - UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector(handleTap)]; - [self addGestureRecognizer : tap]; - UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget: self action:@selector(handleLongPress:)]; - [self addGestureRecognizer : longPress]; - - self.opaque = NO; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) drawRect : (CGRect)rect -{ - // Drawing code - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - //Draw the pictogram for ROOT's file. - const CGPoint topLeftPicCorner = CGPointMake(rect.size.width / 2 - filePictogram.size.width / 2, - (rect.size.height - [FileShortcut textHeight]) / 2 - filePictogram.size.height / 2); - [filePictogram drawAtPoint:topLeftPicCorner]; - - //Draw the file name. - CGContextSetRGBFillColor(ctx, 1.f, 1.f, 1.f, 1.f); - const CGRect textRect = CGRectMake(0.f, [FileShortcut iconHeight] - [FileShortcut textHeight], [FileShortcut iconWidth], [FileShortcut textHeight]); - -#ifdef __IPHONE_6_0 - [fileName drawInRect : textRect withFont : [UIFont systemFontOfSize : 16] lineBreakMode : NSLineBreakByWordWrapping alignment : NSTextAlignmentCenter]; -#else - [fileName drawInRect : textRect withFont : [UIFont systemFontOfSize : 16] lineBreakMode : UILineBreakModeWordWrap alignment : UITextAlignmentCenter]; -#endif -} - -//____________________________________________________________________________________________________ -- (void)dealloc -{ - //Crazy name qualification :( - ROOT::iOS::Browser::FileContainer::DeleteFileContainer(fileContainer); -} - -//____________________________________________________________________________________________________ -- (void) handleTap -{ - RootFileController *parentController = (RootFileController *)controller; - [parentController fileWasSelected : self]; -} - -//____________________________________________________________________________________________________ -- (void) handleLongPress : (UILongPressGestureRecognizer *)longPress -{ - if (longPress.state == UIGestureRecognizerStateBegan) { - RootFileController *parentController = (RootFileController *)controller; - [parentController tryToDelete : self]; - } -} - -//____________________________________________________________________________________________________ -- (ROOT::iOS::Browser::FileContainer *) getFileContainer -{ - return fileContainer; -} - -@end diff --git a/test/ios/RootBrowser/FileUtils.cxx b/test/ios/RootBrowser/FileUtils.cxx deleted file mode 100644 index d52965228ef9c..0000000000000 --- a/test/ios/RootBrowser/FileUtils.cxx +++ /dev/null @@ -1,368 +0,0 @@ -#include -#include -#include - -#include "TMultiGraph.h" -#include "TGraphPolar.h" -#include "TSystem.h" -#include "IOSPad.h" -#include "TFile.h" -#include "TList.h" -#include "TKey.h" -#include "TH1.h" -#include "TF2.h" - -#include "FileUtils.h" - -namespace ROOT { -namespace iOS { -namespace Browser { - -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -void FillVisibleTypes(std::set &types) -{ - types.insert("TH1C"); - types.insert("TH1D"); - types.insert("TH1F"); - types.insert("TH1I"); - types.insert("TH1K"); - types.insert("TH1S"); - types.insert("TH2C"); - types.insert("TH2D"); - types.insert("TH2F"); - types.insert("TH2I"); - types.insert("TH2Poly"); - types.insert("TH2S"); - types.insert("TH3C"); - types.insert("TH3D"); - types.insert("TH3F"); - types.insert("TH3I"); - types.insert("TH3S"); - types.insert("TF2"); - types.insert("TGraphPolar"); - types.insert("TMultiGraph"); -} - -const char *errorOptionToString[] = {"", "E", "E1", "E2", "E3", "E4"}; - -//////////////////////////////////////////////////////////////////////////////// - -void RemoveErrorDrawOption(TString &options) -{ - const Ssiz_t pos = options.Index("E"); - if (pos != kNPOS) { - - Ssiz_t n = 1; - if (pos + 1 < options.Length()) { - const char nextChar = options[pos + 1]; - if (std::isdigit(nextChar) && (nextChar - '0' >= 1 && nextChar - '0' <= 4)) - n = 2; - } - - options.Remove(pos, n); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void RemoveMarkerDrawOption(TString &options) -{ - const Ssiz_t pos = options.Index("P"); - if (pos != kNPOS) - options.Remove(pos, 1); -} - -//////////////////////////////////////////////////////////////////////////////// - -TObject *ReadObjectForKey(TDirectoryFile *inputFile, const TKey *key, TString &option) -{ - option = ""; - - TObject *objPtr = inputFile->Get(key->GetName()); - if (!objPtr) - throw std::runtime_error("bad key in ReadObjectForKey"); - //Objects of some types are onwed by the file. So I have to make - //them free from such ownership to make - //their processing later more uniform. - if (TH1 *hist = dynamic_cast(objPtr)) - hist->SetDirectory(0); - - //The code below can throw, so I use unique_ptr. - std::unique_ptr obj(objPtr); - - //This is the trick, since ROOT seems not to preserve - //Draw's option in a file. - if (dynamic_cast(obj.get())) - option = "surf1"; - if (dynamic_cast(obj.get())) - option = "acp"; - - //All this "home-made memory management" is an ugly and broken thing. - obj->SetBit(kCanDelete, kFALSE); - obj->SetBit(kMustCleanup, kFALSE); - - return obj.release(); -} - -}//Unnamed namespace - -//////////////////////////////////////////////////////////////////////////////// - -FileContainer::FileContainer(const std::string &fileName) - : fFileName(fileName) -{ -} - - -//////////////////////////////////////////////////////////////////////////////// - -FileContainer::~FileContainer() -{ - for (auto dir : fDirectories) - delete dir; - for (auto fileContainer : fObjects) - delete fileContainer; - for (auto pad : fAttachedPads) - delete pad; -} - -//////////////////////////////////////////////////////////////////////////////// - -auto FileContainer::GetNumberOfObjects()const -> size_type -{ - return fObjects.size(); -} - -//////////////////////////////////////////////////////////////////////////////// - -TObject *FileContainer::GetObject(size_type ind)const -{ - return fObjects[ind]; -} - -//////////////////////////////////////////////////////////////////////////////// - -const char *FileContainer::GetDrawOption(size_type ind)const -{ - return fOptions[ind].Data(); -} - -//////////////////////////////////////////////////////////////////////////////// - -Pad *FileContainer::GetPadAttached(size_type ind)const -{ - return fAttachedPads[ind]; -} - -//////////////////////////////////////////////////////////////////////////////// -///Nothing to change. - -void FileContainer::SetErrorDrawOption(size_type ind, EHistogramErrorOption opt) -{ - if (GetErrorDrawOption(ind) == opt) - return; - - //1. Remove previous error options (if any). - RemoveErrorDrawOption(fOptions[ind]); - //2. Add new option. - fOptions[ind] += errorOptionToString[opt]; -} - -//////////////////////////////////////////////////////////////////////////////// - -EHistogramErrorOption FileContainer::GetErrorDrawOption(size_type ind)const -{ - const TString &options = fOptions[ind]; - const Ssiz_t pos = options.Index("E"); - if (pos == kNPOS) - return hetNoError; - - if (pos + 1 < options.Length()) { - const char nextChar = options[pos + 1]; - if (nextChar == '1') - return hetE1; - if (nextChar == '2') - return hetE2; - if (nextChar == '3') - return hetE3; - if (nextChar == '4') - return hetE4; - } - - return hetE; -} - -//////////////////////////////////////////////////////////////////////////////// - -void FileContainer::SetMarkerDrawOption(size_type ind, bool on) -{ - if (GetMarkerDrawOption(ind) == on) - return; - - RemoveMarkerDrawOption(fOptions[ind]); - - if (on) - fOptions[ind] += "P"; -} - -//////////////////////////////////////////////////////////////////////////////// - -bool FileContainer::GetMarkerDrawOption(size_type ind)const -{ - return fOptions[ind].Index("P") != kNPOS; -} - -//////////////////////////////////////////////////////////////////////////////// - -auto FileContainer::GetNumberOfDirectories()const -> size_type -{ - return fDirectories.size(); -} - -//////////////////////////////////////////////////////////////////////////////// - -FileContainer *FileContainer::GetDirectory(size_type ind)const -{ - return fDirectories[ind]; -} - -//////////////////////////////////////////////////////////////////////////////// - -const char *FileContainer::GetFileName()const -{ - return fFileName.c_str(); -} - -//////////////////////////////////////////////////////////////////////////////// - -void FileContainer::AttachPads() -{ - if (!fObjects.size()) - return; - - fAttachedPads.assign(fObjects.size(), 0); - for (size_type i = 0; i < fAttachedPads.size(); ++i) { - std::unique_ptr newPad(new Pad(400, 400));//400 - size is NOT important here, it'll be reset later anyway. - newPad->cd(); - fObjects[i]->Draw(fOptions[i].Data()); - fAttachedPads[i] = newPad.release(); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -auto FileContainer::GetNumberOfDescriptors()const -> size_type -{ - return fContentDescriptors.size(); -} - -//////////////////////////////////////////////////////////////////////////////// - -auto FileContainer::GetElementDescriptor(size_type index)const -> const FileContainerElement & -{ - return fContentDescriptors[index]; -} - -//////////////////////////////////////////////////////////////////////////////// - -void FileContainer::ScanDirectory(TDirectoryFile *dir, const std::set &visibleTypes, FileContainer *currentContainer) -{ - const TList *objKeys = dir->GetListOfKeys(); - if (!objKeys) - return; - - TString option; - std::vector objs; - std::vector dirs; - std::vector opts; - std::vector descriptors; - - TObjLink *link = objKeys->FirstLink(); - - try { - while (link) { - const TKey *key = static_cast(link->GetObject()); - const TString className(key->GetClassName()); - - if (className == "TDirectoryFile") { - std::unique_ptr nestedDir(static_cast(dir->Get(key->GetName()))); - if (nestedDir.get()) { - //Recursion - create nested container. - std::unique_ptr nestedContainer(new FileContainer(key->GetName())); - ScanDirectory(nestedDir.get(), visibleTypes, nestedContainer.get()); - nestedContainer->AttachPads(); - - FileContainerElement newDescriptor(key->GetName(), currentContainer, true, dirs.size()); - descriptors.push_back(newDescriptor); - descriptors.insert(descriptors.end(), nestedContainer->fContentDescriptors.begin(), nestedContainer->fContentDescriptors.end()); - - dirs.push_back(nestedContainer.get()); - nestedContainer.release(); - } - } else if (visibleTypes.find(className) != visibleTypes.end()) { - std::unique_ptr newObject(ReadObjectForKey(dir, key, option)); - opts.push_back(option); - - FileContainerElement newDescriptor(key->GetName(), currentContainer, false, objs.size()); - descriptors.push_back(newDescriptor); - - objs.push_back(newObject.get());//bad_alloc. - newObject.release(); - } - - link = link->Next(); - } - } catch (const std::exception &) { - for (auto obj : objs) - delete obj; - for (auto dir : dirs) - delete dir; - throw; - } - - currentContainer->fObjects.swap(objs); - currentContainer->fDirectories.swap(dirs); - currentContainer->fOptions.swap(opts); - currentContainer->fContentDescriptors.swap(descriptors); -} - -//////////////////////////////////////////////////////////////////////////////// - -FileContainer *FileContainer::CreateFileContainer(const char *fullPath) -{ - try { - std::set visibleTypes; - FillVisibleTypes(visibleTypes); - - std::unique_ptr inputFile(TFile::Open(fullPath, "read")); - if (!inputFile.get()) - return 0; - - const std::string fileName(gSystem->BaseName(fullPath)); - std::unique_ptr topLevel(new FileContainer(fileName)); - - ScanDirectory(inputFile.get(), visibleTypes, topLevel.get()); - - // - //Attach pads. - topLevel->AttachPads(); - // - return topLevel.release(); - } catch (const std::exception &) { - return 0; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void FileContainer::DeleteFileContainer(FileContainer *container) -{ - delete container; -} - -}//namespace Browser -}//namespace iOS -}//namespace ROOT diff --git a/test/ios/RootBrowser/FileUtils.h b/test/ios/RootBrowser/FileUtils.h deleted file mode 100644 index ea6e0ebec13cb..0000000000000 --- a/test/ios/RootBrowser/FileUtils.h +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef ROOT_IOSFileContainer -#define ROOT_IOSFileContainer - -////////////////////////////////////////////////////////////////////////// -// // -// FileContainer // -// // -// Class which owns objects read from root file. // -// // -////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - -#include "TString.h" -#include "TObject.h" - -class TDirectoryFile; - -namespace ROOT { -namespace iOS { - -class Pad; - -namespace Browser { - -enum EHistogramErrorOption { - hetNoError, - hetE, - hetE1, - hetE2, - hetE3, - hetE4 -}; - -class FileContainer { - //Auto ptr must delete file container in case of exception - //in CreateFileContainer and so needs an access to private dtor. - friend class std::unique_ptr; -public: - typedef std::vector::size_type size_type; - - struct FileContainerElement { - FileContainerElement(const std::string &name, FileContainer *owner, bool isDir, size_type index) - : fName(name), fOwner(owner), fIsDir(isDir), fIndex(index) - { - } - std::string fName; - FileContainer *fOwner;//Container-owner. - bool fIsDir;//If entity is a directory. - size_type fIndex;//object or directory index. - }; - - -private: - FileContainer(const std::string &fileName); - ~FileContainer(); - -public: - size_type GetNumberOfObjects()const; - TObject *GetObject(size_type ind)const; - const char *GetDrawOption(size_type ind)const; - Pad *GetPadAttached(size_type ind)const; - void SetErrorDrawOption(size_type ind, EHistogramErrorOption opt); - EHistogramErrorOption GetErrorDrawOption(size_type ind)const; - - void SetMarkerDrawOption(size_type ind, bool on); - bool GetMarkerDrawOption(size_type ind)const; - - size_type GetNumberOfDirectories()const; - FileContainer *GetDirectory(size_type ind)const; - - const char *GetFileName()const; - - size_type GetNumberOfDescriptors()const; - const FileContainerElement &GetElementDescriptor(size_type index)const; - - - static FileContainer *CreateFileContainer(const char *fullPath); - static void DeleteFileContainer(FileContainer *container); - -private: - - void AttachPads(); - void ReadNames(const std::string &baseName, std::vector &names)const; - - static void ScanDirectory(TDirectoryFile *dir, const std::set &visibleTypes, FileContainer *currentContainer); - - std::string fFileName; - - std::vectorfDirectories; - std::vector fObjects; - std::vector fOptions; - - std::vector fAttachedPads; - - std::vector fContentDescriptors; - - FileContainer &operator = (const FileContainer &rhs) = delete; - FileContainer(const FileContainer &rhs) = delete; -}; - -}//namespace Browser -}//namespace iOS -}//namespace ROOT - -#endif diff --git a/test/ios/RootBrowser/FilledAreaInspector.h b/test/ios/RootBrowser/FilledAreaInspector.h deleted file mode 100644 index 2353df84622b1..0000000000000 --- a/test/ios/RootBrowser/FilledAreaInspector.h +++ /dev/null @@ -1,12 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" -#import "HorizontalPickerDelegate.h" - -@interface FilledAreaInspector : UIViewController - -- (void) setROOTObjectController : (ROOTObjectController *) p; -- (void) setROOTObject : (TObject*) obj; -- (NSString *) getComponentName; - -@end diff --git a/test/ios/RootBrowser/FilledAreaInspector.mm b/test/ios/RootBrowser/FilledAreaInspector.mm deleted file mode 100644 index eb2f56f14ca38..0000000000000 --- a/test/ios/RootBrowser/FilledAreaInspector.mm +++ /dev/null @@ -1,200 +0,0 @@ -#import "ROOTObjectController.h" -#import "HorizontalPickerView.h" -#import "FilledAreaInspector.h" -#import "PatternCell.h" -#import "Constants.h" -#import "ColorCell.h" - -//C++ (ROOT) imports: -#import "IOSFillPatterns.h" -#import "TAttFill.h" -#import "TObject.h" - -//It's mm file == C++, consts have internal linkage. -const CGFloat defaultCellW = 50.f; -const CGFloat defaultCellH = 50.f; - -@implementation FilledAreaInspector { - HorizontalPickerView *colorPicker; - HorizontalPickerView *patternPicker; - - NSMutableArray *colorCells; - NSMutableArray *patternCells; - - TAttFill *filledObject; - - __weak ROOTObjectController *parentController; -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - using namespace ROOT::iOS::Browser; - - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - - [self view]; - - if (self) { - const CGRect cellRect = CGRectMake(0.f, 0.f, defaultCellW, defaultCellH); - - colorCells = [[NSMutableArray alloc] init]; - for (unsigned i = 0; i < nROOTDefaultColors; ++i) { - ColorCell * newCell = [[ColorCell alloc] initWithFrame : cellRect]; - [newCell setRGB : predefinedFillColors[i]]; - [colorCells addObject : newCell]; - } - - colorPicker = [[HorizontalPickerView alloc] initWithFrame:CGRectMake(15.f, 15.f, 220.f, 70.f)]; - [colorPicker addItems : colorCells]; - [self.view addSubview : colorPicker]; - colorPicker.pickerDelegate = self; - - patternCells = [[NSMutableArray alloc] init]; - PatternCell *solidFill = [[PatternCell alloc] initWithFrame : cellRect andPattern : 0]; - [solidFill setAsSolid]; - [patternCells addObject : solidFill]; - - for (unsigned i = 0; i < ROOT::iOS::GraphicUtils::kPredefinedFillPatterns; ++i) { - PatternCell *newCell = [[PatternCell alloc] initWithFrame : cellRect andPattern : i]; - [patternCells addObject : newCell]; - } - - patternPicker = [[HorizontalPickerView alloc] initWithFrame:CGRectMake(15.f, 90.f, 220.f, 70.f)]; - [patternPicker addItems : patternCells]; - [self.view addSubview : patternPicker]; - patternPicker.pickerDelegate = self; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - [super didReceiveMemoryWarning]; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *) p -{ - parentController = p; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)obj -{ - //ROOT's standard color pick has 16 colors, - //I have 16 rows in a color picker. - //Fill color is some integer index, not from [0 16), - //but some hardcoded constant (as usually :( ) - - //see TGColorSelect or something like this. - //I hold this indices in colorIndices array of constants, - //since ROOT does not define them. - //If the object color is one of 16 standard colors, - //I find the correct row in a picker and rotate picker - //to this row. If not - it's on zero. - using namespace ROOT::iOS::Browser; - - //I do not check the result of dynamic_cast here. This is done at upper level. - filledObject = dynamic_cast(obj); - - //Set the row in color picker, using fill color from object. - const Color_t colorIndex = filledObject->GetFillColor(); - unsigned pickerItem = 0; - for (unsigned i = 0; i < nROOTDefaultColors; ++i) { - if (colorIndex == colorIndices[i]) { - pickerItem = i; - break; - } - } - - [colorPicker setSelectedItem : pickerItem]; - - //Look for a fill pattern. - namespace Fill = ROOT::iOS::GraphicUtils; - - const Style_t fillStyle = filledObject->GetFillStyle(); - if (fillStyle == Fill::solidFillStyle)//I'm sorry, again, hardcoded constant, ROOT does not define it :(. - pickerItem = 0; - else - pickerItem = filledObject->GetFillStyle() % Fill::stippleBase; - - [patternPicker setSelectedItem : pickerItem]; -} - -//____________________________________________________________________________________________________ -- (NSString *) getComponentName -{ - return @"Fill attributes"; -} - -//____________________________________________________________________________________________________ -- (void) setNewColor : (NSInteger) cellIndex -{ - using namespace ROOT::iOS::Browser; - - if (filledObject && parentController) { - const bool wasHollow = filledObject->GetFillColor() == 0; - if (cellIndex >= 0 && cellIndex < nROOTDefaultColors) { - const bool isHollow = colorIndices[cellIndex] == 0; - filledObject->SetFillColor(colorIndices[cellIndex]); - - if (wasHollow != isHollow) - [parentController objectWasModifiedUpdateSelection : YES]; - else - [parentController objectWasModifiedUpdateSelection : NO]; - } - } -} - -//____________________________________________________________________________________________________ -- (void) setNewPattern : (NSInteger) cellIndex -{ - namespace Fill = ROOT::iOS::GraphicUtils; - - if (filledObject && parentController) { - if (cellIndex > 0 && cellIndex <= Fill::kPredefinedFillPatterns) { - filledObject->SetFillStyle(Fill::stippleBase + cellIndex); - } else if (!cellIndex) { - filledObject->SetFillStyle(Fill::solidFillStyle); - } - - [parentController objectWasModifiedUpdateSelection : NO]; - } -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -#pragma mark - Color/pattern picker's delegate. - -//____________________________________________________________________________________________________ -- (void) item : (unsigned int)item wasSelectedInPicker : (HorizontalPickerView *)picker -{ - if (picker == colorPicker) { - [self setNewColor : item]; - } else { - [self setNewPattern : item]; - } -} - -@end diff --git a/test/ios/RootBrowser/FilledAreaInspector.xib b/test/ios/RootBrowser/FilledAreaInspector.xib deleted file mode 100644 index 43a8e9c97524c..0000000000000 --- a/test/ios/RootBrowser/FilledAreaInspector.xib +++ /dev/null @@ -1,151 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - YES - IBProxyObject - IBUIView - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - {250, 170} - - - - _NS:195 - - 3 - MCAwAA - - IBIPadFramework - - - - - YES - - - view - - - - 10 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 4.IBPluginDependency - - - YES - FilledAreaInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 16 - - - - YES - - FilledAreaInspector - UIViewController - - IBProjectSource - ./Classes/FilledAreaInspector.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 933 - - diff --git a/test/ios/RootBrowser/H1BinsInspector.h b/test/ios/RootBrowser/H1BinsInspector.h deleted file mode 100644 index 2b5cdfaac844e..0000000000000 --- a/test/ios/RootBrowser/H1BinsInspector.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "ObjectInspectorComponent.h" - -@interface H1BinsInspector : UIViewController { -@private - __weak IBOutlet UITextField *titleField; - __weak IBOutlet UILabel *minLabel; - __weak IBOutlet UILabel *maxLabel; - __weak IBOutlet UISwitch *showMarkers; -} - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; - -- (IBAction) textFieldDidEndOnExit : (id) sender; -- (IBAction) textFieldEditingDidEnd : (id) sender; -- (IBAction) toggleMarkers; - - -@end diff --git a/test/ios/RootBrowser/H1BinsInspector.mm b/test/ios/RootBrowser/H1BinsInspector.mm deleted file mode 100644 index d38f7bc82c6c4..0000000000000 --- a/test/ios/RootBrowser/H1BinsInspector.mm +++ /dev/null @@ -1,131 +0,0 @@ -#import "ROOTObjectController.h" -#import "H1BinsInspector.h" -#import "RangeSlider.h" - -#import "TAxis.h" -#import "TH1.h" - -@implementation H1BinsInspector { - RangeSlider *axisRangeSlider; - __weak ROOTObjectController *controller; - TH1 *object; -} - -//____________________________________________________________________________________________________ -- (id) initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - if (self) { - [self view]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void) viewDidLoad -{ - [super viewDidLoad]; - - axisRangeSlider = [[RangeSlider alloc] initWithFrame : CGRectMake(0.f, 210.f, 250.f, 60.f)]; - [self.view addSubview : axisRangeSlider]; - - [axisRangeSlider addTarget:self action:@selector(axisRangeChanged) forControlEvents : UIControlEventValueChanged]; -} - -//____________________________________________________________________________________________________ -- (void) viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL) shouldAutorotateToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ --(void) axisRangeChanged -{ - minLabel.center = CGPointMake([axisRangeSlider getMinThumbX], minLabel.center.y); - minLabel.text = [NSString stringWithFormat:@"%.3g", axisRangeSlider.selectedMinimumValue]; - maxLabel.center = CGPointMake([axisRangeSlider getMaxThumbX], maxLabel.center.y); - maxLabel.text = [NSString stringWithFormat:@"%.3g", axisRangeSlider.selectedMaximumValue]; - - //Update the histogram. - object->GetXaxis()->SetRangeUser(axisRangeSlider.selectedMinimumValue, axisRangeSlider.selectedMaximumValue); - [controller objectWasModifiedUpdateSelection : YES]; -} - -#pragma mark - ObjectInspectorComponent protocol. -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - object = static_cast(o); - // - const char *histTitle = object->GetTitle(); - if (!histTitle || !*histTitle) - titleField.text = @""; - else - titleField.text = [NSString stringWithFormat : @"%s", histTitle]; - - const TAxis *xAxis = object->GetXaxis(); - const unsigned nBins = xAxis->GetNbins(); - - const double xMin = xAxis->GetBinLowEdge(1); - const double xMinSelected = xAxis->GetBinLowEdge(xAxis->GetFirst()); - minLabel.text = [NSString stringWithFormat : @"%.3g", xMinSelected]; - const double xMax = xAxis->GetBinUpEdge(nBins); - const double xMaxSelected = xAxis->GetBinUpEdge(xAxis->GetLast()); - maxLabel.text = [NSString stringWithFormat : @"%.3g", xMaxSelected]; - - [axisRangeSlider setSliderMin : xMin max : xMax selectedMin : xMinSelected selectedMax : xMaxSelected]; - minLabel.center = CGPointMake([axisRangeSlider getMinThumbX], minLabel.center.y); - maxLabel.center = CGPointMake([axisRangeSlider getMaxThumbX], maxLabel.center.y); -} - -#pragma mark - GUI actions. - -//____________________________________________________________________________________________________ -- (IBAction) textFieldDidEndOnExit : (id) sender -{ - object->SetTitle([titleField.text cStringUsingEncoding : [NSString defaultCStringEncoding]]); - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) textFieldEditingDidEnd : (id) sender -{ - [sender resignFirstResponder]; -} - -//____________________________________________________________________________________________________ -- (IBAction) toggleMarkers -{ -// showMarkers.on ? controller.markerDrawOption = @"P" : controller.markerDrawOption = @""; - [controller setMarker : showMarkers.on]; - [controller objectWasModifiedUpdateSelection : YES]; -} - - -@end diff --git a/test/ios/RootBrowser/H1BinsInspector.xib b/test/ios/RootBrowser/H1BinsInspector.xib deleted file mode 100644 index d93da233fd99e..0000000000000 --- a/test/ios/RootBrowser/H1BinsInspector.xib +++ /dev/null @@ -1,508 +0,0 @@ - - - - 1056 - 11B26 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBUITextField - IBUISwitch - IBUIView - IBUILabel - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 292 - {{104, 20}, {42, 21}} - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - Title: - - 1 - MCAwIDAAA - - - 1 - 10 - 1 - - - - 292 - {{20, 49}, {210, 31}} - - - _NS:310 - NO - YES - IBIPadFramework - 0 - - 3 - - 3 - MAA - - 2 - - - 1 - YES - 17 - - 1 - IBCocoaTouchFramework - - 1 - - - - 292 - {{20, 201}, {210, 21}} - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - X axis range: - - - 1 - 10 - 1 - - - - 292 - {{20, 257}, {42, 21}} - - - _NS:327 - - 3 - MC42NjY2NjY2NjY3AA - - NO - YES - 7 - NO - IBIPadFramework - Min - - - 1 - 10 - 1 - - - - 292 - {{188, 257}, {42, 21}} - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Max - - - 1 - 10 - 1 - - - - 292 - {{136, 130}, {94, 27}} - - - _NS:592 - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{20, 133}, {108, 21}} - - - _NS:327 - - 3 - MCAwAA - - NO - YES - 7 - NO - IBIPadFramework - Show markers: - - - 1 - 10 - - - {250, 350} - - - _NS:195 - - IBIPadFramework - - - - - YES - - - view - - - - 10 - - - - minLabel - - - - 14 - - - - maxLabel - - - - 15 - - - - titleField - - - - 16 - - - - textFieldDidEndOnExit: - - - 20 - - 21 - - - - textFieldEditingDidEnd: - - - 19 - - 22 - - - - showMarkers - - - - 25 - - - - toggleMarkers - - - 13 - - 26 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - - - - - - 5 - - - - - 6 - - - - - 9 - - - - - 12 - - - - - 13 - - - - - 23 - - - - - 24 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 12.IBPluginDependency - 13.IBPluginDependency - 23.IBPluginDependency - 24.IBPluginDependency - 4.IBPluginDependency - 5.IBPluginDependency - 6.IBPluginDependency - 9.IBPluginDependency - - - YES - H1BinsInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 26 - - - - YES - - H1BinsInspector - UIViewController - - YES - - YES - textFieldDidEndOnExit: - textFieldEditingDidEnd: - updateNumberOfBins - - - YES - id - id - id - - - - YES - - YES - textFieldDidEndOnExit: - textFieldEditingDidEnd: - updateNumberOfBins - - - YES - - textFieldDidEndOnExit: - id - - - textFieldEditingDidEnd: - id - - - updateNumberOfBins - id - - - - - YES - - YES - binLabel - binSlider - maxLabel - minLabel - titleField - - - YES - UILabel - UISlider - UILabel - UILabel - UITextField - - - - YES - - YES - binLabel - binSlider - maxLabel - minLabel - titleField - - - YES - - binLabel - UILabel - - - binSlider - UISlider - - - maxLabel - UILabel - - - minLabel - UILabel - - - titleField - UITextField - - - - - IBProjectSource - ./Classes/H1BinsInspector.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 534 - - diff --git a/test/ios/RootBrowser/H1ErrorsInspector.h b/test/ios/RootBrowser/H1ErrorsInspector.h deleted file mode 100644 index ce9e7f5fd89ec..0000000000000 --- a/test/ios/RootBrowser/H1ErrorsInspector.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "ObjectInspectorComponent.h" - -@interface H1ErrorsInspector : UIViewController { -@private - __weak IBOutlet UIPickerView *errorTypePicker; -} - -//@property (nonatomic, retain) UIPickerView *errorTypePicker; - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; - -@end diff --git a/test/ios/RootBrowser/H1ErrorsInspector.mm b/test/ios/RootBrowser/H1ErrorsInspector.mm deleted file mode 100644 index f71bbf477c30b..0000000000000 --- a/test/ios/RootBrowser/H1ErrorsInspector.mm +++ /dev/null @@ -1,153 +0,0 @@ -#import - -#import "ROOTObjectController.h" -#import "H1ErrorsInspector.h" - -//C++ imports. -#import "TH1.h" - -#import "FileUtils.h" - -namespace { - -const CGFloat defaultCellW = 180.f; -const CGFloat defaultCellH = 44.f; - - - -enum H1ErrorType { - kNoError, - kSimple, - kEdges, - kRectangles, - kFill, - kContour, - kTotalNumOfTypes -}; - -NSString *errorTypesStrings[] = {@"No error", @"Simple", @"Edges", @"Rectangles", @"Fill", @"Contour"}; - -namespace RIB = ROOT::iOS::Browser; -RIB::EHistogramErrorOption histErrorTypes[] = {RIB::hetNoError, RIB::hetE, RIB::hetE1, RIB::hetE2, RIB::hetE3, RIB::hetE4}; - -} - -@implementation H1ErrorsInspector { - __weak ROOTObjectController *controller; - - TH1 *object; -} - -//____________________________________________________________________________________________________ -- (id) initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - - if (self) { - [self view]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -#pragma mark - Pickerview delegate/data source. - -//____________________________________________________________________________________________________ -- (CGFloat)pickerView : (UIPickerView *)pickerView widthForComponent : (NSInteger)component -{ - return defaultCellW; -} - -//____________________________________________________________________________________________________ -- (CGFloat)pickerView : (UIPickerView *)pickerView rowHeightForComponent : (NSInteger)component -{ - return defaultCellH; -} - -//____________________________________________________________________________________________________ -- (NSInteger)pickerView : (UIPickerView *)pickerView numberOfRowsInComponent : (NSInteger)component -{ - return kTotalNumOfTypes; -} - -//____________________________________________________________________________________________________ -- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView -{ - return 1; -} - -//____________________________________________________________________________________________________ -- (UIView *)pickerView : (UIPickerView *)pickerView viewForRow : (NSInteger)row forComponent : (NSInteger)component reusingView : (UIView *)view -{ - UILabel *label = [[UILabel alloc] initWithFrame : CGRectMake(0.f, 0.f, defaultCellW, defaultCellH)]; - label.text = errorTypesStrings[row]; - label.font = [UIFont fontWithName : @"TimesNewRomanPS-BoldMT" size : 14.f]; - -#ifdef __IPHONE_6_0 - label.textAlignment = NSTextAlignmentCenter; -#else - label.textAlignment = UITextAlignmentCenter; -#endif - - label.backgroundColor = [UIColor colorWithPatternImage : [UIImage imageNamed : @"text_cell_bkn.png"]]; - - return label; -} - -//____________________________________________________________________________________________________ -- (void)pickerView : (UIPickerView *)thePickerView didSelectRow : (NSInteger)row inComponent : (NSInteger)component -{ - if (row >= 0) { - [controller setErrorOption : histErrorTypes[row]]; - [controller objectWasModifiedUpdateSelection : YES]; - } -} - -#pragma mark ObjectInspectorComponent protocol. -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - object = static_cast(o); - //Read error type from hist. -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; -} - -@end diff --git a/test/ios/RootBrowser/H1ErrorsInspector.xib b/test/ios/RootBrowser/H1ErrorsInspector.xib deleted file mode 100644 index 84add0d88d590..0000000000000 --- a/test/ios/RootBrowser/H1ErrorsInspector.xib +++ /dev/null @@ -1,216 +0,0 @@ - - - - 1056 - 11B26 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBUIPickerView - IBUIView - IBUILabel - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 290 - {{25, 67}, {200, 216}} - - - _NS:191 - IBIPadFramework - YES - - - - 292 - {{84, 20}, {83, 21}} - - - _NS:327 - NO - YES - 7 - NO - IBIPadFramework - Errors: - - 1 - MCAwIDAAA - - - 1 - 10 - 1 - - - {250, 350} - - - _NS:195 - - 3 - MCAwAA - - IBIPadFramework - - - - - YES - - - dataSource - - - - 7 - - - - delegate - - - - 8 - - - - view - - - - 9 - - - - errorTypePicker - - - - 10 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - 5 - - - - - 6 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 4.IBPluginDependency - 5.IBPluginDependency - 6.IBPluginDependency - - - YES - H1ErrorsInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 10 - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 534 - - diff --git a/test/ios/RootBrowser/H1Inspector.h b/test/ios/RootBrowser/H1Inspector.h deleted file mode 100644 index cf09a1ca8f65c..0000000000000 --- a/test/ios/RootBrowser/H1Inspector.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "ObjectInspectorComponent.h" - -@interface H1Inspector : UIViewController { -@private - __weak IBOutlet UITabBar *tabBar; -} - -- (void) setROOTObject : (TObject *)o; -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (NSString *) getComponentName; -- (void) resetInspector; - - -@end diff --git a/test/ios/RootBrowser/H1Inspector.mm b/test/ios/RootBrowser/H1Inspector.mm deleted file mode 100644 index 2469723b83d59..0000000000000 --- a/test/ios/RootBrowser/H1Inspector.mm +++ /dev/null @@ -1,142 +0,0 @@ -#import "H1ErrorsInspector.h" -#import "H1BinsInspector.h" -#import "H1Inspector.h" - -//It's mm file, C++ constants have internal linkage. -const CGFloat totalHeight = 399.f; -const CGFloat tabBarHeight = 49.f; -const CGRect nestedComponentFrame = CGRectMake(0.f, tabBarHeight, 250.f, totalHeight - tabBarHeight); - -@interface H1Inspector () { - H1ErrorsInspector *errorInspector; - H1BinsInspector *binsInspector; - - TObject *object; - __weak ROOTObjectController *controller; -} - -- (void) showBinsInspector; -- (void) showErrorInspector; - -@end - -@implementation H1Inspector - -//____________________________________________________________________________________________________ -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - - if (self) { - [self view]; - - errorInspector = [[H1ErrorsInspector alloc] initWithNibName : @"H1ErrorsInspector" bundle : nil]; - errorInspector.view.frame = nestedComponentFrame; - [self.view addSubview : errorInspector.view]; - errorInspector.view.hidden = YES; - - binsInspector = [[H1BinsInspector alloc] initWithNibName : @"H1BinsInspector" bundle : nil]; - binsInspector.view.frame = nestedComponentFrame; - [self.view addSubview : binsInspector.view]; - binsInspector.view.hidden = NO; - - tabBar.selectedItem = [[tabBar items] objectAtIndex : 0]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -#pragma mark - ObjectInspectorComponent protocol. - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - object = o; - [errorInspector setROOTObject : o]; - [binsInspector setROOTObject : o]; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; - [errorInspector setROOTObjectController : c]; - [binsInspector setROOTObjectController : c]; -} - -//____________________________________________________________________________________________________ -- (NSString *) getComponentName -{ - return @"Hist attributes"; -} - -//____________________________________________________________________________________________________ -- (void) resetInspector -{ - tabBar.selectedItem = [[tabBar items] objectAtIndex : 0]; - [self showBinsInspector]; -} - -#pragma mark - Sub-components. - -//____________________________________________________________________________________________________ -- (void) showBinsInspector -{ - binsInspector.view.hidden = NO; - errorInspector.view.hidden = YES; -} - - -//____________________________________________________________________________________________________ -- (void) showErrorInspector -{ - binsInspector.view.hidden = YES; - errorInspector.view.hidden = NO; -} - -#pragma mark - UITabBar's delegate. -//____________________________________________________________________________________________________ -- (void) tabBar : (UITabBar *) tb didSelectItem : (UITabBarItem *)item -{ - if (item.tag == 1) - [self showBinsInspector]; - else if (item.tag == 2) - [self showErrorInspector]; -} - - - -@end diff --git a/test/ios/RootBrowser/H1Inspector.xib b/test/ios/RootBrowser/H1Inspector.xib deleted file mode 100644 index 6c4ecfaffe6e0..0000000000000 --- a/test/ios/RootBrowser/H1Inspector.xib +++ /dev/null @@ -1,258 +0,0 @@ - - - - 1056 - 11B26 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBUITabBar - IBUIView - IBUITabBarItem - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 266 - {250, 49} - - - - _NS:518 - - 3 - MCAwAA - - IBIPadFramework - - YES - - 1 - Title and bins (x) - - NSImage - h1_tab.png - - IBIPadFramework - - - - 2 - Errors - - NSImage - h1_errors_tab.png - - IBIPadFramework - - - - - - {250, 399} - - - - _NS:195 - - IBIPadFramework - - - - - YES - - - delegate - - - - 9 - - - - view - - - - 10 - - - - tabBar - - - - 11 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - 5 - - - YES - - - - - - - 6 - - - - - 8 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 4.IBPluginDependency - 5.IBPluginDependency - 6.IBPluginDependency - 8.IBPluginDependency - - - YES - H1Inspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 12 - - - - YES - - H1Inspector - UIViewController - - tabBar - UITabBar - - - tabBar - - tabBar - UITabBar - - - - IBProjectSource - ./Classes/H1Inspector.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - h1_errors_tab.png - h1_tab.png - - - YES - {30, 30} - {30, 30} - - - 534 - - diff --git a/test/ios/RootBrowser/HorizontalPickerDelegate.h b/test/ios/RootBrowser/HorizontalPickerDelegate.h deleted file mode 100644 index 39185d6ef5d07..0000000000000 --- a/test/ios/RootBrowser/HorizontalPickerDelegate.h +++ /dev/null @@ -1,9 +0,0 @@ -#import - -@class HorizontalPickerView; - -@protocol HorizontalPickerDelegate - -- (void) item : (unsigned)item wasSelectedInPicker : (HorizontalPickerView *)picker; - -@end diff --git a/test/ios/RootBrowser/HorizontalPickerView.h b/test/ios/RootBrowser/HorizontalPickerView.h deleted file mode 100644 index 5e517d84527eb..0000000000000 --- a/test/ios/RootBrowser/HorizontalPickerView.h +++ /dev/null @@ -1,12 +0,0 @@ -#import - -#import "HorizontalPickerDelegate.h" - -@interface HorizontalPickerView : UIView - -@property (nonatomic, weak) id pickerDelegate; - -- (void) addItems : (NSMutableArray *)items; -- (void) setSelectedItem : (unsigned) item; - -@end diff --git a/test/ios/RootBrowser/HorizontalPickerView.mm b/test/ios/RootBrowser/HorizontalPickerView.mm deleted file mode 100644 index d59c3559e369a..0000000000000 --- a/test/ios/RootBrowser/HorizontalPickerView.mm +++ /dev/null @@ -1,166 +0,0 @@ -#import - -#import "HorizontalPickerView.h" - -namespace { -//Obj-C class is not a scope :((( UGLY LANGUAGE! -const CGFloat pickerWidth = 200.f; -const CGFloat cellWidth = 50.f; -const CGFloat cellHeight = 50.f; -const CGFloat xPad = 1.5 * cellWidth; -const CGFloat markerPos = 100.f; - -} - -@implementation HorizontalPickerView { - UIScrollView *contentScroll; - UIImageView *arrowView; - UIImage *frameImage; - UIImage *backgroundImage; - - unsigned selectedItem; -} - - -@synthesize pickerDelegate; - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame -{ - self = [super initWithFrame : frame]; - if (self) { - self.backgroundColor = [UIColor clearColor]; - - contentScroll = [[UIScrollView alloc] initWithFrame : CGRectMake(10.f, 10.f, pickerWidth, cellHeight)]; - contentScroll.scrollEnabled = YES; - contentScroll.pagingEnabled = NO; - contentScroll.delegate = self; - contentScroll.showsVerticalScrollIndicator = NO; - contentScroll.showsHorizontalScrollIndicator = NO; - - contentScroll.backgroundColor = [UIColor clearColor]; - [self addSubview : contentScroll]; - - backgroundImage = [UIImage imageNamed : @"picker_bkn.png"]; - frameImage = [UIImage imageNamed : @"picker_frame_bkn.png"]; - - CAGradientLayer *dropshadowLayer = [CAGradientLayer layer]; - dropshadowLayer.startPoint = CGPointMake(0.0f, 0.0f); - dropshadowLayer.endPoint = CGPointMake(0.0f, 1.0f); - dropshadowLayer.opacity = 1.0; - dropshadowLayer.frame = CGRectMake(contentScroll.frame.origin.x, contentScroll.frame.origin.y, - contentScroll.frame.size.width, contentScroll.frame.size.height); - dropshadowLayer.locations = [NSArray arrayWithObjects : [NSNumber numberWithFloat : 0.0f], - [NSNumber numberWithFloat : 0.05f], - [NSNumber numberWithFloat : 0.2f], - [NSNumber numberWithFloat : 0.8f], - [NSNumber numberWithFloat : 0.95f], - [NSNumber numberWithFloat : 1.0f], nil]; - dropshadowLayer.colors = [NSArray arrayWithObjects : - (id)[[UIColor colorWithRed : 0.05f green : 0.05f blue : 0.05f alpha : 0.75f] CGColor], - (id)[[UIColor colorWithRed : 0.25f green : 0.25f blue : 0.25f alpha : 0.55f] CGColor], - (id)[[UIColor colorWithRed : 1.f green : 1.f blue : 1.f alpha : 0.05f] CGColor], - (id)[[UIColor colorWithRed : 1.f green : 1.f blue : 1.f alpha : 0.05f] CGColor], - (id)[[UIColor colorWithRed : 0.25f green : 0.25f blue : 0.25f alpha : 0.55f] CGColor], - (id)[[UIColor colorWithRed : 0.05f green : 0.05f blue : 0.05f alpha : 0.75f] CGColor], nil]; - - [self.layer insertSublayer:dropshadowLayer above : contentScroll.layer]; - - CAGradientLayer *gradientLayer = [CAGradientLayer layer]; - gradientLayer.startPoint = CGPointMake(0.0f, 0.0f); - gradientLayer.endPoint = CGPointMake(1.0f, 0.0f); - gradientLayer.opacity = 1.0; - gradientLayer.frame = CGRectMake(contentScroll.frame.origin.x, contentScroll.frame.origin.y, - contentScroll.frame.size.width, contentScroll.frame.size.height); - gradientLayer.locations = [NSArray arrayWithObjects: - [NSNumber numberWithFloat:0.0f], - [NSNumber numberWithFloat:0.05f], - [NSNumber numberWithFloat:0.3f], - [NSNumber numberWithFloat:0.7f], - [NSNumber numberWithFloat:0.95f], - [NSNumber numberWithFloat:1.0f], nil]; - gradientLayer.colors = [NSArray arrayWithObjects: - (id)[[UIColor colorWithRed:0.05f green:0.05f blue:0.05f alpha:0.95] CGColor], - (id)[[UIColor colorWithRed:0.25f green:0.25f blue:0.25f alpha:0.8] CGColor], - (id)[[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:0.1] CGColor], - (id)[[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:0.1] CGColor], - (id)[[UIColor colorWithRed:0.25f green:0.25f blue:0.25f alpha:0.8] CGColor], - (id)[[UIColor colorWithRed:0.05f green:0.05f blue:0.05f alpha:0.95] CGColor], nil]; - [self.layer insertSublayer:gradientLayer above:dropshadowLayer]; - - arrowView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"picker_arrow.png"]]; - arrowView.center = CGPointMake(frame.size.width / 2, 60 - arrowView.frame.size.height / 2); - [self addSubview : arrowView]; - [self bringSubviewToFront : arrowView]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)drawRect:(CGRect)rect -{ - [frameImage drawInRect : rect]; - [backgroundImage drawInRect:CGRectMake(10.f, 10.f, 200.f, 50.f)]; -} - -//____________________________________________________________________________________________________ -- (void) adjustScroll -{ - CGPoint offset = contentScroll.contentOffset; - const CGFloat currentPos = markerPos + offset.x - xPad; - selectedItem = unsigned(currentPos / cellWidth); - const CGFloat newPos = selectedItem * cellWidth + 0.5 * cellWidth; - const CGFloat add = newPos - currentPos; - offset.x += add; - [contentScroll setContentOffset : offset animated : YES]; -} - -//____________________________________________________________________________________________________ -- (void) setSelectedItem:(unsigned int)item -{ - selectedItem = item; - const CGFloat x = xPad + selectedItem * cellWidth + 0.5f * cellWidth - markerPos; - contentScroll.contentOffset = CGPointMake(x, 0.f); -} - -//____________________________________________________________________________________________________ -- (void) notify -{ - [pickerDelegate item : selectedItem wasSelectedInPicker : self]; -} - -//____________________________________________________________________________________________________ -- (void) scrollViewDidEndDecelerating : (UIScrollView *) sender -{ - [self adjustScroll]; - [self notify]; -} - -//____________________________________________________________________________________________________ -- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate -{ - if (!decelerate) { - [self adjustScroll]; - [self notify]; - } -} - -#pragma mark - Picker's content management. - -//____________________________________________________________________________________________________ -- (void) addItems : (NSMutableArray *)items -{ - NSEnumerator *enumerator = [items objectEnumerator]; - UIView *v = [enumerator nextObject]; - for (unsigned i = 0; v; v = [enumerator nextObject], ++i) { - //Adjust view position inside a scroll: - const CGRect viewFrame = CGRectMake(i * cellWidth + xPad, 0.f, cellWidth, cellHeight); - v.frame = viewFrame; - [contentScroll addSubview : v]; - } - - contentScroll.contentSize = CGSizeMake(2 * xPad + [items count] * cellWidth, cellHeight); -} - -@end diff --git a/test/ios/RootBrowser/InspectorWithNavigation.h b/test/ios/RootBrowser/InspectorWithNavigation.h deleted file mode 100644 index 6f945898a529e..0000000000000 --- a/test/ios/RootBrowser/InspectorWithNavigation.h +++ /dev/null @@ -1,12 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" - -@interface InspectorWithNavigation : UINavigationController - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)obj; -- (NSString *) getComponentName; -- (void) resetInspector; - -@end diff --git a/test/ios/RootBrowser/InspectorWithNavigation.mm b/test/ios/RootBrowser/InspectorWithNavigation.mm deleted file mode 100644 index fcbbb84afe308..0000000000000 --- a/test/ios/RootBrowser/InspectorWithNavigation.mm +++ /dev/null @@ -1,85 +0,0 @@ -#import "InspectorWithNavigation.h" - -@implementation InspectorWithNavigation - -//____________________________________________________________________________________________________ -- (id) initWithRootViewController : (UIViewController *) rootController -{ - self = [super initWithRootViewController : (UIViewController *)rootController]; - if (self) { - self.navigationBar.hidden = YES; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -/* -// Implement loadView to create a view hierarchy programmatically, without using a nib. -- (void)loadView -{ -} -*/ - -/* -// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. -- (void)viewDidLoad -{ - [super viewDidLoad]; -} -*/ - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - UIViewController *rootController = (UIViewController *)[self.viewControllers objectAtIndex : 0]; - [rootController setROOTObjectController : c]; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)obj -{ - UIViewController *rootController = (UIViewController *)[self.viewControllers objectAtIndex : 0]; - [rootController setROOTObject : obj]; -} - -//____________________________________________________________________________________________________ -- (NSString *) getComponentName -{ - UIViewController *rootController = (UIViewController *)[self.viewControllers objectAtIndex : 0]; - return [rootController getComponentName]; -} - -//____________________________________________________________________________________________________ -- (void) resetInspector -{ - //Pop all controllers from a stack except a top level root controller. - while ([self.viewControllers count] > 1) - [self popViewControllerAnimated : NO]; -} - -@end diff --git a/test/ios/RootBrowser/LineInspector.h b/test/ios/RootBrowser/LineInspector.h deleted file mode 100644 index fea95b36f6684..0000000000000 --- a/test/ios/RootBrowser/LineInspector.h +++ /dev/null @@ -1,27 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" -#import "HorizontalPickerDelegate.h" - - -@class HorizontalPickerView; -@class LineWidthPicker; - -//Line inspector is a composition of two sub-inspectors: line color and width inspector + -//line style inspector. - -@interface LineInspector : UIViewController { -@private - __weak IBOutlet LineWidthPicker *lineWidthPicker; -} - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; -- (NSString *) getComponentName; - -- (void) item : (unsigned int)item wasSelectedInPicker : (HorizontalPickerView *)picker; - -- (IBAction) decLineWidth; -- (IBAction) incLineWidth; - -@end diff --git a/test/ios/RootBrowser/LineInspector.mm b/test/ios/RootBrowser/LineInspector.mm deleted file mode 100644 index fba454c2951d5..0000000000000 --- a/test/ios/RootBrowser/LineInspector.mm +++ /dev/null @@ -1,234 +0,0 @@ -#import "HorizontalPickerView.h" -#import "ROOTObjectController.h" -#import "LineWidthPicker.h" -#import "LineInspector.h" -#import "LineStyleCell.h" -#import "ColorCell.h" -#import "Constants.h" - -//C++ (ROOT) imports. -#import "TAttLine.h" -#import "TObject.h" -#import "TGraph.h" - -//It's mm file == C++, consts have internal linkage. -const int minLineWidth = 1; -const int maxLineWidth = 15; -const CGRect cellFrame = CGRectMake(0.f, 0.f, 50.f, 50.f); - -@interface LineInspector () { - NSMutableArray *lineStyles; - NSMutableArray *lineColors; - - HorizontalPickerView *lineColorPicker; - HorizontalPickerView *lineStylePicker; - - int lineWidth; - - __weak ROOTObjectController *controller; - TAttLine *object; -} - -@end - -@implementation LineInspector - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil -{ - using namespace ROOT::iOS::Browser; - - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - - if (self) { - [self view]; - //Array with cells for "Line style" picker. - lineStyles = [[NSMutableArray alloc] init]; - for (unsigned i = 0; i < 10; ++i) { - LineStyleCell *newCell = [[LineStyleCell alloc] initWithFrame : cellFrame lineStyle : i + 1]; - [lineStyles addObject : newCell]; - } - - lineStylePicker = [[HorizontalPickerView alloc] initWithFrame:CGRectMake(15.f, 20.f, 220.f, 70.f)]; - [lineStylePicker addItems : lineStyles]; - [self.view addSubview : lineStylePicker]; - - lineStylePicker.pickerDelegate = self; - - lineColors = [[NSMutableArray alloc] init]; - for (unsigned i = 0; i < nROOTDefaultColors; ++i) { - ColorCell *newCell = [[ColorCell alloc] initWithFrame : cellFrame]; - [newCell setRGB : predefinedFillColors[i]]; - [lineColors addObject : newCell]; - } - - lineColorPicker = [[HorizontalPickerView alloc] initWithFrame:CGRectMake(15.f, 105, 220.f, 70.f)]; - [lineColorPicker addItems : lineColors]; - [self.view addSubview : lineColorPicker]; - - lineColorPicker.pickerDelegate = self; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - using namespace ROOT::iOS::Browser; - - object = dynamic_cast(o); - - unsigned item = 0; - const Style_t lineStyle = object->GetLineStyle(); - if (lineStyle >= 1 && lineStyle <= 10) - item = lineStyle - 1; - - [lineStylePicker setSelectedItem : item]; - - item = 1;//black. - const Color_t colorIndex = object->GetLineColor(); - for (unsigned i = 0; i < nROOTDefaultColors; ++i) { - if (colorIndex == colorIndices[i]) { - item = i; - break; - } - } - - [lineColorPicker setSelectedItem : item]; - - //Line width is expected to be line width in pixels, - //but it can hold additional information in case of - //TGraph and have value like -2014. - lineWidth = object->GetLineWidth(); - if (lineWidth < minLineWidth || lineWidth > maxLineWidth) { - if (dynamic_cast(o)) { - //"Formula" from ROOT. - lineWidth = TMath::Abs(lineWidth) % 100; - //Still, line width can be out of [1,15] range! - if (!lineWidth) - lineWidth = 1; - else if (lineWidth > maxLineWidth) - lineWidth = maxLineWidth; - } else - lineWidth = minLineWidth; - } - - [lineWidthPicker setLineWidth : lineWidth]; -} - -//____________________________________________________________________________________________________ -- (NSString *) getComponentName -{ - return @"Line attributes"; -} - -#pragma mark - Horizontal picker delegate. - -//____________________________________________________________________________________________________ -- (void) item : (unsigned int)item wasSelectedInPicker : (HorizontalPickerView *)picker -{ - using namespace ROOT::iOS::Browser; - - if (picker == lineColorPicker) { - if (item < nROOTDefaultColors) { - const unsigned colorIndex = colorIndices[item]; - object->SetLineColor(colorIndex); - } else - NSLog(@"check the code, bad item index from horizontal picker: %u, must be < %u", item, nROOTDefaultColors); - } else { - if (item < 10) - object->SetLineStyle(item + 1); - else - NSLog(@"check the code, bad item index from horizontal picker: %u must be < 11", item); - } - - [controller objectWasModifiedUpdateSelection : NO]; -} - -#pragma mark - Code to deal with line width's insanity - -//____________________________________________________________________________________________________ -- (void) updateROOTLineWidth -{ - if (dynamic_cast(object)) { - const int fakeLineWidth = int(object->GetLineWidth()) / 100 * 100; - if (fakeLineWidth >= 0) - object->SetLineWidth(fakeLineWidth + lineWidth); - else - object->SetLineWidth(-(TMath::Abs(fakeLineWidth) + lineWidth)); - } else - object->SetLineWidth(lineWidth); -} - -#pragma mark - Button's handlers. - - - -//____________________________________________________________________________________________________ -- (IBAction) decLineWidth -{ - if (lineWidth == minLineWidth) - return; - - --lineWidth; - [lineWidthPicker setLineWidth : lineWidth]; - - [self updateROOTLineWidth]; - - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) incLineWidth -{ - if (lineWidth == maxLineWidth) - return; - - ++lineWidth; - [lineWidthPicker setLineWidth : lineWidth]; - - [self updateROOTLineWidth]; - - [controller objectWasModifiedUpdateSelection : NO]; -} - -@end diff --git a/test/ios/RootBrowser/LineInspector.xib b/test/ios/RootBrowser/LineInspector.xib deleted file mode 100644 index 7bae908e209c7..0000000000000 --- a/test/ios/RootBrowser/LineInspector.xib +++ /dev/null @@ -1,350 +0,0 @@ - - - - 1296 - 11D50b - 2182 - 1138.32 - 568.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1179 - - - YES - IBProxyObject - IBUIView - IBUIButton - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 292 - {{15, 190}, {40, 70}} - - - - _NS:241 - NO - IBIPadFramework - 0 - 0 - 1 - - 3 - MQA - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - 3 - MC41AA - - - NSImage - dec_line_width.png - - - 2 - 15 - - - Helvetica-Bold - 15 - 16 - - - - - 292 - {{195, 190}, {40, 70}} - - - _NS:241 - NO - IBIPadFramework - 0 - 0 - 1 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - NSImage - inc_line_width.png - - - - - - - 292 - {{55, 190}, {140, 70}} - - - - _NS:212 - - IBIPadFramework - - - {250, 280} - - - - _NS:195 - - 3 - MCAwAA - - IBIPadFramework - - - - - YES - - - view - - - - 7 - - - - lineWidthPicker - - - - 20 - - - - decLineWidth - - - 7 - - 21 - - - - incLineWidth - - - 7 - - 22 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - - 17 - - - - - 18 - - - - - 19 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 17.IBPluginDependency - 18.IBPluginDependency - 19.CustomClassName - 19.IBPluginDependency - 4.IBPluginDependency - - - YES - LineInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - LineWidthPicker - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 22 - - - - YES - - LineInspector - UIViewController - - YES - - YES - decLineWidth - incLineWidth - - - YES - id - id - - - - YES - - YES - decLineWidth - incLineWidth - - - YES - - decLineWidth - id - - - incLineWidth - id - - - - - lineWidthPicker - LineWidthPicker - - - lineWidthPicker - - lineWidthPicker - LineWidthPicker - - - - IBProjectSource - ./Classes/LineInspector.h - - - - LineWidthPicker - UIView - - IBProjectSource - ./Classes/LineWidthPicker.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - dec_line_width.png - inc_line_width.png - - - YES - {40, 70} - {40, 70} - - - 1179 - - diff --git a/test/ios/RootBrowser/LineStyleCell.h b/test/ios/RootBrowser/LineStyleCell.h deleted file mode 100644 index 6afb12d56e20f..0000000000000 --- a/test/ios/RootBrowser/LineStyleCell.h +++ /dev/null @@ -1,7 +0,0 @@ -#import - -@interface LineStyleCell : UIView - -- (id) initWithFrame : (CGRect)frame lineStyle : (unsigned) style; - -@end diff --git a/test/ios/RootBrowser/LineStyleCell.mm b/test/ios/RootBrowser/LineStyleCell.mm deleted file mode 100644 index f6921eb75bc9d..0000000000000 --- a/test/ios/RootBrowser/LineStyleCell.mm +++ /dev/null @@ -1,55 +0,0 @@ -#import -#import - -#import "LineStyleCell.h" - -//C++ (ROOT) imports. -#import "IOSLineStyles.h" - -@implementation LineStyleCell { - unsigned lineStyle; -} - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame lineStyle : (unsigned) style -{ - self = [super initWithFrame:frame]; - - if (self) { - lineStyle = style; - - self.layer.shadowOffset = CGSizeMake(4.f, 4.f); - self.layer.shadowOpacity = 0.7f; - self.layer.shadowColor = [UIColor darkGrayColor].CGColor; - - self.opaque = NO; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)drawRect:(CGRect)rect -{ - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - CGContextSetRGBStrokeColor(ctx, 0.3f, 0.3f, 0.3f, 0.4f); - CGContextStrokeRect(ctx, rect); - - CGContextSetRGBStrokeColor(ctx, 0.f, 0.f, 0.f, 1.f); - - if (lineStyle > 1 && lineStyle <= 10) - CGContextSetLineDash(ctx, 0., ROOT::iOS::GraphicUtils::dashLinePatterns[lineStyle - 1], ROOT::iOS::GraphicUtils::linePatternLengths[lineStyle - 1]); - else - CGContextSetLineDash(ctx, 0., 0, 0); - - CGContextSetLineWidth(ctx, 2.f); - - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, 10.f, rect.size.height - 10.f); - CGContextAddLineToPoint(ctx, rect.size.width - 10, 10.f); - - CGContextStrokePath(ctx); -} - -@end diff --git a/test/ios/RootBrowser/LineWidthCell.h b/test/ios/RootBrowser/LineWidthCell.h deleted file mode 100644 index 33e17e952ffe5..0000000000000 --- a/test/ios/RootBrowser/LineWidthCell.h +++ /dev/null @@ -1,8 +0,0 @@ -#import - -@interface LineWidthCell : UIView - -- (id) initWithFrame : (CGRect) frame width : (CGFloat) lineWidth; -- (void) setLineWidth : (CGFloat)width; - -@end diff --git a/test/ios/RootBrowser/LineWidthCell.mm b/test/ios/RootBrowser/LineWidthCell.mm deleted file mode 100644 index 6ac3e2aa97b42..0000000000000 --- a/test/ios/RootBrowser/LineWidthCell.mm +++ /dev/null @@ -1,54 +0,0 @@ -#import -#import - -#import "LineWidthCell.h" - - -@implementation LineWidthCell { - CGFloat lineWidth; -} - -//____________________________________________________________________________________________________ -- (id)initWithFrame:(CGRect)frame width : (CGFloat)w -{ - self = [super initWithFrame:frame]; - - if (self) { - lineWidth = w; - - self.layer.shadowOpacity = 0.4f; - self.layer.shadowColor = [UIColor darkGrayColor].CGColor; - self.layer.shadowOffset = CGSizeMake(4.f, 4.f); - - self.opaque = NO; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)drawRect:(CGRect)rect -{ - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - //Draw the line. - CGContextSetLineCap(ctx, kCGLineCapRound); - CGContextSetLineWidth(ctx, lineWidth); - CGContextSetRGBStrokeColor(ctx, 0.f, 0.f, 0.f, 1.f); - CGContextBeginPath(ctx); - CGContextMoveToPoint(ctx, 10.f, rect.size.height / 2); - CGContextAddLineToPoint(ctx, rect.size.width - 10, rect.size.height / 2); - CGContextStrokePath(ctx); - - NSString *label = [NSString stringWithFormat:@"(%d)", (int)lineWidth]; - CGContextSetRGBFillColor(ctx, 0.f, 0.f, 1.f, 1.f); - [label drawInRect:CGRectMake(rect.size.width / 2 - 10.f, rect.size.height / 2 - 15.f, 40.f, 60.f) withFont : [UIFont systemFontOfSize : 10]]; -} - -//____________________________________________________________________________________________________ -- (void) setLineWidth : (CGFloat)width -{ - lineWidth = width; -} - -@end diff --git a/test/ios/RootBrowser/LineWidthPicker.h b/test/ios/RootBrowser/LineWidthPicker.h deleted file mode 100644 index 20e4581f8a993..0000000000000 --- a/test/ios/RootBrowser/LineWidthPicker.h +++ /dev/null @@ -1,7 +0,0 @@ -#import - -@interface LineWidthPicker : UIView - -- (void) setLineWidth : (float)width; - -@end diff --git a/test/ios/RootBrowser/LineWidthPicker.mm b/test/ios/RootBrowser/LineWidthPicker.mm deleted file mode 100644 index 1e306721e1f8c..0000000000000 --- a/test/ios/RootBrowser/LineWidthPicker.mm +++ /dev/null @@ -1,45 +0,0 @@ -#import "LineWidthPicker.h" -#import "LineWidthCell.h" - -@implementation LineWidthPicker { - LineWidthCell *lineWidthView; - UIImage *backgroundImage; -} - -//____________________________________________________________________________________________________ -- (void) lateInit -{ - // Initialization code - lineWidthView = [[LineWidthCell alloc] initWithFrame : CGRectMake(10.f, 10.f, 120.f, 50.f) width : 1.f]; - [self addSubview : lineWidthView]; - - backgroundImage = [UIImage imageNamed:@"line_width_bkn.png"]; -} - -//____________________________________________________________________________________________________ -- (id)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self) { - [self lateInit]; - } - return self; -} - -//____________________________________________________________________________________________________ -- (void) drawRect : (CGRect)rect -{ - if (!backgroundImage) - [self lateInit]; - - [backgroundImage drawInRect : rect]; -} - -//____________________________________________________________________________________________________ -- (void) setLineWidth : (float)width -{ - [lineWidthView setLineWidth : width]; - [lineWidthView setNeedsDisplay]; -} - -@end diff --git a/test/ios/RootBrowser/MarkerInspector.h b/test/ios/RootBrowser/MarkerInspector.h deleted file mode 100644 index cce894c05d5c7..0000000000000 --- a/test/ios/RootBrowser/MarkerInspector.h +++ /dev/null @@ -1,20 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" -#import "HorizontalPickerDelegate.h" - -@interface MarkerInspector : UIViewController { -@private - __weak IBOutlet UIButton *plusBtn; - __weak IBOutlet UIButton *minusBtn; - __weak IBOutlet UILabel *sizeLabel; -} - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; -- (NSString *) getComponentName; - -- (IBAction) plusPressed; -- (IBAction) minusPressed; - -@end diff --git a/test/ios/RootBrowser/MarkerInspector.mm b/test/ios/RootBrowser/MarkerInspector.mm deleted file mode 100644 index 2e9674586af22..0000000000000 --- a/test/ios/RootBrowser/MarkerInspector.mm +++ /dev/null @@ -1,228 +0,0 @@ -#import "HorizontalPickerView.h" -#import "ROOTObjectController.h" -#import "MarkerInspector.h" -#import "MarkerStyleCell.h" -#import "ColorCell.h" -#import "Constants.h" - -//C++ (ROOT) imports. -#import "TAttMarker.h" -#import "TObject.h" - -namespace { - -const CGRect cellRect = CGRectMake(0.f, 0.f, 50.f, 50.f); - -const CGFloat maxMarkerSize = 5.f; -const CGFloat sizeStep = 0.1f; - -EMarkerStyle markerStyles[] = {kDot, kPlus, kStar, kCircle, kMultiply, - kFullDotSmall, kFullDotMedium, kFullDotLarge, - kFullCircle, kFullSquare, kFullTriangleUp, - kFullTriangleDown, kOpenCircle, kOpenSquare, - kOpenTriangleUp, kOpenDiamond, kOpenCross, - kFullStar, kOpenStar, kOpenTriangleDown, - kFullDiamond, kFullCross}; - -const unsigned nMarkers = sizeof markerStyles / sizeof markerStyles[0]; - -//____________________________________________________________________________________________________ -BOOL canScaleMarker(Style_t style) -{ - if (style == kDot || style == kFullDotSmall || style == kFullDotMedium) - return NO; - return YES; -} - -} - -@implementation MarkerInspector { - HorizontalPickerView *markerStylePicker; - HorizontalPickerView *markerColorPicker; - - NSMutableArray *styleCells; - NSMutableArray *colorCells; - - __weak ROOTObjectController *controller; - TAttMarker *object; -} - -//____________________________________________________________________________________________________ -- (id) initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - using namespace ROOT::iOS::Browser; - - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - - if (self) { - [self view]; - - styleCells = [[NSMutableArray alloc] init];//]WithCapacity : nMarkers]; - for (unsigned i = 0; i < nMarkers; ++i) { - MarkerStyleCell *newCell = [[MarkerStyleCell alloc] initWithFrame : cellRect andMarkerStyle : markerStyles[i]]; - [styleCells addObject : newCell]; - } - - markerStylePicker = [[HorizontalPickerView alloc] initWithFrame:CGRectMake(15.f, 15.f, 220.f, 70.f)]; - [markerStylePicker addItems : styleCells]; - [self.view addSubview : markerStylePicker]; - markerStylePicker.pickerDelegate = self; - - colorCells = [[NSMutableArray alloc] init]; - for (unsigned i = 0; i < nROOTDefaultColors; ++i) { - ColorCell *newCell = [[ColorCell alloc] initWithFrame : cellRect]; - [newCell setRGB : predefinedFillColors[i]]; - [colorCells addObject : newCell]; - } - - markerColorPicker = [[HorizontalPickerView alloc] initWithFrame:CGRectMake(15.f, 110.f, 220.f, 70.f)]; - [markerColorPicker addItems : colorCells]; - [self.view addSubview : markerColorPicker]; - markerColorPicker.pickerDelegate = self; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void) viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void) viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL) shouldAutorotateToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void) item : (unsigned int)item wasSelectedInPicker : (HorizontalPickerView *)picker -{ - if (picker == markerColorPicker) { - const unsigned colorIndex = ROOT::iOS::Browser::colorIndices[item]; - object->SetMarkerColor(colorIndex); - [controller objectWasModifiedUpdateSelection : YES]; - } else if (picker == markerStylePicker) { - if (item < nMarkers) { - EMarkerStyle style = markerStyles[item]; - if (canScaleMarker(style)) { - plusBtn.enabled = YES; - minusBtn.enabled = YES; - sizeLabel.text = [NSString stringWithFormat : @"%.2g", object->GetMarkerSize()]; - } else { - plusBtn.enabled = NO; - minusBtn.enabled = NO; - sizeLabel.text = @"1"; - } - - object->SetMarkerStyle(style); - } else { - NSLog(@"check horizontal picker code, got item index %u, must be < %u", item, nMarkers); - } - - [controller objectWasModifiedUpdateSelection : YES]; - } -} - -#pragma mark ObjectInspectorComponent protocol. - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - using namespace ROOT::iOS::Browser; - - object = dynamic_cast(o); - - unsigned item = 0; - const EMarkerStyle style = EMarkerStyle(object->GetMarkerStyle());//Mess with all these styles and EMarkerStyles. - for (unsigned i = 0; i < nMarkers; ++i) { - if (style == markerStyles[i]) { - item = i; - break; - } - } - - [markerStylePicker setSelectedItem : item]; - - //Extract marker color. - //The same predefined 16 colors as with fill color. - item = 1;//? - const Color_t colorIndex = object->GetMarkerColor(); - - for (unsigned i = 0; i < nROOTDefaultColors; ++i) { - if (colorIndex == colorIndices[i]) { - item = i; - break; - } - } - - [markerColorPicker setSelectedItem : item]; - - if (!canScaleMarker(object->GetMarkerStyle())) { - plusBtn.enabled = NO; - minusBtn.enabled = NO; - sizeLabel.text = @"1"; - } else { - plusBtn.enabled = YES; - minusBtn.enabled = YES; - sizeLabel.text = [NSString stringWithFormat : @"%.2g", object->GetMarkerSize()]; - } -} - -//____________________________________________________________________________________________________ -- (NSString *) getComponentName -{ - return @"Marker attributes"; -} - -//____________________________________________________________________________________________________ -- (IBAction) plusPressed -{ - - if (object->GetMarkerSize() + sizeStep > maxMarkerSize) - return; - - object->SetMarkerSize(object->GetMarkerSize() + sizeStep); - sizeLabel.text = [NSString stringWithFormat : @"%.2g", object->GetMarkerSize()]; - [controller objectWasModifiedUpdateSelection : YES]; -} - -//____________________________________________________________________________________________________ -- (IBAction) minusPressed -{ - if (object->GetMarkerSize() - sizeStep < 1.) - return; - - object->SetMarkerSize(object->GetMarkerSize() - sizeStep); - sizeLabel.text = [NSString stringWithFormat : @"%.2g", object->GetMarkerSize()]; - [controller objectWasModifiedUpdateSelection : YES]; -} - -@end diff --git a/test/ios/RootBrowser/MarkerInspector.xib b/test/ios/RootBrowser/MarkerInspector.xib deleted file mode 100644 index 9fbd21111ca23..0000000000000 --- a/test/ios/RootBrowser/MarkerInspector.xib +++ /dev/null @@ -1,439 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - YES - IBUIButton - IBUIView - IBUILabel - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 292 - {{19, 213}, {42, 21}} - - - - _NS:327 - - 3 - MCAwAA - - NO - YES - 7 - NO - IBIPadFramework - Size: - - 1 - MCAwIDAAA - - - 1 - 10 - - 1 - 17 - - - Helvetica - 17 - 16 - - - - - 292 - {{85, 213}, {42, 21}} - - - - _NS:327 - - 3 - MC42NjY2NjY2NjY3AA - - NO - YES - 7 - NO - IBIPadFramework - Label - - - 1 - 10 - 1 - - - - - - 292 - {{155, 204}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - 1 - - 3 - MQA - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - 3 - MC41AA - - - NSImage - plus_btn.png - - - Helvetica-Bold - Helvetica - 2 - 15 - - - Helvetica-Bold - 15 - 16 - - - - - 292 - {{195, 204}, {40, 40}} - - - - _NS:237 - NO - IBIPadFramework - 0 - 0 - 1 - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - NSImage - minus_btn.png - - - - - - {250, 254} - - - - _NS:195 - - IBIPadFramework - - - - - YES - - - view - - - - 8 - - - - sizeLabel - - - - 15 - - - - plusBtn - - - - 16 - - - - minusBtn - - - - 17 - - - - plusPressed - - - 7 - - 18 - - - - minusPressed - - - 7 - - 19 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - - - 11 - - - - - 12 - - - - - 13 - - - - - 14 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 11.IBPluginDependency - 12.IBPluginDependency - 13.IBPluginDependency - 14.IBPluginDependency - 4.IBPluginDependency - - - YES - MarkerInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 21 - - - - YES - - MarkerInspector - UIViewController - - YES - - YES - minusPressed - plusPressed - - - YES - id - id - - - - YES - - YES - minusPressed - plusPressed - - - YES - - minusPressed - id - - - plusPressed - id - - - - - YES - - YES - minusBtn - plusBtn - sizeLabel - - - YES - UIButton - UIButton - UILabel - - - - YES - - YES - minusBtn - plusBtn - sizeLabel - - - YES - - minusBtn - UIButton - - - plusBtn - UIButton - - - sizeLabel - UILabel - - - - - IBProjectSource - ./Classes/MarkerInspector.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - minus_btn.png - plus_btn.png - - - YES - {40, 40} - {40, 40} - - - 933 - - diff --git a/test/ios/RootBrowser/MarkerStyleCell.h b/test/ios/RootBrowser/MarkerStyleCell.h deleted file mode 100644 index c37662ca0ce8f..0000000000000 --- a/test/ios/RootBrowser/MarkerStyleCell.h +++ /dev/null @@ -1,9 +0,0 @@ -#import - -#import "TAttMarker.h" - -@interface MarkerStyleCell : UIView - -- (id) initWithFrame : (CGRect)frame andMarkerStyle : (EMarkerStyle)style; - -@end diff --git a/test/ios/RootBrowser/MarkerStyleCell.mm b/test/ios/RootBrowser/MarkerStyleCell.mm deleted file mode 100644 index 5df1cd13f0ecb..0000000000000 --- a/test/ios/RootBrowser/MarkerStyleCell.mm +++ /dev/null @@ -1,40 +0,0 @@ -#import - -#import "MarkerStyleCell.h" - -#import "IOSMarkers.h" -#import "TPoint.h" - -@implementation MarkerStyleCell { - EMarkerStyle markerStyle; -} - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame andMarkerStyle : (EMarkerStyle)style -{ - self = [super initWithFrame : frame]; - if (self) { - markerStyle = style; - self.opaque = NO; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)drawRect : (CGRect)rect -{ - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - CGContextTranslateCTM(ctx, 0.f, rect.size.height); - CGContextScaleCTM(ctx, 1.f, -1.f); - - CGContextSetAllowsAntialiasing(ctx, 0); - CGContextSetRGBFillColor(ctx, 0.f, 0.f, 0.f, 1.f); - CGContextSetRGBStrokeColor(ctx, 0.f, 0.f, 0.f, 1.f); - - TPoint markerPosition(rect.size.width / 2, rect.size.height / 2); - ROOT::iOS::GraphicUtils::DrawPolyMarker(ctx, 1, &markerPosition, 2.5, Style_t(markerStyle));//2.5 is the marker size. -} - -@end diff --git a/test/ios/RootBrowser/ObjectInspector.h b/test/ios/RootBrowser/ObjectInspector.h deleted file mode 100644 index 06de238ef502a..0000000000000 --- a/test/ios/RootBrowser/ObjectInspector.h +++ /dev/null @@ -1,15 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" - -@class EditorView; - -@interface ObjectInspector : UIViewController - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; -- (void) resetInspector; - -- (EditorView *) getEditorView; - -@end diff --git a/test/ios/RootBrowser/ObjectInspector.mm b/test/ios/RootBrowser/ObjectInspector.mm deleted file mode 100644 index 577a5843bc580..0000000000000 --- a/test/ios/RootBrowser/ObjectInspector.mm +++ /dev/null @@ -1,200 +0,0 @@ -#import "InspectorWithNavigation.h" -#import "FilledAreaInspector.h" -#import "ObjectInspector.h" -#import "MarkerInspector.h" -#import "AxisInspector.h" -#import "LineInspector.h" -#import "PadInspector.h" -#import "H1Inspector.h" -#import "EditorView.h" - -//C++ (ROOT) imports. -#import "TAttMarker.h" -#import "TAttLine.h" -#import "TAttFill.h" -#import "TAttAxis.h" -#import "TAttPad.h" -#import "TObject.h" -#import "TClass.h" -#import "TH1.h" - -namespace { - enum { - //Just indices. - kAttLine = 0, - kAttFill = 1, - kAttPad = 2, - kAttAxis = 3, - //Add the new one here. - kAttMarker = 4, - kAttH1 = 5, - kNOfInspectors // - }; -} - -@implementation ObjectInspector { - UIViewController *activeEditors[kNOfInspectors]; - UIViewController *cachedEditors[kNOfInspectors]; - - unsigned nActiveEditors; - - TObject *object; - - EditorView *editorView; -} - - -//____________________________________________________________________________________________________ -- (void) initObjectInspectorView -{ - editorView = [[EditorView alloc] initWithFrame:CGRectMake(0.f, 0.f, [EditorView editorWidth], [EditorView editorHeight])]; - self.view = editorView; -} - -//____________________________________________________________________________________________________ -- (void) cacheEditors -{ - //TAttLine. - cachedEditors[kAttLine] = [[LineInspector alloc] initWithNibName : @"LineInspector" bundle : nil];//lineInspector; - //TAttFill. - cachedEditors[kAttFill] = [[FilledAreaInspector alloc] initWithNibName : @"FilledAreaInspector" bundle : nil]; - //TAttPad. - cachedEditors[kAttPad] = [[PadInspector alloc] initWithNibName : @"PadInspector" bundle : nil];//padInspector; - //TAttAxis. - cachedEditors[kAttAxis] = [[AxisInspector alloc] initWithNibName : @"AxisInspector" bundle : nil]; - //TAttMarker. - cachedEditors[kAttMarker] = [[MarkerInspector alloc] initWithNibName: @"MarkerInspector" bundle : nil]; - //H1's inspector. - cachedEditors[kAttH1] = [[H1Inspector alloc] initWithNibName : @"H1Inspector" bundle : nil]; -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - if (self) { - [self initObjectInspectorView]; - [self cacheEditors]; - } - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -/* -// Implement loadView to create a view hierarchy programmatically, without using a nib. -- (void)loadView -{ -} -*/ - -/* -// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. -- (void)viewDidLoad -{ - [super viewDidLoad]; -} -*/ - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - for (unsigned i = 0; i < nActiveEditors; ++i) - [activeEditors[i] setROOTObjectController : c]; -} - -//____________________________________________________________________________________________________ -- (void) setTitle -{ - if (dynamic_cast(object)) { - //This is special case, as soon as ROOT::iOS::Pad does not have - //ClassDef, the IsA() will be for TVirtualPad, but I want to - //see simply "Pad" as a title. - [editorView setEditorTitle : "Pad"]; - } else { - [editorView setEditorTitle : object->IsA()->GetName()]; - } -} - -//____________________________________________________________________________________________________ -- (void) setActiveEditors -{ - nActiveEditors = 0; - - if (dynamic_cast(object) && !dynamic_cast(object)) - activeEditors[nActiveEditors++] = cachedEditors[kAttLine]; - - if (dynamic_cast(object)) - activeEditors[nActiveEditors++] = cachedEditors[kAttFill]; - - if (dynamic_cast(object)) - activeEditors[nActiveEditors++] = cachedEditors[kAttPad]; - - if (dynamic_cast(object)) - activeEditors[nActiveEditors++] = cachedEditors[kAttAxis]; - - if (dynamic_cast(object)) - activeEditors[nActiveEditors++] = cachedEditors[kAttMarker]; - - if (dynamic_cast(object)) - activeEditors[nActiveEditors++] = cachedEditors[kAttH1]; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - if (o != object) { - //Initialize. - object = o; - - [self setTitle]; - [self setActiveEditors]; - - for (unsigned i = 0; i < nActiveEditors; ++i) - [activeEditors[i] setROOTObject : o]; - - [editorView removeAllEditors]; - - for (unsigned i = 0; i < nActiveEditors; ++i) - [editorView addSubEditor : activeEditors[i].view withName : [activeEditors[i] getComponentName]]; - } -} - -//____________________________________________________________________________________________________ -- (void) resetInspector -{ - for (unsigned i = 0; i < nActiveEditors; ++i) - if ([activeEditors[i] respondsToSelector : @selector(resetInspector)]) - [activeEditors[i] resetInspector]; -} - -//____________________________________________________________________________________________________ -- (EditorView *) getEditorView -{ - return editorView; -} - -@end diff --git a/test/ios/RootBrowser/ObjectInspectorComponent.h b/test/ios/RootBrowser/ObjectInspectorComponent.h deleted file mode 100644 index d8f88bdf936a1..0000000000000 --- a/test/ios/RootBrowser/ObjectInspectorComponent.h +++ /dev/null @@ -1,22 +0,0 @@ -#import - -// -//Protocol to be adopted by every specific "object editor" or -//"object-inspector". -// - -@class ROOTObjectController; - -class TObject; - -@protocol ObjectInspectorComponent - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; - -@optional - -- (NSString*) getComponentName; -- (void) resetInspector; - -@end diff --git a/test/ios/RootBrowser/ObjectShortcut.h b/test/ios/RootBrowser/ObjectShortcut.h deleted file mode 100644 index c7e5456f7d3e2..0000000000000 --- a/test/ios/RootBrowser/ObjectShortcut.h +++ /dev/null @@ -1,23 +0,0 @@ -#import - -@class FileContentController; -@class SpotView; - -@interface ObjectShortcut : UIView - -@property (nonatomic, retain) SpotView *spot; -@property (nonatomic, assign) BOOL isDirectory; -@property (nonatomic, retain) UIImage *icon; -@property (nonatomic, readonly) unsigned objectIndex; -@property (nonatomic, retain) NSString *objectName; - -+ (CGFloat) iconWidth; -+ (CGFloat) iconHeight; -+ (CGFloat) textHeight; -+ (CGRect) defaultRect; - - -- (id) initWithFrame : (CGRect)frame controller : (FileContentController*) c forObjectAtIndex : (unsigned)objIndex withThumbnail : (UIImage *)thumbnail; -- (id) initWithFrame : (CGRect)frame controller : (FileContentController*) c forFolderAtIndex : (unsigned)index; - -@end diff --git a/test/ios/RootBrowser/ObjectShortcut.mm b/test/ios/RootBrowser/ObjectShortcut.mm deleted file mode 100644 index 0df1044f146e8..0000000000000 --- a/test/ios/RootBrowser/ObjectShortcut.mm +++ /dev/null @@ -1,141 +0,0 @@ -#import -#import -#import - -#import "FileContentController.h" -#import "ObjectShortcut.h" -#import "SpotView.h" - -//C++ (ROOT) imports. -#import "FileUtils.h" -#import "TObject.h" - -const CGSize folderIconSize = CGSizeMake(128.f, 128.f); - -@implementation ObjectShortcut { - __weak FileContentController *controller; - - unsigned objectIndex; - NSString *objectName; -} - -@synthesize isDirectory; -@synthesize icon; -@synthesize objectIndex; -@synthesize objectName; -@synthesize spot; - -//____________________________________________________________________________________________________ -+ (CGFloat) iconWidth -{ - return 150.f; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) iconHeight -{ - return 150.f; -} - -//____________________________________________________________________________________________________ -+ (CGFloat) textHeight -{ - return 100.f; -} - -//____________________________________________________________________________________________________ -+ (CGRect) defaultRect -{ - return CGRectMake(0.f, 0.f, [ObjectShortcut iconWidth], [ObjectShortcut iconHeight] + [ObjectShortcut textHeight]); -} - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame controller : (FileContentController*) c forFolderAtIndex : (unsigned)index -{ - using namespace ROOT::iOS::Browser; - - if (self = [super initWithFrame : frame]) { - frame.origin = CGPointZero; - frame.size.height = [ObjectShortcut iconHeight]; - - spot = [[SpotView alloc] initWithFrame : frame]; - [self addSubview : spot]; - - controller = c; - objectIndex = index; - - const FileContainer *cont = controller.fileContainer->GetDirectory(index); - isDirectory = YES; - self.objectName = [NSString stringWithFormat : @"%s", cont->GetFileName()]; - self.icon = [UIImage imageNamed : @"directory.png"]; - self.opaque = NO; - - //Tap gesture to select a directory. - UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)]; - [self addGestureRecognizer : tap]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame controller : (FileContentController*) c forObjectAtIndex : (unsigned)objIndex withThumbnail : (UIImage *)thumbnail -{ - using namespace ROOT::iOS::Browser; - - self = [super initWithFrame:frame]; - - if (self) { - frame.origin = CGPointZero; - frame.size.height = [ObjectShortcut iconHeight]; - - spot = [[SpotView alloc] initWithFrame : frame]; - [self addSubview : spot]; - - //ROOT's staff. - controller = c; - objectIndex = objIndex; - - const TObject *obj = controller.fileContainer->GetObject(objIndex); - self.objectName = [NSString stringWithFormat : @"%s", obj->GetName()]; - self.icon = thumbnail; - - self.opaque = NO; - - //Tap gesture to select an object. - UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)]; - [self addGestureRecognizer : tap]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) drawRect : (CGRect)rect -{ - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - if (isDirectory) { - //Directory's icon is 128 x 128 < than thumbnail. - CGPoint topLeft = CGPointMake([ObjectShortcut iconWidth] / 2 - folderIconSize.width / 2, [ObjectShortcut iconHeight] / 2 - folderIconSize.height / 2); - [icon drawAtPoint : topLeft]; - } else - [icon drawAtPoint : CGPointZero]; - - CGContextSetRGBFillColor(ctx, 1.f, 1.f, 1.f, 1.f); - const CGRect textRect = CGRectMake(0.f, [ObjectShortcut iconHeight], [ObjectShortcut iconWidth], [ObjectShortcut textHeight]); - -#ifdef __IPHONE_6_0 - [objectName drawInRect : textRect withFont : [UIFont systemFontOfSize : 16] lineBreakMode : NSLineBreakByWordWrapping alignment : NSTextAlignmentCenter]; -#else - [objectName drawInRect : textRect withFont : [UIFont systemFontOfSize : 16] lineBreakMode : UILineBreakModeWordWrap alignment : UITextAlignmentCenter]; -#endif -} - -//____________________________________________________________________________________________________ -- (void) handleTap -{ - [controller selectObjectFromFile : self]; -} - -@end diff --git a/test/ios/RootBrowser/PadImageScrollView.h b/test/ios/RootBrowser/PadImageScrollView.h deleted file mode 100644 index d8990e81f549d..0000000000000 --- a/test/ios/RootBrowser/PadImageScrollView.h +++ /dev/null @@ -1,20 +0,0 @@ -#import - -namespace ROOT { -namespace iOS { - -class Pad; - -} -} - -@interface PadImageScrollView : UIScrollView - -+ (CGRect) defaultImageFrame; - -- (id) initWithFrame : (CGRect)frame; - -- (void) setPad : (ROOT::iOS::Pad *)pad; -- (void) resetToFrame : (CGRect)frame; - -@end diff --git a/test/ios/RootBrowser/PadImageScrollView.mm b/test/ios/RootBrowser/PadImageScrollView.mm deleted file mode 100644 index ce11b30317eea..0000000000000 --- a/test/ios/RootBrowser/PadImageScrollView.mm +++ /dev/null @@ -1,213 +0,0 @@ -#import - -#import - -#import "PadImageScrollView.h" -#import "PadView.h" - -//C++ (ROOT) imports. -#import "TObject.h" -#import "IOSPad.h" - -static const CGFloat defaultImageW = 700.f; -static const CGFloat defaultImageH = 700.f; -static const CGFloat maxZoom = 2.f; -static const CGFloat minZoom = 1.f; - -@implementation PadImageScrollView { - ROOT::iOS::Pad *pad; - - PadView *nestedView; -} - -//____________________________________________________________________________________________________ -+ (CGRect) defaultImageFrame -{ - return CGRectMake(0.f, 0.f, defaultImageW, defaultImageH); -} - -//____________________________________________________________________________________________________ -- (CGPoint) adjustOriginForFrame : (CGRect)frame withSize : (CGSize) sz -{ - return CGPointMake(frame.size.width / 2 - sz.width / 2, frame.size.height / 2 - sz.height / 2); -} - -//____________________________________________________________________________________________________ -- (void) initPadView : (CGRect)frame -{ - CGRect padFrame = [PadImageScrollView defaultImageFrame]; - padFrame.origin = [self adjustOriginForFrame : frame withSize : padFrame.size]; - - nestedView = [[PadView alloc] initImmutableViewWithFrame : padFrame]; - nestedView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - - [self addSubview : nestedView]; -} - - -//____________________________________________________________________________________________________ -- (void) setContentSize : (CGSize) size contentOffset : (CGPoint)offset minScale : (CGFloat)min maxScale : (CGFloat)max scale : (CGFloat)scale -{ - self.maximumZoomScale = max; - self.minimumZoomScale = min; - self.zoomScale = scale; - self.contentSize = size; - self.contentOffset = offset; -} - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame -{ - if (self = [super initWithFrame : frame]) { - self.delegate = self; //hehehehe - self.bouncesZoom = NO; - self.bounces = NO; - self.backgroundColor = [UIColor clearColor]; - self.decelerationRate = UIScrollViewDecelerationRateFast; - - [self setContentSize : frame.size contentOffset : CGPointZero minScale : minZoom maxScale : maxZoom scale : 1]; - - UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector(handleDoubleTap:)]; - doubleTap.numberOfTapsRequired = 2; - [self addGestureRecognizer : doubleTap]; - } - - return self; -} - -#pragma mark - Child view's management -//____________________________________________________________________________________________________ -- (void) clearScroll -{ - [self setContentSize : [PadImageScrollView defaultImageFrame].size contentOffset : CGPointZero minScale : minZoom maxScale : maxZoom scale : 1]; - [nestedView removeFromSuperview]; - nestedView = nil; -} - -#pragma mark - Image/pad/geometry management. - -//____________________________________________________________________________________________________ -- (void) setPad : (ROOT::iOS::Pad *)p -{ - pad = p; - pad->SetViewWH(defaultImageW, defaultImageH); - - if (nestedView && nestedView.zoomed) { - [self clearScroll]; - [self initPadView : self.frame]; - } else if (!nestedView) { - [self initPadView : self.frame]; - } - - [nestedView setPad : pad]; - [nestedView setNeedsDisplay]; -} - -//____________________________________________________________________________________________________ -- (void) resetToFrame : (CGRect) newFrame -{ - self.frame = newFrame; - [self setContentSize : newFrame.size contentOffset : CGPointZero minScale : minZoom maxScale : maxZoom scale : 1]; - - if (nestedView.zoomed) { - [self clearScroll]; - [self initPadView : newFrame]; - [nestedView setPad : pad]; - [nestedView setNeedsDisplay]; - } -} - -//_________________________________________________________________ -- (CGRect)centeredFrameForScrollView:(UIScrollView *)scroll andUIView:(UIView *)rView -{ - CGSize boundsSize = scroll.bounds.size; - CGRect frameToCenter = rView.frame; - // center horizontally - if (frameToCenter.size.width < boundsSize.width) { - frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2; - } - else { - frameToCenter.origin.x = 0; - } - // center vertically - if (frameToCenter.size.height < boundsSize.height) { - frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2; - } - else { - frameToCenter.origin.y = 0; - } - - return frameToCenter; -} - -//____________________________________________________________________________________________________ -- (void)scrollViewDidZoom:(UIScrollView *)scroll -{ - nestedView.frame = [self centeredFrameForScrollView : scroll andUIView : nestedView]; -} - -//____________________________________________________________________________________________________ -- (void)scrollViewDidEndZooming : (UIScrollView *)scroll withView : (UIView *)view atScale : (float)scale -{ - const CGPoint offset = [scroll contentOffset]; - const CGRect newFrame = nestedView.frame; - - [scroll setZoomScale : 1.f]; - - const unsigned base = [PadImageScrollView defaultImageFrame].size.width; - - scroll.minimumZoomScale = base / newFrame.size.width; - scroll.maximumZoomScale = maxZoom * base / newFrame.size.width; - - [nestedView removeFromSuperview]; - - nestedView = [[PadView alloc] initImmutableViewWithFrame : newFrame]; - [nestedView setPad : pad]; - - [scroll addSubview : nestedView]; - - scroll.contentSize = newFrame.size; - scroll.contentOffset = offset; - - nestedView.zoomed = YES; -} - -//____________________________________________________________________________________________________ -- (UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView -{ - return nestedView; -} - -//____________________________________________________________________________________________________ -- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center { - - CGRect zoomRect; - - // the zoom rect is in the content view's coordinates. - // At a zoom scale of 1.0, it would be the size of the imageScrollView's bounds. - // As the zoom scale decreases, so more content is visible, the size of the rect grows. - zoomRect.size.height = [self frame].size.height / scale; - zoomRect.size.width = [self frame].size.width / scale; - - // choose an origin so as to get the right center. - zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0); - zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0); - - return zoomRect; -} - -//____________________________________________________________________________________________________ -- (void) handleDoubleTap : (UITapGestureRecognizer *)tap -{ - //Identify, if we should unzoom. - if (fabs(nestedView.frame.size.width - maxZoom * defaultImageW) < 10) { - [self resetToFrame : self.frame]; - } else { - //Zoom in. - const CGFloat newScale = maxZoom * defaultImageW / nestedView.frame.size.width; - CGRect zoomRect = [self zoomRectForScale : newScale withCenter : [tap locationInView : self]]; - [self zoomToRect : zoomRect animated : YES]; - } -} - -@end diff --git a/test/ios/RootBrowser/PadInspector.h b/test/ios/RootBrowser/PadInspector.h deleted file mode 100644 index 8271ee752e0d4..0000000000000 --- a/test/ios/RootBrowser/PadInspector.h +++ /dev/null @@ -1,17 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" - -@interface PadInspector : UIViewController { -@private - __weak IBOutlet UITabBar *tabBar; -} - -+ (CGRect) inspectorFrame; - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; -- (NSString *) getComponentName; -- (void) resetInspector; - -@end diff --git a/test/ios/RootBrowser/PadInspector.mm b/test/ios/RootBrowser/PadInspector.mm deleted file mode 100644 index 535606c22ee45..0000000000000 --- a/test/ios/RootBrowser/PadInspector.mm +++ /dev/null @@ -1,142 +0,0 @@ -#import "PadTicksGridInspector.h" -#import "PadLogScaleInspector.h" -#import "PadInspector.h" - -//It's mm file == C++, consts have internal linkage. -const CGFloat totalHeight = 250.f; -const CGFloat tabBarHeight = 49.f; -const CGRect nestedComponentFrame = CGRectMake(0.f, tabBarHeight, 250.f, totalHeight - tabBarHeight); - -@interface PadInspector () { - PadTicksGridInspector *gridInspector; - PadLogScaleInspector *logScaleInspector; - - __weak ROOTObjectController *controller; - TObject *object; -} - -- (void) showTicksAndGridInspector; -- (void) showLogScaleInspector; - -@end - -@implementation PadInspector - -//____________________________________________________________________________________________________ -+ (CGRect) inspectorFrame -{ - return CGRectMake(0.f, 0.f, 250.f, 250.f); -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - - [self view]; - - if (self) { - //Load inspectors from nib files. - gridInspector = [[PadTicksGridInspector alloc] initWithNibName : @"PadTicksGridInspector" bundle : nil]; - gridInspector.view.frame = nestedComponentFrame; - logScaleInspector = [[PadLogScaleInspector alloc] initWithNibName : @"PadLogScaleInspector" bundle : nil]; - logScaleInspector.view.frame = nestedComponentFrame; - - [self.view addSubview : gridInspector.view]; - [self.view addSubview : logScaleInspector.view]; - - gridInspector.view.hidden = NO; - logScaleInspector.view.hidden = YES; - - tabBar.selectedItem = [[tabBar items] objectAtIndex : 0]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; - [gridInspector setROOTObjectController : c]; - [logScaleInspector setROOTObjectController : c]; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - object = o; - [gridInspector setROOTObject : o]; - [logScaleInspector setROOTObject : o]; -} - -//____________________________________________________________________________________________________ -- (NSString *) getComponentName -{ - return @"Pad attributes"; -} - -//____________________________________________________________________________________________________ -- (void) resetInspector -{ - tabBar.selectedItem = [[tabBar items] objectAtIndex : 0]; - [self showTicksAndGridInspector]; -} - -//____________________________________________________________________________________________________ -- (void) showTicksAndGridInspector -{ - logScaleInspector.view.hidden = YES; - gridInspector.view.hidden = NO; -} - -//____________________________________________________________________________________________________ -- (void) showLogScaleInspector -{ - logScaleInspector.view.hidden = NO; - gridInspector.view.hidden = YES; -} - -#pragma mark - Tabbar delegate. -//____________________________________________________________________________________________________ -- (void) tabBar : (UITabBar *) tb didSelectItem : (UITabBarItem *)item -{ - if (item.tag == 1) - [self showTicksAndGridInspector]; - else if (item.tag == 2) - [self showLogScaleInspector]; -} - -@end diff --git a/test/ios/RootBrowser/PadInspector.xib b/test/ios/RootBrowser/PadInspector.xib deleted file mode 100644 index 6390e3184010e..0000000000000 --- a/test/ios/RootBrowser/PadInspector.xib +++ /dev/null @@ -1,256 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - YES - IBUITabBar - IBUIView - IBUITabBarItem - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 266 - {250, 49} - - - _NS:518 - - 3 - MCAwAA - - IBIPadFramework - - YES - - 1 - Ticks and grid - - NSImage - ticks_tab.png - - IBIPadFramework - - - - 2 - Log scale - - NSImage - lg_tab.png - - IBIPadFramework - - - - - - {250, 250} - - - - _NS:195 - - IBIPadFramework - - - - - YES - - - view - - - - 8 - - - - tabBar - - - - 19 - - - - delegate - - - - 17 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - 14 - - - YES - - - - - - - 15 - - - - - 16 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 14.IBPluginDependency - 15.IBPluginDependency - 16.IBPluginDependency - 4.IBPluginDependency - - - YES - PadInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 19 - - - - YES - - PadInspector - UIViewController - - tabBar - UITabBar - - - tabBar - - tabBar - UITabBar - - - - IBProjectSource - ./Classes/PadInspector.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - lg_tab.png - ticks_tab.png - - - YES - {30, 30} - {30, 30} - - - 933 - - diff --git a/test/ios/RootBrowser/PadLogScaleInspector.h b/test/ios/RootBrowser/PadLogScaleInspector.h deleted file mode 100644 index 5518ea30ffb37..0000000000000 --- a/test/ios/RootBrowser/PadLogScaleInspector.h +++ /dev/null @@ -1,17 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" - -@interface PadLogScaleInspector : UIViewController { -@private - __weak IBOutlet UISwitch *logX; - __weak IBOutlet UISwitch *logY; - __weak IBOutlet UISwitch *logZ; -} - -- (void) setROOTObjectController : (ROOTObjectController *)c; -- (void) setROOTObject : (TObject *)o; - -- (IBAction) logActivated : (UISwitch *) log; - -@end diff --git a/test/ios/RootBrowser/PadLogScaleInspector.mm b/test/ios/RootBrowser/PadLogScaleInspector.mm deleted file mode 100644 index c2620487fc87f..0000000000000 --- a/test/ios/RootBrowser/PadLogScaleInspector.mm +++ /dev/null @@ -1,82 +0,0 @@ -#import "ROOTObjectController.h" -#import "PadLogScaleInspector.h" - -//C++ (ROOT) imports. -#import "TVirtualPad.h" -#import "TObject.h" - -@implementation PadLogScaleInspector { - __weak ROOTObjectController *controller; - TVirtualPad *object; -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - [self view]; - return self; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - object = static_cast(o); - //Result of cast is not checked here, it's done at the upper level. - logX.on = object->GetLogx(); - logY.on = object->GetLogy(); - logZ.on = object->GetLogz(); -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (IBAction) logActivated : (UISwitch *) log -{ - if (log == logX) - object->SetLogx(log.on); - if (log == logY) - object->SetLogy(log.on); - if (log == logZ) - object->SetLogz(log.on); - - [controller objectWasModifiedUpdateSelection : YES];//Now picture changed, so picking buffer is invalid. -} - -@end diff --git a/test/ios/RootBrowser/PadLogScaleInspector.xib b/test/ios/RootBrowser/PadLogScaleInspector.xib deleted file mode 100644 index 91d600f19078f..0000000000000 --- a/test/ios/RootBrowser/PadLogScaleInspector.xib +++ /dev/null @@ -1,429 +0,0 @@ - - - - 1056 - 11B26 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBUISwitch - IBUIView - IBUILabel - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 292 - {{20, 23}, {60, 21}} - - - - _NS:327 - - 3 - MCAwAA - - NO - YES - 7 - NO - IBIPadFramework - Log X: - - 1 - MCAwIDAAA - - - 1 - 10 - - - - 292 - {{20, 90}, {60, 21}} - - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Log Y: - - - 1 - 10 - - - - 292 - {{20, 157}, {60, 21}} - - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Log Z: - - - 1 - 10 - - - - 292 - {{136, 20}, {94, 27}} - - - - _NS:592 - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{136, 87}, {94, 27}} - - - - _NS:592 - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{136, 154}, {94, 27}} - - - - _NS:592 - NO - IBIPadFramework - 0 - 0 - - - {250, 201} - - - - _NS:195 - - IBIPadFramework - - - - - YES - - - logX - - - - 12 - - - - logY - - - - 13 - - - - logZ - - - - 14 - - - - view - - - - 15 - - - - logActivated: - - - 13 - - 17 - - - - logActivated: - - - 13 - - 18 - - - - logActivated: - - - 13 - - 19 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - - - - - 5 - - - - - 6 - - - - - 7 - - - - - 8 - - - - - 9 - - - - - 10 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 10.IBPluginDependency - 4.IBPluginDependency - 5.IBPluginDependency - 6.IBPluginDependency - 7.IBPluginDependency - 8.IBPluginDependency - 9.IBPluginDependency - - - YES - PadLogScaleInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 19 - - - - YES - - PadLogScaleInspector - UIViewController - - YES - - YES - back - logActivated: - - - YES - id - UISwitch - - - - YES - - YES - back - logActivated: - - - YES - - back - id - - - logActivated: - UISwitch - - - - - YES - - YES - logX - logY - logZ - - - YES - UISwitch - UISwitch - UISwitch - - - - YES - - YES - logX - logY - logZ - - - YES - - logX - UISwitch - - - logY - UISwitch - - - logZ - UISwitch - - - - - IBProjectSource - ./Classes/PadLogScaleInspector.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 534 - - diff --git a/test/ios/RootBrowser/PadTicksGridInspector.h b/test/ios/RootBrowser/PadTicksGridInspector.h deleted file mode 100644 index 39178a9c8a6e7..0000000000000 --- a/test/ios/RootBrowser/PadTicksGridInspector.h +++ /dev/null @@ -1,19 +0,0 @@ -#import - -#import "ObjectInspectorComponent.h" - -@interface PadTicksGridInspector : UIViewController { -@private - __weak IBOutlet UISwitch *gridX; - __weak IBOutlet UISwitch *gridY; - __weak IBOutlet UISwitch *ticksX; - __weak IBOutlet UISwitch *ticksY; -} - -- (void) setROOTObjectController : (ROOTObjectController *) c; -- (void) setROOTObject : (TObject *) obj; - -- (IBAction) gridActivated : (UISwitch *) g; -- (IBAction) ticksActivated : (UISwitch *) t; - -@end diff --git a/test/ios/RootBrowser/PadTicksGridInspector.mm b/test/ios/RootBrowser/PadTicksGridInspector.mm deleted file mode 100644 index e10b2b528f4e0..0000000000000 --- a/test/ios/RootBrowser/PadTicksGridInspector.mm +++ /dev/null @@ -1,99 +0,0 @@ -#import "PadTicksGridInspector.h" -#import "ROOTObjectController.h" - -#import "TVirtualPad.h" -#import "TObject.h" - -@implementation PadTicksGridInspector { - __weak ROOTObjectController *controller; - TVirtualPad *object; -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - - [self view]; - - if (self) { - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) setROOTObject : (TObject *)o -{ - object = static_cast(o); - - //I do not check the result of cast here, it's done on upper level. - gridX.on = object->GetGridx(); - gridY.on = object->GetGridy(); - ticksX.on = object->GetTickx(); - ticksY.on = object->GetTicky(); -} - -//____________________________________________________________________________________________________ -- (void) setROOTObjectController : (ROOTObjectController *)c -{ - controller = c; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -#pragma mark - Inspector's actions. - -//____________________________________________________________________________________________________ -- (IBAction) gridActivated : (UISwitch *) g -{ - if (g == gridX) - object->SetGridx(g.on); - else if (g == gridY) - object->SetGridy(g.on); - - [controller objectWasModifiedUpdateSelection : NO]; -} - -//____________________________________________________________________________________________________ -- (IBAction) ticksActivated : (UISwitch *) t -{ - if (t == ticksX) - object->SetTickx(t.on); - else if (t == ticksY) - object->SetTicky(t.on); - - [controller objectWasModifiedUpdateSelection : NO]; -} - -@end diff --git a/test/ios/RootBrowser/PadTicksGridInspector.xib b/test/ios/RootBrowser/PadTicksGridInspector.xib deleted file mode 100644 index f66968449ae55..0000000000000 --- a/test/ios/RootBrowser/PadTicksGridInspector.xib +++ /dev/null @@ -1,447 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - YES - IBUISwitch - IBUIImageView - IBUIView - IBUILabel - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - - YES - - - 292 - {{20, 20}, {65, 21}} - - - _NS:327 - - 3 - MCAwAA - - NO - YES - 7 - NO - IBIPadFramework - Grid X: - - 1 - MCAwIDAAA - - - 1 - 10 - - 1 - 17 - - - Helvetica - 17 - 16 - - - - - 292 - {{20, 55}, {65, 21}} - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Grid Y: - - - 1 - 10 - - - - - - 292 - {{20, 122}, {70, 21}} - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Ticks X: - - - 1 - 10 - - - - - - 292 - {{20, 157}, {70, 21}} - - - _NS:327 - - NO - YES - 7 - NO - IBIPadFramework - Ticks Y: - - - 1 - 10 - - - - - - 292 - {{136, 17}, {94, 27}} - - - _NS:592 - NO - 1 - IBIPadFramework - 0 - 0 - - - - 292 - {{136, 52}, {94, 27}} - - - _NS:592 - NO - 2 - IBIPadFramework - 0 - 0 - - - - 292 - {{136, 119}, {94, 27}} - - - _NS:592 - NO - 3 - IBIPadFramework - 0 - 0 - - - - 292 - {{136, 154}, {94, 27}} - - _NS:592 - NO - 4 - IBIPadFramework - 0 - 0 - - - - 292 - {{10, 99}, {230, 3}} - - - _NS:544 - NO - IBIPadFramework - - NSImage - separator.png - - - - {250, 201} - - - _NS:195 - - IBIPadFramework - - - - - YES - - - view - - - - 18 - - - - gridX - - - - 25 - - - - gridY - - - - 26 - - - - ticksX - - - - 27 - - - - ticksY - - - - 28 - - - - gridActivated: - - - 13 - - 19 - - - - gridActivated: - - - 13 - - 20 - - - - ticksActivated: - - - 13 - - 21 - - - - ticksActivated: - - - 13 - - 22 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - - - - - - - - 5 - - - - - 6 - - - - - 7 - - - - - 8 - - - - - 9 - - - - - 10 - - - - - 11 - - - - - 12 - - - - - 24 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 10.IBPluginDependency - 11.IBPluginDependency - 12.IBPluginDependency - 24.IBPluginDependency - 4.IBPluginDependency - 5.IBPluginDependency - 6.IBPluginDependency - 7.IBPluginDependency - 8.IBPluginDependency - 9.IBPluginDependency - - - YES - PadTicksGridInspector - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 28 - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - separator.png - {230, 3} - - 933 - - diff --git a/test/ios/RootBrowser/PadView.h b/test/ios/RootBrowser/PadView.h deleted file mode 100644 index fdb4a9bbd73d4..0000000000000 --- a/test/ios/RootBrowser/PadView.h +++ /dev/null @@ -1,36 +0,0 @@ -#import - -/////////////////////////////////////////////////////////// -// Custom view, subview for a detail view. -// Delegates all graphics to C++ code. -// This is view for pad in "editable state". -// TODO: find better class name. -/////////////////////////////////////////////////////////// - -namespace ROOT { -namespace iOS { - -class Pad; - -} -} - -@class ROOTObjectController; -@class SelectionView; - -@interface PadView : UIView - -@property (nonatomic, retain) SelectionView *selectionView; -@property (assign) BOOL zoomed; - -- (id) initWithFrame : (CGRect)frame controller : (ROOTObjectController *)c forPad : (ROOT::iOS::Pad*)pad; -- (id) initImmutableViewWithFrame : (CGRect)frame; - -- (void) setPad : (ROOT::iOS::Pad *)newPad; -- (void) clearPad; - -- (BOOL) pointOnSelectedObject : (CGPoint) pt; -- (void) addPanRecognizer; -- (void) removePanRecognizer; - -@end diff --git a/test/ios/RootBrowser/PadView.mm b/test/ios/RootBrowser/PadView.mm deleted file mode 100644 index 7ecb7a4c9820f..0000000000000 --- a/test/ios/RootBrowser/PadView.mm +++ /dev/null @@ -1,390 +0,0 @@ -#import -#import -#import -#import - -#import -#import - -#import "ROOTObjectController.h" -#import "SelectionView.h" -#import "Constants.h" -#import "PadView.h" - -#import "TAxis.h" - -//C++ code (ROOT's ios module) -#import "IOSPad.h" - -const CGFloat tapInterval = 0.15f; - -@interface PadView () { - ROOT::iOS::Pad *pad; - - __weak ROOTObjectController *controller; - - CGFloat currentScale; - - BOOL panActive; - - CGPoint tapPt; - BOOL processSecondTap; - - BOOL isMutable; -} - -- (void) handleSingleTap; -- (void) handleDoubleTap; - -@end - -@implementation PadView - -@synthesize selectionView; -@synthesize zoomed; - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame controller : (ROOTObjectController *)c forPad : (ROOT::iOS::Pad*)pd -{ - self = [super initWithFrame : frame]; - - if (self) { - controller = c; - pad = pd; - - isMutable = YES; - - frame.origin = CGPointZero; - selectionView = [[SelectionView alloc] initWithFrame : frame withPad : pad]; - selectionView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - selectionView.hidden = YES; - [self addSubview : selectionView]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (id) initImmutableViewWithFrame : (CGRect)frame -{ - if (self = [super initWithFrame : frame]) { - controller = nil; - pad = nullptr; - selectionView = nil; - - isMutable = NO; - - self.multipleTouchEnabled = NO; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) setPad : (ROOT::iOS::Pad *)newPad -{ - pad = newPad; - if (isMutable) - [selectionView setPad : newPad]; -} - -//____________________________________________________________________________________________________ -- (void)drawRect : (CGRect)rect -{ - // Drawing code - if (!pad) - return; - - CGContextRef ctx = UIGraphicsGetCurrentContext(); - CGContextClearRect(ctx, rect); - - pad->SetViewWH(rect.size.width, rect.size.height); - CGContextTranslateCTM(ctx, 0.f, rect.size.height); - CGContextScaleCTM(ctx, 1.f, -1.f); - pad->cd(); - pad->SetContext(ctx); - pad->Paint(); - - if (isMutable && !selectionView.hidden) - [selectionView setNeedsDisplay]; -} - -//____________________________________________________________________________________________________ -- (void) clearPad -{ - pad->Clear(); -} - -//____________________________________________________________________________________________________ -- (void) addPanRecognizer -{ - panActive = YES; -} - -//____________________________________________________________________________________________________ -- (void) removePanRecognizer -{ - panActive = NO; -} - -#pragma mark - Picking related stuff here. - -//____________________________________________________________________________________________________ -- (CGImageRef) initCGImageForPicking -{ - if (!isMutable) - return nullptr; - - using namespace ROOT::iOS::Browser; - const CGRect rect = CGRectMake(0.f, 0.f, padW, padH); - //Create bitmap context. - UIGraphicsBeginImageContext(rect.size); - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - //Now draw into this context. - CGContextTranslateCTM(ctx, 0.f, rect.size.height); - CGContextScaleCTM(ctx, 1.f, -1.f); - - //Disable anti-aliasing, to avoid "non-clear" colors. - CGContextSetAllowsAntialiasing(ctx, 0); - //Fill bitmap with black (nothing under cursor). - CGContextSetRGBFillColor(ctx, 0.f, 0.f, 0.f, 1.f); - CGContextFillRect(ctx, rect); - //Set context and paint pad's contents - //with special colors (color == object's identity) - pad->SetViewWH(rect.size.width, rect.size.height); - - pad->cd(); - - pad->SetContext(ctx); - pad->PaintForSelection(); - - UIImage *uiImageForPicking = UIGraphicsGetImageFromCurrentImageContext();//autoreleased UIImage. - CGImageRef cgImageForPicking = uiImageForPicking.CGImage; - CGImageRetain(cgImageForPicking);//It must live as long, as I need :) - - UIGraphicsEndImageContext(); - - return cgImageForPicking; - -} - -//____________________________________________________________________________________________________ -- (BOOL) fillPickingBufferFromCGImage : (CGImageRef) cgImage -{ - if (!isMutable) - return NO; - - const size_t pixelsW = CGImageGetWidth(cgImage); - const size_t pixelsH = CGImageGetHeight(cgImage); - //Declare the number of bytes per row. Each pixel in the bitmap - //is represented by 4 bytes; 8 bits each of red, green, blue, and - //alpha. - const int bitmapBytesPerRow = pixelsW * 4; - const int bitmapByteCount = bitmapBytesPerRow * pixelsH; - - //Use the generic RGB color space. - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - if (!colorSpace) { - //Log error: color space allocation failed. - return NO; - } - - unsigned char *buffer = (unsigned char*)malloc(bitmapByteCount); - if (!buffer) { - //Log error: memory allocation failed. - CGColorSpaceRelease(colorSpace); - return NO; - } - - // Create the bitmap context. We want pre-multiplied ARGB, 8-bits - // per component. Regardless of what the source image format is - // (CMYK, Grayscale, and so on) it will be converted over to the format - // specified here by CGBitmapContextCreate. - CGContextRef ctx = CGBitmapContextCreate(buffer, pixelsW, pixelsH, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedFirst); - - CGColorSpaceRelease(colorSpace); - - if (!ctx) { - //Log error: bitmap context creation failed. - free(buffer); - return NO; - } - - const CGRect rect = CGRectMake(0.f, 0.f, pixelsW, pixelsH); - //Draw the image to the bitmap context. Once we draw, the memory - //allocated for the context for rendering will then contain the - //raw image data in the specified color space. - - CGContextSetAllowsAntialiasing(ctx, 0);//Check, if I need this for a bitmap. - CGContextDrawImage(ctx, rect, cgImage); - - pad->SetSelectionBuffer(pixelsW, pixelsH, buffer); - // When finished, release the context - CGContextRelease(ctx); - free(buffer); - - return YES; -} - -//____________________________________________________________________________________________________ -- (BOOL) initPadPicking -{ - if (!isMutable) - return NO; - - CGImageRef cgImage = [self initCGImageForPicking]; - if (!cgImage) - return NO; - - const BOOL res = [self fillPickingBufferFromCGImage : cgImage]; - CGImageRelease(cgImage); - - return res; -} - -//____________________________________________________________________________________________________ -- (CGPoint) scaledPoint : (CGPoint)pt -{ - const CGFloat scale = ROOT::iOS::Browser::padW / self.frame.size.width; - return CGPointMake(pt.x * scale, pt.y * scale); -} - -//____________________________________________________________________________________________________ -- (BOOL) pointOnSelectedObject : (CGPoint) pt -{ - //check if there is any object in pt. - - if (!isMutable) - return NO; - - if (!pad->SelectionIsValid() && ![self initPadPicking]) - return NO; - - const CGPoint newPt = [self scaledPoint : pt]; - if (pad->GetSelected() == pad->ObjectInPoint(newPt.x, newPt.y)) - return YES; - - return NO; -} - -//____________________________________________________________________________________________________ -- (void) handleSingleTap -{ - //Make a selection, fill the editor, disable double tap. - - if (!isMutable) - return; - - const CGPoint scaledTapPt = [self scaledPoint : tapPt]; - if (!pad->SelectionIsValid() && ![self initPadPicking]) - return; - - pad->Pick(scaledTapPt.x, scaledTapPt.y); - //Tell controller that selection has probably changed. - [controller objectWasSelected : pad->GetSelected()]; - processSecondTap = NO; -} - -//____________________________________________________________________________________________________ -- (void) touchesBegan : (NSSet *)touches withEvent : (UIEvent *)event -{ - if (!isMutable) - return; - - UITouch *touch = [touches anyObject]; - if (touch.tapCount == 1) { - //Interaction has started. - tapPt = [touch locationInView : self]; - //Gesture can be any of them: - processSecondTap = YES; - } -} - -//____________________________________________________________________________________________________ -- (void) touchesMoved : (NSSet *)touches withEvent : (UIEvent *)event -{ - if (!isMutable) - return; - - if (panActive) { - processSecondTap = NO; - TObject *selected = pad->GetSelected(); - if (TAxis *axis = dynamic_cast(selected)) { - if (!selectionView.panActive) { - selectionView.panActive = YES; - if (!strcmp(axis->GetName(), "xaxis")) - selectionView.verticalPanDirection = NO; - else - selectionView.verticalPanDirection = YES; - selectionView.panStart = tapPt; - - pad->ExecuteEventAxis(kButton1Down, tapPt.x, tapPt.y, axis); - } else { - const CGPoint newPt = [[touches anyObject] locationInView : self]; - selectionView.currentPanPoint = newPt; - pad->ExecuteEventAxis(kButton1Motion, newPt.x, newPt.y, axis); - [selectionView setNeedsDisplay]; - } - } else { - //We move object in a canvas now. - } - } -} - -//____________________________________________________________________________________________________ -- (void) touchesEnded : (NSSet *)touches withEvent : (UIEvent *)event -{ - if (!isMutable) - return; - - UITouch *touch = [touches anyObject]; - if (touch.tapCount == 1 && !panActive) { - [self performSelector : @selector(handleSingleTap) withObject : nil afterDelay : tapInterval]; - } else if (touch.tapCount == 2 && processSecondTap) { - [NSObject cancelPreviousPerformRequestsWithTarget : self]; - [self handleDoubleTap]; - } - - if (selectionView.panActive) { - panActive = NO; - selectionView.panActive = NO; - const CGPoint pt = [touch locationInView : self]; - pad->ExecuteEventAxis(kButton1Up, pt.x, pt.y, (TAxis *)pad->GetSelected()); - pad->InvalidateSelection(kTRUE); - [self setNeedsDisplay]; - - UIScrollView *parent = (UIScrollView *)[self superview]; - parent.canCancelContentTouches = YES; - parent.delaysContentTouches = YES; - } -} - -//____________________________________________________________________________________________________ -- (void) handleDoubleTap -{ - //This is zoom/unzoom action or axis unzoom. - if (!isMutable) - return; - - const CGPoint scaledTapPt = [self scaledPoint : tapPt]; - TAxis *axis = dynamic_cast(pad->GetSelected()); - - if (!pad->SelectionIsValid() && ![self initPadPicking]) - return; - - if (axis && pad->ObjectInPoint(scaledTapPt.x, scaledTapPt.y) == axis) { - axis->UnZoom(); - pad->InvalidateSelection(kFALSE);//kTRUE); - [controller objectWasSelected : pad]; - [self setNeedsDisplay]; - } else { - [controller handleDoubleTapOnPad : tapPt]; - } - - UIScrollView *parent = (UIScrollView *)[self superview]; - parent.canCancelContentTouches = YES; - parent.delaysContentTouches = YES; -} - -@end diff --git a/test/ios/RootBrowser/PatternCell.h b/test/ios/RootBrowser/PatternCell.h deleted file mode 100644 index af290c71fd0c3..0000000000000 --- a/test/ios/RootBrowser/PatternCell.h +++ /dev/null @@ -1,8 +0,0 @@ -#import - -@interface PatternCell : UIView - -- (id) initWithFrame : (CGRect) frame andPattern : (unsigned) index; -- (void) setAsSolid; - -@end diff --git a/test/ios/RootBrowser/PatternCell.mm b/test/ios/RootBrowser/PatternCell.mm deleted file mode 100644 index 3d1a92cce692f..0000000000000 --- a/test/ios/RootBrowser/PatternCell.mm +++ /dev/null @@ -1,71 +0,0 @@ -#import -#import - -//C++ (ROOT) imports. -#import "IOSFillPatterns.h" - -#import "PatternCell.h" - -@implementation PatternCell { - unsigned patternIndex; - BOOL solid; -} - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame andPattern : (unsigned) index -{ - self = [super initWithFrame : frame]; - - if (self) { - patternIndex = index; - solid = NO; - - self.opaque = NO; - self.layer.shadowColor = [UIColor darkGrayColor].CGColor; - self.layer.shadowOpacity = 0.4f; - self.layer.shadowOffset = CGSizeMake(4.f, 4.f); - - //Shadows are quite expensive if path is not specified. - self.layer.shadowPath = [UIBezierPath bezierPathWithRect : CGRectMake(10.f, 10.f, frame.size.width - 20.f, frame.size.height - 20.f)].CGPath; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) setAsSolid -{ - solid = YES; -} - -//____________________________________________________________________________________________________ -- (void)drawRect:(CGRect)rect -{ - rect.origin.x = 10.f; - rect.origin.y = 10.f; - rect.size.width -= 20.f; - rect.size.height -= 20.f; - - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - //Fill view with pattern. - CGContextSetRGBFillColor(ctx, 1.f, 1.f, 1.f, 1.f); - CGContextFillRect(ctx, rect); - - if (!solid) { //Solid fill - no pattern. - float rgb[] = {0.f, 0.f, 0.f}; - CGPatternRef pattern = ROOT::iOS::GraphicUtils::gPatternGenerators[patternIndex](rgb); - - CGColorSpaceRef colorSpace = CGColorSpaceCreatePattern(0); - const float alpha = 1.f; - - CGContextSetFillColorSpace(ctx, colorSpace); - CGContextSetFillPattern(ctx, pattern, &alpha); - CGContextFillRect(ctx, rect); - - CGColorSpaceRelease(colorSpace); - CGPatternRelease(pattern); - } -} - -@end diff --git a/test/ios/RootBrowser/ROOTObjectController.h b/test/ios/RootBrowser/ROOTObjectController.h deleted file mode 100644 index 3ff55b323f25e..0000000000000 --- a/test/ios/RootBrowser/ROOTObjectController.h +++ /dev/null @@ -1,28 +0,0 @@ -#import -#import - -#import "FileUtils.h" - -@class ScrollViewWithPadView; - -class TObject; - -@interface ROOTObjectController : UIViewController { -@private - __weak IBOutlet ScrollViewWithPadView *padScrollView; - __weak IBOutlet UIScrollView *navigationScrollView; -} - -- (void) setNavigationForObjectWithIndex : (unsigned) index fromContainer : (ROOT::iOS::Browser::FileContainer *)fileContainer; -- (void) handleDoubleTapOnPad : (CGPoint)tapPt; -- (void) objectWasSelected : (TObject *)object; -- (void) objectWasModifiedUpdateSelection : (BOOL)needUpdate; -- (void) setupObjectInspector; - -- (ROOT::iOS::Browser::EHistogramErrorOption) getErrorOption; -- (void) setErrorOption : (ROOT::iOS::Browser::EHistogramErrorOption) errorOption; - -- (BOOL) markerIsOn; -- (void) setMarker : (BOOL)on; - -@end diff --git a/test/ios/RootBrowser/ROOTObjectController.mm b/test/ios/RootBrowser/ROOTObjectController.mm deleted file mode 100644 index 057225999456a..0000000000000 --- a/test/ios/RootBrowser/ROOTObjectController.mm +++ /dev/null @@ -1,805 +0,0 @@ -#import - -#import - -#import "ScrollViewWithPadView.h" -#import "ROOTObjectController.h" -#import "PadImageScrollView.h" -#import "TransparentToolbar.h" -#import "ObjectInspector.h" -#import "ObjectShortcut.h" -#import "SelectionView.h" -#import "EditorView.h" -#import "Constants.h" -#import "PadView.h" - -//C++ imports. -#import "TObject.h" -#import "TClass.h" -#import "IOSPad.h" - -#import "FileUtils.h" - -namespace { -//Ugly Obj-C, implementation block is not a scope, so either static or unnamed namespace :( - -//This constant is used to check, if pad was -//scaled to possible maximum or still can be zoomed in. -const CGFloat scaledToMaxEpsilon = 5.f; -const CGFloat maximumZoom = 2.f; - -enum Mode { - ocmNavigation, - ocmEdit -}; - -} - -@implementation ROOTObjectController { - Mode mode; - - __weak EditorView *editorView; - ObjectInspector *objectInspector; - - PadView *editablePadView; - - ROOT::iOS::Browser::FileContainer *fileContainer; - - TObject *selectedObject; - - BOOL zoomed; - - PadImageScrollView *navScrolls[3]; - - unsigned currentObject; - unsigned nextObject; - unsigned previousObject; - - UIBarButtonItem *editBtn; -} - - -#pragma mark - Special methods to manage drawing options. - -//____________________________________________________________________________________________________ -- (ROOT::iOS::Browser::EHistogramErrorOption) getErrorOption -{ - return fileContainer->GetErrorDrawOption(currentObject); -} - -//____________________________________________________________________________________________________ -- (void) setErrorOption : (ROOT::iOS::Browser::EHistogramErrorOption) errorOption -{ - fileContainer->SetErrorDrawOption(currentObject, errorOption); - //Ugly as hell :(( But ROOT holds draw options inside TObjLink in a pad. - fileContainer->GetPadAttached(currentObject)->cd(); - fileContainer->GetObject(currentObject)->SetDrawOption(fileContainer->GetDrawOption(currentObject)); -} - -//____________________________________________________________________________________________________ -- (BOOL) markerIsOn -{ - return fileContainer->GetMarkerDrawOption(currentObject); -} - -//____________________________________________________________________________________________________ -- (void) setMarker : (BOOL)on -{ - fileContainer->SetMarkerDrawOption(currentObject, bool(on)); - //Ugly as hell :(( But ROOT holds draw options inside TObjLink in a pad. - fileContainer->GetPadAttached(currentObject)->cd(); - fileContainer->GetObject(currentObject)->SetDrawOption(fileContainer->GetDrawOption(currentObject)); -} - -//____________________________________________________________________________________________________ -- (void) initToolbarItems -{ - UIToolbar *toolbar = [[TransparentToolbar alloc] initWithFrame : CGRectMake(0.f, 0.f, 180.f, 44.f)]; - toolbar.barStyle = UIBarStyleBlackTranslucent; - - - NSMutableArray *buttons = [[NSMutableArray alloc] initWithCapacity : 2]; - - UIBarButtonItem *saveBtn = [[UIBarButtonItem alloc] initWithTitle:@"Save and send" style : UIBarButtonItemStyleBordered target : self action : @selector(sendEmail)]; - [buttons addObject : saveBtn]; - - editBtn = [[UIBarButtonItem alloc] initWithTitle:@"Edit" style : UIBarButtonItemStyleBordered target:self action:@selector(toggleEditor)]; - [buttons addObject : editBtn]; - - [toolbar setItems : buttons animated : NO]; - - UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithCustomView : toolbar]; - rightItem.style = UIBarButtonItemStylePlain; - self.navigationItem.rightBarButtonItem = rightItem; -} - -//____________________________________________________________________________________________________ -- (void) viewDidLoad -{ - [self initToolbarItems]; - [super viewDidLoad]; -} - -//____________________________________________________________________________________________________ -- (void) resetEditorButton -{ - editBtn.style = mode == ocmEdit ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered; - editBtn.title = mode == ocmEdit ? @"Done" : @"Edit"; -} - -#pragma mark - Initialization code, called from initWithNibname - -//____________________________________________________________________________________________________ -- (void) loadObjectInspector -{ - objectInspector = [[ObjectInspector alloc] initWithNibName : nil bundle : nil]; - editorView = [objectInspector getEditorView]; - [self.view addSubview : editorView]; - editorView.hidden = YES; -} - -//____________________________________________________________________________________________________ -- (void) setupScrollForEditablePadView -{ - padScrollView.delegate = self; - [padScrollView setMaximumZoomScale : 2.]; - padScrollView.bounces = NO; - padScrollView.bouncesZoom = NO; - //By default, this view is hidden (mode != ocmEdit). - padScrollView.hidden = YES; -} - -//____________________________________________________________________________________________________ -- (void) setupNavigationScrollView -{ - navigationScrollView.delegate = self; - -// navigationScrollView.canCancelContentTouches = NO; -// navigationScrollView.delaysContentTouches = NO; - navigationScrollView.decelerationRate = UIScrollViewDecelerationRateFast; - navigationScrollView.bounces = NO; - navigationScrollView.bouncesZoom = NO; - navigationScrollView.pagingEnabled = YES; - navigationScrollView.showsVerticalScrollIndicator = NO; - navigationScrollView.showsHorizontalScrollIndicator = NO; - //By default, this view is visible (mode == ocmNavigation). - navigationScrollView.hidden = NO; -} - -//____________________________________________________________________________________________________ -- (void) createEditablePad -{ - using namespace ROOT::iOS::Browser; - - const CGPoint padCenter = CGPointMake(padScrollView.frame.size.width / 2, padScrollView.frame.size.height / 2); - const CGRect padRect = CGRectMake(padCenter.x - padW / 2, padCenter.y - padH / 2, padW, padH); - selectedObject = fileContainer->GetPadAttached(currentObject); - //Init the inspector for the IOSPad. - [self setupObjectInspector]; - - fileContainer->GetPadAttached(currentObject)->SetViewWH(padRect.size.width, padRect.size.height); - editablePadView = [[PadView alloc] initWithFrame : padRect controller : self forPad : fileContainer->GetPadAttached(currentObject)]; - [padScrollView addSubview : editablePadView]; -} - -#pragma mark - Geometry code. - -//____________________________________________________________________________________________________ -- (void) correctEditablePadFrame : (UIInterfaceOrientation) orientation -{ - //The most tricky part, since this code can be called - //for animation. - using namespace ROOT::iOS::Browser; - - CGRect padFrame = CGRectMake(0.f, 0.f, padW, padH); - - if (UIInterfaceOrientationIsPortrait(orientation)) { - padFrame.size.width = padWSmall; - padFrame.size.height = padHSmall; - - padFrame.origin.x = padXWithEditorP; - padFrame.origin.y = padYWithEditorP; - } else { - padFrame.origin.x = padXWithEditorL; - padFrame.origin.y = padYWithEditorL; - } - - editablePadView.frame = padFrame; - //pad sizes changed, to have correct picture, - //I have to redraw pad's contents. - //It seems to be fast even in case of animation, - //but may require changes in future. - [editablePadView setNeedsDisplay]; -} - -//_________________________________________________________________ -- (CGRect) centeredFrameForScrollView : (UIScrollView *)scroll andUIView : (UIView *)rView -{ - CGSize boundsSize = scroll.bounds.size; - CGRect frameToCenter = rView.frame; - // center horizontally - if (frameToCenter.size.width < boundsSize.width) { - frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2; - } - else { - frameToCenter.origin.x = 0; - } - // center vertically - if (frameToCenter.size.height < boundsSize.height) { - frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2; - } - else { - frameToCenter.origin.y = 0; - } - - return frameToCenter; -} - -//____________________________________________________________________________________________________ -- (void) correctEditablePadFrameForOrientation : (UIInterfaceOrientation) orientation -{ - if (!zoomed) { - [self correctEditablePadFrame : orientation]; - } else { - editablePadView.frame = [self centeredFrameForScrollView : padScrollView andUIView : editablePadView]; - } -} - -//____________________________________________________________________________________________________ -- (void) correctFramesForOrientation : (UIInterfaceOrientation) orientation -{ - using namespace ROOT::iOS::Browser; - - CGRect mainFrame; - CGRect scrollFrame; - - if (UIInterfaceOrientationIsPortrait(orientation)) { - mainFrame = CGRectMake(viewX, viewY, viewWP, viewHP); - scrollFrame = CGRectMake(scrollX, scrollY, scrollWP, scrollHP); - } else { - mainFrame = CGRectMake(viewX, viewY, viewWL, viewHL); - scrollFrame = CGRectMake(scrollX, scrollY, scrollWL, scrollHL); - } - - self.view.frame = mainFrame; - padScrollView.frame = scrollFrame; - navigationScrollView.frame = scrollFrame; - - scrollFrame.origin = CGPointZero; - for (unsigned i = 0; i < 3; ++i) { - scrollFrame.origin.x = i * scrollFrame.size.width; - [navScrolls[i] resetToFrame : scrollFrame]; - } - scrollFrame.origin = CGPointZero; - - if (fileContainer && fileContainer->GetNumberOfObjects() > 1) { - navigationScrollView.contentSize = CGSizeMake(3 * scrollFrame.size.width, scrollFrame.size.height); - [navigationScrollView scrollRectToVisible : navScrolls[1].frame animated : NO]; - } else { - navigationScrollView.contentSize = scrollFrame.size; - } - - const CGFloat editorAddY = 100.f; - const CGRect editorFrame = CGRectMake(mainFrame.size.width - [EditorView editorWidth], editorAddY, [EditorView editorWidth], mainFrame.size.height - 2 * editorAddY); - editorView.frame = editorFrame; - [editorView correctFrames]; - - if (editablePadView) - [self correctEditablePadFrameForOrientation : orientation]; -} - -#pragma mark - Controller's lifecycle. - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - - if (self) { - [self view];//force view loading. - - mode = ocmNavigation; - - [self loadObjectInspector]; - [self setupScrollForEditablePadView]; - [self setupNavigationScrollView]; - //[self createEditablePad]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)willAnimateRotationToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation duration : (NSTimeInterval) duration -{ - [self correctFramesForOrientation : interfaceOrientation]; -} - -//____________________________________________________________________________________________________ -- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation -{ - //Now, after rotation is finished we can show the shadow again. -} - -//____________________________________________________________________________________________________ -- (void) viewWillAppear : (BOOL)animated -{ - [self correctFramesForOrientation : self.interfaceOrientation]; -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void) animateEditor -{ - //Do animation. - // First create a CATransition object to describe the transition - CATransition *transition = [CATransition animation]; - // Animate over 3/4 of a second - transition.duration = 0.15; - // using the ease in/out timing function - transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; - // Now to set the type of transition. - transition.type = kCATransitionPush; - - if (!editorView.hidden) - transition.subtype = kCATransitionFromRight; - else - transition.subtype = kCATransitionFromLeft; - transition.delegate = self; - // Next add it to the containerView's layer. This will perform the transition based on how we change its contents. - [editorView.layer addAnimation : transition forKey : nil]; -} - -//____________________________________________________________________________________________________ -- (void) resetEditablePad -{ - //Reset the pad sizes, reset the scroll, hide the editor. - using namespace ROOT::iOS::Browser; - - zoomed = NO; - editablePadView.transform = CGAffineTransformIdentity; - editablePadView.frame = CGRectMake(0.f, 0.f, padW, padH); - - padScrollView.contentOffset = CGPointZero; - padScrollView.maximumZoomScale = maximumZoom; - padScrollView.minimumZoomScale = 1.f; -} - -//____________________________________________________________________________________________________ -- (void) resetSelectionView -{ - using namespace ROOT::iOS::Browser; - - editablePadView.selectionView.hidden = YES; - editablePadView.selectionView.transform = CGAffineTransformIdentity; - editablePadView.selectionView.frame = CGRectMake(0.f, 0.f, padW, padH); -} - -//____________________________________________________________________________________________________ -- (void) toggleEditor -{ - mode = mode == ocmEdit ? ocmNavigation : ocmEdit; - [self resetEditorButton]; - - if (mode == ocmEdit) { - [self resetEditablePad]; - [self resetSelectionView]; - - ROOT::iOS::Pad *pad = fileContainer->GetPadAttached(currentObject); - //pad->SetViewWH(editablePadView.frame.size.width, editablePadView.frame.size.height); - selectedObject = pad; - [editablePadView setPad : pad]; - [editablePadView setNeedsDisplay]; - - [self setupObjectInspector]; - - //Check this. - [objectInspector resetInspector]; - // - - editorView.hidden = NO; - navigationScrollView.hidden = YES; - padScrollView.hidden = NO; - } else { - ROOT::iOS::Pad *pad = fileContainer->GetPadAttached(currentObject); - pad->Unpick(); - selectedObject = pad; - - padScrollView.hidden = YES; - editorView.hidden = YES; - - if (fileContainer->GetNumberOfObjects() > 1) - [navScrolls[1] setPad : fileContainer->GetPadAttached(currentObject)]; - else - [navScrolls[0] setPad : fileContainer->GetPadAttached(currentObject)]; - - navigationScrollView.hidden = NO; - } - - [self correctFramesForOrientation : self.interfaceOrientation]; - [self animateEditor]; -} - -//____________________________________________________________________________________________________ -- (void) adjustPrevNextIndices -{ - nextObject = currentObject + 1 < fileContainer->GetNumberOfObjects() ? currentObject + 1 : 0; - previousObject = currentObject ? currentObject - 1 : fileContainer->GetNumberOfObjects() - 1; -} - -//____________________________________________________________________________________________________ -- (void) setNavigationForObjectWithIndex : (unsigned) index fromContainer : (ROOT::iOS::Browser::FileContainer *)container; -{ - //This method is called after initWithNibName was called, so it's the second step - //of controller's construction. The default mode is ocmNavigation, so setup navigation - //views/pad etc. - mode = ocmNavigation; - - - fileContainer = container; - self.navigationItem.title = [NSString stringWithFormat : @"%s", fileContainer->GetObject(index)->GetName()]; - - currentObject = index; - [self adjustPrevNextIndices]; - - CGRect scrollFrame = navigationScrollView.frame; - scrollFrame.origin = CGPointZero; - navScrolls[0] = [[PadImageScrollView alloc] initWithFrame : scrollFrame]; - if (fileContainer->GetNumberOfObjects() == 1) { - [navScrolls[0] setPad : fileContainer->GetPadAttached(currentObject)]; - } else { - [navScrolls[0] setPad : fileContainer->GetPadAttached(previousObject)]; - } - - [navigationScrollView addSubview : navScrolls[0]]; - - if (fileContainer->GetNumberOfObjects() > 1) { - //The [1] contains the current object. - scrollFrame.origin.x = scrollFrame.size.width; - navScrolls[1] = [[PadImageScrollView alloc] initWithFrame : scrollFrame]; - [navScrolls[1] setPad : fileContainer->GetPadAttached(currentObject)]; - [navigationScrollView addSubview : navScrolls[1]]; - - //The [2] contains the next object (can be the same as previous). - scrollFrame.origin.x = scrollFrame.size.width * 2; - navScrolls[2] = [[PadImageScrollView alloc] initWithFrame : scrollFrame]; - [navScrolls[2] setPad : fileContainer->GetPadAttached(nextObject)]; - [navigationScrollView addSubview : navScrolls[2]]; - - navigationScrollView.contentSize = CGSizeMake(scrollFrame.size.width * 3, scrollFrame.size.height); - //Visible rect is always middle scroll-view ([1]). - [navigationScrollView scrollRectToVisible : navScrolls[1].frame animated : NO]; - } else - navigationScrollView.contentSize = scrollFrame.size; - - [self createEditablePad]; -} - -#pragma mark - delegate for editable pad's scroll-view. - -//____________________________________________________________________________________________________ -- (UIView *)viewForZoomingInScrollView : (UIScrollView *)scrollView -{ - //For ocmEdit mode. - return editablePadView; -} - -//____________________________________________________________________________________________________ -- (void)scrollViewDidZoom:(UIScrollView *)scroll -{ - //For ocmEdit mode. - editablePadView.frame = [self centeredFrameForScrollView : scroll andUIView : editablePadView]; -} - -//____________________________________________________________________________________________________ -- (void)scrollViewDidEndZooming:(UIScrollView *)scroll withView:(UIView *)view atScale:(float)scale -{ - //For ocmEdit mode. - using namespace ROOT::iOS::Browser; - - const CGPoint offset = [scroll contentOffset]; - const CGRect newFrame = editablePadView.frame; - - [scroll setZoomScale : 1.f]; - scroll.contentSize = newFrame.size; - scroll.contentOffset = offset; - - scroll.minimumZoomScale = padW / newFrame.size.width; - scroll.maximumZoomScale = 2 * padW / newFrame.size.width; - - editablePadView.transform = CGAffineTransformIdentity; - - editablePadView.frame = newFrame; - editablePadView.selectionView.frame = CGRectMake(0.f, 0.f, newFrame.size.width, newFrame.size.height); - - //Most probably, this must be removed. - fileContainer->GetPadAttached(currentObject)->SetViewWH(newFrame.size.width, newFrame.size.height); - // - - [editablePadView setNeedsDisplay]; - - zoomed = YES; -} - -//____________________________________________________________________________________________________ -- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center { - - CGRect zoomRect; - - // the zoom rect is in the content view's coordinates. - // At a zoom scale of 1.0, it would be the size of the imageScrollView's bounds. - // As the zoom scale decreases, so more content is visible, the size of the rect grows. - zoomRect.size.height = [padScrollView frame].size.height / scale; - zoomRect.size.width = [padScrollView frame].size.width / scale; - - // choose an origin so as to get the right center. - zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0); - zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0); - - return zoomRect; -} - -//____________________________________________________________________________________________________ -- (void) handleDoubleTapOnPad : (CGPoint) tapPt -{ - //For ocmEdit mode. - using namespace ROOT::iOS::Browser; - - BOOL scaleToMax = YES; - - if (fabs(editablePadView.frame.size.width - padW * maximumZoom) < scaledToMaxEpsilon) - scaleToMax = NO; - - if (scaleToMax) { - //maximize - zoomed = YES; - const CGFloat newScale = padW * maximumZoom / editablePadView.frame.size.width; - CGRect zoomRect = [self zoomRectForScale : newScale withCenter : tapPt]; - [padScrollView zoomToRect : zoomRect animated : YES]; -// [self scrollViewDidEndZooming : scrollView withView : padView atScale : maximumZoom]; - } else { - zoomed = NO; - editablePadView.frame = CGRectMake(0.f, 0.f, padW, padH); - editablePadView.selectionView.frame = CGRectMake(0.f, 0.f, padW, padH); - // - fileContainer->GetPadAttached(currentObject)->SetViewWH(padW, padH); - // pad->SetViewWH(padW, padH); - // - padScrollView.maximumZoomScale = maximumZoom; - padScrollView.minimumZoomScale = 1.f; - padScrollView.contentOffset = CGPointZero; - padScrollView.contentSize = editablePadView.frame.size; - //[scrollView addSubview : padView]; - //[padView release]; - [editablePadView setNeedsDisplay]; - [self correctFramesForOrientation : self.interfaceOrientation]; - } -} - -#pragma mark - picking and editing. - -//____________________________________________________________________________________________________ -- (void) objectWasSelected : (TObject *)object -{ - if (object != selectedObject) {//New object was selected. - object ? selectedObject = object : (selectedObject = fileContainer->GetPadAttached(currentObject)); - [self setupObjectInspector]; - [objectInspector resetInspector]; - } - - if (object) { - editablePadView.selectionView.hidden = NO; - [editablePadView.selectionView setNeedsDisplay]; - } else - editablePadView.selectionView.hidden = YES; -} - -//____________________________________________________________________________________________________ -- (void) setupObjectInspector -{ - [objectInspector setROOTObject : selectedObject]; - [objectInspector setROOTObjectController : self]; -} - -//____________________________________________________________________________________________________ -- (void) objectWasModifiedUpdateSelection : (BOOL)needUpdate -{ - if (needUpdate) - fileContainer->GetPadAttached(currentObject)->InvalidateSelection(kTRUE);//invalidate selection buffer only. the selected object is the same. - - [editablePadView setNeedsDisplay]; -} - -#pragma mark - File contents navigation: scrolling through objects. - -//____________________________________________________________________________________________________ -- (void) scrollToLeft -{ - currentObject + 1 < fileContainer->GetNumberOfObjects() ? ++currentObject : currentObject = 0; - [self adjustPrevNextIndices]; - //Current is becoming prev, next is becoming current, load new into prev, which is becoming next. - PadImageScrollView *prevView = navScrolls[1]; - PadImageScrollView *currentView = navScrolls[2]; - PadImageScrollView *nextView = navScrolls[0]; - - CGRect prevFrame = prevView.frame; - prevFrame.origin = CGPointZero; - prevView.frame = prevFrame; - [prevView resetToFrame : prevView.frame]; - - CGRect currFrame = currentView.frame; - currFrame.origin.x = navigationScrollView.frame.size.width; - currentView.frame = currFrame; - - CGRect nextFrame = nextView.frame; - nextFrame.origin.x = 2 * navigationScrollView.frame.size.width; - nextView.frame = nextFrame; - [nextView setPad:fileContainer->GetPadAttached(nextObject)]; - - navScrolls[0] = prevView; - navScrolls[1] = currentView; - navScrolls[2] = nextView; - - [navigationScrollView scrollRectToVisible : navScrolls[1].frame animated : NO]; - - self.navigationItem.title = [NSString stringWithFormat : @"%s", fileContainer->GetObject(currentObject)->GetName()]; -} - -//____________________________________________________________________________________________________ -- (void) scrollToRight -{ - currentObject ? --currentObject : currentObject = fileContainer->GetNumberOfObjects() - 1; - [self adjustPrevNextIndices]; - //Current is becoming next, prev - current, prev must be loaded. - - PadImageScrollView *nextView = navScrolls[1]; - PadImageScrollView *currView = navScrolls[0]; - PadImageScrollView *prevView = navScrolls[2]; - - CGRect currFrame = currView.frame; - currFrame.origin.x = navigationScrollView.frame.size.width; - currView.frame = currFrame; - - CGRect nextFrame = nextView.frame; - nextFrame.origin.x = 2 * navigationScrollView.frame.size.width; - nextView.frame = nextFrame; - [nextView resetToFrame : nextFrame]; - - CGRect prevFrame = prevView.frame; - prevFrame.origin = CGPointZero; - prevView.frame = prevFrame; - [prevView setPad : fileContainer->GetPadAttached(previousObject)]; - - navScrolls[0] = prevView; - navScrolls[1] = currView; - navScrolls[2] = nextView; - - [navigationScrollView scrollRectToVisible : navScrolls[1].frame animated : NO]; - self.navigationItem.title = [NSString stringWithFormat : @"%s", fileContainer->GetObject(currentObject)->GetName()]; -} - -//____________________________________________________________________________________________________ -- (void) scrollViewDidEndDecelerating : (UIScrollView *) sender -{ - if (sender == navigationScrollView) { - if (sender.contentOffset.x > navigationScrollView.frame.size.width) - [self scrollToLeft]; - else if (sender.contentOffset.x < navigationScrollView.frame.size.width) - [self scrollToRight]; - } -} - -#pragma mark - Save modified object as pdf and root files. - -//___________________________________________________________ -- (void) createPDFFileWithPage :(CGRect)pageRect fileName : (const char*)filename -{ - CFStringRef path = CFStringCreateWithCString (NULL, filename, kCFStringEncodingUTF8); - CFURLRef url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, 0); - CFRelease(path); - // This dictionary contains extra options mostly for 'signing' the PDF - CFMutableDictionaryRef myDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("PDF File")); - CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("Timur Pocheptsov")); - // Create our PDF Context with the CFURL, the CGRect we provide, and the above defined dictionary - CGContextRef ctx = CGPDFContextCreateWithURL (url, &pageRect, myDictionary); - // Cleanup our mess - CFRelease(myDictionary); - CFRelease(url); - // Done creating our PDF Context, now it's time to draw to it - - // Starts our first page - CGContextBeginPage (ctx, &pageRect); - // Draws a black rectangle around the page inset by 50 on all sides - CGContextSetRGBFillColor(ctx, 1.f, 0.4f, 0.f, 1.f); - CGContextFillRect(ctx, pageRect); - - ROOT::iOS::Pad *padToSave = fileContainer->GetPadAttached(currentObject);//mode == ROOT_IOSObjectController::ocmEdit ? pad : navPad; - - padToSave->cd(); - padToSave->SetContext(ctx); - padToSave->SetViewWH(pageRect.size.width, pageRect.size.height); - padToSave->Paint(); - - CGContextEndPage(ctx); - // We are done with our context now, so we release it - CGContextRelease (ctx); -} - -#pragma mark - MFMailComposeViewController delegate - -//___________________________________________________________ -- (void) sendEmail -{ - if (![MFMailComposeViewController canSendMail]) { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle : @"Send e-mail:" - message : @"Please, add your e-mail account in device settings" - delegate : nil - cancelButtonTitle : @"Close" - otherButtonTitles : nil]; - [alert show]; - return; - } - - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *saveDirectory = [paths objectAtIndex : 0]; - NSString *saveFileName = [NSString stringWithFormat:@"%s.pdf", fileContainer->GetObject(currentObject)->GetName()]; - NSString *newFilePath = [saveDirectory stringByAppendingPathComponent : saveFileName]; - const char *filename = [newFilePath UTF8String]; - - [self createPDFFileWithPage: CGRectMake(0, 0, 600, 600) fileName : filename]; - -/* - NSString *rootFileName = [NSString stringWithFormat:@"%s.root", fileContainer->GetObject(currentObject)->GetName()]; - NSString *rootFilePath = [saveDirectory stringByAppendingPathComponent : rootFileName]; - const char *cFileName = [rootFilePath UTF8String]; - TFile f(cFileName, "recreate"); - f.cd(); - fileContainer->GetObject(currentObject)->Write(); -*/ - - MFMailComposeViewController * mailComposer = [[MFMailComposeViewController alloc] init]; - [mailComposer setSubject:@"E-mail from ROOT's iPad"]; - [mailComposer setMessageBody : @"This is a test message sent to you by ROOT browser for iPad" isHTML : NO]; - mailComposer.mailComposeDelegate = self; - - NSString *path = [NSString stringWithFormat : @"%s", filename]; - if ([[NSFileManager defaultManager] fileExistsAtPath : path]) { - NSData *myData = [NSData dataWithContentsOfFile : path]; - [mailComposer addAttachmentData : myData mimeType : @"application/octet-stream" fileName : saveFileName]; - } - - [self presentModalViewController : mailComposer animated : YES]; -} - -//___________________________________________________________ -- (void) mailComposeController : (MFMailComposeViewController *)controller didFinishWithResult : (MFMailComposeResult)result error : (NSError *)error -{ - [self becomeFirstResponder]; - [self dismissModalViewControllerAnimated : YES]; -} - -@end diff --git a/test/ios/RootBrowser/ROOTObjectController.xib b/test/ios/RootBrowser/ROOTObjectController.xib deleted file mode 100644 index b8c63a5534381..0000000000000 --- a/test/ios/RootBrowser/ROOTObjectController.xib +++ /dev/null @@ -1,271 +0,0 @@ - - - - 1056 - 11B26 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBProxyObject - IBUIView - IBUIScrollView - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 256 - - YES - - - 274 - {1024, 748} - - - _NS:189 - - 3 - MCAwAA - - YES - YES - IBIPadFramework - YES - NO - NO - NO - NO - - - - 274 - {{0, 31}, {1024, 687}} - - - - - YES - YES - IBIPadFramework - NO - - - {{0, 20}, {1024, 748}} - - - - - NO - 2 - - 2 - - - 3 - 3 - - IBIPadFramework - - - - - YES - - - view - - - - 11 - - - - navigationScrollView - - - - 14 - - - - padScrollView - - - - 15 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - YES - - - - - - - 8 - - - YES - - - - - 13 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 13.IBPluginDependency - 2.IBPluginDependency - 8.CustomClassName - 8.IBPluginDependency - - - YES - ROOTObjectController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - ScrollViewWithPadView - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 15 - - - - YES - - ROOTObjectController - UIViewController - - YES - - YES - navigationScrollView - padScrollView - - - YES - UIScrollView - ScrollViewWithPadView - - - - YES - - YES - navigationScrollView - padScrollView - - - YES - - navigationScrollView - UIScrollView - - - padScrollView - ScrollViewWithPadView - - - - - IBProjectSource - ./Classes/ROOTObjectController.h - - - - ScrollViewWithPadView - UIScrollView - - IBProjectSource - ./Classes/ScrollViewWithPadView.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 534 - - diff --git a/test/ios/RootBrowser/RangeSlider.h b/test/ios/RootBrowser/RangeSlider.h deleted file mode 100644 index 0c3ac79c1ea23..0000000000000 --- a/test/ios/RootBrowser/RangeSlider.h +++ /dev/null @@ -1,38 +0,0 @@ -//Very nice double range slider -//by Mal Curtis (http://buildmobile.com). -//Tpochep had to modify it to make it work: initWithFrame was -//wrong (coordinates for UIImageView's), -//added setSliderxxxx method. - -#import - -@interface RangeSlider : UIControl { -@private - float minimumValue; - float maximumValue; - float minimumRange; - float selectedMinimumValue; - float selectedMaximumValue; - - float padding; - - BOOL maxThumbOn; - BOOL minThumbOn; - - UIImageView *minThumb; - UIImageView *maxThumb; - UIImageView *track; -} - -@property(nonatomic) float minimumValue; -@property(nonatomic) float maximumValue; -@property(nonatomic) float minimumRange; -@property(nonatomic) float selectedMinimumValue; -@property(nonatomic) float selectedMaximumValue; - -- (void) setSliderMin : (float)min max : (float)max selectedMin : (float)sMin selectedMax : (float)sMax; - -- (CGFloat) getMinThumbX; -- (CGFloat) getMaxThumbX; - -@end diff --git a/test/ios/RootBrowser/RangeSlider.mm b/test/ios/RootBrowser/RangeSlider.mm deleted file mode 100644 index 155e9086becca..0000000000000 --- a/test/ios/RootBrowser/RangeSlider.mm +++ /dev/null @@ -1,152 +0,0 @@ -#import "RangeSlider.h" - -@interface RangeSlider (PrivateMethods) --(float) xForValue : (float)value; --(float) valueForX : (float)x; --(void)updateTrackHighlight; -@end - -@implementation RangeSlider - -@synthesize minimumValue, maximumValue, minimumRange, selectedMinimumValue, selectedMaximumValue; - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame -{ - self = [super initWithFrame : frame]; - - if (self) { - // Set the initial state - minimumValue = 0.f; - maximumValue = 1.f; - selectedMinimumValue = 0.f; - selectedMaximumValue = 1.f; - - minThumbOn = NO; - maxThumbOn = NO; - - minimumRange = 4.f;//FIXME - padding = 20; - - UIImageView *trackBackground = [[UIImageView alloc] initWithImage : [UIImage imageNamed : @"bar-background.png"]]; - trackBackground.frame = CGRectMake(0.f, self.frame.size.height / 2 - trackBackground.frame.size.height / 2, self.frame.size.width - padding * 2, trackBackground.frame.size.height); - trackBackground.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2); - [self addSubview : trackBackground]; - - track = [[UIImageView alloc] initWithImage : [UIImage imageNamed:@"bar-highlight.png"]]; - track.frame = CGRectMake(0.f, self.frame.size.height / 2 - track.frame.size.height / 2, self.frame.size.width - padding * 2, track.frame.size.height); - track.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2); - [self addSubview : track]; - - minThumb = [[UIImageView alloc] initWithImage : [UIImage imageNamed : @"handle.png"] highlightedImage : [UIImage imageNamed : @"handle-hover.png"]]; - minThumb.frame = CGRectMake(0.f, 0.f, self.frame.size.height,self.frame.size.height); - minThumb.contentMode = UIViewContentModeCenter; - minThumb.center = CGPointMake([self xForValue : selectedMinimumValue], self.frame.size.height / 2); - [self addSubview : minThumb]; - - maxThumb = [[UIImageView alloc] initWithImage : [UIImage imageNamed : @"handle.png"] highlightedImage : [UIImage imageNamed : @"handle-hover.png"]]; - maxThumb.frame = CGRectMake(0.f, 0.f, self.frame.size.height, self.frame.size.height); - maxThumb.contentMode = UIViewContentModeCenter; - maxThumb.center = CGPointMake([self xForValue : selectedMaximumValue], self.frame.size.height / 2); - [self addSubview : maxThumb]; - - [self updateTrackHighlight]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) setSliderMin : (float)min max : (float)max selectedMin : (float)sMin selectedMax : (float)sMax -{ - minimumValue = min; - maximumValue = max; - selectedMinimumValue = sMin; - selectedMaximumValue = sMax; - - minimumRange = 0.2 * (maximumValue - minimumValue); - - minThumb.center = CGPointMake([self xForValue : selectedMinimumValue], self.frame.size.height / 2); - maxThumb.center = CGPointMake([self xForValue : selectedMaximumValue], self.frame.size.height / 2); - - [self updateTrackHighlight]; -} - - -//____________________________________________________________________________________________________ -- (CGFloat) getMinThumbX -{ - return minThumb.center.x; -} - -//____________________________________________________________________________________________________ -- (CGFloat) getMaxThumbX -{ - return maxThumb.center.x; -} - -//____________________________________________________________________________________________________ --(float) xForValue : (float)value -{ - return (self.frame.size.width-(padding * 2))*((value - minimumValue) / (maximumValue - minimumValue)) + padding; -} - -//____________________________________________________________________________________________________ --(float) valueForX : (float)x -{ - return minimumValue + (x - padding) / (self.frame.size.width - (padding * 2)) * (maximumValue - minimumValue); -} - -//____________________________________________________________________________________________________ --(BOOL) continueTrackingWithTouch : (UITouch *)touch withEvent : (UIEvent *)event -{ - if(!minThumbOn && !maxThumbOn) - return NO; - - CGPoint touchPoint = [touch locationInView:self]; - if(minThumbOn) { - minThumb.center = CGPointMake(MAX([self xForValue : minimumValue], MIN(touchPoint.x, [self xForValue : selectedMaximumValue - minimumRange])), minThumb.center.y); - selectedMinimumValue = [self valueForX : minThumb.center.x]; - } - - if (maxThumbOn) { - maxThumb.center = CGPointMake(MIN([self xForValue : maximumValue], MAX(touchPoint.x, [self xForValue : selectedMinimumValue + minimumRange])), maxThumb.center.y); - selectedMaximumValue = [self valueForX : maxThumb.center.x]; - } - - [self updateTrackHighlight]; - [self setNeedsDisplay]; - - [self sendActionsForControlEvents : UIControlEventValueChanged]; - - return YES; -} - -//____________________________________________________________________________________________________ --(BOOL) beginTrackingWithTouch : (UITouch *)touch withEvent : (UIEvent *)event -{ - CGPoint touchPoint = [touch locationInView : self]; - if (CGRectContainsPoint(minThumb.frame, touchPoint)) { - minThumbOn = YES; - } else if (CGRectContainsPoint(maxThumb.frame, touchPoint)) { - maxThumbOn = YES; - } - - return YES; -} - -//____________________________________________________________________________________________________ --(void) endTrackingWithTouch : (UITouch *)touch withEvent : (UIEvent *)event -{ - minThumbOn = false; - maxThumbOn = false; -} - -//____________________________________________________________________________________________________ --(void) updateTrackHighlight -{ - track.frame = CGRectMake(minThumb.center.x, track.center.y - (track.frame.size.height / 2), - maxThumb.center.x - minThumb.center.x, track.frame.size.height); -} - -@end diff --git a/test/ios/RootBrowser/RootBrowser.xcodeproj/project.pbxproj b/test/ios/RootBrowser/RootBrowser.xcodeproj/project.pbxproj deleted file mode 100644 index 036719a0bf1f5..0000000000000 --- a/test/ios/RootBrowser/RootBrowser.xcodeproj/project.pbxproj +++ /dev/null @@ -1,971 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 70078C2D146AC4C400C19F4D /* FileUtils.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 70078C2C146AC4C400C19F4D /* FileUtils.cxx */; }; - 700ED6CB146BCDF200526D1C /* directory.png in Resources */ = {isa = PBXBuildFile; fileRef = 700ED6CA146BCDF100526D1C /* directory.png */; }; - 7014410F140E18390070459F /* SelectionView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7014410E140E18390070459F /* SelectionView.mm */; }; - 70144120140E3F1D0070459F /* LineStyleCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7014411F140E3F1D0070459F /* LineStyleCell.mm */; }; - 70144129140E553C0070459F /* line_cell.png in Resources */ = {isa = PBXBuildFile; fileRef = 70144128140E553C0070459F /* line_cell.png */; }; - 702357DB14345C0A00A95000 /* H1ErrorsInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 702357D914345C0A00A95000 /* H1ErrorsInspector.mm */; }; - 702357DC14345C0A00A95000 /* H1ErrorsInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 702357DA14345C0A00A95000 /* H1ErrorsInspector.xib */; }; - 702357E11434658900A95000 /* H1Inspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 702357DF1434658900A95000 /* H1Inspector.mm */; }; - 702357E21434658900A95000 /* H1Inspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 702357E01434658900A95000 /* H1Inspector.xib */; }; - 70235803143494F400A95000 /* MarkerInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70235801143494F400A95000 /* MarkerInspector.mm */; }; - 70235804143494F400A95000 /* MarkerInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 70235802143494F400A95000 /* MarkerInspector.xib */; }; - 702358081434A93C00A95000 /* H1BinsInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 702358061434A93B00A95000 /* H1BinsInspector.mm */; }; - 702358091434A93C00A95000 /* H1BinsInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 702358071434A93C00A95000 /* H1BinsInspector.xib */; }; - 7023580B1434ACC700A95000 /* h1_errors_tab.png in Resources */ = {isa = PBXBuildFile; fileRef = 7023580A1434ACC700A95000 /* h1_errors_tab.png */; }; - 7023580D1434B48C00A95000 /* h1_tab.png in Resources */ = {isa = PBXBuildFile; fileRef = 7023580C1434B48C00A95000 /* h1_tab.png */; }; - 7023805E140514C8002A5331 /* file_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 7023805D140514C8002A5331 /* file_icon.png */; }; - 70249BDC1403D644006A19E6 /* PadView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70249BDA1403D644006A19E6 /* PadView.mm */; }; - 70252F7C140CDD8D00F3660F /* Constants.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 70252F7A140CDD8D00F3660F /* Constants.cxx */; }; - 702BB9D714482E2200D3842F /* picker_arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = 702BB9D514482E2200D3842F /* picker_arrow.png */; }; - 702BB9D814482E2200D3842F /* picker_frame_bkn.png in Resources */ = {isa = PBXBuildFile; fileRef = 702BB9D614482E2200D3842F /* picker_frame_bkn.png */; }; - 702BB9DC14482E3C00D3842F /* HorizontalPickerView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 702BB9DA14482E3C00D3842F /* HorizontalPickerView.mm */; }; - 702BB9E01448559A00D3842F /* line_width_bkn.png in Resources */ = {isa = PBXBuildFile; fileRef = 702BB9DF1448559A00D3842F /* line_width_bkn.png */; }; - 702BB9E21448584E00D3842F /* dec_line_width.png in Resources */ = {isa = PBXBuildFile; fileRef = 702BB9E11448584E00D3842F /* dec_line_width.png */; }; - 702BB9E414485E4200D3842F /* inc_line_width.png in Resources */ = {isa = PBXBuildFile; fileRef = 702BB9E314485E4200D3842F /* inc_line_width.png */; }; - 702BB9E71448680200D3842F /* LineWidthPicker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 702BB9E61448680200D3842F /* LineWidthPicker.mm */; }; - 702DDD1B1415FEA1009FC6F3 /* LineInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 702DDD191415FEA1009FC6F3 /* LineInspector.mm */; }; - 702DDD1C1415FEA1009FC6F3 /* LineInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 702DDD1A1415FEA1009FC6F3 /* LineInspector.xib */; }; - 702DDD2914161789009FC6F3 /* InspectorWithNavigation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 702DDD2814161789009FC6F3 /* InspectorWithNavigation.mm */; }; - 70360B1A142C7AC6001F77E1 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70360B19142C7AC6001F77E1 /* MessageUI.framework */; }; - 7044980D1429D13D00E83799 /* PadImageScrollView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7044980C1429D13D00E83799 /* PadImageScrollView.mm */; }; - 7053E8B6143B076F001C364D /* MarkerStyleCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7053E8B5143B076F001C364D /* MarkerStyleCell.mm */; }; - 705A503614066421004C1C8B /* ScrollViewWithPadView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 705A503514066421004C1C8B /* ScrollViewWithPadView.mm */; }; - 706241D01435F86700202121 /* RangeSlider.mm in Sources */ = {isa = PBXBuildFile; fileRef = 706241CE1435F86700202121 /* RangeSlider.mm */; }; - 706241D51435F94500202121 /* bar-background.png in Resources */ = {isa = PBXBuildFile; fileRef = 706241D11435F94500202121 /* bar-background.png */; }; - 706241D61435F94500202121 /* bar-highlight.png in Resources */ = {isa = PBXBuildFile; fileRef = 706241D21435F94500202121 /* bar-highlight.png */; }; - 706241D71435F94500202121 /* handle-hover.png in Resources */ = {isa = PBXBuildFile; fileRef = 706241D31435F94500202121 /* handle-hover.png */; }; - 706241D81435F94500202121 /* handle.png in Resources */ = {isa = PBXBuildFile; fileRef = 706241D41435F94500202121 /* handle.png */; }; - 7066FB31143338AF00F88A2C /* brush_tab.png in Resources */ = {isa = PBXBuildFile; fileRef = 7066FB30143338AF00F88A2C /* brush_tab.png */; }; - 7066FB3414333E7300F88A2C /* line_style_tab.png in Resources */ = {isa = PBXBuildFile; fileRef = 7066FB3314333E7300F88A2C /* line_style_tab.png */; }; - 7066FB36143341A900F88A2C /* ticks_tab.png in Resources */ = {isa = PBXBuildFile; fileRef = 7066FB35143341A900F88A2C /* ticks_tab.png */; }; - 7066FB38143342C700F88A2C /* lg_tab.png in Resources */ = {isa = PBXBuildFile; fileRef = 7066FB37143342C700F88A2C /* lg_tab.png */; }; - 7066FB3A1433459200F88A2C /* title_tab.png in Resources */ = {isa = PBXBuildFile; fileRef = 7066FB391433459200F88A2C /* title_tab.png */; }; - 7066FB3C1433470F00F88A2C /* label_tab.png in Resources */ = {isa = PBXBuildFile; fileRef = 7066FB3B1433470F00F88A2C /* label_tab.png */; }; - 70681C0D1416365900F8338A /* PadInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70681C0B1416365900F8338A /* PadInspector.mm */; }; - 70681C0E1416365900F8338A /* PadInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 70681C0C1416365900F8338A /* PadInspector.xib */; }; - 70681C1314163A2300F8338A /* PadTicksGridInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 70681C1114163A2300F8338A /* PadTicksGridInspector.xib */; }; - 70681C1514163D3F00F8338A /* PadTicksGridInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70681C1414163D3F00F8338A /* PadTicksGridInspector.mm */; }; - 70681C1914163F0C00F8338A /* PadLogScaleInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70681C1714163F0C00F8338A /* PadLogScaleInspector.mm */; }; - 70681C1A14163F0C00F8338A /* PadLogScaleInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 70681C1814163F0C00F8338A /* PadLogScaleInspector.xib */; }; - 70681C1E1416474000F8338A /* FilledAreaInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70681C1C1416474000F8338A /* FilledAreaInspector.mm */; }; - 70681C1F1416474000F8338A /* FilledAreaInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 70681C1D1416474000F8338A /* FilledAreaInspector.xib */; }; - 70681C221416586D00F8338A /* ObjectInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70681C211416586D00F8338A /* ObjectInspector.mm */; }; - 7068963F1446F9FD00C2E3E7 /* picker_bkn.png in Resources */ = {isa = PBXBuildFile; fileRef = 7068963E1446F9FD00C2E3E7 /* picker_bkn.png */; }; - 7068FF1F1419FCBC003560A1 /* separator.png in Resources */ = {isa = PBXBuildFile; fileRef = 7068FF1E1419FCBC003560A1 /* separator.png */; }; - 7068FF24141A0EAF003560A1 /* AxisFontInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7068FF22141A0EAF003560A1 /* AxisFontInspector.mm */; }; - 7068FF25141A0EAF003560A1 /* AxisFontInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7068FF23141A0EAF003560A1 /* AxisFontInspector.xib */; }; - 7068FF2B141A2F6A003560A1 /* text_cell_bkn.png in Resources */ = {isa = PBXBuildFile; fileRef = 7068FF2A141A2F6A003560A1 /* text_cell_bkn.png */; }; - 7068FF31141A3944003560A1 /* AxisLabelsInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7068FF2F141A3943003560A1 /* AxisLabelsInspector.mm */; }; - 7068FF32141A3944003560A1 /* AxisLabelsInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7068FF30141A3944003560A1 /* AxisLabelsInspector.xib */; }; - 7073A275141757BC001A0FE2 /* AxisTicksInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7073A273141757BB001A0FE2 /* AxisTicksInspector.mm */; }; - 7073A276141757BC001A0FE2 /* AxisTicksInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7073A274141757BB001A0FE2 /* AxisTicksInspector.xib */; }; - 7073A27E14177A03001A0FE2 /* AxisInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7073A27C14177A03001A0FE2 /* AxisInspector.mm */; }; - 7073A27F14177A03001A0FE2 /* AxisInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7073A27D14177A03001A0FE2 /* AxisInspector.xib */; }; - 7073A28214179A6D001A0FE2 /* minus_btn.png in Resources */ = {isa = PBXBuildFile; fileRef = 7073A28014179A6C001A0FE2 /* minus_btn.png */; }; - 7073A28314179A6D001A0FE2 /* plus_btn.png in Resources */ = {isa = PBXBuildFile; fileRef = 7073A28114179A6D001A0FE2 /* plus_btn.png */; }; - 7073A2871417AA10001A0FE2 /* AxisTitleInspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7073A2851417AA0F001A0FE2 /* AxisTitleInspector.mm */; }; - 7073A2881417AA10001A0FE2 /* AxisTitleInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7073A2861417AA10001A0FE2 /* AxisTitleInspector.xib */; }; - 7073A9AE14277D1B006F6D67 /* Default-Portrait.png in Resources */ = {isa = PBXBuildFile; fileRef = 7073A9A914277D16006F6D67 /* Default-Portrait.png */; }; - 7073A9AF14277D1B006F6D67 /* Default-PortraitUpsideDown.png in Resources */ = {isa = PBXBuildFile; fileRef = 7073A9AA14277D17006F6D67 /* Default-PortraitUpsideDown.png */; }; - 7073A9B014277D1B006F6D67 /* Default-Landscape.png in Resources */ = {isa = PBXBuildFile; fileRef = 7073A9AB14277D18006F6D67 /* Default-Landscape.png */; }; - 7073A9B114277D1B006F6D67 /* Default-LandscapeLeft.png in Resources */ = {isa = PBXBuildFile; fileRef = 7073A9AC14277D19006F6D67 /* Default-LandscapeLeft.png */; }; - 7073A9B214277D1B006F6D67 /* Default-LandscapeRight.png in Resources */ = {isa = PBXBuildFile; fileRef = 7073A9AD14277D1A006F6D67 /* Default-LandscapeRight.png */; }; - 7077853214139EBF00450A1B /* editor_plate.png in Resources */ = {isa = PBXBuildFile; fileRef = 7077853114139EBF00450A1B /* editor_plate.png */; }; - 7077901E13FE50EB00C0FFA1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7077901D13FE50EB00C0FFA1 /* UIKit.framework */; }; - 7077902013FE50EB00C0FFA1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7077901F13FE50EB00C0FFA1 /* Foundation.framework */; }; - 7077902213FE50EB00C0FFA1 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7077902113FE50EB00C0FFA1 /* CoreGraphics.framework */; }; - 7077902813FE50EB00C0FFA1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7077902613FE50EB00C0FFA1 /* InfoPlist.strings */; }; - 7077902B13FE50EB00C0FFA1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7077902A13FE50EB00C0FFA1 /* main.m */; }; - 7077902E13FE50EB00C0FFA1 /* root_browserAppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077902D13FE50EB00C0FFA1 /* root_browserAppDelegate.mm */; }; - 7077903113FE50EB00C0FFA1 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7077902F13FE50EB00C0FFA1 /* MainWindow.xib */; }; - 7077903A13FE51B400C0FFA1 /* RootFileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077903813FE51B400C0FFA1 /* RootFileController.mm */; }; - 7077903B13FE51B400C0FFA1 /* RootFileController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7077903913FE51B400C0FFA1 /* RootFileController.xib */; }; - 7077903F13FE549300C0FFA1 /* FileContentController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077903D13FE549300C0FFA1 /* FileContentController.mm */; }; - 7077904013FE549300C0FFA1 /* FileContentController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7077903E13FE549300C0FFA1 /* FileContentController.xib */; }; - 7077904313FE554E00C0FFA1 /* FileShortcut.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077904213FE554E00C0FFA1 /* FileShortcut.mm */; }; - 7077905113FE6B8F00C0FFA1 /* file_shortcut_background.png in Resources */ = {isa = PBXBuildFile; fileRef = 7077905013FE6B8F00C0FFA1 /* file_shortcut_background.png */; }; - 7077905D13FE840000C0FFA1 /* SlideshowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077905B13FE840000C0FFA1 /* SlideshowController.mm */; }; - 7077905E13FE840000C0FFA1 /* SlideshowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7077905C13FE840000C0FFA1 /* SlideshowController.xib */; }; - 7077906213FE847600C0FFA1 /* ROOTObjectController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077906013FE847600C0FFA1 /* ROOTObjectController.mm */; }; - 7077906313FE847600C0FFA1 /* ROOTObjectController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7077906113FE847600C0FFA1 /* ROOTObjectController.xib */; }; - 7077906613FE87D000C0FFA1 /* ObjectShortcut.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077906513FE87D000C0FFA1 /* ObjectShortcut.mm */; }; - 7077907E13FE96C300C0FFA1 /* EditorView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077906B13FE96C200C0FFA1 /* EditorView.mm */; }; - 7077908013FE96C300C0FFA1 /* ScrollViewWithPickers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077906E13FE96C200C0FFA1 /* ScrollViewWithPickers.mm */; }; - 7077908113FE96C300C0FFA1 /* EditorPlateView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077906F13FE96C200C0FFA1 /* EditorPlateView.mm */; }; - 7077908713FE96C300C0FFA1 /* PatternCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077907913FE96C300C0FFA1 /* PatternCell.mm */; }; - 7077908813FE96C300C0FFA1 /* ColorCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7077907B13FE96C300C0FFA1 /* ColorCell.mm */; }; - 7077908B13FE96DC00C0FFA1 /* editor_state_arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = 7077908913FE96DC00C0FFA1 /* editor_state_arrow.png */; }; - 7077908E13FE972D00C0FFA1 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7077908D13FE972D00C0FFA1 /* QuartzCore.framework */; }; - 7077909013FE973A00C0FFA1 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7077908F13FE973A00C0FFA1 /* CoreText.framework */; }; - 7095949C13FE978400B9E8B6 /* libRoot.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7095949813FE978400B9E8B6 /* libRoot.a */; }; - 7095949D13FE978400B9E8B6 /* libfreetype.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7095949913FE978400B9E8B6 /* libfreetype.a */; }; - 7095949E13FE978400B9E8B6 /* liblzma.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7095949A13FE978400B9E8B6 /* liblzma.a */; }; - 7095949F13FE978400B9E8B6 /* libpcre.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7095949B13FE978400B9E8B6 /* libpcre.a */; }; - 709594A213FE978C00B9E8B6 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 709594A113FE978C00B9E8B6 /* libz.dylib */; }; - 709594A513FE97AF00B9E8B6 /* system.rootrc in Resources */ = {isa = PBXBuildFile; fileRef = 709594A313FE97AF00B9E8B6 /* system.rootrc */; }; - 709594A613FE97AF00B9E8B6 /* system.plugins-ios in Resources */ = {isa = PBXBuildFile; fileRef = 709594A413FE97AF00B9E8B6 /* system.plugins-ios */; }; - 70989EFD1473E73200515FC5 /* SpotView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70989EFC1473E73200515FC5 /* SpotView.mm */; }; - 709CD05314025148005B2AF4 /* demos.root in Resources */ = {isa = PBXBuildFile; fileRef = 709CD05214025148005B2AF4 /* demos.root */; }; - 709CD0981402768B005B2AF4 /* Shortcuts.mm in Sources */ = {isa = PBXBuildFile; fileRef = 709CD0971402768B005B2AF4 /* Shortcuts.mm */; }; - 70AC541E146966E7009A0942 /* ThumbnailView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70AC541C146966E7009A0942 /* ThumbnailView.mm */; }; - 70C1D67B1468162600514DC0 /* LineWidthCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70C1D67A1468162600514DC0 /* LineWidthCell.mm */; }; - 70C1D67D1468166100514DC0 /* SlideView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70C1D67C1468166100514DC0 /* SlideView.mm */; }; - 70E0B62114150F630077E4A8 /* back_btn.png in Resources */ = {isa = PBXBuildFile; fileRef = 70E0B62014150F630077E4A8 /* back_btn.png */; }; - 70E0B624141510880077E4A8 /* forward_btn.png in Resources */ = {isa = PBXBuildFile; fileRef = 70E0B623141510880077E4A8 /* forward_btn.png */; }; - 70E16B091455CBC00050C281 /* app_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 70E16B081455CBC00050C281 /* app_icon.png */; }; - 70E36B571472965E004AEB6A /* FileContainerElement.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70E36B561472965E004AEB6A /* FileContainerElement.mm */; }; - 70E4FE5214715ABD00296BFF /* TransparentToolbar.m in Sources */ = {isa = PBXBuildFile; fileRef = 70E4FE5114715ABD00296BFF /* TransparentToolbar.m */; }; - 70E4FE5B1471685700296BFF /* SearchController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70E4FE5A1471685700296BFF /* SearchController.mm */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 70078C2B146AC4C400C19F4D /* FileUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileUtils.h; sourceTree = ""; }; - 70078C2C146AC4C400C19F4D /* FileUtils.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileUtils.cxx; sourceTree = ""; }; - 700ED6CA146BCDF100526D1C /* directory.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = directory.png; sourceTree = ""; }; - 7014410D140E18390070459F /* SelectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionView.h; sourceTree = ""; }; - 7014410E140E18390070459F /* SelectionView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SelectionView.mm; sourceTree = ""; }; - 7014411E140E3F1D0070459F /* LineStyleCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineStyleCell.h; sourceTree = ""; }; - 7014411F140E3F1D0070459F /* LineStyleCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LineStyleCell.mm; sourceTree = ""; }; - 70144121140E3F320070459F /* LineWidthCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineWidthCell.h; sourceTree = ""; }; - 70144128140E553C0070459F /* line_cell.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = line_cell.png; sourceTree = ""; }; - 702357D814345C0A00A95000 /* H1ErrorsInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = H1ErrorsInspector.h; sourceTree = ""; }; - 702357D914345C0A00A95000 /* H1ErrorsInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = H1ErrorsInspector.mm; sourceTree = ""; }; - 702357DA14345C0A00A95000 /* H1ErrorsInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = H1ErrorsInspector.xib; sourceTree = ""; }; - 702357DE1434658900A95000 /* H1Inspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = H1Inspector.h; sourceTree = ""; }; - 702357DF1434658900A95000 /* H1Inspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = H1Inspector.mm; sourceTree = ""; }; - 702357E01434658900A95000 /* H1Inspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = H1Inspector.xib; sourceTree = ""; }; - 70235800143494F400A95000 /* MarkerInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkerInspector.h; sourceTree = ""; }; - 70235801143494F400A95000 /* MarkerInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MarkerInspector.mm; sourceTree = ""; }; - 70235802143494F400A95000 /* MarkerInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MarkerInspector.xib; sourceTree = ""; }; - 702358051434A93B00A95000 /* H1BinsInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = H1BinsInspector.h; sourceTree = ""; }; - 702358061434A93B00A95000 /* H1BinsInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = H1BinsInspector.mm; sourceTree = ""; }; - 702358071434A93C00A95000 /* H1BinsInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = H1BinsInspector.xib; sourceTree = ""; }; - 7023580A1434ACC700A95000 /* h1_errors_tab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = h1_errors_tab.png; sourceTree = ""; }; - 7023580C1434B48C00A95000 /* h1_tab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = h1_tab.png; sourceTree = ""; }; - 7023805D140514C8002A5331 /* file_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_icon.png; sourceTree = ""; }; - 70249BDA1403D644006A19E6 /* PadView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PadView.mm; sourceTree = ""; }; - 70252F7A140CDD8D00F3660F /* Constants.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Constants.cxx; sourceTree = ""; }; - 70252F7B140CDD8D00F3660F /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = ""; }; - 702BB9D514482E2200D3842F /* picker_arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = picker_arrow.png; sourceTree = ""; }; - 702BB9D614482E2200D3842F /* picker_frame_bkn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = picker_frame_bkn.png; sourceTree = ""; }; - 702BB9DA14482E3C00D3842F /* HorizontalPickerView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HorizontalPickerView.mm; sourceTree = ""; }; - 702BB9DB14482E3C00D3842F /* HorizontalPickerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HorizontalPickerView.h; sourceTree = ""; }; - 702BB9DF1448559A00D3842F /* line_width_bkn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = line_width_bkn.png; sourceTree = ""; }; - 702BB9E11448584E00D3842F /* dec_line_width.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dec_line_width.png; sourceTree = ""; }; - 702BB9E314485E4200D3842F /* inc_line_width.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = inc_line_width.png; sourceTree = ""; }; - 702BB9E51448680100D3842F /* LineWidthPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineWidthPicker.h; sourceTree = ""; }; - 702BB9E61448680200D3842F /* LineWidthPicker.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LineWidthPicker.mm; sourceTree = ""; }; - 702DDD161415FDDB009FC6F3 /* ObjectInspectorComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectInspectorComponent.h; sourceTree = ""; }; - 702DDD181415FEA1009FC6F3 /* LineInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineInspector.h; sourceTree = ""; }; - 702DDD191415FEA1009FC6F3 /* LineInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LineInspector.mm; sourceTree = ""; }; - 702DDD1A1415FEA1009FC6F3 /* LineInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LineInspector.xib; sourceTree = ""; }; - 702DDD2714161789009FC6F3 /* InspectorWithNavigation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorWithNavigation.h; sourceTree = ""; }; - 702DDD2814161789009FC6F3 /* InspectorWithNavigation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorWithNavigation.mm; sourceTree = ""; }; - 70360B19142C7AC6001F77E1 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; - 7044980B1429D13D00E83799 /* PadImageScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PadImageScrollView.h; sourceTree = ""; }; - 7044980C1429D13D00E83799 /* PadImageScrollView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PadImageScrollView.mm; sourceTree = ""; }; - 704B5A211520CC8D00FEF9C8 /* PadView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PadView.h; sourceTree = ""; }; - 7053E8B4143B076F001C364D /* MarkerStyleCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkerStyleCell.h; sourceTree = ""; }; - 7053E8B5143B076F001C364D /* MarkerStyleCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MarkerStyleCell.mm; sourceTree = ""; }; - 705A503414066421004C1C8B /* ScrollViewWithPadView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollViewWithPadView.h; sourceTree = ""; }; - 705A503514066421004C1C8B /* ScrollViewWithPadView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollViewWithPadView.mm; sourceTree = ""; }; - 705F1A66142347CA003045D9 /* SlideView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlideView.h; sourceTree = ""; }; - 706241CE1435F86700202121 /* RangeSlider.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RangeSlider.mm; sourceTree = ""; }; - 706241CF1435F86700202121 /* RangeSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RangeSlider.h; sourceTree = ""; }; - 706241D11435F94500202121 /* bar-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bar-background.png"; sourceTree = ""; }; - 706241D21435F94500202121 /* bar-highlight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bar-highlight.png"; sourceTree = ""; }; - 706241D31435F94500202121 /* handle-hover.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "handle-hover.png"; sourceTree = ""; }; - 706241D41435F94500202121 /* handle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = handle.png; sourceTree = ""; }; - 7066FB30143338AF00F88A2C /* brush_tab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = brush_tab.png; sourceTree = ""; }; - 7066FB3314333E7300F88A2C /* line_style_tab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = line_style_tab.png; sourceTree = ""; }; - 7066FB35143341A900F88A2C /* ticks_tab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ticks_tab.png; sourceTree = ""; }; - 7066FB37143342C700F88A2C /* lg_tab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = lg_tab.png; sourceTree = ""; }; - 7066FB391433459200F88A2C /* title_tab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = title_tab.png; sourceTree = ""; }; - 7066FB3B1433470F00F88A2C /* label_tab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = label_tab.png; sourceTree = ""; }; - 70681C0A1416365900F8338A /* PadInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PadInspector.h; sourceTree = ""; }; - 70681C0B1416365900F8338A /* PadInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PadInspector.mm; sourceTree = ""; }; - 70681C0C1416365900F8338A /* PadInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PadInspector.xib; sourceTree = ""; }; - 70681C0F14163A2300F8338A /* PadTicksGridInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PadTicksGridInspector.h; sourceTree = ""; }; - 70681C1114163A2300F8338A /* PadTicksGridInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PadTicksGridInspector.xib; sourceTree = ""; }; - 70681C1414163D3F00F8338A /* PadTicksGridInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PadTicksGridInspector.mm; sourceTree = ""; }; - 70681C1614163F0C00F8338A /* PadLogScaleInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PadLogScaleInspector.h; sourceTree = ""; }; - 70681C1714163F0C00F8338A /* PadLogScaleInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PadLogScaleInspector.mm; sourceTree = ""; }; - 70681C1814163F0C00F8338A /* PadLogScaleInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PadLogScaleInspector.xib; sourceTree = ""; }; - 70681C1B1416474000F8338A /* FilledAreaInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FilledAreaInspector.h; sourceTree = ""; }; - 70681C1C1416474000F8338A /* FilledAreaInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FilledAreaInspector.mm; sourceTree = ""; }; - 70681C1D1416474000F8338A /* FilledAreaInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FilledAreaInspector.xib; sourceTree = ""; }; - 70681C201416586D00F8338A /* ObjectInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectInspector.h; sourceTree = ""; }; - 70681C211416586D00F8338A /* ObjectInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ObjectInspector.mm; sourceTree = ""; }; - 7068963E1446F9FD00C2E3E7 /* picker_bkn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = picker_bkn.png; sourceTree = ""; }; - 7068FF1E1419FCBC003560A1 /* separator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = separator.png; sourceTree = ""; }; - 7068FF21141A0EAF003560A1 /* AxisFontInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AxisFontInspector.h; sourceTree = ""; }; - 7068FF22141A0EAF003560A1 /* AxisFontInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AxisFontInspector.mm; sourceTree = ""; }; - 7068FF23141A0EAF003560A1 /* AxisFontInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AxisFontInspector.xib; sourceTree = ""; }; - 7068FF2A141A2F6A003560A1 /* text_cell_bkn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = text_cell_bkn.png; sourceTree = ""; }; - 7068FF2E141A3943003560A1 /* AxisLabelsInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AxisLabelsInspector.h; sourceTree = ""; }; - 7068FF2F141A3943003560A1 /* AxisLabelsInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AxisLabelsInspector.mm; sourceTree = ""; }; - 7068FF30141A3944003560A1 /* AxisLabelsInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AxisLabelsInspector.xib; sourceTree = ""; }; - 7073A272141757BB001A0FE2 /* AxisTicksInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AxisTicksInspector.h; sourceTree = ""; }; - 7073A273141757BB001A0FE2 /* AxisTicksInspector.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = AxisTicksInspector.mm; sourceTree = ""; }; - 7073A274141757BB001A0FE2 /* AxisTicksInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AxisTicksInspector.xib; sourceTree = ""; }; - 7073A27B14177A03001A0FE2 /* AxisInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AxisInspector.h; sourceTree = ""; }; - 7073A27C14177A03001A0FE2 /* AxisInspector.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = AxisInspector.mm; sourceTree = ""; }; - 7073A27D14177A03001A0FE2 /* AxisInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AxisInspector.xib; sourceTree = ""; }; - 7073A28014179A6C001A0FE2 /* minus_btn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = minus_btn.png; sourceTree = ""; }; - 7073A28114179A6D001A0FE2 /* plus_btn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = plus_btn.png; sourceTree = ""; }; - 7073A2841417AA0F001A0FE2 /* AxisTitleInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AxisTitleInspector.h; sourceTree = ""; }; - 7073A2851417AA0F001A0FE2 /* AxisTitleInspector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AxisTitleInspector.mm; sourceTree = ""; }; - 7073A2861417AA10001A0FE2 /* AxisTitleInspector.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AxisTitleInspector.xib; sourceTree = ""; }; - 7073A9A914277D16006F6D67 /* Default-Portrait.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait.png"; sourceTree = ""; }; - 7073A9AA14277D17006F6D67 /* Default-PortraitUpsideDown.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-PortraitUpsideDown.png"; sourceTree = ""; }; - 7073A9AB14277D18006F6D67 /* Default-Landscape.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape.png"; sourceTree = ""; }; - 7073A9AC14277D19006F6D67 /* Default-LandscapeLeft.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-LandscapeLeft.png"; sourceTree = ""; }; - 7073A9AD14277D1A006F6D67 /* Default-LandscapeRight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-LandscapeRight.png"; sourceTree = ""; }; - 7077853114139EBF00450A1B /* editor_plate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = editor_plate.png; sourceTree = ""; }; - 7077901913FE50EB00C0FFA1 /* RootBrowser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RootBrowser.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7077901D13FE50EB00C0FFA1 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 7077901F13FE50EB00C0FFA1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 7077902113FE50EB00C0FFA1 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 7077902513FE50EB00C0FFA1 /* root_browser-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "root_browser-Info.plist"; sourceTree = ""; }; - 7077902713FE50EB00C0FFA1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 7077902913FE50EB00C0FFA1 /* RootBrowser-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RootBrowser-Prefix.pch"; sourceTree = ""; }; - 7077902A13FE50EB00C0FFA1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 7077902C13FE50EB00C0FFA1 /* root_browserAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = root_browserAppDelegate.h; sourceTree = ""; }; - 7077902D13FE50EB00C0FFA1 /* root_browserAppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = root_browserAppDelegate.mm; sourceTree = ""; }; - 7077903013FE50EB00C0FFA1 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = ""; }; - 7077903713FE51B400C0FFA1 /* RootFileController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootFileController.h; sourceTree = ""; }; - 7077903813FE51B400C0FFA1 /* RootFileController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RootFileController.mm; sourceTree = ""; }; - 7077903913FE51B400C0FFA1 /* RootFileController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RootFileController.xib; sourceTree = ""; }; - 7077903C13FE549300C0FFA1 /* FileContentController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileContentController.h; sourceTree = ""; }; - 7077903D13FE549300C0FFA1 /* FileContentController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FileContentController.mm; sourceTree = ""; }; - 7077903E13FE549300C0FFA1 /* FileContentController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FileContentController.xib; sourceTree = ""; }; - 7077904113FE554E00C0FFA1 /* FileShortcut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileShortcut.h; sourceTree = ""; }; - 7077904213FE554E00C0FFA1 /* FileShortcut.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FileShortcut.mm; sourceTree = ""; }; - 7077905013FE6B8F00C0FFA1 /* file_shortcut_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_shortcut_background.png; sourceTree = ""; }; - 7077905A13FE840000C0FFA1 /* SlideshowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlideshowController.h; sourceTree = ""; }; - 7077905B13FE840000C0FFA1 /* SlideshowController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SlideshowController.mm; sourceTree = ""; }; - 7077905C13FE840000C0FFA1 /* SlideshowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SlideshowController.xib; sourceTree = ""; }; - 7077905F13FE847600C0FFA1 /* ROOTObjectController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ROOTObjectController.h; sourceTree = ""; }; - 7077906013FE847600C0FFA1 /* ROOTObjectController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ROOTObjectController.mm; sourceTree = ""; }; - 7077906113FE847600C0FFA1 /* ROOTObjectController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ROOTObjectController.xib; sourceTree = ""; }; - 7077906413FE87D000C0FFA1 /* ObjectShortcut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectShortcut.h; sourceTree = ""; }; - 7077906513FE87D000C0FFA1 /* ObjectShortcut.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ObjectShortcut.mm; sourceTree = ""; }; - 7077906B13FE96C200C0FFA1 /* EditorView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EditorView.mm; sourceTree = ""; }; - 7077906C13FE96C200C0FFA1 /* EditorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditorView.h; sourceTree = ""; }; - 7077906E13FE96C200C0FFA1 /* ScrollViewWithPickers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollViewWithPickers.mm; sourceTree = ""; }; - 7077906F13FE96C200C0FFA1 /* EditorPlateView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EditorPlateView.mm; sourceTree = ""; }; - 7077907013FE96C200C0FFA1 /* ScrollViewWithPickers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollViewWithPickers.h; sourceTree = ""; }; - 7077907713FE96C200C0FFA1 /* EditorPlateView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditorPlateView.h; sourceTree = ""; }; - 7077907913FE96C300C0FFA1 /* PatternCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PatternCell.mm; sourceTree = ""; }; - 7077907A13FE96C300C0FFA1 /* PatternCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PatternCell.h; sourceTree = ""; }; - 7077907B13FE96C300C0FFA1 /* ColorCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ColorCell.mm; sourceTree = ""; }; - 7077907C13FE96C300C0FFA1 /* ColorCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColorCell.h; sourceTree = ""; }; - 7077908913FE96DC00C0FFA1 /* editor_state_arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = editor_state_arrow.png; sourceTree = ""; }; - 7077908D13FE972D00C0FFA1 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - 7077908F13FE973A00C0FFA1 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; - 7095949813FE978400B9E8B6 /* libRoot.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libRoot.a; path = ../../../lib/libRoot.a; sourceTree = ""; }; - 7095949913FE978400B9E8B6 /* libfreetype.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfreetype.a; path = ../../../lib/libfreetype.a; sourceTree = ""; }; - 7095949A13FE978400B9E8B6 /* liblzma.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liblzma.a; path = ../../../lib/liblzma.a; sourceTree = ""; }; - 7095949B13FE978400B9E8B6 /* libpcre.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpcre.a; path = ../../../lib/libpcre.a; sourceTree = ""; }; - 709594A113FE978C00B9E8B6 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; - 709594A313FE97AF00B9E8B6 /* system.rootrc */ = {isa = PBXFileReference; lastKnownFileType = text; name = system.rootrc; path = ../../../etc/system.rootrc; sourceTree = ""; }; - 709594A413FE97AF00B9E8B6 /* system.plugins-ios */ = {isa = PBXFileReference; lastKnownFileType = text; name = "system.plugins-ios"; path = "../../../etc/system.plugins-ios"; sourceTree = ""; }; - 70989EFB1473E73200515FC5 /* SpotView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpotView.h; sourceTree = ""; }; - 70989EFC1473E73200515FC5 /* SpotView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SpotView.mm; sourceTree = ""; }; - 709CD05214025148005B2AF4 /* demos.root */ = {isa = PBXFileReference; lastKnownFileType = file; path = demos.root; sourceTree = ""; }; - 709CD0961402768B005B2AF4 /* Shortcuts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shortcuts.h; sourceTree = ""; }; - 709CD0971402768B005B2AF4 /* Shortcuts.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Shortcuts.mm; sourceTree = ""; }; - 70AC541C146966E7009A0942 /* ThumbnailView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ThumbnailView.mm; sourceTree = ""; }; - 70AC541D146966E7009A0942 /* ThumbnailView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThumbnailView.h; sourceTree = ""; }; - 70B2B408144C274800FAE3DD /* HorizontalPickerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HorizontalPickerDelegate.h; sourceTree = ""; }; - 70C1D67A1468162600514DC0 /* LineWidthCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LineWidthCell.mm; sourceTree = ""; }; - 70C1D67C1468166100514DC0 /* SlideView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SlideView.mm; sourceTree = ""; }; - 70E0B62014150F630077E4A8 /* back_btn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = back_btn.png; sourceTree = ""; }; - 70E0B623141510880077E4A8 /* forward_btn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = forward_btn.png; sourceTree = ""; }; - 70E16B081455CBC00050C281 /* app_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = app_icon.png; sourceTree = ""; }; - 70E36B551472965E004AEB6A /* FileContainerElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileContainerElement.h; sourceTree = ""; }; - 70E36B561472965E004AEB6A /* FileContainerElement.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FileContainerElement.mm; sourceTree = ""; }; - 70E4FE5014715ABD00296BFF /* TransparentToolbar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TransparentToolbar.h; sourceTree = ""; }; - 70E4FE5114715ABD00296BFF /* TransparentToolbar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TransparentToolbar.m; sourceTree = ""; }; - 70E4FE591471685700296BFF /* SearchController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchController.h; sourceTree = ""; }; - 70E4FE5A1471685700296BFF /* SearchController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SearchController.mm; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7077901613FE50EB00C0FFA1 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 70360B1A142C7AC6001F77E1 /* MessageUI.framework in Frameworks */, - 709594A213FE978C00B9E8B6 /* libz.dylib in Frameworks */, - 7095949C13FE978400B9E8B6 /* libRoot.a in Frameworks */, - 7095949D13FE978400B9E8B6 /* libfreetype.a in Frameworks */, - 7095949E13FE978400B9E8B6 /* liblzma.a in Frameworks */, - 7095949F13FE978400B9E8B6 /* libpcre.a in Frameworks */, - 7077909013FE973A00C0FFA1 /* CoreText.framework in Frameworks */, - 7077908E13FE972D00C0FFA1 /* QuartzCore.framework in Frameworks */, - 7077901E13FE50EB00C0FFA1 /* UIKit.framework in Frameworks */, - 7077902013FE50EB00C0FFA1 /* Foundation.framework in Frameworks */, - 7077902213FE50EB00C0FFA1 /* CoreGraphics.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 706241CC1435F84400202121 /* Custom controls */ = { - isa = PBXGroup; - children = ( - 706241CE1435F86700202121 /* RangeSlider.mm */, - 706241CF1435F86700202121 /* RangeSlider.h */, - 70E4FE5014715ABD00296BFF /* TransparentToolbar.h */, - 70E4FE5114715ABD00296BFF /* TransparentToolbar.m */, - ); - name = "Custom controls"; - sourceTree = ""; - }; - 7077900E13FE50EB00C0FFA1 = { - isa = PBXGroup; - children = ( - 706241CC1435F84400202121 /* Custom controls */, - 70360B19142C7AC6001F77E1 /* MessageUI.framework */, - 70E0B5E31414E4B80077E4A8 /* General */, - 70E0B5D81414E2B50077E4A8 /* Top level view controllers */, - 70E0B5D41414E0F10077E4A8 /* Object Inspector */, - 7077902313FE50EB00C0FFA1 /* root_browser */, - 7077901C13FE50EB00C0FFA1 /* Frameworks */, - 7077901A13FE50EB00C0FFA1 /* Products */, - ); - sourceTree = ""; - }; - 7077901A13FE50EB00C0FFA1 /* Products */ = { - isa = PBXGroup; - children = ( - 7077901913FE50EB00C0FFA1 /* RootBrowser.app */, - ); - name = Products; - sourceTree = ""; - }; - 7077901C13FE50EB00C0FFA1 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 7077908F13FE973A00C0FFA1 /* CoreText.framework */, - 7077908D13FE972D00C0FFA1 /* QuartzCore.framework */, - 7077901D13FE50EB00C0FFA1 /* UIKit.framework */, - 7077901F13FE50EB00C0FFA1 /* Foundation.framework */, - 7077902113FE50EB00C0FFA1 /* CoreGraphics.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 7077902313FE50EB00C0FFA1 /* root_browser */ = { - isa = PBXGroup; - children = ( - 7077902C13FE50EB00C0FFA1 /* root_browserAppDelegate.h */, - 7077902D13FE50EB00C0FFA1 /* root_browserAppDelegate.mm */, - 7077902F13FE50EB00C0FFA1 /* MainWindow.xib */, - 7077902413FE50EB00C0FFA1 /* Supporting Files */, - ); - path = root_browser; - sourceTree = ""; - }; - 7077902413FE50EB00C0FFA1 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 7077902513FE50EB00C0FFA1 /* root_browser-Info.plist */, - 7077902613FE50EB00C0FFA1 /* InfoPlist.strings */, - 7077902913FE50EB00C0FFA1 /* RootBrowser-Prefix.pch */, - 7077902A13FE50EB00C0FFA1 /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 70E0B5D41414E0F10077E4A8 /* Object Inspector */ = { - isa = PBXGroup; - children = ( - 70E0B5E11414E4710077E4A8 /* Views */, - 70E0B5D71414E1510077E4A8 /* xibs */, - 70E0B5D61414E11C0077E4A8 /* Classes and protocols */, - 70E0B5D51414E1110077E4A8 /* Icons and pictures */, - ); - name = "Object Inspector"; - sourceTree = ""; - }; - 70E0B5D51414E1110077E4A8 /* Icons and pictures */ = { - isa = PBXGroup; - children = ( - 7068FF2A141A2F6A003560A1 /* text_cell_bkn.png */, - 7068FF1E1419FCBC003560A1 /* separator.png */, - 7073A28014179A6C001A0FE2 /* minus_btn.png */, - 7073A28114179A6D001A0FE2 /* plus_btn.png */, - 7023580C1434B48C00A95000 /* h1_tab.png */, - 7023580A1434ACC700A95000 /* h1_errors_tab.png */, - 7066FB3B1433470F00F88A2C /* label_tab.png */, - 7066FB391433459200F88A2C /* title_tab.png */, - 7066FB37143342C700F88A2C /* lg_tab.png */, - 7066FB35143341A900F88A2C /* ticks_tab.png */, - 7066FB3314333E7300F88A2C /* line_style_tab.png */, - 7066FB30143338AF00F88A2C /* brush_tab.png */, - 702BB9E314485E4200D3842F /* inc_line_width.png */, - 702BB9E11448584E00D3842F /* dec_line_width.png */, - 702BB9DF1448559A00D3842F /* line_width_bkn.png */, - 702BB9D514482E2200D3842F /* picker_arrow.png */, - 702BB9D614482E2200D3842F /* picker_frame_bkn.png */, - 7068963E1446F9FD00C2E3E7 /* picker_bkn.png */, - 706241D11435F94500202121 /* bar-background.png */, - 706241D21435F94500202121 /* bar-highlight.png */, - 706241D31435F94500202121 /* handle-hover.png */, - 706241D41435F94500202121 /* handle.png */, - 70E0B623141510880077E4A8 /* forward_btn.png */, - 70E0B62014150F630077E4A8 /* back_btn.png */, - 7077908913FE96DC00C0FFA1 /* editor_state_arrow.png */, - 70144128140E553C0070459F /* line_cell.png */, - 7077853114139EBF00450A1B /* editor_plate.png */, - ); - name = "Icons and pictures"; - sourceTree = ""; - }; - 70E0B5D61414E11C0077E4A8 /* Classes and protocols */ = { - isa = PBXGroup; - children = ( - 702DDD161415FDDB009FC6F3 /* ObjectInspectorComponent.h */, - 702DDD181415FEA1009FC6F3 /* LineInspector.h */, - 702DDD191415FEA1009FC6F3 /* LineInspector.mm */, - 702DDD2714161789009FC6F3 /* InspectorWithNavigation.h */, - 702DDD2814161789009FC6F3 /* InspectorWithNavigation.mm */, - 70681C0A1416365900F8338A /* PadInspector.h */, - 70681C0B1416365900F8338A /* PadInspector.mm */, - 70681C0F14163A2300F8338A /* PadTicksGridInspector.h */, - 70681C1414163D3F00F8338A /* PadTicksGridInspector.mm */, - 70681C1614163F0C00F8338A /* PadLogScaleInspector.h */, - 70681C1714163F0C00F8338A /* PadLogScaleInspector.mm */, - 70681C1B1416474000F8338A /* FilledAreaInspector.h */, - 70681C1C1416474000F8338A /* FilledAreaInspector.mm */, - 70681C201416586D00F8338A /* ObjectInspector.h */, - 70681C211416586D00F8338A /* ObjectInspector.mm */, - 7073A272141757BB001A0FE2 /* AxisTicksInspector.h */, - 7073A273141757BB001A0FE2 /* AxisTicksInspector.mm */, - 7073A27B14177A03001A0FE2 /* AxisInspector.h */, - 7073A27C14177A03001A0FE2 /* AxisInspector.mm */, - 7073A2841417AA0F001A0FE2 /* AxisTitleInspector.h */, - 7073A2851417AA0F001A0FE2 /* AxisTitleInspector.mm */, - 7068FF21141A0EAF003560A1 /* AxisFontInspector.h */, - 7068FF22141A0EAF003560A1 /* AxisFontInspector.mm */, - 7068FF2E141A3943003560A1 /* AxisLabelsInspector.h */, - 7068FF2F141A3943003560A1 /* AxisLabelsInspector.mm */, - 702357DE1434658900A95000 /* H1Inspector.h */, - 702357DF1434658900A95000 /* H1Inspector.mm */, - 702357D814345C0A00A95000 /* H1ErrorsInspector.h */, - 702357D914345C0A00A95000 /* H1ErrorsInspector.mm */, - 70235800143494F400A95000 /* MarkerInspector.h */, - 70235801143494F400A95000 /* MarkerInspector.mm */, - 702358051434A93B00A95000 /* H1BinsInspector.h */, - 702358061434A93B00A95000 /* H1BinsInspector.mm */, - 70B2B408144C274800FAE3DD /* HorizontalPickerDelegate.h */, - ); - name = "Classes and protocols"; - sourceTree = ""; - }; - 70E0B5D71414E1510077E4A8 /* xibs */ = { - isa = PBXGroup; - children = ( - 702DDD1A1415FEA1009FC6F3 /* LineInspector.xib */, - 70681C1D1416474000F8338A /* FilledAreaInspector.xib */, - 70681C0C1416365900F8338A /* PadInspector.xib */, - 70681C1814163F0C00F8338A /* PadLogScaleInspector.xib */, - 70681C1114163A2300F8338A /* PadTicksGridInspector.xib */, - 7073A274141757BB001A0FE2 /* AxisTicksInspector.xib */, - 7073A27D14177A03001A0FE2 /* AxisInspector.xib */, - 7073A2861417AA10001A0FE2 /* AxisTitleInspector.xib */, - 7068FF23141A0EAF003560A1 /* AxisFontInspector.xib */, - 7068FF30141A3944003560A1 /* AxisLabelsInspector.xib */, - 702357DA14345C0A00A95000 /* H1ErrorsInspector.xib */, - 702357E01434658900A95000 /* H1Inspector.xib */, - 702358071434A93C00A95000 /* H1BinsInspector.xib */, - 70235802143494F400A95000 /* MarkerInspector.xib */, - ); - name = xibs; - sourceTree = ""; - }; - 70E0B5D81414E2B50077E4A8 /* Top level view controllers */ = { - isa = PBXGroup; - children = ( - 70E0B5DE1414E3FC0077E4A8 /* Views */, - 70E0B5DB1414E2FD0077E4A8 /* Classes */, - 70E0B5DA1414E2F00077E4A8 /* xibs */, - 70E0B5D91414E2E00077E4A8 /* Icons and pictures */, - ); - name = "Top level view controllers"; - sourceTree = ""; - }; - 70E0B5D91414E2E00077E4A8 /* Icons and pictures */ = { - isa = PBXGroup; - children = ( - 7077905013FE6B8F00C0FFA1 /* file_shortcut_background.png */, - 700ED6CA146BCDF100526D1C /* directory.png */, - 7023805D140514C8002A5331 /* file_icon.png */, - ); - name = "Icons and pictures"; - sourceTree = ""; - }; - 70E0B5DA1414E2F00077E4A8 /* xibs */ = { - isa = PBXGroup; - children = ( - 7077905C13FE840000C0FFA1 /* SlideshowController.xib */, - 7077903913FE51B400C0FFA1 /* RootFileController.xib */, - 7077903E13FE549300C0FFA1 /* FileContentController.xib */, - 7077906113FE847600C0FFA1 /* ROOTObjectController.xib */, - ); - name = xibs; - sourceTree = ""; - }; - 70E0B5DB1414E2FD0077E4A8 /* Classes */ = { - isa = PBXGroup; - children = ( - 7077905F13FE847600C0FFA1 /* ROOTObjectController.h */, - 7077906013FE847600C0FFA1 /* ROOTObjectController.mm */, - 7077903713FE51B400C0FFA1 /* RootFileController.h */, - 7077903813FE51B400C0FFA1 /* RootFileController.mm */, - 7077903C13FE549300C0FFA1 /* FileContentController.h */, - 7077903D13FE549300C0FFA1 /* FileContentController.mm */, - 7077905A13FE840000C0FFA1 /* SlideshowController.h */, - 7077905B13FE840000C0FFA1 /* SlideshowController.mm */, - ); - name = Classes; - sourceTree = ""; - }; - 70E0B5DE1414E3FC0077E4A8 /* Views */ = { - isa = PBXGroup; - children = ( - 70AC541C146966E7009A0942 /* ThumbnailView.mm */, - 70AC541D146966E7009A0942 /* ThumbnailView.h */, - 7077904113FE554E00C0FFA1 /* FileShortcut.h */, - 7077904213FE554E00C0FFA1 /* FileShortcut.mm */, - 7077906413FE87D000C0FFA1 /* ObjectShortcut.h */, - 7077906513FE87D000C0FFA1 /* ObjectShortcut.mm */, - 7014410D140E18390070459F /* SelectionView.h */, - 7014410E140E18390070459F /* SelectionView.mm */, - 704B5A211520CC8D00FEF9C8 /* PadView.h */, - 70249BDA1403D644006A19E6 /* PadView.mm */, - 705A503414066421004C1C8B /* ScrollViewWithPadView.h */, - 705A503514066421004C1C8B /* ScrollViewWithPadView.mm */, - 705F1A66142347CA003045D9 /* SlideView.h */, - 70C1D67C1468166100514DC0 /* SlideView.mm */, - 7044980B1429D13D00E83799 /* PadImageScrollView.h */, - 7044980C1429D13D00E83799 /* PadImageScrollView.mm */, - 70E4FE591471685700296BFF /* SearchController.h */, - 70E4FE5A1471685700296BFF /* SearchController.mm */, - 70E36B551472965E004AEB6A /* FileContainerElement.h */, - 70E36B561472965E004AEB6A /* FileContainerElement.mm */, - 70989EFB1473E73200515FC5 /* SpotView.h */, - 70989EFC1473E73200515FC5 /* SpotView.mm */, - ); - name = Views; - sourceTree = ""; - }; - 70E0B5E11414E4710077E4A8 /* Views */ = { - isa = PBXGroup; - children = ( - 702BB9DA14482E3C00D3842F /* HorizontalPickerView.mm */, - 702BB9DB14482E3C00D3842F /* HorizontalPickerView.h */, - 7077906E13FE96C200C0FFA1 /* ScrollViewWithPickers.mm */, - 7077907013FE96C200C0FFA1 /* ScrollViewWithPickers.h */, - 7077906B13FE96C200C0FFA1 /* EditorView.mm */, - 7077906C13FE96C200C0FFA1 /* EditorView.h */, - 70144121140E3F320070459F /* LineWidthCell.h */, - 70C1D67A1468162600514DC0 /* LineWidthCell.mm */, - 7014411E140E3F1D0070459F /* LineStyleCell.h */, - 7014411F140E3F1D0070459F /* LineStyleCell.mm */, - 7077906F13FE96C200C0FFA1 /* EditorPlateView.mm */, - 7077907713FE96C200C0FFA1 /* EditorPlateView.h */, - 7077907913FE96C300C0FFA1 /* PatternCell.mm */, - 7077907A13FE96C300C0FFA1 /* PatternCell.h */, - 7077907B13FE96C300C0FFA1 /* ColorCell.mm */, - 7077907C13FE96C300C0FFA1 /* ColorCell.h */, - 702BB9E51448680100D3842F /* LineWidthPicker.h */, - 702BB9E61448680200D3842F /* LineWidthPicker.mm */, - 7053E8B4143B076F001C364D /* MarkerStyleCell.h */, - 7053E8B5143B076F001C364D /* MarkerStyleCell.mm */, - ); - name = Views; - sourceTree = ""; - }; - 70E0B5E31414E4B80077E4A8 /* General */ = { - isa = PBXGroup; - children = ( - 70E0B5E71414E5200077E4A8 /* ROOT libs */, - 70E0B5E61414E5080077E4A8 /* ROOT-related files */, - 70E0B5E51414E4ED0077E4A8 /* Icons and images */, - 70E0B5E41414E4C80077E4A8 /* Code */, - ); - name = General; - sourceTree = ""; - }; - 70E0B5E41414E4C80077E4A8 /* Code */ = { - isa = PBXGroup; - children = ( - 70078C2B146AC4C400C19F4D /* FileUtils.h */, - 70078C2C146AC4C400C19F4D /* FileUtils.cxx */, - 70252F7A140CDD8D00F3660F /* Constants.cxx */, - 70252F7B140CDD8D00F3660F /* Constants.h */, - 709CD0961402768B005B2AF4 /* Shortcuts.h */, - 709CD0971402768B005B2AF4 /* Shortcuts.mm */, - ); - name = Code; - sourceTree = ""; - }; - 70E0B5E51414E4ED0077E4A8 /* Icons and images */ = { - isa = PBXGroup; - children = ( - 70E16B081455CBC00050C281 /* app_icon.png */, - 7073A9A914277D16006F6D67 /* Default-Portrait.png */, - 7073A9AA14277D17006F6D67 /* Default-PortraitUpsideDown.png */, - 7073A9AB14277D18006F6D67 /* Default-Landscape.png */, - 7073A9AC14277D19006F6D67 /* Default-LandscapeLeft.png */, - 7073A9AD14277D1A006F6D67 /* Default-LandscapeRight.png */, - ); - name = "Icons and images"; - sourceTree = ""; - }; - 70E0B5E61414E5080077E4A8 /* ROOT-related files */ = { - isa = PBXGroup; - children = ( - 709CD05214025148005B2AF4 /* demos.root */, - 709594A313FE97AF00B9E8B6 /* system.rootrc */, - 709594A413FE97AF00B9E8B6 /* system.plugins-ios */, - ); - name = "ROOT-related files"; - sourceTree = ""; - }; - 70E0B5E71414E5200077E4A8 /* ROOT libs */ = { - isa = PBXGroup; - children = ( - 709594A113FE978C00B9E8B6 /* libz.dylib */, - 7095949813FE978400B9E8B6 /* libRoot.a */, - 7095949913FE978400B9E8B6 /* libfreetype.a */, - 7095949A13FE978400B9E8B6 /* liblzma.a */, - 7095949B13FE978400B9E8B6 /* libpcre.a */, - ); - name = "ROOT libs"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 7077901813FE50EB00C0FFA1 /* RootBrowser */ = { - isa = PBXNativeTarget; - buildConfigurationList = 7077903413FE50EB00C0FFA1 /* Build configuration list for PBXNativeTarget "RootBrowser" */; - buildPhases = ( - 7077901513FE50EB00C0FFA1 /* Sources */, - 7077901613FE50EB00C0FFA1 /* Frameworks */, - 7077901713FE50EB00C0FFA1 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = RootBrowser; - productName = root_browser; - productReference = 7077901913FE50EB00C0FFA1 /* RootBrowser.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 7077901013FE50EB00C0FFA1 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0420; - }; - buildConfigurationList = 7077901313FE50EB00C0FFA1 /* Build configuration list for PBXProject "RootBrowser" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 7077900E13FE50EB00C0FFA1; - productRefGroup = 7077901A13FE50EB00C0FFA1 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 7077901813FE50EB00C0FFA1 /* RootBrowser */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 7077901713FE50EB00C0FFA1 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 70E16B091455CBC00050C281 /* app_icon.png in Resources */, - 702BB9E414485E4200D3842F /* inc_line_width.png in Resources */, - 702BB9E21448584E00D3842F /* dec_line_width.png in Resources */, - 702BB9E01448559A00D3842F /* line_width_bkn.png in Resources */, - 702BB9D714482E2200D3842F /* picker_arrow.png in Resources */, - 702BB9D814482E2200D3842F /* picker_frame_bkn.png in Resources */, - 7068963F1446F9FD00C2E3E7 /* picker_bkn.png in Resources */, - 706241D51435F94500202121 /* bar-background.png in Resources */, - 706241D61435F94500202121 /* bar-highlight.png in Resources */, - 706241D71435F94500202121 /* handle-hover.png in Resources */, - 706241D81435F94500202121 /* handle.png in Resources */, - 7023580D1434B48C00A95000 /* h1_tab.png in Resources */, - 7023580B1434ACC700A95000 /* h1_errors_tab.png in Resources */, - 7066FB3C1433470F00F88A2C /* label_tab.png in Resources */, - 7066FB3A1433459200F88A2C /* title_tab.png in Resources */, - 7066FB38143342C700F88A2C /* lg_tab.png in Resources */, - 7066FB36143341A900F88A2C /* ticks_tab.png in Resources */, - 7066FB3414333E7300F88A2C /* line_style_tab.png in Resources */, - 7066FB31143338AF00F88A2C /* brush_tab.png in Resources */, - 7073A9AE14277D1B006F6D67 /* Default-Portrait.png in Resources */, - 7073A9AF14277D1B006F6D67 /* Default-PortraitUpsideDown.png in Resources */, - 7073A9B014277D1B006F6D67 /* Default-Landscape.png in Resources */, - 7073A9B114277D1B006F6D67 /* Default-LandscapeLeft.png in Resources */, - 7073A9B214277D1B006F6D67 /* Default-LandscapeRight.png in Resources */, - 7068FF2B141A2F6A003560A1 /* text_cell_bkn.png in Resources */, - 7068FF1F1419FCBC003560A1 /* separator.png in Resources */, - 7073A28214179A6D001A0FE2 /* minus_btn.png in Resources */, - 7073A28314179A6D001A0FE2 /* plus_btn.png in Resources */, - 70E0B624141510880077E4A8 /* forward_btn.png in Resources */, - 70E0B62114150F630077E4A8 /* back_btn.png in Resources */, - 7077853214139EBF00450A1B /* editor_plate.png in Resources */, - 70144129140E553C0070459F /* line_cell.png in Resources */, - 7023805E140514C8002A5331 /* file_icon.png in Resources */, - 709CD05314025148005B2AF4 /* demos.root in Resources */, - 709594A513FE97AF00B9E8B6 /* system.rootrc in Resources */, - 709594A613FE97AF00B9E8B6 /* system.plugins-ios in Resources */, - 7077908B13FE96DC00C0FFA1 /* editor_state_arrow.png in Resources */, - 7077905113FE6B8F00C0FFA1 /* file_shortcut_background.png in Resources */, - 7077902813FE50EB00C0FFA1 /* InfoPlist.strings in Resources */, - 7077903113FE50EB00C0FFA1 /* MainWindow.xib in Resources */, - 7077903B13FE51B400C0FFA1 /* RootFileController.xib in Resources */, - 7077904013FE549300C0FFA1 /* FileContentController.xib in Resources */, - 7077905E13FE840000C0FFA1 /* SlideshowController.xib in Resources */, - 7077906313FE847600C0FFA1 /* ROOTObjectController.xib in Resources */, - 702DDD1C1415FEA1009FC6F3 /* LineInspector.xib in Resources */, - 70681C0E1416365900F8338A /* PadInspector.xib in Resources */, - 70681C1314163A2300F8338A /* PadTicksGridInspector.xib in Resources */, - 70681C1A14163F0C00F8338A /* PadLogScaleInspector.xib in Resources */, - 70681C1F1416474000F8338A /* FilledAreaInspector.xib in Resources */, - 7073A276141757BC001A0FE2 /* AxisTicksInspector.xib in Resources */, - 7073A27F14177A03001A0FE2 /* AxisInspector.xib in Resources */, - 7073A2881417AA10001A0FE2 /* AxisTitleInspector.xib in Resources */, - 7068FF25141A0EAF003560A1 /* AxisFontInspector.xib in Resources */, - 7068FF32141A3944003560A1 /* AxisLabelsInspector.xib in Resources */, - 702357DC14345C0A00A95000 /* H1ErrorsInspector.xib in Resources */, - 702357E21434658900A95000 /* H1Inspector.xib in Resources */, - 70235804143494F400A95000 /* MarkerInspector.xib in Resources */, - 702358091434A93C00A95000 /* H1BinsInspector.xib in Resources */, - 700ED6CB146BCDF200526D1C /* directory.png in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 7077901513FE50EB00C0FFA1 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7077902B13FE50EB00C0FFA1 /* main.m in Sources */, - 7077902E13FE50EB00C0FFA1 /* root_browserAppDelegate.mm in Sources */, - 7077903A13FE51B400C0FFA1 /* RootFileController.mm in Sources */, - 7077903F13FE549300C0FFA1 /* FileContentController.mm in Sources */, - 7077904313FE554E00C0FFA1 /* FileShortcut.mm in Sources */, - 7077905D13FE840000C0FFA1 /* SlideshowController.mm in Sources */, - 7077906213FE847600C0FFA1 /* ROOTObjectController.mm in Sources */, - 7077906613FE87D000C0FFA1 /* ObjectShortcut.mm in Sources */, - 7077907E13FE96C300C0FFA1 /* EditorView.mm in Sources */, - 7077908013FE96C300C0FFA1 /* ScrollViewWithPickers.mm in Sources */, - 7077908113FE96C300C0FFA1 /* EditorPlateView.mm in Sources */, - 7077908713FE96C300C0FFA1 /* PatternCell.mm in Sources */, - 7077908813FE96C300C0FFA1 /* ColorCell.mm in Sources */, - 709CD0981402768B005B2AF4 /* Shortcuts.mm in Sources */, - 70249BDC1403D644006A19E6 /* PadView.mm in Sources */, - 705A503614066421004C1C8B /* ScrollViewWithPadView.mm in Sources */, - 70252F7C140CDD8D00F3660F /* Constants.cxx in Sources */, - 7014410F140E18390070459F /* SelectionView.mm in Sources */, - 70144120140E3F1D0070459F /* LineStyleCell.mm in Sources */, - 702DDD1B1415FEA1009FC6F3 /* LineInspector.mm in Sources */, - 702DDD2914161789009FC6F3 /* InspectorWithNavigation.mm in Sources */, - 70681C0D1416365900F8338A /* PadInspector.mm in Sources */, - 70681C1514163D3F00F8338A /* PadTicksGridInspector.mm in Sources */, - 70681C1914163F0C00F8338A /* PadLogScaleInspector.mm in Sources */, - 70681C1E1416474000F8338A /* FilledAreaInspector.mm in Sources */, - 70681C221416586D00F8338A /* ObjectInspector.mm in Sources */, - 7073A275141757BC001A0FE2 /* AxisTicksInspector.mm in Sources */, - 7073A27E14177A03001A0FE2 /* AxisInspector.mm in Sources */, - 7073A2871417AA10001A0FE2 /* AxisTitleInspector.mm in Sources */, - 7068FF24141A0EAF003560A1 /* AxisFontInspector.mm in Sources */, - 7068FF31141A3944003560A1 /* AxisLabelsInspector.mm in Sources */, - 7044980D1429D13D00E83799 /* PadImageScrollView.mm in Sources */, - 702357DB14345C0A00A95000 /* H1ErrorsInspector.mm in Sources */, - 702357E11434658900A95000 /* H1Inspector.mm in Sources */, - 70235803143494F400A95000 /* MarkerInspector.mm in Sources */, - 702358081434A93C00A95000 /* H1BinsInspector.mm in Sources */, - 706241D01435F86700202121 /* RangeSlider.mm in Sources */, - 7053E8B6143B076F001C364D /* MarkerStyleCell.mm in Sources */, - 702BB9DC14482E3C00D3842F /* HorizontalPickerView.mm in Sources */, - 702BB9E71448680200D3842F /* LineWidthPicker.mm in Sources */, - 70C1D67B1468162600514DC0 /* LineWidthCell.mm in Sources */, - 70C1D67D1468166100514DC0 /* SlideView.mm in Sources */, - 70AC541E146966E7009A0942 /* ThumbnailView.mm in Sources */, - 70078C2D146AC4C400C19F4D /* FileUtils.cxx in Sources */, - 70E4FE5214715ABD00296BFF /* TransparentToolbar.m in Sources */, - 70E4FE5B1471685700296BFF /* SearchController.mm in Sources */, - 70E36B571472965E004AEB6A /* FileContainerElement.mm in Sources */, - 70989EFD1473E73200515FC5 /* SpotView.mm in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 7077902613FE50EB00C0FFA1 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 7077902713FE50EB00C0FFA1 /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; - 7077902F13FE50EB00C0FFA1 /* MainWindow.xib */ = { - isa = PBXVariantGroup; - children = ( - 7077903013FE50EB00C0FFA1 /* en */, - ); - name = MainWindow.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 7077903213FE50EB00C0FFA1 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_ENABLE_OBJC_ARC = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = DEBUG; - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - OTHER_LDFLAGS = ../../../hist/hist/src/G__Hist.o; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = 2; - }; - name = Debug; - }; - 7077903313FE50EB00C0FFA1 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_ENABLE_OBJC_ARC = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - OTHER_LDFLAGS = ../../../hist/hist/src/G__Hist.o; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = 2; - }; - name = Release; - }; - 7077903513FE50EB00C0FFA1 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_ENABLE_OBJC_ARC = YES; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_PRECOMPILE_PREFIX_HEADER = NO; - GCC_PREFIX_HEADER = "root_browser/RootBrowser-Prefix.pch"; - HEADER_SEARCH_PATHS = ../../../include; - INFOPLIST_FILE = "root_browser/root_browser-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ../../../lib; - OTHER_LDFLAGS = ( - ../../../hist/hist/src/G__Hist.o, - ../../../hist/histpainter/src/G__HistPainter.o, - ../../../graf3d/g3d/src/G__G3D.o, - ../../../net/net/src/G__Net.o, - ../../../io/io/src/G__IO.o, - ); - PRODUCT_NAME = RootBrowser; - VALID_ARCHS = armv7; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - 7077903613FE50EB00C0FFA1 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_ENABLE_OBJC_ARC = YES; - COPY_PHASE_STRIP = YES; - GCC_PRECOMPILE_PREFIX_HEADER = NO; - GCC_PREFIX_HEADER = "root_browser/RootBrowser-Prefix.pch"; - HEADER_SEARCH_PATHS = ../../../include; - INFOPLIST_FILE = "root_browser/root_browser-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ../../../lib; - OTHER_LDFLAGS = ( - ../../../hist/hist/src/G__Hist.o, - ../../../hist/histpainter/src/G__HistPainter.o, - ../../../graf3d/g3d/src/G__G3D.o, - ../../../net/net/src/G__Net.o, - ../../../io/io/src/G__IO.o, - ); - PRODUCT_NAME = RootBrowser; - VALIDATE_PRODUCT = YES; - VALID_ARCHS = armv7; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 7077901313FE50EB00C0FFA1 /* Build configuration list for PBXProject "RootBrowser" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7077903213FE50EB00C0FFA1 /* Debug */, - 7077903313FE50EB00C0FFA1 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 7077903413FE50EB00C0FFA1 /* Build configuration list for PBXNativeTarget "RootBrowser" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 7077903513FE50EB00C0FFA1 /* Debug */, - 7077903613FE50EB00C0FFA1 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 7077901013FE50EB00C0FFA1 /* Project object */; -} diff --git a/test/ios/RootBrowser/RootBrowser.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/test/ios/RootBrowser/RootBrowser.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 6efe21a8d6a38..0000000000000 --- a/test/ios/RootBrowser/RootBrowser.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/test/ios/RootBrowser/RootFileController.h b/test/ios/RootBrowser/RootFileController.h deleted file mode 100644 index 0640fc430d648..0000000000000 --- a/test/ios/RootBrowser/RootFileController.h +++ /dev/null @@ -1,19 +0,0 @@ -#import - -@class FileShortcut; - -@interface RootFileController : UIViewController { -@private - __weak IBOutlet UIScrollView *scrollView; - __weak IBOutlet UIView *fileOpenView; - __weak IBOutlet UITextField *fileNameField; -} - -- (void) fileWasSelected : (FileShortcut*)shortcut; -- (void) tryToDelete : (FileShortcut*)shortcut; -- (void) addRootFile : (NSString *)fileName; - -- (IBAction) textFieldDidEndOnExit : (id) sender; -- (IBAction) textFieldEditingDidEnd : (id) sender; - -@end diff --git a/test/ios/RootBrowser/RootFileController.mm b/test/ios/RootBrowser/RootFileController.mm deleted file mode 100644 index 5fb86d5efdb9f..0000000000000 --- a/test/ios/RootBrowser/RootFileController.mm +++ /dev/null @@ -1,247 +0,0 @@ -#import - -#import "FileContentController.h" -#import "RootFileController.h" -#import "FileShortcut.h" -#import "Shortcuts.h" - -//C++ imports. -#import "FileUtils.h" - -@interface RootFileController () { -@private - NSMutableArray *fileContainers; - __weak FileShortcut *fileToDelete; -} - -- (void) hideFileOpenView; - -@end - -@implementation RootFileController - -//____________________________________________________________________________________________________ -- (id) initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - - if (self) { - [self view]; - - fileContainers = [[NSMutableArray alloc] init]; - - self.navigationItem.title = @"ROOT files"; - self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle : @"Back to ROOT files" style:UIBarButtonItemStylePlain target : nil action : nil]; - self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle : @"Open file" style:UIBarButtonItemStylePlain target : self action : @selector(showFileOpenView)]; - - scrollView.bounces = NO; - - [self.view bringSubviewToFront : fileOpenView]; - - fileNameField.clearButtonMode = UITextFieldViewModeAlways; - - UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideFileOpenView)]; - [self.view addGestureRecognizer : tap]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void) placeFileShortcuts -{ - if ([scrollView.subviews count]) - [ShorcutUtil placeShortcuts : fileContainers inScrollView : scrollView withSize : CGSizeMake([FileShortcut iconWidth], [FileShortcut iconHeight]) andSpace : 25.f]; -} - -//____________________________________________________________________________________________________ -- (void) correctFramesForOrientation : (UIInterfaceOrientation) orientation -{ - CGRect mainFrame; - CGRect scrollFrame; - CGRect fileViewFrame; - - if (UIInterfaceOrientationIsPortrait(orientation)) { - mainFrame = CGRectMake(0.f, 0.f, 768.f, 1004.f); - scrollFrame = CGRectMake(0.f, 44.f, 768.f, 960.f); - fileViewFrame = CGRectMake(0.f, 44.f, 768.f, 120.f); - } else { - mainFrame = CGRectMake(0.f, 0.f, 1024.f, 748.f); - scrollFrame = CGRectMake(0.f, 44.f, 1024.f, 704.f); - fileViewFrame = CGRectMake(0.f, 44.f, 1024.f, 120.f); - } - - self.view.frame = mainFrame; - scrollView.frame = scrollFrame; - - fileOpenView.frame = fileViewFrame; - - [self placeFileShortcuts]; -} - -//____________________________________________________________________________________________________ -- (void) viewWillAppear : (BOOL)animated -{ - [self correctFramesForOrientation : self.interfaceOrientation]; - [fileNameField resignFirstResponder]; - //Check if I have to call [super viewWillAppear]; -} - -//____________________________________________________________________________________________________ -- (void) viewDidLoad -{ - [super viewDidLoad]; -} - -//____________________________________________________________________________________________________ -- (void) viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (BOOL) shouldAutorotateToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -//____________________________________________________________________________________________________ -- (void)willAnimateRotationToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation duration : (NSTimeInterval) duration -{ - [self correctFramesForOrientation : interfaceOrientation]; -} - -#pragma mark - View management. - -//____________________________________________________________________________________________________ -- (void) addRootFile : (NSString *) fileName -{ - //Open the file and read its contents. - using namespace ROOT::iOS::Browser; - - FileContainer *fileContainer = FileContainer::CreateFileContainer([fileName cStringUsingEncoding : [NSString defaultCStringEncoding]]); - - if (!fileContainer) { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle : @"File Open Error:" - message : [NSString stringWithFormat:@"Could not open %@", fileName] - delegate : nil - cancelButtonTitle : @"Close" - otherButtonTitles : nil]; - [alert show]; - return; - } - - const CGRect shortcutFrame = CGRectMake(0.f, 0.f, [FileShortcut iconWidth], [FileShortcut iconHeight]); - FileShortcut *newShortcut = [[FileShortcut alloc] initWithFrame : shortcutFrame controller : self fileContainer : fileContainer]; - if (newShortcut) {//What if alloc returned nil? - [fileContainers addObject : newShortcut]; - [scrollView addSubview : newShortcut]; - [self placeFileShortcuts]; - } else - FileContainer::DeleteFileContainer(fileContainer); -} - -//____________________________________________________________________________________________________ -- (void) fileWasSelected : (FileShortcut*) shortcut -{ - FileContentController *contentController = [[FileContentController alloc] initWithNibName : @"FileContentController" bundle : nil]; - [contentController activateForFile : [shortcut getFileContainer]]; - [self.navigationController pushViewController : contentController animated : YES]; -} - -//____________________________________________________________________________________________________ -- (void) tryToDelete : (FileShortcut*)shortcut -{ - NSString *message = [NSString stringWithFormat : @"Do you really want to close %@?", shortcut.fileName]; - UIActionSheet *dialog = [[UIActionSheet alloc] initWithTitle : message delegate : self cancelButtonTitle : @"Cancel" destructiveButtonTitle : @"Yes" otherButtonTitles : nil]; - fileToDelete = shortcut; - [dialog showInView : self.view]; -} - -#pragma mark - Action sheet delegate, delete the file. - -//____________________________________________________________________________________________________ -- (void)actionSheet : (UIActionSheet *)actionSheet didDismissWithButtonIndex : (NSInteger)buttonIndex -{ - if (!buttonIndex) { - [fileContainers removeObject:fileToDelete]; - [fileToDelete removeFromSuperview]; - [self correctFramesForOrientation : self.interfaceOrientation]; - } -} - -#pragma mark - File open operations. - -//____________________________________________________________________________________________________ -- (void) animateFileOpenView -{ - //Do animation. - // First create a CATransition object to describe the transition - CATransition *transition = [CATransition animation]; - transition.duration = 0.15; - // using the ease in/out timing function - transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; - // Now to set the type of transition. - transition.type = kCATransitionPush; - - if (!fileOpenView.hidden) - transition.subtype = kCATransitionFromBottom; - else - transition.subtype = kCATransitionFromTop; - transition.delegate = self; - // Next add it to the containerView's layer. This will perform the transition based on how we change its contents. - [fileOpenView.layer addAnimation : transition forKey : nil]; -} - -//____________________________________________________________________________________________________ -- (void) showFileOpenView -{ - fileOpenView.hidden = !fileOpenView.hidden; - // - [self animateFileOpenView]; - - if (!fileOpenView.hidden) - [fileNameField becomeFirstResponder]; - else - [fileNameField resignFirstResponder]; -} - -//____________________________________________________________________________________________________ -- (IBAction) textFieldDidEndOnExit : (id) sender -{ - NSString *filePath = fileNameField.text; - if (filePath) {//TODO - do I need this check? - [self addRootFile : filePath]; - } -} - -//____________________________________________________________________________________________________ -- (IBAction) textFieldEditingDidEnd : (id) sender -{ - [sender resignFirstResponder]; - fileOpenView.hidden = YES; - [self animateFileOpenView]; -} - -//____________________________________________________________________________________________________ -- (void) hideFileOpenView -{ - [fileNameField resignFirstResponder]; - fileOpenView.hidden = YES; - [self animateFileOpenView]; -} - -@end diff --git a/test/ios/RootBrowser/RootFileController.xib b/test/ios/RootBrowser/RootFileController.xib deleted file mode 100644 index 5f592103b7abf..0000000000000 --- a/test/ios/RootBrowser/RootFileController.xib +++ /dev/null @@ -1,398 +0,0 @@ - - - - 1056 - 10K549 - 1305 - 1038.36 - 461.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 300 - - - YES - IBUITextField - IBUIScrollView - IBUIView - IBUILabel - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 256 - - YES - - - 274 - {{0, 22}, {1024, 704}} - - - - - 3 - MCAwAA - - NO - YES - YES - IBIPadFramework - - - - -2147483374 - - YES - - - 258 - {{20, 69}, {360, 31}} - - - NO - YES - IBIPadFramework - 0 - - 3 - - 3 - MAA - - 2 - - - YES - 17 - - 3 - 1 - YES - IBCocoaTouchFramework - - - - - 256 - {{114, 28}, {172, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Enter the file name: - - 1 - MSAxIDEAA - - 1 - - - - 1 - 10 - 1 - - - {{312, 314}, {400, 120}} - - - - - 1 - MCAwIDAAA - - NO - 0.89999997615814209 - IBIPadFramework - - - {{0, 20}, {1024, 748}} - - - - - 3 - MC4zMzMzMzMzMzMzAA - - NO - - 2 - - - 3 - 3 - - IBIPadFramework - - - - - YES - - - scrollView - - - - 22 - - - - view - - - - 26 - - - - fileOpenView - - - - 31 - - - - fileNameField - - - - 32 - - - - textFieldDidEndOnExit: - - - 20 - - 40 - - - - textFieldEditingDidEnd: - - - 19 - - 41 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - YES - - - - - - - 27 - - - YES - - - - - - - 29 - - - - - 28 - - - - - 18 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 18.IBPluginDependency - 2.IBEditorWindowLastContentRect - 2.IBPluginDependency - 27.IBPluginDependency - 28.IBPluginDependency - 29.IBPluginDependency - - - YES - RootFileController - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - {{353, 156}, {1024, 768}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 41 - - - - YES - - RootFileController - UIViewController - - YES - - YES - textFieldDidEndOnExit: - textFieldEditingDidDone: - - - YES - id - id - - - - YES - - YES - textFieldDidEndOnExit: - textFieldEditingDidDone: - - - YES - - textFieldDidEndOnExit: - id - - - textFieldEditingDidDone: - id - - - - - YES - - YES - fileNameField - fileOpenView - scrollView - - - YES - UITextField - UIView - UIScrollView - - - - YES - - YES - fileNameField - fileOpenView - scrollView - - - YES - - fileNameField - UITextField - - - fileOpenView - UIView - - - scrollView - UIScrollView - - - - - IBProjectSource - ./Classes/RootFileController.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 300 - - diff --git a/test/ios/RootBrowser/ScrollViewWithPadView.h b/test/ios/RootBrowser/ScrollViewWithPadView.h deleted file mode 100644 index 2a546bf69a121..0000000000000 --- a/test/ios/RootBrowser/ScrollViewWithPadView.h +++ /dev/null @@ -1,8 +0,0 @@ -/* -This is scroll-view for pad in editable mode. -TODO: Find better class name. -*/ -#import - -@interface ScrollViewWithPadView : UIScrollView -@end diff --git a/test/ios/RootBrowser/ScrollViewWithPadView.mm b/test/ios/RootBrowser/ScrollViewWithPadView.mm deleted file mode 100644 index 40fd3c2298473..0000000000000 --- a/test/ios/RootBrowser/ScrollViewWithPadView.mm +++ /dev/null @@ -1,28 +0,0 @@ -#import "ScrollViewWithPadView.h" -#import "PadView.h" - -@implementation ScrollViewWithPadView - -//____________________________________________________________________________________________________ -- (UIView *) hitTest : (CGPoint)point withEvent : (UIEvent *)event -{ - UIView * v = [super hitTest : point withEvent : event]; - - if ([v isKindOfClass : [PadView class]]) { - PadView *padView = (PadView *)v; - - if ([padView pointOnSelectedObject : [self convertPoint : point toView : padView]]) { - self.canCancelContentTouches = NO; - self.delaysContentTouches = NO; - [padView addPanRecognizer]; - } else { - [padView removePanRecognizer]; - self.canCancelContentTouches = YES; - self.delaysContentTouches = YES; - } - } - - return v; -} - -@end diff --git a/test/ios/RootBrowser/ScrollViewWithPickers.h b/test/ios/RootBrowser/ScrollViewWithPickers.h deleted file mode 100644 index 1e0016ec72c34..0000000000000 --- a/test/ios/RootBrowser/ScrollViewWithPickers.h +++ /dev/null @@ -1,11 +0,0 @@ -#import - -//This is small class, inheriting UIScrollView. -//The only reason to exist at all - inspector's -//window has a scroll-view, which can include -//UIPickerView, and UIPickerView is not so easy -//to rotate in a scroll-view. - -@interface ScrollViewWithPickers : UIScrollView - -@end diff --git a/test/ios/RootBrowser/ScrollViewWithPickers.mm b/test/ios/RootBrowser/ScrollViewWithPickers.mm deleted file mode 100644 index 0d6424906ecdc..0000000000000 --- a/test/ios/RootBrowser/ScrollViewWithPickers.mm +++ /dev/null @@ -1,23 +0,0 @@ -#import "ScrollViewWithPickers.h" - - -@implementation ScrollViewWithPickers - -//____________________________________________________________________________________________________ -- (UIView *) hitTest : (CGPoint)point withEvent : (UIEvent *)event -{ - UIView * v = [super hitTest : point withEvent : event]; - - if ([v isKindOfClass : [UIPickerView class]] || [v.superview isKindOfClass : [UIPickerView class]]) { - self.canCancelContentTouches = NO; - self.delaysContentTouches = NO; - } else { - self.canCancelContentTouches = YES; - self.delaysContentTouches = YES; - } - - return v; -} - - -@end diff --git a/test/ios/RootBrowser/SearchController.h b/test/ios/RootBrowser/SearchController.h deleted file mode 100644 index 3de47b9a77a40..0000000000000 --- a/test/ios/RootBrowser/SearchController.h +++ /dev/null @@ -1,19 +0,0 @@ -#import - -@class FileContainerElement; -@class SearchController; - -@protocol SearchDelegate -- (void) searchesController : (SearchController *)controller didSelectKey : (FileContainerElement *)key; -@end - - -@interface SearchController : UITableViewController - -@property (nonatomic, weak) id delegate; -@property (nonatomic, retain) NSMutableArray *keys; - -- (void) filterResultsUsingString : (NSString *)filterString; - - -@end diff --git a/test/ios/RootBrowser/SearchController.mm b/test/ios/RootBrowser/SearchController.mm deleted file mode 100644 index 5b29d8bc076ad..0000000000000 --- a/test/ios/RootBrowser/SearchController.mm +++ /dev/null @@ -1,88 +0,0 @@ -#import "FileContainerElement.h" -#import "SearchController.h" - -@implementation SearchController { - NSArray *visibleKeys; -} - -@synthesize delegate; -@synthesize keys; - -- (void) setKeys : (NSMutableArray *)k -{ - keys = k; - visibleKeys = k; - - [self.tableView reloadData]; -} - -- (void) viewDidLoad -{ - [super viewDidLoad]; - - self.title = @"Objects and directories"; - self.contentSizeForViewInPopover = CGSizeMake(600.f, 280.f); -} - - -- (void) viewWillAppear : (BOOL)animated -{ - - // Ensure the complete list of recents is shown on first display. - [super viewWillAppear : animated]; -} - - -- (BOOL) shouldAutorotateToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation -{ - return YES; -} - - -- (void)viewDidUnload -{ - [super viewDidUnload]; -} - - -- (void) filterResultsUsingString : (NSString *) filterString -{ - // If the search string is zero-length, then restore the full list - // otherwise create a predicate to filter the recent searches using the search string. - - if ([filterString length] == 0) { - visibleKeys = keys; - } else { - NSPredicate *filterPredicate = [NSPredicate predicateWithFormat : @"self.elementName BEGINSWITH[cd] %@", filterString]; - visibleKeys = [keys filteredArrayUsingPredicate : filterPredicate]; - } - - [self.tableView reloadData]; -} - -#pragma mark Table view methods - -- (NSInteger) tableView : (UITableView *)tableView numberOfRowsInSection : (NSInteger)section -{ - return [visibleKeys count]; -} - -- (UITableViewCell *) tableView : (UITableView *)tableView cellForRowAtIndexPath : (NSIndexPath *)indexPath -{ - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier : @"Cell"]; - if (cell == nil) - cell = [[UITableViewCell alloc] initWithStyle : UITableViewCellStyleDefault reuseIdentifier : @"Cell"]; - - FileContainerElement *key = (FileContainerElement *)[visibleKeys objectAtIndex : indexPath.row]; - cell.textLabel.text = key.elementName; - return cell; -} - - -- (void) tableView : (UITableView *)tableView didSelectRowAtIndexPath : (NSIndexPath *)indexPath -{ - // Notify the delegate if a row is selected. - [delegate searchesController : self didSelectKey : (FileContainerElement *)[visibleKeys objectAtIndex : indexPath.row]]; -} - -@end diff --git a/test/ios/RootBrowser/SelectionMarkers.mm b/test/ios/RootBrowser/SelectionMarkers.mm deleted file mode 100644 index cdc529e7d71f7..0000000000000 --- a/test/ios/RootBrowser/SelectionMarkers.mm +++ /dev/null @@ -1,12 +0,0 @@ -#import "SelectionMarkers.h" - -namespace ROOT { -namespace iOS { - -void DrawBoxMarkers(CGContextRef ctx, const CGRect &box) -{ -// CGContextSetRGB -} - -} -} \ No newline at end of file diff --git a/test/ios/RootBrowser/SelectionView.h b/test/ios/RootBrowser/SelectionView.h deleted file mode 100644 index 9e79ef5567695..0000000000000 --- a/test/ios/RootBrowser/SelectionView.h +++ /dev/null @@ -1,21 +0,0 @@ -#import - -namespace ROOT { -namespace iOS { - -class Pad; - -} -} - -@interface SelectionView : UIView - -@property (nonatomic, assign) BOOL panActive; -@property (nonatomic, assign) CGPoint panStart; -@property (nonatomic, assign) CGPoint currentPanPoint; -@property (nonatomic, assign) BOOL verticalPanDirection; - -- (id)initWithFrame : (CGRect)frame withPad : (ROOT::iOS::Pad *)p; -- (void) setPad : (ROOT::iOS::Pad *)p; - -@end diff --git a/test/ios/RootBrowser/SelectionView.mm b/test/ios/RootBrowser/SelectionView.mm deleted file mode 100644 index 8a0b32f7e4326..0000000000000 --- a/test/ios/RootBrowser/SelectionView.mm +++ /dev/null @@ -1,121 +0,0 @@ -#import - -#import "IOSSelectionMarkers.h" -#import "SelectionView.h" -#import "Constants.h" -#import "PadView.h" -#import "TAxis.h" - -//C++ (ROOT) imports. -#import "IOSPad.h" - -@implementation SelectionView { - ROOT::iOS::Pad *pad; -} - -@synthesize panActive; -@synthesize panStart; -@synthesize currentPanPoint; -@synthesize verticalPanDirection; - -//____________________________________________________________________________________________________ -+ (void) setShadowColor : (CGContextRef) ctx -{ - UIColor *shadowColor = [UIColor colorWithRed : 0.f green : 0.f blue : 0.f alpha : 0.7f]; - CGContextSetShadowWithColor(ctx, CGSizeMake(3.f, 3.f), 4.f, shadowColor.CGColor); -} - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame withPad : (ROOT::iOS::Pad *) p -{ - self = [super initWithFrame:frame]; - - if (self) { - pad = p; - self.opaque = NO; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) showSelectedAxis : (CGContextRef)ctx withRect : (CGRect)rect -{ - //"Special case" function to show axis selection. - using namespace ROOT::iOS; - const CGFloat xMin = pad->GetUxmin(); - const CGFloat xMax = pad->GetUxmax(); - const CGFloat yMin = pad->GetUymin(); - const CGFloat yMax = pad->GetUymax(); - - ROOT::iOS::SpaceConverter converter(rect.size.width, pad->GetX1(), pad->GetX2(), rect.size.height, pad->GetY1(), pad->GetY2()); - GraphicUtils::DrawSelectionMarker(ctx, CGPointMake(converter.XToView(xMin), converter.YToView(yMin))); - - const TAxis *axis = static_cast(pad->GetSelected()); - if (!strcmp(axis->GetName(), "xaxis")) { - GraphicUtils::DrawSelectionMarker(ctx, CGPointMake(converter.XToView(xMax), converter.YToView(yMin))); - } else if (!strcmp(axis->GetName(), "yaxis")){ - GraphicUtils::DrawSelectionMarker(ctx, CGPointMake(converter.XToView(xMin), converter.YToView(yMax))); - }//else is "Z" but we do not care. -} - -//____________________________________________________________________________________________________ -- (void)drawRect : (CGRect)rect -{ - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - CGContextSaveGState(ctx); - - CGContextClearRect(ctx, rect); - CGContextTranslateCTM(ctx, 0.f, rect.size.height); - CGContextScaleCTM(ctx, 1.f, -1.f); - - pad->cd(); - pad->SetViewWH(rect.size.width, rect.size.height); - pad->SetContext(ctx); - - //Selected object will cast a shadow. - //if (useShadows) - if (!ROOT::iOS::Browser::deviceIsiPad3) { - [SelectionView setShadowColor : ctx]; - pad->PaintSelected(); - } else { - CGContextTranslateCTM(ctx, 2.5f, 2.5f); - pad->PaintShadowForSelected(); - CGContextTranslateCTM(ctx, -2.5f, -2.5f); - pad->PaintSelected(); - } - - //If we selected object has a polyline or polygon, markers will be painted. - //But if it's a TAxis, I can not simply draw a marker for a line segment, - //since TAxis has a lot of lines (ticks and marks). - //I have to find the position for this markers here and paint them. - if (dynamic_cast(pad->GetSelected())) - [self showSelectedAxis : ctx withRect : rect]; - - CGContextRestoreGState(ctx); - - if (panActive) { - CGContextSetRGBFillColor(ctx, 0.f, 0.f, 1.f, 0.2f); - if (!verticalPanDirection) - CGContextFillRect(ctx, CGRectMake(panStart.x, 0.f, currentPanPoint.x - panStart.x, rect.size.height)); - else - CGContextFillRect(ctx, CGRectMake(0.f, panStart.y, rect.size.width, currentPanPoint.y - panStart.y)); - } -} - -//____________________________________________________________________________________________________ -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *) event -{ - //Thanks to gyim, - //http://stackoverflow.com/questions/1694529/allowing-interaction-with-a-uiview-under-another-uiview - return NO; -} - -//____________________________________________________________________________________________________ -- (void) setPad : (ROOT::iOS::Pad *)p -{ - pad = p; -} - -@end diff --git a/test/ios/RootBrowser/Shortcuts.h b/test/ios/RootBrowser/Shortcuts.h deleted file mode 100644 index 02c02ea7d10e3..0000000000000 --- a/test/ios/RootBrowser/Shortcuts.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Shortcuts.h -// root_browser -// -// Created by Timur Pocheptsov on 8/22/11. -// Copyright 2011 __MyCompanyName__. All rights reserved. -// - -#import - - -@interface ShorcutUtil : NSObject { -} - -+(void) placeShortcuts :(NSMutableArray *)shortcuts inScrollView : (UIScrollView *) scrollView withSize : (CGSize) size andSpace : (CGFloat) space; - -@end - - diff --git a/test/ios/RootBrowser/Shortcuts.mm b/test/ios/RootBrowser/Shortcuts.mm deleted file mode 100644 index 5eb0290bd40af..0000000000000 --- a/test/ios/RootBrowser/Shortcuts.mm +++ /dev/null @@ -1,39 +0,0 @@ -// -// Shortcuts.m -// root_browser -// -// Created by Timur Pocheptsov on 8/22/11. -// Copyright 2011 __MyCompanyName__. All rights reserved. -// - -#import "Shortcuts.h" - -@implementation ShorcutUtil - -+(void) placeShortcuts :(NSMutableArray *)shortcuts inScrollView : (UIScrollView *) scrollView withSize : (CGSize) size andSpace : (CGFloat) addSpace -{ - const CGRect scrollFrame = scrollView.frame; - const CGFloat shortcutWidth = size.width; - const CGFloat shortcutHeight = size.height; - const unsigned nPicksInRow = scrollFrame.size.width / (shortcutWidth + addSpace); - const CGFloat addXY = (scrollFrame.size.width - (shortcutWidth + addSpace) * nPicksInRow) / 2; - - NSEnumerator *enumerator = [shortcuts objectEnumerator]; - UIView *v = [enumerator nextObject]; - for (unsigned n = 0; v; v = [enumerator nextObject], ++n) { - const unsigned col = n % nPicksInRow; - const unsigned row = n / nPicksInRow; - - const CGFloat x = addXY + addSpace / 2 + col * (shortcutWidth + addSpace); - const CGFloat y = row * shortcutHeight + addXY; - - CGRect frame = v.frame; - frame.origin = CGPointMake(x, y); - v.frame = frame; - } - - scrollView.contentSize = CGSizeMake(scrollFrame.size.width, addXY + ([shortcuts count] + nPicksInRow - 1) / nPicksInRow * shortcutHeight); - scrollView.contentOffset = CGPointZero; -} - -@end diff --git a/test/ios/RootBrowser/SlideView.h b/test/ios/RootBrowser/SlideView.h deleted file mode 100644 index 7bf9139fad6b7..0000000000000 --- a/test/ios/RootBrowser/SlideView.h +++ /dev/null @@ -1,19 +0,0 @@ -#import - -namespace ROOT { -namespace iOS { - -class Pad; - -} -} - -@interface SlideView : UIView - -+ (CGSize) slideSize; -+ (CGRect) slideFrame; - -- (id) initWithFrame : (CGRect)rect; -- (void) setPad : (ROOT::iOS::Pad *)pad; - -@end diff --git a/test/ios/RootBrowser/SlideView.mm b/test/ios/RootBrowser/SlideView.mm deleted file mode 100644 index 038a3024174ec..0000000000000 --- a/test/ios/RootBrowser/SlideView.mm +++ /dev/null @@ -1,68 +0,0 @@ -#import -#import - -#import "SlideView.h" - -//C++ (ROOT) imports. -#import "IOSPad.h" - -const CGRect slideFrame = CGRectMake(0.f, 0.f, 650.f, 650.f); - -@implementation SlideView { - ROOT::iOS::Pad *pad; -} - -//____________________________________________________________________________________________________ -+ (CGSize) slideSize -{ - return slideFrame.size; -} - -//____________________________________________________________________________________________________ -+ (CGRect) slideFrame -{ - return slideFrame; -} - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame -{ - self = [super initWithFrame : frame]; - - if (self) { - self.layer.shadowOpacity = 0.3f; - self.layer.shadowColor = [UIColor blackColor].CGColor; - self.layer.shadowOffset = CGSizeMake(10.f, 10.f); - self.layer.shadowPath = [UIBezierPath bezierPathWithRect : slideFrame].CGPath; - } - - return self; -} - -- (void) setPad : (ROOT::iOS::Pad *)newPad -{ - pad = newPad; -} - -//____________________________________________________________________________________________________ -- (void) drawRect : (CGRect)rect -{ - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - CGContextSetRGBFillColor(ctx, 1.f, 1.f, 1.f, 1.f); - CGContextFillRect(ctx, rect); - - if (!pad) - return; - - CGContextTranslateCTM(ctx, 0.f, rect.size.height); - CGContextScaleCTM(ctx, 1.f, -1.f); - - pad->cd(); - pad->SetViewWH(rect.size.width, rect.size.height); - pad->SetContext(ctx); - pad->Paint(); -} - - -@end diff --git a/test/ios/RootBrowser/SlideshowController.h b/test/ios/RootBrowser/SlideshowController.h deleted file mode 100644 index 4a4b917c59d12..0000000000000 --- a/test/ios/RootBrowser/SlideshowController.h +++ /dev/null @@ -1,21 +0,0 @@ -#import - -namespace ROOT { -namespace iOS { -namespace Browser { - -class FileContainer; - -} -} -} - -@interface SlideshowController : UIViewController { -@private - __weak IBOutlet UIView *parentView; - __weak IBOutlet UIView *padParentView; -} - -- (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil fileContainer : (ROOT::iOS::Browser::FileContainer *)container; - -@end diff --git a/test/ios/RootBrowser/SlideshowController.mm b/test/ios/RootBrowser/SlideshowController.mm deleted file mode 100644 index 47bff4b4099c1..0000000000000 --- a/test/ios/RootBrowser/SlideshowController.mm +++ /dev/null @@ -1,192 +0,0 @@ -#import - -#import - -#import "SlideshowController.h" -#import "SlideView.h" - -//C++ imports. -#import "IOSPad.h" - -#import "FileUtils.h" - -@implementation SlideshowController { - SlideView *padViews[2];//The current and the next in a slide show. - - unsigned visiblePad; - unsigned nCurrentObject; - - ROOT::iOS::Browser::FileContainer *fileContainer; - - NSTimer *timer; -} - -//____________________________________________________________________________________________________ -- (void) correctFramesForOrientation : (UIInterfaceOrientation) orientation -{ - CGRect mainFrame; - UIInterfaceOrientationIsPortrait(orientation) ? mainFrame = CGRectMake(0.f, 44.f, 768.f, 960.f) - : (mainFrame = CGRectMake(0.f, 44.f, 1024.f, 704.f)); - - - parentView.frame = mainFrame; - - CGRect padFrame = [SlideView slideFrame]; - padFrame.origin = CGPointMake(mainFrame.size.width / 2 - padFrame.size.width / 2, mainFrame.size.height / 2 - padFrame.size.height / 2); - - padParentView.frame = padFrame; - - if (padViews[0]) { - padFrame.origin = CGPointZero; - padViews[0].frame = padFrame; - padViews[1].frame = padFrame; - } -} - -//____________________________________________________________________________________________________ -- (void) initPadViews -{ - const CGRect padFrame = [SlideView slideFrame]; - - unsigned nObjects = fileContainer->GetNumberOfObjects(); - if (nObjects > 2) - nObjects = 2; - - for (unsigned i = 0; i < nObjects; ++i) { - padViews[i] = [[SlideView alloc] initWithFrame : padFrame]; - [padParentView addSubview : padViews[i]]; - padViews[i].hidden = YES; - } -} - -//____________________________________________________________________________________________________ -- (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil fileContainer : (ROOT::iOS::Browser::FileContainer *)container -{ - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - - if (self) { - [self view]; - - fileContainer = container; - - if (fileContainer->GetNumberOfObjects()) { - [self initPadViews]; - - nCurrentObject = 0; - visiblePad = 0; - - [padViews[0] setPad : fileContainer->GetPadAttached(0)]; - [padViews[0] setNeedsDisplay]; - - if (fileContainer->GetNumberOfObjects() > 1) { - [padViews[1] setPad:fileContainer->GetPadAttached(1)]; - [padParentView addSubview : padViews[1]]; - } - - //Ready for show now. - } - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) dealloc -{ - if (timer) - [timer invalidate]; -} - -//____________________________________________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//____________________________________________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - - [self correctFramesForOrientation : self.interfaceOrientation]; -} - -//____________________________________________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//____________________________________________________________________________________________________ -- (void) viewWillAppear : (BOOL)animated -{ - [self correctFramesForOrientation : self.interfaceOrientation]; - padViews[0].hidden = NO; -} - -//____________________________________________________________________________________________________ -- (void) viewDidAppear : (BOOL)animated -{ - if (fileContainer->GetNumberOfObjects() > 1) - timer = [NSTimer scheduledTimerWithTimeInterval : 2.f target : self selector : @selector(changeViews) userInfo : nil repeats : YES]; -} - - -//____________________________________________________________________________________________________ -- (void) viewDidDisappear:(BOOL)animated -{ - if (timer) { - [timer invalidate]; - timer = 0; - } -} - -//____________________________________________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - - return YES; -} - -//____________________________________________________________________________________________________ -- (void)willAnimateRotationToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation duration : (NSTimeInterval)duration { - [self correctFramesForOrientation : interfaceOrientation]; -} - -#pragma mark - Animation. - -//____________________________________________________________________________________________________ -- (void) changeViews -{ - const UIViewAnimationTransition animations[] = {UIViewAnimationTransitionFlipFromLeft, UIViewAnimationTransitionFlipFromRight, - UIViewAnimationTransitionCurlUp, UIViewAnimationTransitionCurlDown}; - const UIViewAnimationTransition currentAnimation = animations[rand() % 4]; - - const unsigned viewToHide = visiblePad; - const unsigned viewToShow = !visiblePad; - - [UIView beginAnimations : @"hide view" context : nil]; - [UIView setAnimationDuration : 0.5]; - [UIView setAnimationCurve : UIViewAnimationCurveEaseInOut]; - [UIView setAnimationTransition : currentAnimation forView : padParentView cache : YES]; - - padViews[viewToHide].hidden = YES; - padViews[viewToShow].hidden = NO; - - [UIView commitAnimations]; - - nCurrentObject + 1 == fileContainer->GetNumberOfObjects() ? nCurrentObject = 0 : ++nCurrentObject; - visiblePad = viewToShow; - const unsigned next = nCurrentObject + 1 == fileContainer->GetNumberOfObjects() ? 0 : nCurrentObject + 1; - [padViews[viewToHide] setPad : fileContainer->GetPadAttached(next)]; - [padViews[viewToHide] setNeedsDisplay]; -} - -@end diff --git a/test/ios/RootBrowser/SlideshowController.xib b/test/ios/RootBrowser/SlideshowController.xib deleted file mode 100644 index 75c14bdad7dc9..0000000000000 --- a/test/ios/RootBrowser/SlideshowController.xib +++ /dev/null @@ -1,261 +0,0 @@ - - - - 1056 - 11B26 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBProxyObject - IBUIView - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 256 - - YES - - - 274 - - YES - - - 274 - {{46, -37}, {1024, 709}} - - - _NS:195 - - 3 - MQA - - 2 - - - IBIPadFramework - - - {{0, 28}, {1024, 709}} - - - _NS:195 - - 3 - MC4zMzMzMzMzMzMzAA - - IBIPadFramework - - - {{0, 20}, {1024, 748}} - - - - - NO - - 2 - - - 3 - 3 - - IBIPadFramework - - - - - YES - - - parentView - - - - 20 - - - - view - - - - 21 - - - - padParentView - - - - 23 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - YES - - - - - - 18 - - - YES - - - - - - 22 - - - YES - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 18.IBPluginDependency - 2.IBPluginDependency - 22.IBPluginDependency - - - YES - SlideshowController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 25 - - - - YES - - SlideshowController - UIViewController - - YES - - YES - padParentView - parentView - - - YES - UIView - UIView - - - - YES - - YES - padParentView - parentView - - - YES - - padParentView - UIView - - - parentView - UIView - - - - - IBProjectSource - ./Classes/SlideshowController.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 534 - - diff --git a/test/ios/RootBrowser/SpotView.h b/test/ios/RootBrowser/SpotView.h deleted file mode 100644 index dacf3342dd635..0000000000000 --- a/test/ios/RootBrowser/SpotView.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface SpotView : UIView - -@end diff --git a/test/ios/RootBrowser/SpotView.mm b/test/ios/RootBrowser/SpotView.mm deleted file mode 100644 index 6a4ff24be6cff..0000000000000 --- a/test/ios/RootBrowser/SpotView.mm +++ /dev/null @@ -1,18 +0,0 @@ -#import - -#import "SpotView.h" - -@implementation SpotView - -- (id)initWithFrame:(CGRect)frame -{ - if ([super initWithFrame : frame]) { - self.alpha = 0.f; - self.multipleTouchEnabled = NO; - self.backgroundColor = [UIColor orangeColor]; - } - - return self; -} - -@end diff --git a/test/ios/RootBrowser/ThumbnailView.h b/test/ios/RootBrowser/ThumbnailView.h deleted file mode 100644 index 6cd44bac22c82..0000000000000 --- a/test/ios/RootBrowser/ThumbnailView.h +++ /dev/null @@ -1,49 +0,0 @@ -#import - -@class ThumbnailView; - -@protocol ThumbnailViewDelegate -@required -- (unsigned) numberOfThumbnailsInView : (ThumbnailView *)view; -- (UIView *) thumbnailAtIndex : (unsigned)index; -@optional -- (void) cacheDataForThumbnail : (UIView *)view; -- (void) loadDataForVisibleRange; -@end - -/* - -View with nested scroll-view with thumbnails. -Thumbnails are created by delegate. -Real data for thumbnail is loaded by delegate. -View places these thumbnails in a grid, -durign scrolling thumbnails, which became invisible, -are recycled - used for thumbnails, which became visible. -Thumbnails can contain some generic images, when scroll stopped, -delegate can load real data and create real images. -Delegate can cache images for previously shown thumbnails, -if view scrolls back, such cached images can be used instead -of loading. - -ThumbnailView must be created with initWithFrame method. -Thumbnail's size (width) + addW must be < scroll.width - 2 * addSide. - -This class was inspired by ATArrayView (Andrey Tarantsov, http://tarantsov.com/) -*/ - -@interface ThumbnailView : UIView - -@property (nonatomic, weak) id delegate; -@property (nonatomic, assign) CGFloat addSide; -@property (nonatomic, assign) CGFloat addTop; -@property (nonatomic, assign) CGFloat addW; -@property (nonatomic, assign) CGFloat addH; -@property (nonatomic, assign) CGSize itemSize; - -@property (nonatomic, readonly) unsigned firstVisibleThumbnail; -@property (nonatomic, readonly) unsigned lastVisibleThumbnail; - -- (void) loadData; -- (UIView *) getThumbnailFromCache; - -@end diff --git a/test/ios/RootBrowser/ThumbnailView.mm b/test/ios/RootBrowser/ThumbnailView.mm deleted file mode 100644 index 2409dfbe11226..0000000000000 --- a/test/ios/RootBrowser/ThumbnailView.mm +++ /dev/null @@ -1,287 +0,0 @@ -#import "ThumbnailView.h" - - -const int preloadRows = 2; - -@interface ThumbnailView () { - UIScrollView *scroll; - - NSMutableSet *visibleThumbnails; - NSMutableSet *cachedThumbnails; - - //Grid parameters. - unsigned nItems; - unsigned nCols; - unsigned nRows; - - CGFloat addX;//addSide + remaining width. -} - -- (void) calculateGridParameters; -- (void) placeThumbnail : (UIView *)thumbnail; -- (void) placeThumbnails : (BOOL)fixPositions; - -- (CGRect) frameForThumbnailAtIndex : (unsigned)index; -- (UIView *) thumbnailWithTag : (unsigned)tag; -- (void) cacheThumbnail : (UIView *)thumbnail; - -@end - -@implementation ThumbnailView - -@synthesize delegate; -@synthesize addSide; -@synthesize addTop; -@synthesize addW; -@synthesize addH; -@synthesize itemSize; - -#pragma mark - Initialization. - -//____________________________________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame -{ - //View MUST be initialized using this method. - if (self = [super initWithFrame : frame]) { - //Grid. No data load yet. - nItems = 0; - nRows = 0; - nCols = 0; - //Some "default" values for grid's geometry, - //can be modified using properties. - addTop = 50.f; - addSide = 50.f; - addW = 50.f; - addH = 50.f; - itemSize = CGSizeMake(150.f, 150.f); - - visibleThumbnails = [[NSMutableSet alloc] init]; - cachedThumbnails = [[NSMutableSet alloc] init]; - - //Setup nested scrollview. - frame.origin = CGPointZero; - - scroll = [[UIScrollView alloc] initWithFrame : frame]; - scroll.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | - UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; - scroll.contentMode = UIViewContentModeScaleToFill; - scroll.showsVerticalScrollIndicator = YES; - scroll.showsHorizontalScrollIndicator = NO; - scroll.delegate = self; - [self addSubview : scroll]; - } - - return self; -} - -//____________________________________________________________________________________________________ -- (void) loadData -{ - nItems = [delegate numberOfThumbnailsInView : self]; - - for (UIView *v in visibleThumbnails) - [self cacheThumbnail : v]; - - [visibleThumbnails removeAllObjects]; - - if (nItems) { - [self calculateGridParameters]; - [self placeThumbnails : YES]; - } -} - -#pragma mark - Geometry management. - -//____________________________________________________________________________________________________ -- (void) layoutSubviews -{ - if (nItems) { - [self calculateGridParameters]; - [self placeThumbnails : YES]; - } -} - -#pragma mark - Grid's management. - -//____________________________________________________________________________________________________ -- (void) showFirstLast -{ - NSLog(@"first %d last %d", self.firstVisibleThumbnail, self.lastVisibleThumbnail); -} - -//____________________________________________________________________________________________________ -- (void) setItemSize : (CGSize)newItemSize -{ - if (newItemSize.width + addW > scroll.bounds.size.width - 2 * addSide) { - NSLog(@"ThumbnailView -setItemSize, item size is too big"); - exit(1);//Must be an exception. Check this later. - } - - itemSize = newItemSize; -} - -//____________________________________________________________________________________________________ -- (unsigned) firstVisibleThumbnail -{ - const int firstRow = (scroll.bounds.origin.y - addTop) / (itemSize.height + addH) - preloadRows; - if (firstRow < 0) - return 0; - - return firstRow * nCols; -} - -//____________________________________________________________________________________________________ -- (unsigned) lastVisibleThumbnail -{ - //Pre-condition: nItems > 0, nCols > 0. - const int lastRow = (CGRectGetMaxY(scroll.bounds) - addTop) / (itemSize.height + addH) + 1 + preloadRows; - if (lastRow < 0) - return 0; - - if (lastRow * nCols > nItems) - return nItems - 1; - - return lastRow * nCols - 1; -} - -//____________________________________________________________________________________________________ -- (void) calculateGridParameters -{ - //Pre-condition: scroll width must be big enough to - //position at least 1 thumbnail + additional spaces. - const CGSize scrollSize = scroll.bounds.size; - - if (scrollSize.width - addSide * 2 < itemSize.width + addW) { - //I do not know, if Apple's code can somehow set the bounds to - //be so small. - NSLog(@"scroll is to small to place any thumbnail of required size"); - exit(1); - } - - nCols = (scrollSize.width - addSide * 2) / (itemSize.width + addW); - nRows = (nItems + nCols - 1) / nCols; - addX = (scrollSize.width - nCols * (itemSize.width + addW)) / 2; -} - -//____________________________________________________________________________________________________ -- (void) placeThumbnail : (UIView *)thumbnail -{ - thumbnail.frame = [self frameForThumbnailAtIndex : thumbnail.tag]; - [thumbnail setNeedsDisplay]; -} - -//____________________________________________________________________________________________________ -- (void) placeThumbnails : (BOOL) fixPos -{ - scroll.contentSize = CGSizeMake(scroll.frame.size.width, addTop * 2 + (itemSize.height + addH) * nRows - addH); - - const unsigned first = self.firstVisibleThumbnail; - const unsigned last = self.lastVisibleThumbnail; - - for (UIView *thumbnail in visibleThumbnails) { - if (thumbnail.tag < first || thumbnail.tag > last) { - //Thumbnail became invisible, remove it from scroll, - //move it into cache, cache image data. - [self cacheThumbnail : thumbnail]; - } - } - - //Remove now invisible thumbnails. - [visibleThumbnails minusSet : cachedThumbnails]; - - //Position visible thumbnails. - for (unsigned tag = first; tag <= last; ++tag) { - UIView *thumbnail = [self thumbnailWithTag : tag]; - if (!thumbnail) { - thumbnail = [delegate thumbnailAtIndex : tag]; - thumbnail.tag = tag; - [scroll addSubview : thumbnail]; - [visibleThumbnails addObject : thumbnail]; - } else if (!fixPos)//For example, during scroll, no need to update anything. - continue; - - [self placeThumbnail : thumbnail]; - } -} - -//____________________________________________________________________________________________________ -- (CGRect) frameForThumbnailAtIndex : (unsigned)index -{ - const unsigned row = index / nCols; - const unsigned col = index % nCols; - - CGRect frame = CGRectZero; - frame.origin.x = addX + (itemSize.width + addW) * col + 0.5 * addW; - frame.origin.y = addTop + (itemSize.height + addH) * row; - frame.size = itemSize; - - return frame; -} - -#pragma mark - Thumbnails caching. - -//____________________________________________________________________________________________________ -- (UIView *) getThumbnailFromCache -{ - UIView *thumbnail = (UIView *)[cachedThumbnails anyObject]; - if (thumbnail) - [cachedThumbnails removeObject : thumbnail]; - - return thumbnail; -} - -//____________________________________________________________________________________________________ -- (UIView *) thumbnailWithTag : (unsigned)tag -{ - for (UIView * view in visibleThumbnails) { - if (view.tag == tag) - return view; - } - - return nil; -} - -//____________________________________________________________________________________________________ -- (void) cacheThumbnail : (UIView *)thumbnail -{ - [cachedThumbnails addObject : thumbnail]; - - if ([delegate respondsToSelector : @selector(cacheDataForThumbnail:)]) - [delegate cacheDataForThumbnail : thumbnail];//Save icon in a cache. - - [thumbnail removeFromSuperview]; -} - -#pragma mark - Scrollview delegate. - -//____________________________________________________________________________________________________ -- (void) loadDataForVisibleRange -{ - if ([delegate respondsToSelector : @selector(loadDataForVisibleRange)]) - [delegate loadDataForVisibleRange]; -} - -//____________________________________________________________________________________________________ -- (void) scrollViewDidScroll : (UIScrollView *)scrollView -{ - [self placeThumbnails : NO]; - [self showFirstLast]; -} - -//____________________________________________________________________________________________________ -- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView -{ - //Now, ask delegate to really load objects. - [self loadDataForVisibleRange]; -} - -//____________________________________________________________________________________________________ -- (void) scrollViewDidEndDragging : (UIScrollView *)scrollView willDecelerate : (BOOL)decelerate -{ - if (!decelerate) { - //Load objects. - [self loadDataForVisibleRange]; - } -} - -@end diff --git a/test/ios/RootBrowser/TransparentToolbar.h b/test/ios/RootBrowser/TransparentToolbar.h deleted file mode 100644 index 21408c0f63ded..0000000000000 --- a/test/ios/RootBrowser/TransparentToolbar.h +++ /dev/null @@ -1,3 +0,0 @@ -@interface TransparentToolbar : UIToolbar - -@end diff --git a/test/ios/RootBrowser/TransparentToolbar.m b/test/ios/RootBrowser/TransparentToolbar.m deleted file mode 100644 index 731649c01a35f..0000000000000 --- a/test/ios/RootBrowser/TransparentToolbar.m +++ /dev/null @@ -1,10 +0,0 @@ -#import "TransparentToolbar.h" - -@implementation TransparentToolbar - -- (void) drawRect:(CGRect)rect -{ - //Ask apple, why I need this. -} - -@end diff --git a/test/ios/RootBrowser/app_icon.png b/test/ios/RootBrowser/app_icon.png deleted file mode 100644 index a1159be157589..0000000000000 Binary files a/test/ios/RootBrowser/app_icon.png and /dev/null differ diff --git a/test/ios/RootBrowser/back_btn.png b/test/ios/RootBrowser/back_btn.png deleted file mode 100644 index 03e0d1105f42a..0000000000000 Binary files a/test/ios/RootBrowser/back_btn.png and /dev/null differ diff --git a/test/ios/RootBrowser/bar-background.png b/test/ios/RootBrowser/bar-background.png deleted file mode 100644 index de3b9b38c9a86..0000000000000 Binary files a/test/ios/RootBrowser/bar-background.png and /dev/null differ diff --git a/test/ios/RootBrowser/bar-highlight.png b/test/ios/RootBrowser/bar-highlight.png deleted file mode 100644 index 9f02ed879ca3d..0000000000000 Binary files a/test/ios/RootBrowser/bar-highlight.png and /dev/null differ diff --git a/test/ios/RootBrowser/brush_tab.png b/test/ios/RootBrowser/brush_tab.png deleted file mode 100644 index 9a7518d7987c7..0000000000000 Binary files a/test/ios/RootBrowser/brush_tab.png and /dev/null differ diff --git a/test/ios/RootBrowser/dec_line_width.png b/test/ios/RootBrowser/dec_line_width.png deleted file mode 100644 index b8bda1e72dce2..0000000000000 Binary files a/test/ios/RootBrowser/dec_line_width.png and /dev/null differ diff --git a/test/ios/RootBrowser/demos.root b/test/ios/RootBrowser/demos.root deleted file mode 100644 index 24096290a1f6e..0000000000000 Binary files a/test/ios/RootBrowser/demos.root and /dev/null differ diff --git a/test/ios/RootBrowser/directory.png b/test/ios/RootBrowser/directory.png deleted file mode 100644 index 744d77c129071..0000000000000 Binary files a/test/ios/RootBrowser/directory.png and /dev/null differ diff --git a/test/ios/RootBrowser/editor_plate.png b/test/ios/RootBrowser/editor_plate.png deleted file mode 100644 index 3a44424bd4463..0000000000000 Binary files a/test/ios/RootBrowser/editor_plate.png and /dev/null differ diff --git a/test/ios/RootBrowser/editor_state_arrow.png b/test/ios/RootBrowser/editor_state_arrow.png deleted file mode 100644 index 136a73d836a4a..0000000000000 Binary files a/test/ios/RootBrowser/editor_state_arrow.png and /dev/null differ diff --git a/test/ios/RootBrowser/file_icon.png b/test/ios/RootBrowser/file_icon.png deleted file mode 100644 index a70295c283fd9..0000000000000 Binary files a/test/ios/RootBrowser/file_icon.png and /dev/null differ diff --git a/test/ios/RootBrowser/file_shortcut_background.png b/test/ios/RootBrowser/file_shortcut_background.png deleted file mode 100644 index afdcd5c1f4995..0000000000000 Binary files a/test/ios/RootBrowser/file_shortcut_background.png and /dev/null differ diff --git a/test/ios/RootBrowser/forward_btn.png b/test/ios/RootBrowser/forward_btn.png deleted file mode 100644 index d6790babfb97c..0000000000000 Binary files a/test/ios/RootBrowser/forward_btn.png and /dev/null differ diff --git a/test/ios/RootBrowser/h1_errors_tab.png b/test/ios/RootBrowser/h1_errors_tab.png deleted file mode 100644 index 011a146a5ddcc..0000000000000 Binary files a/test/ios/RootBrowser/h1_errors_tab.png and /dev/null differ diff --git a/test/ios/RootBrowser/h1_tab.png b/test/ios/RootBrowser/h1_tab.png deleted file mode 100644 index 115ae7f42bdd6..0000000000000 Binary files a/test/ios/RootBrowser/h1_tab.png and /dev/null differ diff --git a/test/ios/RootBrowser/handle-hover.png b/test/ios/RootBrowser/handle-hover.png deleted file mode 100644 index 600db3c51e835..0000000000000 Binary files a/test/ios/RootBrowser/handle-hover.png and /dev/null differ diff --git a/test/ios/RootBrowser/handle.png b/test/ios/RootBrowser/handle.png deleted file mode 100644 index f73001ec6aa30..0000000000000 Binary files a/test/ios/RootBrowser/handle.png and /dev/null differ diff --git a/test/ios/RootBrowser/inc_line_width.png b/test/ios/RootBrowser/inc_line_width.png deleted file mode 100644 index a2d32f2a2b45d..0000000000000 Binary files a/test/ios/RootBrowser/inc_line_width.png and /dev/null differ diff --git a/test/ios/RootBrowser/label_tab.png b/test/ios/RootBrowser/label_tab.png deleted file mode 100644 index 213a703701286..0000000000000 Binary files a/test/ios/RootBrowser/label_tab.png and /dev/null differ diff --git a/test/ios/RootBrowser/lg_tab.png b/test/ios/RootBrowser/lg_tab.png deleted file mode 100644 index fb21c37836573..0000000000000 Binary files a/test/ios/RootBrowser/lg_tab.png and /dev/null differ diff --git a/test/ios/RootBrowser/line_cell.png b/test/ios/RootBrowser/line_cell.png deleted file mode 100644 index f098f5f713138..0000000000000 Binary files a/test/ios/RootBrowser/line_cell.png and /dev/null differ diff --git a/test/ios/RootBrowser/line_style_tab.png b/test/ios/RootBrowser/line_style_tab.png deleted file mode 100644 index 9d765c22ea40f..0000000000000 Binary files a/test/ios/RootBrowser/line_style_tab.png and /dev/null differ diff --git a/test/ios/RootBrowser/line_width_bkn.png b/test/ios/RootBrowser/line_width_bkn.png deleted file mode 100644 index ff935d4c63c86..0000000000000 Binary files a/test/ios/RootBrowser/line_width_bkn.png and /dev/null differ diff --git a/test/ios/RootBrowser/minus_btn.png b/test/ios/RootBrowser/minus_btn.png deleted file mode 100644 index a41d20a91f947..0000000000000 Binary files a/test/ios/RootBrowser/minus_btn.png and /dev/null differ diff --git a/test/ios/RootBrowser/picker_arrow.png b/test/ios/RootBrowser/picker_arrow.png deleted file mode 100644 index 4591562d3bf4b..0000000000000 Binary files a/test/ios/RootBrowser/picker_arrow.png and /dev/null differ diff --git a/test/ios/RootBrowser/picker_bkn.png b/test/ios/RootBrowser/picker_bkn.png deleted file mode 100644 index ebfca5e217ba3..0000000000000 Binary files a/test/ios/RootBrowser/picker_bkn.png and /dev/null differ diff --git a/test/ios/RootBrowser/picker_frame_bkn.png b/test/ios/RootBrowser/picker_frame_bkn.png deleted file mode 100644 index 2087face6dc77..0000000000000 Binary files a/test/ios/RootBrowser/picker_frame_bkn.png and /dev/null differ diff --git a/test/ios/RootBrowser/plus_btn.png b/test/ios/RootBrowser/plus_btn.png deleted file mode 100644 index ae9e57983c663..0000000000000 Binary files a/test/ios/RootBrowser/plus_btn.png and /dev/null differ diff --git a/test/ios/RootBrowser/root_browser/RootBrowser-Prefix.pch b/test/ios/RootBrowser/root_browser/RootBrowser-Prefix.pch deleted file mode 100644 index 1b5328ce79a93..0000000000000 --- a/test/ios/RootBrowser/root_browser/RootBrowser-Prefix.pch +++ /dev/null @@ -1,14 +0,0 @@ -// -// Prefix header for all source files of the 'root_browser' target in the 'root_browser' project -// - -#import - -#ifndef __IPHONE_3_0 -#warning "This project uses features only available in iPhone SDK 3.0 and later." -#endif - -#ifdef __OBJC__ - #import - #import -#endif diff --git a/test/ios/RootBrowser/root_browser/en.lproj/InfoPlist.strings b/test/ios/RootBrowser/root_browser/en.lproj/InfoPlist.strings deleted file mode 100644 index 477b28ff8f86a..0000000000000 --- a/test/ios/RootBrowser/root_browser/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,2 +0,0 @@ -/* Localized versions of Info.plist keys */ - diff --git a/test/ios/RootBrowser/root_browser/en.lproj/MainWindow.xib b/test/ios/RootBrowser/root_browser/en.lproj/MainWindow.xib deleted file mode 100644 index 763101b31d6e5..0000000000000 --- a/test/ios/RootBrowser/root_browser/en.lproj/MainWindow.xib +++ /dev/null @@ -1,163 +0,0 @@ - - - - 800 - 10K549 - 1305 - 1038.36 - 461.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 300 - - - YES - IBProxyObject - IBUIWindow - IBUICustomObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - {768, 1024} - - - 3 - MC4zMzMzMzMzMzMzAA - - NO - NO - - 2 - - IBIPadFramework - YES - - - IBIPadFramework - - - - - YES - - - window - - - - 7 - - - - delegate - - - - 8 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - - - 6 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 2.IBEditorWindowLastContentRect - 2.IBPluginDependency - 6.CustomClassName - 6.IBPluginDependency - - - YES - UIApplication - UIResponder - {{226, 57}, {783, 799}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - root_browserAppDelegate - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 8 - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 300 - - diff --git a/test/ios/RootBrowser/root_browser/main.m b/test/ios/RootBrowser/root_browser/main.m deleted file mode 100644 index 8a6f93d9a6952..0000000000000 --- a/test/ios/RootBrowser/root_browser/main.m +++ /dev/null @@ -1,8 +0,0 @@ -#import - -int main(int argc, char *argv[]) -{ - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, nil); - } -} diff --git a/test/ios/RootBrowser/root_browser/root_browser-Info.plist b/test/ios/RootBrowser/root_browser/root_browser-Info.plist deleted file mode 100644 index 192990744f9cd..0000000000000 --- a/test/ios/RootBrowser/root_browser/root_browser-Info.plist +++ /dev/null @@ -1,70 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - ${PRODUCT_NAME} - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIconFile - app_icon.png - CFBundleIdentifier - ROOT.${PRODUCT_NAME:rfc1034identifier} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - LSApplicationCategoryType - - LSRequiresIPhoneOS - - NSMainNibFile - MainWindow - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CFBundleDocumentTypes - - - CFBundleTypeName - Root - LSHandlerRank - Owner - CFBundleTypeRole - Viewer - LSItemContentTypes - - ch.cern.root - - - - UTExportedTypeDeclarations - - - UTTypeIdentifier - ch.cern.root - UTTypeTagSpecification - - public.filename-extension - root - public.mime-type - root/root_browser - - - - - diff --git a/test/ios/RootBrowser/root_browser/root_browserAppDelegate.h b/test/ios/RootBrowser/root_browser/root_browserAppDelegate.h deleted file mode 100644 index 1824e81864870..0000000000000 --- a/test/ios/RootBrowser/root_browser/root_browserAppDelegate.h +++ /dev/null @@ -1,9 +0,0 @@ -#import - -@class RootFileController; - -@interface root_browserAppDelegate : NSObject - -@property (nonatomic, retain) IBOutlet UIWindow *window; - -@end diff --git a/test/ios/RootBrowser/root_browser/root_browserAppDelegate.mm b/test/ios/RootBrowser/root_browser/root_browserAppDelegate.mm deleted file mode 100644 index 149116d99b08f..0000000000000 --- a/test/ios/RootBrowser/root_browser/root_browserAppDelegate.mm +++ /dev/null @@ -1,143 +0,0 @@ -#import -#import - -#import -#import - -#include - -#import "TApplication.h" - -#import "root_browserAppDelegate.h" -#import "RootFileController.h" -#import "Constants.h" - - -namespace ROOT { -namespace iOS { - -bool deviceIsiPad3 = false; - -} -} - -@implementation root_browserAppDelegate { - TApplication *rootApp; - - UINavigationController *navigationController; - __weak RootFileController *rc; -} - -@synthesize window=_window; - -//____________________________________________________________________________________________________ -- (void) initRootController -{ - RootFileController *rootController = [[RootFileController alloc] initWithNibName : @"RootFileController" bundle : nil]; - rc = rootController; - - NSString *demosPath = [[NSBundle mainBundle] pathForResource : @"demos" ofType : @"root"]; - if (demosPath) - [rootController addRootFile : demosPath]; - - navigationController = [[UINavigationController alloc] initWithRootViewController : rootController]; - - navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent; - navigationController.delegate = rootController; - -#ifdef __IPHONE_6_0 - self.window.rootViewController = navigationController; -#endif - - [self.window addSubview : navigationController.view]; - [self.window makeKeyAndVisible]; -} - -//____________________________________________________________________________________________________ -- (BOOL) application : (UIApplication *)application didFinishLaunchingWithOptions : (NSDictionary *)launchOptions -{ - // Override point for customization after application launch. - rootApp = new TApplication("iosApp", 0, 0); - [self initRootController]; - - std::size_t dataSize = 0; - sysctlbyname("hw.machine", nullptr, &dataSize, nullptr, 0); - if (dataSize) { - std::vector line(dataSize); - sysctlbyname("hw.machine", &line[0], &dataSize, nullptr, 0); - NSString *machineName = [NSString stringWithCString : &line[0] encoding : NSASCIIStringEncoding]; - if ([machineName hasPrefix : @"iPad3,"]) - ROOT::iOS::Browser::deviceIsiPad3 = true; - } - - return YES; -} - -//____________________________________________________________________________________________________ -- (void) applicationWillResignActive : (UIApplication *)application -{ - /* - Sent when the application is about to move from active to inactive state. This can occur for certain - types of temporary interruptions (such as an incoming phone call or SMS message) or when the user - quits the application and it begins the transition to the background state. - Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. - Games should use this method to pause the game. - */ -} - -//____________________________________________________________________________________________________ -- (void) applicationDidEnterBackground : (UIApplication *)application -{ - /* - Use this method to release shared resources, save user data, invalidate timers, and store enough application - state information to restore your application to its current state in case it is terminated later. - If your application supports background execution, this method is called instead of applicationWillTerminate: - when the user quits. - */ -} - -//____________________________________________________________________________________________________ -- (void) applicationWillEnterForeground : (UIApplication *)application -{ - /* - Called as part of the transition from the background to the inactive state; - here you can undo many of the changes made on entering the background. - */ -} - -//____________________________________________________________________________________________________ -- (void) applicationDidBecomeActive : (UIApplication *)application -{ - /* - Restart any tasks that were paused (or not yet started) while the application was inactive. - If the application was previously in the background, optionally refresh the user interface. - */ -} - -//____________________________________________________________________________________________________ -- (void) applicationWillTerminate : (UIApplication *)application -{ - /* - Called when the application is about to terminate. - Save data if appropriate. - See also applicationDidEnterBackground:. - */ -} - -//____________________________________________________________________________________________________ -- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation -{ - while ([navigationController.viewControllers count] > 1) - [navigationController popViewControllerAnimated : NO]; - - [rc addRootFile : [url path]]; - return YES; -} - -//____________________________________________________________________________________________________ -- (void) dealloc -{ - delete rootApp; -} - -@end diff --git a/test/ios/RootBrowser/root_browser_icon.png b/test/ios/RootBrowser/root_browser_icon.png deleted file mode 100644 index ecd0521f03910..0000000000000 Binary files a/test/ios/RootBrowser/root_browser_icon.png and /dev/null differ diff --git a/test/ios/RootBrowser/separator.png b/test/ios/RootBrowser/separator.png deleted file mode 100644 index 98dff8ecedb7f..0000000000000 Binary files a/test/ios/RootBrowser/separator.png and /dev/null differ diff --git a/test/ios/RootBrowser/text_cell_bkn.png b/test/ios/RootBrowser/text_cell_bkn.png deleted file mode 100644 index d6fc8b22309c8..0000000000000 Binary files a/test/ios/RootBrowser/text_cell_bkn.png and /dev/null differ diff --git a/test/ios/RootBrowser/ticks_tab.png b/test/ios/RootBrowser/ticks_tab.png deleted file mode 100644 index a55f9097844a4..0000000000000 Binary files a/test/ios/RootBrowser/ticks_tab.png and /dev/null differ diff --git a/test/ios/RootBrowser/title_tab.png b/test/ios/RootBrowser/title_tab.png deleted file mode 100644 index 030d587487298..0000000000000 Binary files a/test/ios/RootBrowser/title_tab.png and /dev/null differ diff --git a/test/ios/Tutorials/DemoBase.cxx b/test/ios/Tutorials/DemoBase.cxx deleted file mode 100644 index ed434d6d1e9b0..0000000000000 --- a/test/ios/Tutorials/DemoBase.cxx +++ /dev/null @@ -1,15 +0,0 @@ -#include "DemoBase.h" - -namespace ROOT { -namespace iOS { -namespace Demos { - -//////////////////////////////////////////////////////////////////////////////// - -DemoBase::~DemoBase() -{ -} - -} -} -} diff --git a/test/ios/Tutorials/DemoBase.h b/test/ios/Tutorials/DemoBase.h deleted file mode 100644 index 0bba9f8e9156a..0000000000000 --- a/test/ios/Tutorials/DemoBase.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef ROOT_DemoBase -#define ROOT_DemoBase - -namespace ROOT { -namespace iOS { - -class Pad; - -namespace Demos { - -class DemoBase { -public: - virtual ~DemoBase(); - - virtual void ResetDemo() = 0; - virtual bool IsAnimated() const = 0; - virtual unsigned NumOfFrames() const = 0; - virtual double AnimationTime() const = 0; - virtual void StartAnimation() = 0; - virtual void NextStep() = 0; - virtual void StopAnimation() = 0; - - virtual void AdjustPad(Pad *pad) = 0; - - virtual void PresentDemo() = 0; - - virtual bool Supports3DRotation() const = 0; -}; - -} -} -} - -#endif diff --git a/test/ios/Tutorials/DemoHelper.cxx b/test/ios/Tutorials/DemoHelper.cxx deleted file mode 100644 index b625ea2198c5e..0000000000000 --- a/test/ios/Tutorials/DemoHelper.cxx +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -#include "ExclusionGraphDemo.h" -#include "PolarGraphDemo.h" -#include "HsimpleDemo.h" -#include "SurfaceDemo.h" -#include "H2PolyDemo.h" -#include "DemoHelper.h" -#include "LegoDemo.h" - -namespace ROOT { -namespace iOS { -namespace Demos { - -bool CreateTutorials(DemoBase **demos, const char *filePath) -{ - try { - std::unique_ptr demo0(new HsimpleDemo); - std::unique_ptr demo1(new SurfaceDemo); - std::unique_ptr demo2(new PolarGraphDemo); - std::unique_ptr demo3(new LegoDemo); - std::unique_ptr demo4(new ExclusionGraphDemo); - std::unique_ptr demo5(new H2PolyDemo(filePath)); - - demos[0] = demo0.release(); - demos[1] = demo1.release(); - demos[2] = demo2.release(); - demos[3] = demo3.release(); - demos[4] = demo4.release(); - demos[5] = demo5.release(); - } catch (const std::exception &e) { - return false; - } - - return true; -} - -} -} -} diff --git a/test/ios/Tutorials/DemoHelper.h b/test/ios/Tutorials/DemoHelper.h deleted file mode 100644 index 5e50d7f77eb91..0000000000000 --- a/test/ios/Tutorials/DemoHelper.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef ROOT_DemoHelper -#define ROOT_DemoHelper - -namespace ROOT { -namespace iOS { -namespace Demos { - -bool CreateTutorials(class DemoBase **demos, const char *filePath); - -} -} -} - -#endif diff --git a/test/ios/Tutorials/ExclusionGraphDemo.cxx b/test/ios/Tutorials/ExclusionGraphDemo.cxx deleted file mode 100644 index d0340ec3109f5..0000000000000 --- a/test/ios/Tutorials/ExclusionGraphDemo.cxx +++ /dev/null @@ -1,80 +0,0 @@ -#include "TMultiGraph.h" -#include "TGraph.h" -#include "TMath.h" - -#include "ExclusionGraphDemo.h" -#include "IOSPad.h" - -namespace ROOT { -namespace iOS { -namespace Demos { - -//////////////////////////////////////////////////////////////////////////////// - -ExclusionGraphDemo::ExclusionGraphDemo() - : fMultiGraph(new TMultiGraph) -{ - fMultiGraph->SetTitle("Exclusion graphs"); - - Double_t x1[kNPoints], x2[kNPoints], x3[kNPoints]; - Double_t y1[kNPoints], y2[kNPoints], y3[kNPoints]; - - for (UInt_t i = 0; i < kNPoints; ++i) { - x1[i] = i * 0.1; - x2[i] = x1[i]; - x3[i] = x1[i] + 0.5; - y1[i] = 10 * TMath::Sin(x1[i]); - y2[i] = 10 * TMath::Cos(x1[i]); - y3[i] = 10 * TMath::Sin(x1[i]) - 2; - } - - std::unique_ptr graph1(new TGraph(kNPoints, x1, y1)); - graph1->SetLineColor(2); - graph1->SetLineWidth(1504); - graph1->SetFillStyle(3005); - - std::unique_ptr graph2(new TGraph(kNPoints, x2, y2)); - graph2->SetLineColor(4); - graph2->SetLineWidth(-2002); - graph2->SetFillStyle(3004); - graph2->SetFillColor(9); - - std::unique_ptr graph3(new TGraph(kNPoints, x3, y3)); - graph3->SetLineColor(5); - graph3->SetLineWidth(-802); - graph3->SetFillStyle(3002); - graph3->SetFillColor(2); - - fMultiGraph->Add(graph1.get()); - fMultiGraph->Add(graph2.get()); - fMultiGraph->Add(graph3.get()); - - graph1.release(); - graph2.release(); - graph3.release(); -} - -//////////////////////////////////////////////////////////////////////////////// -///Just for unique_ptr's dtor. - -ExclusionGraphDemo::~ExclusionGraphDemo() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void ExclusionGraphDemo::AdjustPad(Pad *pad) -{ - pad->SetFillColor(0); -} - -//////////////////////////////////////////////////////////////////////////////// - -void ExclusionGraphDemo::PresentDemo() -{ - fMultiGraph->Draw("AC"); -} - -} -} -} diff --git a/test/ios/Tutorials/ExclusionGraphDemo.h b/test/ios/Tutorials/ExclusionGraphDemo.h deleted file mode 100644 index d74dbe81ff9ee..0000000000000 --- a/test/ios/Tutorials/ExclusionGraphDemo.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef ROOT_ExclusionGraphDemo -#define ROOT_ExclusionGraphDemo - -#include - -#include "DemoBase.h" - -class TMultiGraph; - -namespace ROOT { -namespace iOS { -namespace Demos { - -class ExclusionGraphDemo : public DemoBase { -private: - enum { - kNPoints = 35 - }; -public: - ExclusionGraphDemo(); - ~ExclusionGraphDemo(); - - //overriders. - void ResetDemo() {} - bool IsAnimated()const {return false;} - unsigned NumOfFrames()const {return 1;} - double AnimationTime()const {return 0.;} - - void StartAnimation(){} - void NextStep(){} - void StopAnimation(){} - - void AdjustPad(Pad *); - - void PresentDemo(); - - bool Supports3DRotation() const {return false;} -private: - std::unique_ptr fMultiGraph; - - ExclusionGraphDemo(const ExclusionGraphDemo &rhs); - ExclusionGraphDemo &operator = (const ExclusionGraphDemo &rhs); -}; - -} -} -} - -#endif diff --git a/test/ios/Tutorials/H2PolyDemo.cxx b/test/ios/Tutorials/H2PolyDemo.cxx deleted file mode 100644 index b14efb1dbfa7c..0000000000000 --- a/test/ios/Tutorials/H2PolyDemo.cxx +++ /dev/null @@ -1,44 +0,0 @@ -#include "TRandom.h" -#include "TH2Poly.h" -#include "TFile.h" -#include "TMath.h" -#include "TKey.h" - -#include "H2PolyDemo.h" - -namespace ROOT { -namespace iOS { -namespace Demos { - -//////////////////////////////////////////////////////////////////////////////// - -H2PolyDemo::H2PolyDemo(const char *fileName) -{ - std::unique_ptr inputFile(TFile::Open(fileName, "read")); - if (!inputFile.get()) - return; - - fPoly.reset(dynamic_cast(inputFile->Get("h2poly"))); - if (fPoly.get()) - fPoly->SetDirectory(0); -} - -//////////////////////////////////////////////////////////////////////////////// -///For unique_ptr's dtor only. - -H2PolyDemo::~H2PolyDemo() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void H2PolyDemo::PresentDemo() -{ - if (fPoly.get()) - fPoly->Draw("COLZ"); -} - - -} -} -} diff --git a/test/ios/Tutorials/H2PolyDemo.h b/test/ios/Tutorials/H2PolyDemo.h deleted file mode 100644 index 0589c78568515..0000000000000 --- a/test/ios/Tutorials/H2PolyDemo.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef ROOT_H2PolyDemo -#define ROOT_H2PolyDemo - -#include - -#include "DemoBase.h" - -class TH2Poly; - -namespace ROOT { -namespace iOS { -namespace Demos { - -class H2PolyDemo : public DemoBase { -public: - H2PolyDemo(const char *fileName); - ~H2PolyDemo(); - - //overriders. - void ResetDemo() {} - bool IsAnimated()const {return false;} - unsigned NumOfFrames()const {return 1;} - double AnimationTime()const {return 0.;} - - void StartAnimation(){} - void NextStep(){} - void StopAnimation(){} - - void AdjustPad(Pad * /*pad*/) {} - - void PresentDemo(); - - bool Supports3DRotation() const {return false;} -private: - std::unique_ptr fPoly; - - H2PolyDemo(const H2PolyDemo &rhs); - H2PolyDemo &operator = (const H2PolyDemo &rhs); -}; - -} -} -} - -#endif diff --git a/test/ios/Tutorials/HintView.h b/test/ios/Tutorials/HintView.h deleted file mode 100644 index 6993e218d42c5..0000000000000 --- a/test/ios/Tutorials/HintView.h +++ /dev/null @@ -1,7 +0,0 @@ -#import - -//View which contains hint's pictogram and textual description. - -@interface HintView : UIView -- (void) setHintIcon : (NSString*) iconName hintText : (NSString*)text; -@end diff --git a/test/ios/Tutorials/HintView.mm b/test/ios/Tutorials/HintView.mm deleted file mode 100644 index f6814dc13c65f..0000000000000 --- a/test/ios/Tutorials/HintView.mm +++ /dev/null @@ -1,54 +0,0 @@ -#import - -#import "HintView.h" - -@implementation HintView { - UIImage *iconImage; - NSString *hintText; -} - -//_________________________________________________________________ -- (id) initWithFrame : (CGRect)frame -{ - self = [super initWithFrame : frame]; - - if (self) { - // Initialization code - self.opaque = NO; - } - - return self; -} - -//_________________________________________________________________ -- (void) setHintIcon : (NSString *)iconName hintText : (NSString *)text -{ - iconImage = [UIImage imageNamed : iconName]; - hintText = text; -} - -//_________________________________________________________________ -- (void) drawRect : (CGRect)rect -{ - CGContextRef ctx = UIGraphicsGetCurrentContext(); - CGContextSetRGBFillColor(ctx, 0.3f, 0.3f, 0.3f, 0.7f); - - CGContextFillRect(ctx, rect); - - //Draw the hint's text. - CGContextSetRGBFillColor(ctx, 1.f, 1.f, 1.f, 1.f); - [hintText drawInRect:CGRectMake(0.f, 350.f, rect.size.width, rect.size.height) withFont:[UIFont systemFontOfSize:32] lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentCenter]; - - const CGPoint iconPlace = CGPointMake(rect.size.width / 2.f - 40.f, rect.size.height / 2.f - 40.f); - CGContextSetRGBFillColor(ctx, 1.f, 1.f, 1.f, 1.f); - CGContextFillRect(ctx, CGRectMake(iconPlace.x, iconPlace.y, 80.f, 80.f)); - [iconImage drawAtPoint:iconPlace]; -} - -//_________________________________________________________________ -- (void) handleTap : (UITapGestureRecognizer *)tap -{ - self.hidden = YES; -} - -@end diff --git a/test/ios/Tutorials/HsimpleDemo.cxx b/test/ios/Tutorials/HsimpleDemo.cxx deleted file mode 100644 index b8ccca3b388cc..0000000000000 --- a/test/ios/Tutorials/HsimpleDemo.cxx +++ /dev/null @@ -1,109 +0,0 @@ -#include - -#include "TRandom.h" -#include "TFrame.h" -#include "IOSPad.h" -#include "TH1.h" - -#include "HsimpleDemo.h" - - -namespace ROOT { -namespace iOS { -namespace Demos { - -//////////////////////////////////////////////////////////////////////////////// - -HsimpleDemo::HsimpleDemo() - : fHist(new TH1F("hpx", "This is the px distribution", 100, -4.f, 4.f)) -{ - if (!gRandom) - throw std::runtime_error("gRandom is null"); - - fHist->SetFillColor(48); -} - -//////////////////////////////////////////////////////////////////////////////// -///For auto-ptr dtor only. - -HsimpleDemo::~HsimpleDemo() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -///Clear old contents of the histogram. - -void HsimpleDemo::ResetDemo() -{ - fHist->Reset(); -} - -//////////////////////////////////////////////////////////////////////////////// - -Bool_t HsimpleDemo::IsAnimated()const -{ - return kTRUE; -} - -//////////////////////////////////////////////////////////////////////////////// - -unsigned HsimpleDemo::NumOfFrames() const -{ - return 25; -} - -//////////////////////////////////////////////////////////////////////////////// -///0.5 second of animation. - -double HsimpleDemo::AnimationTime() const -{ - return 0.5; -} - -//////////////////////////////////////////////////////////////////////////////// - -void HsimpleDemo::StartAnimation() -{ - fHist->Reset(); - gRandom->SetSeed(); -} - -//////////////////////////////////////////////////////////////////////////////// -///Fill histograms randomly (2D Rannor is taken from original code sample). - -void HsimpleDemo::NextStep() -{ - Float_t x = 0.f, dummyY = 0.f; - - for (UInt_t i = 0; i < 1000; ++i) { - gRandom->Rannor(x, dummyY); - fHist->Fill(x); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -void HsimpleDemo::StopAnimation() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void HsimpleDemo::AdjustPad(Pad *pad) -{ - pad->SetFillColor(42); - pad->GetFrame()->SetFillColor(21); - pad->GetFrame()->SetBorderSize(6); - pad->GetFrame()->SetBorderMode(-1); -} - -//////////////////////////////////////////////////////////////////////////////// - -void HsimpleDemo::PresentDemo() -{ - fHist->Draw(); -} - -} -} -} diff --git a/test/ios/Tutorials/HsimpleDemo.h b/test/ios/Tutorials/HsimpleDemo.h deleted file mode 100644 index b2363135accb2..0000000000000 --- a/test/ios/Tutorials/HsimpleDemo.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef ROOT_HsimpleDemo -#define ROOT_HsimpleDemo - -#include - -#include "DemoBase.h" - -class TH1F; - -namespace ROOT { -namespace iOS { -namespace Demos { - -class HsimpleDemo : public DemoBase { -public: - HsimpleDemo(); - ~HsimpleDemo(); - - //Overriders. - void ResetDemo(); - bool IsAnimated()const; - - unsigned NumOfFrames() const; - double AnimationTime() const; - - void StartAnimation(); - void NextStep(); - void StopAnimation(); - - void AdjustPad(Pad *pad); - - void PresentDemo(); - - bool Supports3DRotation() const {return false;} - -private: - std::unique_ptr fHist; - - HsimpleDemo(const HsimpleDemo &rhs); - HsimpleDemo &operator = (const HsimpleDemo &rhs); -}; - -} -} -} - -#endif diff --git a/test/ios/Tutorials/LegoDemo.cxx b/test/ios/Tutorials/LegoDemo.cxx deleted file mode 100644 index f3332bb766125..0000000000000 --- a/test/ios/Tutorials/LegoDemo.cxx +++ /dev/null @@ -1,44 +0,0 @@ -#include "IOSPad.h" -#include "TFrame.h" -#include "TF2.h" - -#include "LegoDemo.h" - -namespace ROOT { -namespace iOS { -namespace Demos { - -//////////////////////////////////////////////////////////////////////////////// -///Ctor. - -LegoDemo::LegoDemo() - : fLego(new TF2("fun1","1000*((sin(x)/x)*(sin(y)/y))+200", -6., 6., -6., 6.)) -{ - fLego->SetFillColor(kOrange); -} - -//////////////////////////////////////////////////////////////////////////////// -///Just for std::unique_ptr's dtor. - -LegoDemo::~LegoDemo() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void LegoDemo::AdjustPad(Pad *pad) -{ - pad->SetFillColor(0); -} - -//////////////////////////////////////////////////////////////////////////////// -///Draw fun of x and y as lego. - -void LegoDemo::PresentDemo() -{ - fLego->Draw("lego"); -} - -} -} -} diff --git a/test/ios/Tutorials/LegoDemo.h b/test/ios/Tutorials/LegoDemo.h deleted file mode 100644 index daccadad37988..0000000000000 --- a/test/ios/Tutorials/LegoDemo.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef ROOT_LegoDemo -#define ROOT_LegoDemo - -#include - -#include "DemoBase.h" - -class TF2; - -namespace ROOT { -namespace iOS { -namespace Demos { - -class LegoDemo : public DemoBase { -public: - LegoDemo(); - ~LegoDemo(); - - //overriders. - void ResetDemo() {} - bool IsAnimated()const {return false;} - unsigned NumOfFrames()const {return 1;} - double AnimationTime()const {return 0.;} - - void StartAnimation(){} - void NextStep(){} - void StopAnimation(){} - - void AdjustPad(Pad *pad); - - void PresentDemo(); - - bool Supports3DRotation() const {return true;} -private: - std::unique_ptr fLego; - - LegoDemo(const LegoDemo &rhs); - LegoDemo &operator = (const LegoDemo &rhs); - -}; - -} -} -} - -#endif diff --git a/test/ios/Tutorials/PadOptionsController.h b/test/ios/Tutorials/PadOptionsController.h deleted file mode 100644 index 8e57268003472..0000000000000 --- a/test/ios/Tutorials/PadOptionsController.h +++ /dev/null @@ -1,37 +0,0 @@ -#import -#import - -@class PadView; - -namespace ROOT { -namespace iOS { - -class Pad; - -} -} - - -@interface PadOptionsController : UIViewController { - __weak IBOutlet UISwitch *tickX_; - __weak IBOutlet UISwitch *tickY_; - - __weak IBOutlet UISwitch *gridX_; - __weak IBOutlet UISwitch *gridY_; - - __weak IBOutlet UISwitch *logX_; - __weak IBOutlet UISwitch *logY_; - __weak IBOutlet UISwitch *logZ_; - - __weak IBOutlet UIPickerView *colorPicker_; - __weak IBOutlet UIPickerView *patternPicker_; -} - -- (void) setView : (PadView *) view andPad : (ROOT::iOS::Pad *) pad; - - -- (IBAction) tickActivated : (id) control; -- (IBAction) gridActivated : (id) control; -- (IBAction) logActivated : (id) control; - -@end diff --git a/test/ios/Tutorials/PadOptionsController.mm b/test/ios/Tutorials/PadOptionsController.mm deleted file mode 100644 index 211b73325cec5..0000000000000 --- a/test/ios/Tutorials/PadOptionsController.mm +++ /dev/null @@ -1,236 +0,0 @@ -#import "PadOptionsController.h" -#import "PatternCell.h" -#import "ColorCell.h" -#import "PadView.h" - -//C++ code (ROOT) -#import "IOSFillPatterns.h" -#import "IOSPad.h" - -const double predefinedFillColors[16][3] = { -{1., 1., 1.}, -{0., 0., 0.}, -{251 / 255., 0., 24 / 255.}, -{40 / 255., 253 / 255., 44 / 255.}, -{31 / 255., 29 / 255., 251 / 255.}, -{253 / 255., 254 / 255., 52 / 255.}, -{253 / 255., 29 / 255., 252 / 255.}, -{53 / 255., 1., 254 / 255.}, -{94 / 255., 211 / 255., 90 / 255.}, -{92 / 255., 87 / 255., 214 / 255.}, -{135 / 255., 194 / 255., 164 / 255.}, -{127 / 255., 154 / 255., 207 / 255.}, -{211 / 255., 206 / 255., 138 / 255.}, -{220 / 255., 185 / 255., 138 / 255.}, -{209 / 255., 89 / 255., 86 / 255.}, -{147 / 255., 29 / 255., 251 / 255.} -}; - - -//Color indices in a standard ROOT's color selection control: -const unsigned colorIndices[16] = { -0, 1, 2, 3, -4, 5, 6, 7, -8, 9, 30, 38, -41, 42, 50, 51}; - - -@implementation PadOptionsController { - NSMutableArray *colors_; - NSMutableArray *patterns_; - - ROOT::iOS::Pad *pad; - PadView *padView; -} - -//_________________________________________________________________ -- (id) initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; - - if (self) { - //Color views. - colors_ = [[NSMutableArray alloc] init]; - for (unsigned i = 0; i < 16; ++i) { - ColorCell *newCell = [[ColorCell alloc] initWithFrame : CGRectMake(0.f, 0.f, 80.f, 44.f)]; - [newCell setRGB : predefinedFillColors[i]]; - [colors_ addObject : newCell]; - } - - //Patterns. - patterns_ = [[NSMutableArray alloc] init]; - //The first pattern - solid fill. - PatternCell *solidFill = [[PatternCell alloc] initWithFrame : CGRectMake(0.f, 0.f, 80.f, 44.f) andPattern : 0]; - [solidFill setAsSolid]; - [patterns_ addObject : solidFill]; - - for (unsigned i = 0; i < ROOT::iOS::GraphicUtils::kPredefinedFillPatterns; ++i) { - PatternCell *newCell = [[PatternCell alloc] initWithFrame : CGRectMake(0.f, 0.f, 80.f, 44.f) andPattern : i]; - [patterns_ addObject : newCell]; - } - - //Pattern views. - } - - return self; -} - -//_________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Release any cached data, images, etc that aren't in use. -} - -#pragma mark - View lifecycle - -//_________________________________________________________________ -- (void)viewDidLoad -{ - [super viewDidLoad]; - // Do any additional setup after loading the view from its nib. -} - -//_________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; -} - -//_________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - // Return YES for supported orientations - return YES; -} - -#pragma mark - editing. - -//_________________________________________________________________ -- (void) setView : (PadView *) view andPad : (ROOT::iOS::Pad *) newPad -{ - padView = view; - pad = newPad; - - gridX_.on = pad->GetGridx(); - gridY_.on = pad->GetGridy(); - tickX_.on = pad->GetTickx(); - tickY_.on = pad->GetTicky(); - - logX_.on = pad->GetLogx(); - logY_.on = pad->GetLogy(); - logZ_.on = pad->GetLogz(); -} - -//_________________________________________________________________ -- (IBAction) tickActivated : (id) control -{ - const unsigned on = [control isOn]; - if (control == tickX_) { - pad->SetTickx(on); - } else if (control == tickY_) { - pad->SetTicky(on); - } - - [padView setNeedsDisplay]; -} - -//_________________________________________________________________ -- (IBAction) gridActivated : (id) control -{ - const unsigned on = [control isOn]; - if (control == gridX_) { - pad->SetGridx(on); - } else if (control == gridY_) { - pad->SetGridy(on); - } - - [padView setNeedsDisplay]; -} - -//_________________________________________________________________ -- (IBAction) logActivated : (id) control -{ - const unsigned on = [control isOn]; - - if (control == logX_) - pad->SetLogx(on); - - if (control == logY_) - pad->SetLogy(on); - - if (control == logZ_) - pad->SetLogz(on); - - [padView setNeedsDisplay]; -} - -#pragma mark - color/pattern picker dataSource. -//_________________________________________________________________ -- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component -{ - return 80.; -} - -//_________________________________________________________________ -- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component -{ - return 44.; -} - -//_________________________________________________________________ -- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component -{ - if (pickerView == colorPicker_) - return [colors_ count]; - else if (pickerView == patternPicker_) - return [patterns_ count]; - return 0; -} - -//_________________________________________________________________ -- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView -{ - return 1; -} - -#pragma mark UIPickerViewDelegate - -// tell the picker which view to use for a given component and row, we have an array of views to show -//_________________________________________________________________ -- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row - forComponent:(NSInteger)component reusingView:(UIView *)view -{ - if (pickerView == colorPicker_) - return [colors_ objectAtIndex : row]; - else if (pickerView == patternPicker_) - return [patterns_ objectAtIndex : row]; - - return 0; -} - -//_________________________________________________________________ -- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { - - if (thePickerView == colorPicker_) { - if (row >= 0 && row < 16) { - pad->SetFillColor(colorIndices[row]); - [padView setNeedsDisplay]; - } - } else if (thePickerView == patternPicker_) { - //<= because of solid fill pattern. - if (row > 0 && row <= ROOT::iOS::GraphicUtils::kPredefinedFillPatterns) { - // NSLog(@"%p", pad); - pad->SetFillStyle(3000 + row); - [padView setNeedsDisplay]; - } else if (!row) { - pad->SetFillStyle(1001); - [padView setNeedsDisplay]; - } - } -} - -@end diff --git a/test/ios/Tutorials/PadOptionsController.xib b/test/ios/Tutorials/PadOptionsController.xib deleted file mode 100644 index db7a8effe383b..0000000000000 --- a/test/ios/Tutorials/PadOptionsController.xib +++ /dev/null @@ -1,882 +0,0 @@ - - - - 1056 - 10K549 - 1305 - 1038.36 - 461.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 300 - - - YES - IBUIPickerView - IBUISwitch - IBUIView - IBUILabel - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 256 - - YES - - - 290 - {{20, 90}, {100, 216}} - - - - IBIPadFramework - YES - - - - 290 - {{130, 90}, {100, 216}} - - - - IBIPadFramework - YES - - - - 292 - {{104, 20}, {42, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Pad: - - 1 - MC45ODkwNTEwOTQ5IDAgMAA - - - 1 - 10 - 1 - - - - 292 - {{43, 61}, {54, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Fill color - - 1 - MCAwIDAAA - - - 1 - 10 - - - - 292 - {{154, 61}, {52, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Fill style - - - 1 - 10 - - - - 292 - {{130, 335}, {94, 27}} - - - - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{130, 378}, {94, 27}} - - - - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{130, 423}, {94, 27}} - - - - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{130, 466}, {94, 27}} - - - - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{130, 510}, {94, 27}} - - - - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{130, 553}, {94, 27}} - - - - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{130, 595}, {94, 27}} - - - NO - IBIPadFramework - 0 - 0 - - - - 292 - {{43, 338}, {42, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Tick X: - - - 1 - 10 - - - - 292 - {{43, 381}, {42, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Tick Y: - - - 1 - 10 - - - - 292 - {{43, 426}, {42, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Grid X: - - - 1 - 10 - - - - 292 - {{43, 469}, {42, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Grid Y: - - - 1 - 10 - - - - 292 - {{43, 513}, {42, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Log X: - - - 1 - 10 - - - - 292 - {{43, 556}, {42, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Log Y: - - - 1 - 10 - - - - 292 - {{43, 598}, {42, 21}} - - - - NO - YES - 7 - NO - IBIPadFramework - Log Z: - - - 1 - 10 - - - {250, 650} - - - - - 3 - MC42NjY2NjY2NjY3AA - - IBIPadFramework - - - - - YES - - - view - - - - 24 - - - - colorPicker_ - - - - 25 - - - - patternPicker_ - - - - 26 - - - - tickX_ - - - - 27 - - - - tickY_ - - - - 28 - - - - gridX_ - - - - 29 - - - - gridY_ - - - - 30 - - - - logX_ - - - - 31 - - - - logY_ - - - - 32 - - - - logZ_ - - - - 33 - - - - delegate - - - - 34 - - - - delegate - - - - 35 - - - - dataSource - - - - 36 - - - - dataSource - - - - 37 - - - - tickActivated: - - - 13 - - 38 - - - - tickActivated: - - - 13 - - 39 - - - - gridActivated: - - - 13 - - 40 - - - - gridActivated: - - - 13 - - 41 - - - - logActivated: - - - 13 - - 42 - - - - logActivated: - - - 13 - - 43 - - - - logActivated: - - - 13 - - 44 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - YES - - - - - - - - - - - - - - - - - - - - - - - - 5 - - - - - 6 - - - - - 7 - - - - - 8 - - - - - 9 - - - - - 10 - - - - - 11 - - - - - 12 - - - - - 13 - - - - - 14 - - - - - 15 - - - - - 16 - - - - - 17 - - - - - 18 - - - - - 19 - - - - - 20 - - - - - 21 - - - - - 22 - - - - - 23 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 10.IBPluginDependency - 11.IBPluginDependency - 12.IBPluginDependency - 13.IBPluginDependency - 14.IBPluginDependency - 15.IBPluginDependency - 16.IBPluginDependency - 17.IBPluginDependency - 18.IBPluginDependency - 19.IBPluginDependency - 20.IBPluginDependency - 21.IBPluginDependency - 22.IBPluginDependency - 23.IBPluginDependency - 4.IBPluginDependency - 5.IBPluginDependency - 6.IBPluginDependency - 7.IBPluginDependency - 8.IBPluginDependency - 9.IBPluginDependency - - - YES - PadOptionsController - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 44 - - - - YES - - PadOptionsController - UIViewController - - YES - - YES - gridActivated: - logActivated: - tickActivated: - - - YES - id - id - id - - - - YES - - YES - gridActivated: - logActivated: - tickActivated: - - - YES - - gridActivated: - id - - - logActivated: - id - - - tickActivated: - id - - - - - YES - - YES - colorPicker_ - gridX_ - gridY_ - logX_ - logY_ - logZ_ - patternPicker_ - tickX_ - tickY_ - - - YES - UIPickerView - UISwitch - UISwitch - UISwitch - UISwitch - UISwitch - UIPickerView - UISwitch - UISwitch - - - - YES - - YES - colorPicker_ - gridX_ - gridY_ - logX_ - logY_ - logZ_ - patternPicker_ - tickX_ - tickY_ - - - YES - - colorPicker_ - UIPickerView - - - gridX_ - UISwitch - - - gridY_ - UISwitch - - - logX_ - UISwitch - - - logY_ - UISwitch - - - logZ_ - UISwitch - - - patternPicker_ - UIPickerView - - - tickX_ - UISwitch - - - tickY_ - UISwitch - - - - - IBProjectSource - ./Classes/PadOptionsController.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 300 - - diff --git a/test/ios/Tutorials/PadView.h b/test/ios/Tutorials/PadView.h deleted file mode 100644 index 4a48a475d1bdf..0000000000000 --- a/test/ios/Tutorials/PadView.h +++ /dev/null @@ -1,28 +0,0 @@ -#import - -/////////////////////////////////////////////////////////// -// Custom view, subview for a detail view. -// Delegates all graphics to C++ code. -/////////////////////////////////////////////////////////// - -@class SelectionView; - -namespace ROOT { -namespace iOS { - -class Pad; - -} -} - -@interface PadView : UIView - -- (id) initWithFrame : (CGRect)frame forPad : (ROOT::iOS::Pad*)pad; - -- (void) clearPad; -- (void) setSelectionView : (SelectionView *) sv; -- (void) setProcessPan : (BOOL)p; -- (void) setProcessTap : (BOOL)t; - - -@end diff --git a/test/ios/Tutorials/PadView.mm b/test/ios/Tutorials/PadView.mm deleted file mode 100644 index 6c8305ede38ec..0000000000000 --- a/test/ios/Tutorials/PadView.mm +++ /dev/null @@ -1,235 +0,0 @@ -#import -#import -#import - -#import -#import - -#import "SelectionView.h" -#import "PadView.h" - -//C++ code (ROOT's ios module) -#import "IOSPad.h" - -@interface PadView () { - ROOT::iOS::Pad *pad; - - float scaleFactor; - SelectionView *selectionView; - - BOOL processPan; - BOOL processTap; -} - -- (void) handlePanGesture : (UIPanGestureRecognizer *)panGesture; -- (void) handleTapGesture : (UITapGestureRecognizer *)tapGesture; - -@end - -@implementation PadView - -//_________________________________________________________________ -- (id) initWithFrame:(CGRect)frame forPad : (ROOT::iOS::Pad*)pd -{ - self = [super initWithFrame : frame]; - - if (self) { - //Initialize C++ objects here. - pad = pd; - - scaleFactor = frame.size.width / 640.f; - } - - return self; -} - -//_________________________________________________________________ -- (void)drawRect : (CGRect)rect -{ - // Drawing code - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - CGContextClearRect(ctx, rect); - - CGContextTranslateCTM(ctx, 0.f, rect.size.height); - CGContextScaleCTM(ctx, 1.f, -1.f); - - CGContextScaleCTM(ctx, scaleFactor, scaleFactor); - - pad->cd(); - pad->SetContext(ctx); - pad->Paint(); -} - -//_________________________________________________________________ -- (void) clearPad -{ - pad->Clear(); -} - -//_________________________________________________________________ -- (void) handlePanGesture : (UIPanGestureRecognizer *)panGesture -{ - if (!processPan) - return; - - const CGPoint p = [panGesture locationInView:self]; - [selectionView setPad : pad]; - [selectionView setShowRotation : YES]; - - if (panGesture.state == UIGestureRecognizerStateBegan) { - selectionView.hidden = NO; - [selectionView setEvent : kButton1Down atX : p.x andY : p.y]; - [selectionView setNeedsDisplay]; - } else if (panGesture.state == UIGestureRecognizerStateChanged) { - [selectionView setEvent : kButton1Motion atX : p.x andY : p.y]; - [selectionView setNeedsDisplay]; - } else if (panGesture.state == UIGestureRecognizerStateEnded) { - [selectionView setEvent : kButton1Up atX : p.x andY : p.y]; - [selectionView setNeedsDisplay]; - selectionView.hidden = YES; - [self setNeedsDisplay]; - } -} - -//_________________________________________________________________ -- (CGImageRef) initCGImageForPicking -{ - const CGRect rect = CGRectMake(0.f, 0.f, 640.f, 640.f); - //Create bitmap context. - UIGraphicsBeginImageContext(rect.size); - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - //Now draw into this context. - CGContextTranslateCTM(ctx, 0.f, rect.size.height); - CGContextScaleCTM(ctx, 1.f, -1.f); - - //Disable anti-aliasing, to avoid "non-clear" colors. - CGContextSetAllowsAntialiasing(ctx, 0); - //Fill bitmap with black (nothing under cursor). - CGContextSetRGBFillColor(ctx, 0.f, 0.f, 0.f, 1.f); - CGContextFillRect(ctx, rect); - //Set context and paint pad's contents - //with special colors (color == object's identity) - pad->SetContext(ctx); - pad->PaintForSelection(); - - UIImage *uiImageForPicking = UIGraphicsGetImageFromCurrentImageContext();//autoreleased UIImage. - CGImageRef cgImageForPicking = uiImageForPicking.CGImage; - CGImageRetain(cgImageForPicking);//It must live as long, as I need :) - - UIGraphicsEndImageContext(); - - return cgImageForPicking; - -} - -//_________________________________________________________________ -- (BOOL) fillPickingBufferFromCGImage : (CGImageRef) cgImage -{ - const size_t pixelsW = CGImageGetWidth(cgImage); - const size_t pixelsH = CGImageGetHeight(cgImage); - //Declare the number of bytes per row. Each pixel in the bitmap - //is represented by 4 bytes; 8 bits each of red, green, blue, and - //alpha. - const int bitmapBytesPerRow = pixelsW * 4; - const int bitmapByteCount = bitmapBytesPerRow * pixelsH; - - //Use the generic RGB color space. - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - if (!colorSpace) { - //Log error: color space allocation failed. - return NO; - } - - unsigned char *buffer = (unsigned char*)malloc(bitmapByteCount); - if (!buffer) { - //Log error: memory allocation failed. - CGColorSpaceRelease(colorSpace); - return NO; - } - - // Create the bitmap context. We want pre-multiplied ARGB, 8-bits - // per component. Regardless of what the source image format is - // (CMYK, Grayscale, and so on) it will be converted over to the format - // specified here by CGBitmapContextCreate. - CGContextRef ctx = CGBitmapContextCreate(buffer, pixelsW, pixelsH, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedFirst); - - CGColorSpaceRelease(colorSpace); - - if (!ctx) { - //Log error: bitmap context creation failed. - free(buffer); - return NO; - } - - const CGRect rect = CGRectMake(0.f, 0.f, pixelsW, pixelsH); - //Draw the image to the bitmap context. Once we draw, the memory - //allocated for the context for rendering will then contain the - //raw image data in the specified color space. - - CGContextSetAllowsAntialiasing(ctx, 0);//Check, if I need this for a bitmap. - CGContextDrawImage(ctx, rect, cgImage); - - pad->SetSelectionBuffer(pixelsW, pixelsH, buffer); - // When finished, release the context - CGContextRelease(ctx); - free(buffer); - - return YES; -} - -//_________________________________________________________________ -- (BOOL) initPadPicking -{ - CGImageRef cgImage = [self initCGImageForPicking]; - if (!cgImage) - return NO; - - const BOOL res = [self fillPickingBufferFromCGImage : cgImage]; - CGImageRelease(cgImage); - - return res; -} - -//_________________________________________________________________ -- (void) handleTapGesture : (UITapGestureRecognizer *) tapGesture -{ - if (processTap) { - const CGPoint tapPt = [tapGesture locationInView : self]; - - if (!pad->SelectionIsValid() && ![self initPadPicking]) - return; - - pad->Pick(tapPt.x, tapPt.y); - - if (pad->GetSelected()) { - [selectionView setShowRotation : NO]; - [selectionView setPad : pad]; - [selectionView setNeedsDisplay]; - selectionView.hidden = NO; - } else { - selectionView.hidden = YES; - } - } -} - -//_________________________________________________________________ -- (void) setSelectionView:(SelectionView *)sv -{ - selectionView = sv; -} - -//_________________________________________________________________ -- (void) setProcessPan : (BOOL) p -{ - processPan = p; -} - -//_________________________________________________________________ -- (void) setProcessTap : (BOOL) t -{ - processTap = t; -} - -@end diff --git a/test/ios/Tutorials/PatternCell.h b/test/ios/Tutorials/PatternCell.h deleted file mode 100644 index 8aac56416b44c..0000000000000 --- a/test/ios/Tutorials/PatternCell.h +++ /dev/null @@ -1,9 +0,0 @@ -#import - - -@interface PatternCell : UIView - -- (id) initWithFrame : (CGRect) frame andPattern : (unsigned) index; -- (void) setAsSolid; - -@end diff --git a/test/ios/Tutorials/PatternCell.mm b/test/ios/Tutorials/PatternCell.mm deleted file mode 100644 index b068f2232059a..0000000000000 --- a/test/ios/Tutorials/PatternCell.mm +++ /dev/null @@ -1,55 +0,0 @@ -#import - -#import "IOSFillPatterns.h" - -#import "PatternCell.h" - -@implementation PatternCell { - unsigned patternIndex; - BOOL solid; -} - -//______________________________________________________________________________ -- (id)initWithFrame:(CGRect)frame andPattern : (unsigned) index -{ - if (self = [super initWithFrame : frame]) { - // Initialization code - patternIndex = index; - solid = NO; - } - - return self; -} - -//______________________________________________________________________________ -- (void) setAsSolid -{ - solid = YES; -} - -//______________________________________________________________________________ -- (void)drawRect:(CGRect)rect -{ - CGContextRef ctx = UIGraphicsGetCurrentContext(); - - //Fill view with pattern. - CGContextSetRGBFillColor(ctx, 1.f, 1.f, 1.f, 1.f); - CGContextFillRect(ctx, rect); - - if (!solid) { //Solid fill - no pattern. - float rgb[] = {0.f, 0.f, 0.f}; - CGPatternRef pattern = ROOT::iOS::GraphicUtils::gPatternGenerators[patternIndex](rgb); - - CGColorSpaceRef colorSpace = CGColorSpaceCreatePattern(0); - const float alpha = 1.f; - - CGContextSetFillColorSpace(ctx, colorSpace); - CGContextSetFillPattern(ctx, pattern, &alpha); - CGContextFillRect(ctx, rect); - - CGColorSpaceRelease(colorSpace); - CGPatternRelease(pattern); - } -} - -@end diff --git a/test/ios/Tutorials/PictView.h b/test/ios/Tutorials/PictView.h deleted file mode 100644 index f47e48f774f83..0000000000000 --- a/test/ios/Tutorials/PictView.h +++ /dev/null @@ -1,9 +0,0 @@ -#import - -/* - Small (50x50) view to draw a hint's pictogram. -*/ - -@interface PictView : UIImageView -- (id) initWithFrame : (CGRect)frame andIcon:(NSString *)iconName; -@end diff --git a/test/ios/Tutorials/PictView.m b/test/ios/Tutorials/PictView.m deleted file mode 100644 index 6bfbadc0305e6..0000000000000 --- a/test/ios/Tutorials/PictView.m +++ /dev/null @@ -1,28 +0,0 @@ -#import - -#import "PictView.h" - -@implementation PictView - -//_________________________________________________________________ -- (id) initWithFrame : (CGRect)frame andIcon : (NSString *)iconName -{ - //self = [super initWithFrame:frame]; - - self = [super initWithImage : [UIImage imageNamed : iconName]]; - - if (self) { - self.frame = frame; - //View is transparent with shadow (under non-transparent pixels in a picture). - self.opaque = NO; - self.alpha = 0.5f; - self.layer.shadowColor = [UIColor blackColor].CGColor; - self.layer.shadowOpacity = 0.7f; - self.layer.shadowOffset = CGSizeMake(3.f, 3.f); - self.userInteractionEnabled = YES; - } - - return self; -} - -@end diff --git a/test/ios/Tutorials/Pictures/DarkBackground.png b/test/ios/Tutorials/Pictures/DarkBackground.png deleted file mode 100644 index fb83ceee1a14e..0000000000000 Binary files a/test/ios/Tutorials/Pictures/DarkBackground.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/Default-Landscape.png b/test/ios/Tutorials/Pictures/Default-Landscape.png deleted file mode 100644 index 2446a15c84878..0000000000000 Binary files a/test/ios/Tutorials/Pictures/Default-Landscape.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/Default-LandscapeLeft.png b/test/ios/Tutorials/Pictures/Default-LandscapeLeft.png deleted file mode 100644 index 2446a15c84878..0000000000000 Binary files a/test/ios/Tutorials/Pictures/Default-LandscapeLeft.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/Default-LandscapeRight.png b/test/ios/Tutorials/Pictures/Default-LandscapeRight.png deleted file mode 100644 index 2446a15c84878..0000000000000 Binary files a/test/ios/Tutorials/Pictures/Default-LandscapeRight.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/Default-Portrait.png b/test/ios/Tutorials/Pictures/Default-Portrait.png deleted file mode 100644 index 4e5b9e255d90a..0000000000000 Binary files a/test/ios/Tutorials/Pictures/Default-Portrait.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/Default-PortraitUpsideDown.png b/test/ios/Tutorials/Pictures/Default-PortraitUpsideDown.png deleted file mode 100644 index 4e5b9e255d90a..0000000000000 Binary files a/test/ios/Tutorials/Pictures/Default-PortraitUpsideDown.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/LightBackground.png b/test/ios/Tutorials/Pictures/LightBackground.png deleted file mode 100644 index 956cc261897c5..0000000000000 Binary files a/test/ios/Tutorials/Pictures/LightBackground.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/double_tap_gesture_icon.png b/test/ios/Tutorials/Pictures/double_tap_gesture_icon.png deleted file mode 100644 index 0bc2ec859f2c0..0000000000000 Binary files a/test/ios/Tutorials/Pictures/double_tap_gesture_icon.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/double_tap_gesture_icon_small.png b/test/ios/Tutorials/Pictures/double_tap_gesture_icon_small.png deleted file mode 100644 index 4fad8620e86e3..0000000000000 Binary files a/test/ios/Tutorials/Pictures/double_tap_gesture_icon_small.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/exclusion_icon_n.png b/test/ios/Tutorials/Pictures/exclusion_icon_n.png deleted file mode 100644 index a4303675addd4..0000000000000 Binary files a/test/ios/Tutorials/Pictures/exclusion_icon_n.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/h2poly_icon.png b/test/ios/Tutorials/Pictures/h2poly_icon.png deleted file mode 100644 index 2156ffc3264b3..0000000000000 Binary files a/test/ios/Tutorials/Pictures/h2poly_icon.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/hsimple_icon_n.png b/test/ios/Tutorials/Pictures/hsimple_icon_n.png deleted file mode 100644 index 83bc13282495a..0000000000000 Binary files a/test/ios/Tutorials/Pictures/hsimple_icon_n.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/lego_icon_n.png b/test/ios/Tutorials/Pictures/lego_icon_n.png deleted file mode 100644 index 9b8d4049a4745..0000000000000 Binary files a/test/ios/Tutorials/Pictures/lego_icon_n.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/no_gesture_icon.png b/test/ios/Tutorials/Pictures/no_gesture_icon.png deleted file mode 100644 index bc9af23145c4e..0000000000000 Binary files a/test/ios/Tutorials/Pictures/no_gesture_icon.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/no_gesture_icon_small.png b/test/ios/Tutorials/Pictures/no_gesture_icon_small.png deleted file mode 100644 index b065d9af42dc4..0000000000000 Binary files a/test/ios/Tutorials/Pictures/no_gesture_icon_small.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/pan_gesture_icon.png b/test/ios/Tutorials/Pictures/pan_gesture_icon.png deleted file mode 100644 index 74481d8d06bb1..0000000000000 Binary files a/test/ios/Tutorials/Pictures/pan_gesture_icon.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/pan_gesture_icon_small.png b/test/ios/Tutorials/Pictures/pan_gesture_icon_small.png deleted file mode 100644 index c07cbea33a585..0000000000000 Binary files a/test/ios/Tutorials/Pictures/pan_gesture_icon_small.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/pinch_gesture_icon.png b/test/ios/Tutorials/Pictures/pinch_gesture_icon.png deleted file mode 100644 index 4ccebb8b687c6..0000000000000 Binary files a/test/ios/Tutorials/Pictures/pinch_gesture_icon.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/pinch_gesture_icon_small.png b/test/ios/Tutorials/Pictures/pinch_gesture_icon_small.png deleted file mode 100644 index 61fbcf8f53787..0000000000000 Binary files a/test/ios/Tutorials/Pictures/pinch_gesture_icon_small.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/polar_icon_n.png b/test/ios/Tutorials/Pictures/polar_icon_n.png deleted file mode 100644 index 9faee2b304edc..0000000000000 Binary files a/test/ios/Tutorials/Pictures/polar_icon_n.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/rotate_icon.png b/test/ios/Tutorials/Pictures/rotate_icon.png deleted file mode 100644 index c9568761cf31b..0000000000000 Binary files a/test/ios/Tutorials/Pictures/rotate_icon.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/rotate_icon_small.png b/test/ios/Tutorials/Pictures/rotate_icon_small.png deleted file mode 100644 index e4597ba28035e..0000000000000 Binary files a/test/ios/Tutorials/Pictures/rotate_icon_small.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/select_mode.png b/test/ios/Tutorials/Pictures/select_mode.png deleted file mode 100644 index 6d19e2b356452..0000000000000 Binary files a/test/ios/Tutorials/Pictures/select_mode.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/single_tap_icon.png b/test/ios/Tutorials/Pictures/single_tap_icon.png deleted file mode 100644 index 3acf29e455143..0000000000000 Binary files a/test/ios/Tutorials/Pictures/single_tap_icon.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/single_tap_icon_small.png b/test/ios/Tutorials/Pictures/single_tap_icon_small.png deleted file mode 100644 index cd4d1f2c642af..0000000000000 Binary files a/test/ios/Tutorials/Pictures/single_tap_icon_small.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/surface_icon_n.png b/test/ios/Tutorials/Pictures/surface_icon_n.png deleted file mode 100644 index eb5ca81288a18..0000000000000 Binary files a/test/ios/Tutorials/Pictures/surface_icon_n.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/tutorials_app_icon.png b/test/ios/Tutorials/Pictures/tutorials_app_icon.png deleted file mode 100644 index 60163c201174f..0000000000000 Binary files a/test/ios/Tutorials/Pictures/tutorials_app_icon.png and /dev/null differ diff --git a/test/ios/Tutorials/Pictures/zoom_mode_icon.png b/test/ios/Tutorials/Pictures/zoom_mode_icon.png deleted file mode 100644 index 774298b2d9b1b..0000000000000 Binary files a/test/ios/Tutorials/Pictures/zoom_mode_icon.png and /dev/null differ diff --git a/test/ios/Tutorials/PolarGraphDemo.cxx b/test/ios/Tutorials/PolarGraphDemo.cxx deleted file mode 100644 index 279dd3196fc8e..0000000000000 --- a/test/ios/Tutorials/PolarGraphDemo.cxx +++ /dev/null @@ -1,88 +0,0 @@ -#include "TGraphPolar.h" -#include "IOSPad.h" -#include "TFrame.h" -#include "TMath.h" - -#include "PolarGraphDemo.h" - -namespace ROOT { -namespace iOS { -namespace Demos { - -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -Double_t FPlot(Double_t x) -{ - return TMath::Cos(2. * x) * TMath::Cos(20. * x); -} - -} - -//////////////////////////////////////////////////////////////////////////////// - -PolarGraphDemo::PolarGraphDemo() -{ - const Double_t xMin = 0; - const Double_t xMax = TMath::TwoPi(); - const Double_t xStep = (xMax - xMin) / kNPointsAFL; - - Double_t xAFL[kNPointsAFL]; - Double_t yAFL[kNPointsAFL]; - - for (UInt_t i = 0; i < kNPointsAFL; ++i) { - xAFL[i] = i * xStep + xMin; - yAFL[i] = FPlot(xAFL[i]); - } - - fPolarAFL.reset(new TGraphPolar(kNPointsAFL, xAFL, yAFL)); - fPolarAFL->SetLineColor(2); - fPolarAFL->SetLineWidth(0.2); - fPolarAFL->SetFillStyle(3012); - fPolarAFL->SetFillColor(2); - - Double_t xCP[kNPointsCP]; - Double_t yCP[kNPointsCP]; - - for (Int_t i = 0; i < kNPointsCP; ++i) { - xCP[i] = xAFL[kNPointsAFL / kNPointsCP * i]; - yCP[i] = yAFL[kNPointsAFL / kNPointsCP * i]; - } - - fPolarCP.reset(new TGraphPolar(kNPointsCP, xCP, yCP)); - fPolarCP->SetMarkerStyle(kFullStar); - - fPolarCP->SetMarkerSize(2); - fPolarCP->SetMarkerColor(4); - fPolarCP->SetLineColor(4); -} - -//////////////////////////////////////////////////////////////////////////////// -///Just for std::unique_ptr's dtor. - -PolarGraphDemo::~PolarGraphDemo() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void PolarGraphDemo::AdjustPad(Pad *pad) -{ - pad->SetFillColor(0); - pad->GetFrame()->SetFillColor(0); - pad->GetFrame()->SetBorderSize(1); - pad->GetFrame()->SetBorderMode(0); -} - -//////////////////////////////////////////////////////////////////////////////// - -void PolarGraphDemo::PresentDemo() -{ - fPolarAFL->Draw("AFL"); - fPolarCP->Draw("CP"); -} - -} -} -} diff --git a/test/ios/Tutorials/PolarGraphDemo.h b/test/ios/Tutorials/PolarGraphDemo.h deleted file mode 100644 index b90d2b4fc20ef..0000000000000 --- a/test/ios/Tutorials/PolarGraphDemo.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef ROOT_PolarGraphDemo -#define ROOT_PolarGraphDemo - -#include - -#include "DemoBase.h" - -class TGraphPolar; - -namespace ROOT { -namespace iOS { -namespace Demos { - -class PolarGraphDemo : public DemoBase { -private: - enum { - kNPointsAFL = 1000, - kNPointsCP = 20 - }; -public: - PolarGraphDemo(); - ~PolarGraphDemo(); - - //overriders. - void ResetDemo() {} - bool IsAnimated()const {return false;} - unsigned NumOfFrames() const {return 1;} - double AnimationTime() const {return 0.;} - - void StartAnimation() {} - void NextStep() {} - void StopAnimation() {} - - void AdjustPad(Pad *pad); - - void PresentDemo(); - - bool Supports3DRotation() const {return false;} -private: - std::unique_ptr fPolarAFL; //polar graph with draw option "AFL" - std::unique_ptr fPolarCP; //polar graph with draw option "CP" - - PolarGraphDemo(const PolarGraphDemo &rhs); - PolarGraphDemo &operator = (const PolarGraphDemo &rhs); -}; - -} -} -} - -#endif diff --git a/test/ios/Tutorials/SelectionView.h b/test/ios/Tutorials/SelectionView.h deleted file mode 100644 index f11305496c1e0..0000000000000 --- a/test/ios/Tutorials/SelectionView.h +++ /dev/null @@ -1,17 +0,0 @@ -#import - -namespace ROOT { -namespace iOS { - -class Pad; - -} -} - -@interface SelectionView : UIView - -- (void) setShowRotation : (BOOL) show; -- (void) setEvent : (int) ev atX : (int) x andY : (int) y; -- (void) setPad : (ROOT::iOS::Pad *)pad; - -@end diff --git a/test/ios/Tutorials/SelectionView.mm b/test/ios/Tutorials/SelectionView.mm deleted file mode 100644 index 21039962c77a7..0000000000000 --- a/test/ios/Tutorials/SelectionView.mm +++ /dev/null @@ -1,80 +0,0 @@ -#import "SelectionView.h" -#import "PadView.h" - -//C++ (ROOT) -#import "IOSPad.h" - -@implementation SelectionView { - BOOL showRotation; - int ev; - int px; - int py; - ROOT::iOS::Pad *pad; - - PadView *view; -} - -//______________________________________________________________________________ -- (id)initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame : frame]) { - // Initialization code - self.opaque = NO; - } - - return self; -} - -//______________________________________________________________________________ -- (void) setPad : (ROOT::iOS::Pad *)newPad -{ - pad = newPad; -} - -//______________________________________________________________________________ -- (void) setEvent : (int) e atX : (int) x andY : (int) y -{ - ev = e; - px = x; - py = y; -} - -//______________________________________________________________________________ -- (void) drawRect:(CGRect)rect -{ - if (!pad) - return; - - CGContextRef ctx = UIGraphicsGetCurrentContext(); - CGContextClearRect(ctx, rect); - - CGContextTranslateCTM(ctx, 0.f, rect.size.height); - CGContextScaleCTM(ctx, 1.f, -1.f); - - pad->cd(); - pad->SetContext(ctx); - if (showRotation) { - pad->ExecuteRotateView(ev, px, py); - } else { - CGContextTranslateCTM(ctx, 2.5f, 2.5f); - pad->PaintShadowForSelected(); - CGContextTranslateCTM(ctx, -2.5f, -2.5f); - pad->PaintSelected(); - } -} - -//______________________________________________________________________________ -- (void) setShowRotation : (BOOL) show -{ - showRotation = show; -} - -//______________________________________________________________________________ -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *) event -{ - //Thanks to gyim, - //http://stackoverflow.com/questions/1694529/allowing-interaction-with-a-uiview-under-another-uiview - return NO; -} - -@end diff --git a/test/ios/Tutorials/SurfaceDemo.cxx b/test/ios/Tutorials/SurfaceDemo.cxx deleted file mode 100644 index b371bd4577dda..0000000000000 --- a/test/ios/Tutorials/SurfaceDemo.cxx +++ /dev/null @@ -1,42 +0,0 @@ -#include "TFrame.h" -#include "IOSPad.h" -#include "TF2.h" - -#include "SurfaceDemo.h" - -namespace ROOT { -namespace iOS { -namespace Demos { - -//////////////////////////////////////////////////////////////////////////////// - -SurfaceDemo::SurfaceDemo() - : fSurface(new TF2("fun1","1000*((sin(x)/x)*(sin(y)/y))+200", -6., 6., -6., 6.)) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -///For unique_ptr dtor only. - -SurfaceDemo::~SurfaceDemo() -{ -} - -//////////////////////////////////////////////////////////////////////////////// - -void SurfaceDemo::AdjustPad(Pad *pad) -{ - pad->SetFillColor(38); -} - -//////////////////////////////////////////////////////////////////////////////// - -void SurfaceDemo::PresentDemo() -{ - fSurface->Draw("surf1"); -} - - -} -} -} diff --git a/test/ios/Tutorials/SurfaceDemo.h b/test/ios/Tutorials/SurfaceDemo.h deleted file mode 100644 index d1b5043af0827..0000000000000 --- a/test/ios/Tutorials/SurfaceDemo.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef ROOT_SurfaceDemo -#define ROOT_SurfaceDemo - -#include - -#include "DemoBase.h" - -class TF2; - -namespace ROOT { -namespace iOS { -namespace Demos { - -class SurfaceDemo : public DemoBase { -public: - SurfaceDemo(); - ~SurfaceDemo(); - - //overriders. - void ResetDemo() {} - bool IsAnimated()const {return false;} - unsigned NumOfFrames()const {return 1;} - double AnimationTime()const {return 0.;} - - void StartAnimation(){} - void NextStep(){} - void StopAnimation(){} - - void AdjustPad(Pad *pad); - - void PresentDemo(); - - bool Supports3DRotation() const {return true;} -private: - std::unique_ptr fSurface; - - SurfaceDemo(const SurfaceDemo &rhs); - SurfaceDemo &operator = (const SurfaceDemo &rhs); -}; - -} -} -} - -#endif diff --git a/test/ios/Tutorials/Tutorials.xcodeproj/ColorCell.h b/test/ios/Tutorials/Tutorials.xcodeproj/ColorCell.h deleted file mode 100644 index 7d5fc0721f1af..0000000000000 --- a/test/ios/Tutorials/Tutorials.xcodeproj/ColorCell.h +++ /dev/null @@ -1,11 +0,0 @@ -#import - -// -//This is a small and simple custom view, used inside color picker (UIPickerView). -// - -@interface ColorCell : UIView - -- (void) setRGB : (const double *) rgb; - -@end diff --git a/test/ios/Tutorials/Tutorials.xcodeproj/ColorCell.m b/test/ios/Tutorials/Tutorials.xcodeproj/ColorCell.m deleted file mode 100644 index d7d51cfb31be2..0000000000000 --- a/test/ios/Tutorials/Tutorials.xcodeproj/ColorCell.m +++ /dev/null @@ -1,36 +0,0 @@ -#import - -#import "ColorCell.h" - -@implementation ColorCell { - double rgb[3]; -} - -//______________________________________________________________________________ -- (id) initWithFrame : (CGRect)frame -{ - if (self = [super initWithFrame : frame]) { - // Initialization code - self.backgroundColor = [UIColor clearColor]; - } - - return self; -} - -//______________________________________________________________________________ -- (void) setRGB : (const double *) newRgb -{ - rgb[0] = newRgb[0]; - rgb[1] = newRgb[1]; - rgb[2] = newRgb[2]; -} - -//______________________________________________________________________________ -- (void)drawRect:(CGRect)rect -{ - CGContextRef ctx = UIGraphicsGetCurrentContext(); - CGContextSetRGBFillColor(ctx, (CGFloat)rgb[0], (CGFloat)rgb[1], (CGFloat)rgb[2], 1.f); - CGContextFillRect(ctx, rect); -} - -@end diff --git a/test/ios/Tutorials/Tutorials.xcodeproj/project.pbxproj b/test/ios/Tutorials/Tutorials.xcodeproj/project.pbxproj deleted file mode 100644 index 0cec8766b96f4..0000000000000 --- a/test/ios/Tutorials/Tutorials.xcodeproj/project.pbxproj +++ /dev/null @@ -1,614 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 700542EE13E5B2F40093B598 /* zoom_mode_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 700542ED13E5B2F40093B598 /* zoom_mode_icon.png */; }; - 700B010F13F3D40A00F84650 /* PadOptionsController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 700B010D13F3D40A00F84650 /* PadOptionsController.mm */; }; - 700B011013F3D40A00F84650 /* PadOptionsController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 700B010E13F3D40A00F84650 /* PadOptionsController.xib */; }; - 700B013013F3FD6700F84650 /* ColorCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 700B012F13F3FD6600F84650 /* ColorCell.m */; }; - 700B013313F4051000F84650 /* PatternCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 700B013213F4051000F84650 /* PatternCell.mm */; }; - 7010C3691455B64100018E6D /* tutorials_app_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 7010C3681455B64100018E6D /* tutorials_app_icon.png */; }; - 701EC32513D9762200FE395E /* SelectionView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 701EC32413D9762200FE395E /* SelectionView.mm */; }; - 702C4FCA13F2BE2D00C645D8 /* h2poly.root in Resources */ = {isa = PBXBuildFile; fileRef = 702C4FC913F2BE2D00C645D8 /* h2poly.root */; }; - 7032144C13E68F5E00908306 /* HelpView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7032144B13E68F5E00908306 /* HelpView.xib */; }; - 7032144E13E6963400908306 /* exclusion_icon_n.png in Resources */ = {isa = PBXBuildFile; fileRef = 7032144D13E6963400908306 /* exclusion_icon_n.png */; }; - 7059E24513CC394C0007E4E1 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7059E24413CC394C0007E4E1 /* libz.dylib */; }; - 707327D413DF126C00E5B12B /* Default-LandscapeRight.png in Resources */ = {isa = PBXBuildFile; fileRef = 707327D113DF126C00E5B12B /* Default-LandscapeRight.png */; }; - 707327D513DF126C00E5B12B /* Default-LandscapeLeft.png in Resources */ = {isa = PBXBuildFile; fileRef = 707327D213DF126C00E5B12B /* Default-LandscapeLeft.png */; }; - 707327D613DF126C00E5B12B /* Default-Landscape.png in Resources */ = {isa = PBXBuildFile; fileRef = 707327D313DF126C00E5B12B /* Default-Landscape.png */; }; - 7074C90413DF0F99000CABF5 /* Default-PortraitUpsideDown.png in Resources */ = {isa = PBXBuildFile; fileRef = 7074C90213DF0F99000CABF5 /* Default-PortraitUpsideDown.png */; }; - 7074C90513DF0F99000CABF5 /* Default-Portrait.png in Resources */ = {isa = PBXBuildFile; fileRef = 7074C90313DF0F99000CABF5 /* Default-Portrait.png */; }; - 707644B113EFC6AA00C302F9 /* H2PolyDemo.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 707644AF13EFC6AA00C302F9 /* H2PolyDemo.cxx */; }; - 707CF11513F8128700829823 /* libRoot.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 707CF11113F8128600829823 /* libRoot.a */; }; - 707CF11613F8128700829823 /* libfreetype.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 707CF11213F8128600829823 /* libfreetype.a */; }; - 707CF11713F8128700829823 /* liblzma.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 707CF11313F8128600829823 /* liblzma.a */; }; - 707CF11813F8128700829823 /* libpcre.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 707CF11413F8128600829823 /* libpcre.a */; }; - 707CF12313F8143700829823 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 707CF12213F8143700829823 /* QuartzCore.framework */; }; - 707CF12513F8145800829823 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 707CF12413F8145800829823 /* CoreText.framework */; }; - 707EECB713DF3FC100873F81 /* no_gesture_icon_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 707EECB513DF3FC100873F81 /* no_gesture_icon_small.png */; }; - 707EECB813DF3FC100873F81 /* no_gesture_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 707EECB613DF3FC100873F81 /* no_gesture_icon.png */; }; - 7085572013C73AD900022713 /* PadView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7085571F13C73AD900022713 /* PadView.mm */; }; - 7098E93F13F2BA470032D660 /* h2poly_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 7098E93E13F2BA470032D660 /* h2poly_icon.png */; }; - 709A653313EFD53700612A38 /* system.rootrc in Resources */ = {isa = PBXBuildFile; fileRef = 709A653213EFD53700612A38 /* system.rootrc */; }; - 70A3D4BE13E84F8200C39E40 /* select_mode.png in Resources */ = {isa = PBXBuildFile; fileRef = 70A3D4BD13E84F8200C39E40 /* select_mode.png */; }; - 70BA9B4413C5F89100102BC9 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70BA9B4313C5F89100102BC9 /* UIKit.framework */; }; - 70BA9B4613C5F89100102BC9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70BA9B4513C5F89100102BC9 /* Foundation.framework */; }; - 70BA9B4813C5F89100102BC9 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70BA9B4713C5F89100102BC9 /* CoreGraphics.framework */; }; - 70BA9B4E13C5F89100102BC9 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 70BA9B4C13C5F89100102BC9 /* InfoPlist.strings */; }; - 70BA9B5113C5F89100102BC9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 70BA9B5013C5F89100102BC9 /* main.m */; }; - 70BA9B5413C5F89100102BC9 /* TutorialsAppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70BA9B5313C5F89100102BC9 /* TutorialsAppDelegate.mm */; }; - 70BA9B5713C5F89100102BC9 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 70BA9B5513C5F89100102BC9 /* MainWindow.xib */; }; - 70BA9B5A13C5F89100102BC9 /* DetailViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70BA9B5913C5F89100102BC9 /* DetailViewController.mm */; }; - 70BA9B5D13C5F89100102BC9 /* DetailView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 70BA9B5B13C5F89100102BC9 /* DetailView.xib */; }; - 70BA9B6013C5F89100102BC9 /* RootViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70BA9B5F13C5F89100102BC9 /* RootViewController.mm */; }; - 70C8237C13CF790E00F884FF /* HintView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 70C8237B13CF790E00F884FF /* HintView.mm */; }; - 70CC7E4A1456A7050036FF4C /* DemoHelper.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 70CC7E481456A7050036FF4C /* DemoHelper.cxx */; }; - 70D3FB5213E7F605005BADA3 /* single_tap_icon_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 70D3FB5013E7F605005BADA3 /* single_tap_icon_small.png */; }; - 70D3FB5313E7F605005BADA3 /* single_tap_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 70D3FB5113E7F605005BADA3 /* single_tap_icon.png */; }; - 70D4848013F057430043110B /* system.plugins-ios in Resources */ = {isa = PBXBuildFile; fileRef = 70D4847F13F057430043110B /* system.plugins-ios */; }; - 70D645FD13D3243A00CE9FB1 /* PictView.m in Sources */ = {isa = PBXBuildFile; fileRef = 70D645FC13D3243A00CE9FB1 /* PictView.m */; }; - 70DF816013DDBA6400AD2F4D /* DemoBase.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 70DF815A13DDBA6400AD2F4D /* DemoBase.cxx */; }; - 70DF816113DDBA6400AD2F4D /* ExclusionGraphDemo.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 70DF815B13DDBA6400AD2F4D /* ExclusionGraphDemo.cxx */; }; - 70DF816213DDBA6400AD2F4D /* HsimpleDemo.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 70DF815C13DDBA6400AD2F4D /* HsimpleDemo.cxx */; }; - 70DF816313DDBA6400AD2F4D /* LegoDemo.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 70DF815D13DDBA6400AD2F4D /* LegoDemo.cxx */; }; - 70DF816413DDBA6400AD2F4D /* PolarGraphDemo.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 70DF815E13DDBA6400AD2F4D /* PolarGraphDemo.cxx */; }; - 70DF816513DDBA6400AD2F4D /* SurfaceDemo.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 70DF815F13DDBA6400AD2F4D /* SurfaceDemo.cxx */; }; - 70DF817613DDBB0D00AD2F4D /* double_tap_gesture_icon_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF816713DDBB0D00AD2F4D /* double_tap_gesture_icon_small.png */; }; - 70DF817713DDBB0D00AD2F4D /* double_tap_gesture_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF816813DDBB0D00AD2F4D /* double_tap_gesture_icon.png */; }; - 70DF817813DDBB0D00AD2F4D /* hsimple_icon_n.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF816913DDBB0D00AD2F4D /* hsimple_icon_n.png */; }; - 70DF817913DDBB0D00AD2F4D /* lego_icon_n.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF816A13DDBB0D00AD2F4D /* lego_icon_n.png */; }; - 70DF817A13DDBB0D00AD2F4D /* pan_gesture_icon_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF816B13DDBB0D00AD2F4D /* pan_gesture_icon_small.png */; }; - 70DF817B13DDBB0D00AD2F4D /* pan_gesture_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF816C13DDBB0D00AD2F4D /* pan_gesture_icon.png */; }; - 70DF817C13DDBB0D00AD2F4D /* pinch_gesture_icon_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF816D13DDBB0D00AD2F4D /* pinch_gesture_icon_small.png */; }; - 70DF817D13DDBB0D00AD2F4D /* pinch_gesture_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF816E13DDBB0D00AD2F4D /* pinch_gesture_icon.png */; }; - 70DF817E13DDBB0D00AD2F4D /* polar_icon_n.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF816F13DDBB0D00AD2F4D /* polar_icon_n.png */; }; - 70DF817F13DDBB0D00AD2F4D /* rotate_icon_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF817013DDBB0D00AD2F4D /* rotate_icon_small.png */; }; - 70DF818013DDBB0D00AD2F4D /* rotate_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF817113DDBB0D00AD2F4D /* rotate_icon.png */; }; - 70DF818213DDBB0D00AD2F4D /* surface_icon_n.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF817313DDBB0D00AD2F4D /* surface_icon_n.png */; }; - 70DF818A13DDBC1800AD2F4D /* DarkBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF818813DDBC1800AD2F4D /* DarkBackground.png */; }; - 70DF818B13DDBC1800AD2F4D /* LightBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = 70DF818913DDBC1800AD2F4D /* LightBackground.png */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 700542ED13E5B2F40093B598 /* zoom_mode_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = zoom_mode_icon.png; path = Pictures/zoom_mode_icon.png; sourceTree = ""; }; - 700B010C13F3D40A00F84650 /* PadOptionsController.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = PadOptionsController.h; sourceTree = ""; }; - 700B010D13F3D40A00F84650 /* PadOptionsController.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = PadOptionsController.mm; sourceTree = ""; }; - 700B010E13F3D40A00F84650 /* PadOptionsController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = PadOptionsController.xib; path = ../PadOptionsController.xib; sourceTree = ""; }; - 700B012E13F3FD6600F84650 /* ColorCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ColorCell.h; path = Tutorials.xcodeproj/ColorCell.h; sourceTree = ""; }; - 700B012F13F3FD6600F84650 /* ColorCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ColorCell.m; path = Tutorials.xcodeproj/ColorCell.m; sourceTree = ""; }; - 700B013113F4051000F84650 /* PatternCell.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = PatternCell.h; sourceTree = ""; }; - 700B013213F4051000F84650 /* PatternCell.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = PatternCell.mm; sourceTree = ""; }; - 7010C3681455B64100018E6D /* tutorials_app_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tutorials_app_icon.png; path = Pictures/tutorials_app_icon.png; sourceTree = ""; }; - 701EC32313D9762200FE395E /* SelectionView.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = SelectionView.h; sourceTree = ""; }; - 701EC32413D9762200FE395E /* SelectionView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SelectionView.mm; sourceTree = ""; }; - 702C4FC913F2BE2D00C645D8 /* h2poly.root */ = {isa = PBXFileReference; lastKnownFileType = file; path = h2poly.root; sourceTree = ""; }; - 7032144B13E68F5E00908306 /* HelpView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HelpView.xib; sourceTree = ""; }; - 7032144D13E6963400908306 /* exclusion_icon_n.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = exclusion_icon_n.png; path = Pictures/exclusion_icon_n.png; sourceTree = ""; }; - 7059E24413CC394C0007E4E1 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; - 707327D113DF126C00E5B12B /* Default-LandscapeRight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-LandscapeRight.png"; path = "Pictures/Default-LandscapeRight.png"; sourceTree = ""; }; - 707327D213DF126C00E5B12B /* Default-LandscapeLeft.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-LandscapeLeft.png"; path = "Pictures/Default-LandscapeLeft.png"; sourceTree = ""; }; - 707327D313DF126C00E5B12B /* Default-Landscape.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-Landscape.png"; path = "Pictures/Default-Landscape.png"; sourceTree = ""; }; - 7074C90213DF0F99000CABF5 /* Default-PortraitUpsideDown.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-PortraitUpsideDown.png"; path = "Pictures/Default-PortraitUpsideDown.png"; sourceTree = ""; }; - 7074C90313DF0F99000CABF5 /* Default-Portrait.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-Portrait.png"; path = "Pictures/Default-Portrait.png"; sourceTree = ""; }; - 707644AF13EFC6AA00C302F9 /* H2PolyDemo.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = H2PolyDemo.cxx; sourceTree = ""; }; - 707644B013EFC6AA00C302F9 /* H2PolyDemo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = H2PolyDemo.h; sourceTree = ""; }; - 707CF11113F8128600829823 /* libRoot.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libRoot.a; path = ../../../../lib/libRoot.a; sourceTree = ""; }; - 707CF11213F8128600829823 /* libfreetype.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfreetype.a; path = ../../../../lib/libfreetype.a; sourceTree = ""; }; - 707CF11313F8128600829823 /* liblzma.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liblzma.a; path = ../../../../lib/liblzma.a; sourceTree = ""; }; - 707CF11413F8128600829823 /* libpcre.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpcre.a; path = ../../../../lib/libpcre.a; sourceTree = ""; }; - 707CF12213F8143700829823 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - 707CF12413F8145800829823 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; - 707EECB513DF3FC100873F81 /* no_gesture_icon_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = no_gesture_icon_small.png; path = Pictures/no_gesture_icon_small.png; sourceTree = ""; }; - 707EECB613DF3FC100873F81 /* no_gesture_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = no_gesture_icon.png; path = Pictures/no_gesture_icon.png; sourceTree = ""; }; - 7085571E13C73AD900022713 /* PadView.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = PadView.h; sourceTree = ""; }; - 7085571F13C73AD900022713 /* PadView.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = PadView.mm; sourceTree = ""; }; - 7098E93E13F2BA470032D660 /* h2poly_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = h2poly_icon.png; path = Pictures/h2poly_icon.png; sourceTree = ""; }; - 709A653213EFD53700612A38 /* system.rootrc */ = {isa = PBXFileReference; lastKnownFileType = text; name = system.rootrc; path = ../../../etc/system.rootrc; sourceTree = ""; }; - 70A3D4BD13E84F8200C39E40 /* select_mode.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = select_mode.png; path = Pictures/select_mode.png; sourceTree = ""; }; - 70B059C413C9927700583EDB /* DemoBase.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = DemoBase.h; sourceTree = ""; }; - 70B059C813C9948000583EDB /* HsimpleDemo.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = HsimpleDemo.h; sourceTree = ""; }; - 70BA9B3F13C5F89100102BC9 /* Tutorials.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Tutorials.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 70BA9B4313C5F89100102BC9 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 70BA9B4513C5F89100102BC9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 70BA9B4713C5F89100102BC9 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 70BA9B4B13C5F89100102BC9 /* Tutorials-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tutorials-Info.plist"; sourceTree = ""; }; - 70BA9B4D13C5F89100102BC9 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 70BA9B4F13C5F89100102BC9 /* Tutorials-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tutorials-Prefix.pch"; sourceTree = ""; }; - 70BA9B5013C5F89100102BC9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Tutorials/main.m; sourceTree = ""; }; - 70BA9B5213C5F89100102BC9 /* TutorialsAppDelegate.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; name = TutorialsAppDelegate.h; path = Tutorials/TutorialsAppDelegate.h; sourceTree = ""; }; - 70BA9B5313C5F89100102BC9 /* TutorialsAppDelegate.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; name = TutorialsAppDelegate.mm; path = Tutorials/TutorialsAppDelegate.mm; sourceTree = ""; }; - 70BA9B5613C5F89100102BC9 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = ""; }; - 70BA9B5813C5F89100102BC9 /* DetailViewController.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; name = DetailViewController.h; path = Tutorials/DetailViewController.h; sourceTree = ""; }; - 70BA9B5913C5F89100102BC9 /* DetailViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = DetailViewController.mm; path = Tutorials/DetailViewController.mm; sourceTree = ""; }; - 70BA9B5C13C5F89100102BC9 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/DetailView.xib; sourceTree = ""; }; - 70BA9B5E13C5F89100102BC9 /* RootViewController.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; name = RootViewController.h; path = Tutorials/RootViewController.h; sourceTree = ""; }; - 70BA9B5F13C5F89100102BC9 /* RootViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = RootViewController.mm; path = Tutorials/RootViewController.mm; sourceTree = ""; }; - 70C8237A13CF790E00F884FF /* HintView.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = HintView.h; sourceTree = ""; }; - 70C8237B13CF790E00F884FF /* HintView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HintView.mm; sourceTree = ""; }; - 70CC7E481456A7050036FF4C /* DemoHelper.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DemoHelper.cxx; sourceTree = ""; }; - 70CC7E491456A7050036FF4C /* DemoHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoHelper.h; sourceTree = ""; }; - 70D3FB5013E7F605005BADA3 /* single_tap_icon_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = single_tap_icon_small.png; path = Pictures/single_tap_icon_small.png; sourceTree = ""; }; - 70D3FB5113E7F605005BADA3 /* single_tap_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = single_tap_icon.png; path = Pictures/single_tap_icon.png; sourceTree = ""; }; - 70D4847F13F057430043110B /* system.plugins-ios */ = {isa = PBXFileReference; lastKnownFileType = text; name = "system.plugins-ios"; path = "../../../etc/system.plugins-ios"; sourceTree = ""; }; - 70D645FB13D3243A00CE9FB1 /* PictView.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = PictView.h; sourceTree = ""; }; - 70D645FC13D3243A00CE9FB1 /* PictView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PictView.m; sourceTree = ""; }; - 70DF815A13DDBA6400AD2F4D /* DemoBase.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DemoBase.cxx; sourceTree = ""; }; - 70DF815B13DDBA6400AD2F4D /* ExclusionGraphDemo.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExclusionGraphDemo.cxx; sourceTree = ""; }; - 70DF815C13DDBA6400AD2F4D /* HsimpleDemo.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HsimpleDemo.cxx; sourceTree = ""; }; - 70DF815D13DDBA6400AD2F4D /* LegoDemo.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LegoDemo.cxx; sourceTree = ""; }; - 70DF815E13DDBA6400AD2F4D /* PolarGraphDemo.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PolarGraphDemo.cxx; sourceTree = ""; }; - 70DF815F13DDBA6400AD2F4D /* SurfaceDemo.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SurfaceDemo.cxx; sourceTree = ""; }; - 70DF816713DDBB0D00AD2F4D /* double_tap_gesture_icon_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = double_tap_gesture_icon_small.png; path = Pictures/double_tap_gesture_icon_small.png; sourceTree = ""; }; - 70DF816813DDBB0D00AD2F4D /* double_tap_gesture_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = double_tap_gesture_icon.png; path = Pictures/double_tap_gesture_icon.png; sourceTree = ""; }; - 70DF816913DDBB0D00AD2F4D /* hsimple_icon_n.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = hsimple_icon_n.png; path = Pictures/hsimple_icon_n.png; sourceTree = ""; }; - 70DF816A13DDBB0D00AD2F4D /* lego_icon_n.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = lego_icon_n.png; path = Pictures/lego_icon_n.png; sourceTree = ""; }; - 70DF816B13DDBB0D00AD2F4D /* pan_gesture_icon_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = pan_gesture_icon_small.png; path = Pictures/pan_gesture_icon_small.png; sourceTree = ""; }; - 70DF816C13DDBB0D00AD2F4D /* pan_gesture_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = pan_gesture_icon.png; path = Pictures/pan_gesture_icon.png; sourceTree = ""; }; - 70DF816D13DDBB0D00AD2F4D /* pinch_gesture_icon_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = pinch_gesture_icon_small.png; path = Pictures/pinch_gesture_icon_small.png; sourceTree = ""; }; - 70DF816E13DDBB0D00AD2F4D /* pinch_gesture_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = pinch_gesture_icon.png; path = Pictures/pinch_gesture_icon.png; sourceTree = ""; }; - 70DF816F13DDBB0D00AD2F4D /* polar_icon_n.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = polar_icon_n.png; path = Pictures/polar_icon_n.png; sourceTree = ""; }; - 70DF817013DDBB0D00AD2F4D /* rotate_icon_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = rotate_icon_small.png; path = Pictures/rotate_icon_small.png; sourceTree = ""; }; - 70DF817113DDBB0D00AD2F4D /* rotate_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = rotate_icon.png; path = Pictures/rotate_icon.png; sourceTree = ""; }; - 70DF817313DDBB0D00AD2F4D /* surface_icon_n.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = surface_icon_n.png; path = Pictures/surface_icon_n.png; sourceTree = ""; }; - 70DF818813DDBC1800AD2F4D /* DarkBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = DarkBackground.png; path = Pictures/DarkBackground.png; sourceTree = ""; }; - 70DF818913DDBC1800AD2F4D /* LightBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = LightBackground.png; path = Pictures/LightBackground.png; sourceTree = ""; }; - 70ED86D313CB46BA00919971 /* SurfaceDemo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SurfaceDemo.h; sourceTree = ""; }; - 70ED86D713CB504A00919971 /* PolarGraphDemo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolarGraphDemo.h; sourceTree = ""; }; - 70ED86DB13CB76C400919971 /* LegoDemo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LegoDemo.h; sourceTree = ""; }; - 70ED86DE13CB788A00919971 /* ExclusionGraphDemo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExclusionGraphDemo.h; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 70BA9B3C13C5F89100102BC9 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 707CF12513F8145800829823 /* CoreText.framework in Frameworks */, - 707CF12313F8143700829823 /* QuartzCore.framework in Frameworks */, - 707CF11513F8128700829823 /* libRoot.a in Frameworks */, - 707CF11613F8128700829823 /* libfreetype.a in Frameworks */, - 707CF11713F8128700829823 /* liblzma.a in Frameworks */, - 707CF11813F8128700829823 /* libpcre.a in Frameworks */, - 7059E24513CC394C0007E4E1 /* libz.dylib in Frameworks */, - 70BA9B4413C5F89100102BC9 /* UIKit.framework in Frameworks */, - 70BA9B4613C5F89100102BC9 /* Foundation.framework in Frameworks */, - 70BA9B4813C5F89100102BC9 /* CoreGraphics.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 707CF10C13F8118D00829823 /* ROOT files */ = { - isa = PBXGroup; - children = ( - 709A653213EFD53700612A38 /* system.rootrc */, - 70D4847F13F057430043110B /* system.plugins-ios */, - 702C4FC913F2BE2D00C645D8 /* h2poly.root */, - ); - name = "ROOT files"; - sourceTree = ""; - }; - 707CF10D13F811AD00829823 /* Images */ = { - isa = PBXGroup; - children = ( - 7010C3681455B64100018E6D /* tutorials_app_icon.png */, - 70DF818813DDBC1800AD2F4D /* DarkBackground.png */, - 70DF818913DDBC1800AD2F4D /* LightBackground.png */, - 70DF816713DDBB0D00AD2F4D /* double_tap_gesture_icon_small.png */, - 70DF816813DDBB0D00AD2F4D /* double_tap_gesture_icon.png */, - 70DF816913DDBB0D00AD2F4D /* hsimple_icon_n.png */, - 70DF816A13DDBB0D00AD2F4D /* lego_icon_n.png */, - 70DF816B13DDBB0D00AD2F4D /* pan_gesture_icon_small.png */, - 70DF816C13DDBB0D00AD2F4D /* pan_gesture_icon.png */, - 70DF816D13DDBB0D00AD2F4D /* pinch_gesture_icon_small.png */, - 70DF816E13DDBB0D00AD2F4D /* pinch_gesture_icon.png */, - 70DF816F13DDBB0D00AD2F4D /* polar_icon_n.png */, - 70DF817013DDBB0D00AD2F4D /* rotate_icon_small.png */, - 70DF817113DDBB0D00AD2F4D /* rotate_icon.png */, - 70DF817313DDBB0D00AD2F4D /* surface_icon_n.png */, - 70D3FB5013E7F605005BADA3 /* single_tap_icon_small.png */, - 70D3FB5113E7F605005BADA3 /* single_tap_icon.png */, - 7032144D13E6963400908306 /* exclusion_icon_n.png */, - 700542ED13E5B2F40093B598 /* zoom_mode_icon.png */, - 707EECB513DF3FC100873F81 /* no_gesture_icon_small.png */, - 707EECB613DF3FC100873F81 /* no_gesture_icon.png */, - 707327D113DF126C00E5B12B /* Default-LandscapeRight.png */, - 707327D213DF126C00E5B12B /* Default-LandscapeLeft.png */, - 707327D313DF126C00E5B12B /* Default-Landscape.png */, - 7074C90213DF0F99000CABF5 /* Default-PortraitUpsideDown.png */, - 7074C90313DF0F99000CABF5 /* Default-Portrait.png */, - 70A3D4BD13E84F8200C39E40 /* select_mode.png */, - 7098E93E13F2BA470032D660 /* h2poly_icon.png */, - ); - name = Images; - sourceTree = ""; - }; - 7099E64713CB2BF000D31765 /* Classes */ = { - isa = PBXGroup; - children = ( - 700B012E13F3FD6600F84650 /* ColorCell.h */, - 700B012F13F3FD6600F84650 /* ColorCell.m */, - 700B013113F4051000F84650 /* PatternCell.h */, - 700B013213F4051000F84650 /* PatternCell.mm */, - 700B010C13F3D40A00F84650 /* PadOptionsController.h */, - 700B010D13F3D40A00F84650 /* PadOptionsController.mm */, - 70D645FB13D3243A00CE9FB1 /* PictView.h */, - 70D645FC13D3243A00CE9FB1 /* PictView.m */, - 7085571F13C73AD900022713 /* PadView.mm */, - 7085571E13C73AD900022713 /* PadView.h */, - 70BA9B5213C5F89100102BC9 /* TutorialsAppDelegate.h */, - 70BA9B5313C5F89100102BC9 /* TutorialsAppDelegate.mm */, - 70BA9B5813C5F89100102BC9 /* DetailViewController.h */, - 70BA9B5913C5F89100102BC9 /* DetailViewController.mm */, - 70BA9B5E13C5F89100102BC9 /* RootViewController.h */, - 70BA9B5F13C5F89100102BC9 /* RootViewController.mm */, - 70BA9B5013C5F89100102BC9 /* main.m */, - 70C8237A13CF790E00F884FF /* HintView.h */, - 70C8237B13CF790E00F884FF /* HintView.mm */, - 701EC32313D9762200FE395E /* SelectionView.h */, - 701EC32413D9762200FE395E /* SelectionView.mm */, - ); - name = Classes; - sourceTree = ""; - }; - 70BA9B3413C5F89100102BC9 = { - isa = PBXGroup; - children = ( - 707CF10D13F811AD00829823 /* Images */, - 707CF10C13F8118D00829823 /* ROOT files */, - 70ED86D913CB75FD00919971 /* Demos (C++ code) */, - 7099E64713CB2BF000D31765 /* Classes */, - 70BA9B4913C5F89100102BC9 /* Nibs and libs */, - 70BA9B4213C5F89100102BC9 /* Frameworks */, - 70BA9B4013C5F89100102BC9 /* Products */, - ); - sourceTree = ""; - }; - 70BA9B4013C5F89100102BC9 /* Products */ = { - isa = PBXGroup; - children = ( - 70BA9B3F13C5F89100102BC9 /* Tutorials.app */, - ); - name = Products; - sourceTree = ""; - }; - 70BA9B4213C5F89100102BC9 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 707CF12413F8145800829823 /* CoreText.framework */, - 707CF12213F8143700829823 /* QuartzCore.framework */, - 70BA9B4313C5F89100102BC9 /* UIKit.framework */, - 70BA9B4513C5F89100102BC9 /* Foundation.framework */, - 70BA9B4713C5F89100102BC9 /* CoreGraphics.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 70BA9B4913C5F89100102BC9 /* Nibs and libs */ = { - isa = PBXGroup; - children = ( - 7059E24413CC394C0007E4E1 /* libz.dylib */, - 707CF11113F8128600829823 /* libRoot.a */, - 707CF11213F8128600829823 /* libfreetype.a */, - 707CF11313F8128600829823 /* liblzma.a */, - 707CF11413F8128600829823 /* libpcre.a */, - 700B010E13F3D40A00F84650 /* PadOptionsController.xib */, - 70BA9B5513C5F89100102BC9 /* MainWindow.xib */, - 7032144B13E68F5E00908306 /* HelpView.xib */, - 70BA9B5B13C5F89100102BC9 /* DetailView.xib */, - 70BA9B4A13C5F89100102BC9 /* Supporting Files */, - ); - name = "Nibs and libs"; - path = Tutorials; - sourceTree = ""; - }; - 70BA9B4A13C5F89100102BC9 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 70BA9B4B13C5F89100102BC9 /* Tutorials-Info.plist */, - 70BA9B4C13C5F89100102BC9 /* InfoPlist.strings */, - 70BA9B4F13C5F89100102BC9 /* Tutorials-Prefix.pch */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 70ED86D913CB75FD00919971 /* Demos (C++ code) */ = { - isa = PBXGroup; - children = ( - 70CC7E481456A7050036FF4C /* DemoHelper.cxx */, - 70CC7E491456A7050036FF4C /* DemoHelper.h */, - 70DF815A13DDBA6400AD2F4D /* DemoBase.cxx */, - 70B059C413C9927700583EDB /* DemoBase.h */, - 70DF815B13DDBA6400AD2F4D /* ExclusionGraphDemo.cxx */, - 70ED86DE13CB788A00919971 /* ExclusionGraphDemo.h */, - 70DF815C13DDBA6400AD2F4D /* HsimpleDemo.cxx */, - 70B059C813C9948000583EDB /* HsimpleDemo.h */, - 70DF815D13DDBA6400AD2F4D /* LegoDemo.cxx */, - 70ED86DB13CB76C400919971 /* LegoDemo.h */, - 70DF815E13DDBA6400AD2F4D /* PolarGraphDemo.cxx */, - 70ED86D713CB504A00919971 /* PolarGraphDemo.h */, - 70DF815F13DDBA6400AD2F4D /* SurfaceDemo.cxx */, - 70ED86D313CB46BA00919971 /* SurfaceDemo.h */, - 707644AF13EFC6AA00C302F9 /* H2PolyDemo.cxx */, - 707644B013EFC6AA00C302F9 /* H2PolyDemo.h */, - ); - name = "Demos (C++ code)"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 70BA9B3E13C5F89100102BC9 /* Tutorials */ = { - isa = PBXNativeTarget; - buildConfigurationList = 70BA9B6313C5F89100102BC9 /* Build configuration list for PBXNativeTarget "Tutorials" */; - buildPhases = ( - 70BA9B3B13C5F89100102BC9 /* Sources */, - 70BA9B3C13C5F89100102BC9 /* Frameworks */, - 70BA9B3D13C5F89100102BC9 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Tutorials; - productName = Tutorials; - productReference = 70BA9B3F13C5F89100102BC9 /* Tutorials.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 70BA9B3613C5F89100102BC9 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0420; - }; - buildConfigurationList = 70BA9B3913C5F89100102BC9 /* Build configuration list for PBXProject "Tutorials" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 70BA9B3413C5F89100102BC9; - productRefGroup = 70BA9B4013C5F89100102BC9 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 70BA9B3E13C5F89100102BC9 /* Tutorials */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 70BA9B3D13C5F89100102BC9 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7010C3691455B64100018E6D /* tutorials_app_icon.png in Resources */, - 702C4FCA13F2BE2D00C645D8 /* h2poly.root in Resources */, - 7098E93F13F2BA470032D660 /* h2poly_icon.png in Resources */, - 70D4848013F057430043110B /* system.plugins-ios in Resources */, - 709A653313EFD53700612A38 /* system.rootrc in Resources */, - 70A3D4BE13E84F8200C39E40 /* select_mode.png in Resources */, - 70D3FB5213E7F605005BADA3 /* single_tap_icon_small.png in Resources */, - 70D3FB5313E7F605005BADA3 /* single_tap_icon.png in Resources */, - 7032144E13E6963400908306 /* exclusion_icon_n.png in Resources */, - 700542EE13E5B2F40093B598 /* zoom_mode_icon.png in Resources */, - 707EECB713DF3FC100873F81 /* no_gesture_icon_small.png in Resources */, - 707EECB813DF3FC100873F81 /* no_gesture_icon.png in Resources */, - 707327D413DF126C00E5B12B /* Default-LandscapeRight.png in Resources */, - 707327D513DF126C00E5B12B /* Default-LandscapeLeft.png in Resources */, - 707327D613DF126C00E5B12B /* Default-Landscape.png in Resources */, - 7074C90413DF0F99000CABF5 /* Default-PortraitUpsideDown.png in Resources */, - 7074C90513DF0F99000CABF5 /* Default-Portrait.png in Resources */, - 70DF818A13DDBC1800AD2F4D /* DarkBackground.png in Resources */, - 70DF818B13DDBC1800AD2F4D /* LightBackground.png in Resources */, - 70DF817613DDBB0D00AD2F4D /* double_tap_gesture_icon_small.png in Resources */, - 70DF817713DDBB0D00AD2F4D /* double_tap_gesture_icon.png in Resources */, - 70DF817813DDBB0D00AD2F4D /* hsimple_icon_n.png in Resources */, - 70DF817913DDBB0D00AD2F4D /* lego_icon_n.png in Resources */, - 70DF817A13DDBB0D00AD2F4D /* pan_gesture_icon_small.png in Resources */, - 70DF817B13DDBB0D00AD2F4D /* pan_gesture_icon.png in Resources */, - 70DF817C13DDBB0D00AD2F4D /* pinch_gesture_icon_small.png in Resources */, - 70DF817D13DDBB0D00AD2F4D /* pinch_gesture_icon.png in Resources */, - 70DF817E13DDBB0D00AD2F4D /* polar_icon_n.png in Resources */, - 70DF817F13DDBB0D00AD2F4D /* rotate_icon_small.png in Resources */, - 70DF818013DDBB0D00AD2F4D /* rotate_icon.png in Resources */, - 70DF818213DDBB0D00AD2F4D /* surface_icon_n.png in Resources */, - 70BA9B4E13C5F89100102BC9 /* InfoPlist.strings in Resources */, - 70BA9B5713C5F89100102BC9 /* MainWindow.xib in Resources */, - 70BA9B5D13C5F89100102BC9 /* DetailView.xib in Resources */, - 7032144C13E68F5E00908306 /* HelpView.xib in Resources */, - 700B011013F3D40A00F84650 /* PadOptionsController.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 70BA9B3B13C5F89100102BC9 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 70BA9B5113C5F89100102BC9 /* main.m in Sources */, - 70BA9B5413C5F89100102BC9 /* TutorialsAppDelegate.mm in Sources */, - 70BA9B5A13C5F89100102BC9 /* DetailViewController.mm in Sources */, - 70BA9B6013C5F89100102BC9 /* RootViewController.mm in Sources */, - 7085572013C73AD900022713 /* PadView.mm in Sources */, - 70C8237C13CF790E00F884FF /* HintView.mm in Sources */, - 70D645FD13D3243A00CE9FB1 /* PictView.m in Sources */, - 701EC32513D9762200FE395E /* SelectionView.mm in Sources */, - 70DF816013DDBA6400AD2F4D /* DemoBase.cxx in Sources */, - 70DF816113DDBA6400AD2F4D /* ExclusionGraphDemo.cxx in Sources */, - 70DF816213DDBA6400AD2F4D /* HsimpleDemo.cxx in Sources */, - 70DF816313DDBA6400AD2F4D /* LegoDemo.cxx in Sources */, - 70DF816413DDBA6400AD2F4D /* PolarGraphDemo.cxx in Sources */, - 70DF816513DDBA6400AD2F4D /* SurfaceDemo.cxx in Sources */, - 707644B113EFC6AA00C302F9 /* H2PolyDemo.cxx in Sources */, - 700B010F13F3D40A00F84650 /* PadOptionsController.mm in Sources */, - 700B013013F3FD6700F84650 /* ColorCell.m in Sources */, - 700B013313F4051000F84650 /* PatternCell.mm in Sources */, - 70CC7E4A1456A7050036FF4C /* DemoHelper.cxx in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 70BA9B4C13C5F89100102BC9 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 70BA9B4D13C5F89100102BC9 /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; - 70BA9B5513C5F89100102BC9 /* MainWindow.xib */ = { - isa = PBXVariantGroup; - children = ( - 70BA9B5613C5F89100102BC9 /* en */, - ); - name = MainWindow.xib; - sourceTree = ""; - }; - 70BA9B5B13C5F89100102BC9 /* DetailView.xib */ = { - isa = PBXVariantGroup; - children = ( - 70BA9B5C13C5F89100102BC9 /* en */, - ); - name = DetailView.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 70BA9B6113C5F89100102BC9 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; - CLANG_ENABLE_OBJC_ARC = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = DEBUG; - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ../../../lib; - OTHER_LDFLAGS = ../../../io/io/src/G__IO.o; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = 2; - }; - name = Debug; - }; - 70BA9B6213C5F89100102BC9 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; - CLANG_ENABLE_OBJC_ARC = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ../../../lib; - OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - OTHER_LDFLAGS = ../../../io/io/src/G__IO.o; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = 2; - }; - name = Release; - }; - 70BA9B6413C5F89100102BC9 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "compiler-default"; - CLANG_ENABLE_OBJC_ARC = YES; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Tutorials/Tutorials-Prefix.pch"; - "HEADER_SEARCH_PATHS[arch=*]" = ../../../include; - INFOPLIST_FILE = "Tutorials/Tutorials-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ../../../lib; - "LIBRARY_SEARCH_PATHS[arch=*]" = "$(inherited)"; - OTHER_LDFLAGS = ( - ../../../io/io/src/G__IO.o, - ../../../net/net/src/G__Net.o, - ../../../hist/hist/src/G__Hist.o, - ../../../hist/histpainter/src/G__HistPainter.o, - ../../../graf3d/g3d/src/G__G3D.o, - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - USER_HEADER_SEARCH_PATHS = ../../../lib; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - 70BA9B6513C5F89100102BC9 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "compiler-default"; - CLANG_ENABLE_OBJC_ARC = YES; - COPY_PHASE_STRIP = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Tutorials/Tutorials-Prefix.pch"; - "HEADER_SEARCH_PATHS[arch=*]" = ../../../include; - INFOPLIST_FILE = "Tutorials/Tutorials-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ../../../lib; - "LIBRARY_SEARCH_PATHS[arch=*]" = "$(inherited)"; - OTHER_LDFLAGS = ( - ../../../io/io/src/G__IO.o, - ../../../net/net/src/G__Net.o, - ../../../hist/hist/src/G__Hist.o, - ../../../hist/histpainter/src/G__HistPainter.o, - ../../../graf3d/g3d/src/G__G3D.o, - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - USER_HEADER_SEARCH_PATHS = ../../../lib; - VALIDATE_PRODUCT = YES; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 70BA9B3913C5F89100102BC9 /* Build configuration list for PBXProject "Tutorials" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 70BA9B6113C5F89100102BC9 /* Debug */, - 70BA9B6213C5F89100102BC9 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 70BA9B6313C5F89100102BC9 /* Build configuration list for PBXNativeTarget "Tutorials" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 70BA9B6413C5F89100102BC9 /* Debug */, - 70BA9B6513C5F89100102BC9 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 70BA9B3613C5F89100102BC9 /* Project object */; -} diff --git a/test/ios/Tutorials/Tutorials.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/test/ios/Tutorials/Tutorials.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 079055719138b..0000000000000 --- a/test/ios/Tutorials/Tutorials.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/test/ios/Tutorials/Tutorials/DetailViewController.h b/test/ios/Tutorials/Tutorials/DetailViewController.h deleted file mode 100644 index 93f34ecbe5711..0000000000000 --- a/test/ios/Tutorials/Tutorials/DetailViewController.h +++ /dev/null @@ -1,27 +0,0 @@ -#import - -namespace ROOT { -namespace iOS { - -namespace Demos { -class DemoBase; -} - -} -} - -@interface DetailViewController : UIViewController - -@property (nonatomic, retain) IBOutlet UITabBar *tabBar; -@property (nonatomic, retain) IBOutlet UIToolbar *toolbar; -@property (nonatomic, retain) IBOutlet UIView *help; - -- (void) setActiveDemo : (ROOT::iOS::Demos::DemoBase *)demo; -- (void) dismissPopover; - -- (IBAction) zoomButtonPressed; -- (IBAction) editButtonPressed : (id) sender; -- (IBAction) selectButtonPressed; -- (IBAction) showHelp; - -@end diff --git a/test/ios/Tutorials/Tutorials/DetailViewController.mm b/test/ios/Tutorials/Tutorials/DetailViewController.mm deleted file mode 100644 index d9951328ce974..0000000000000 --- a/test/ios/Tutorials/Tutorials/DetailViewController.mm +++ /dev/null @@ -1,740 +0,0 @@ -#import - -#import "PadOptionsController.h" -#import "DetailViewController.h" -#import "RootViewController.h" -#import "SelectionView.h" -#import "HintView.h" -#import "PictView.h" -#import "PadView.h" - -//C++ code. -//ROOT -#import "IOSPad.h" - -//Demos. -#import "DemoBase.h" - -/* -DetailViewController has several views - two pad views (to make animation while changing demos), -two scroll views to be parent of pad-views (to enable zoom and scroll) -and parent view. PadView can be placed in a parent view, or in a scroll-view (which will be placed -in parent view). Actually, I do not need all these view, but there's no serious reason to -modify this code already. This was a testbed. -*/ - -namespace { - -enum ETutorialsMode { - kTAZoom, - kTASelect -}; - -enum ETutorialsDefaults { - kTDNOfPads = 2 -}; - -} - -//Hidden implementation details. -@interface DetailViewController () { - - //"Editor" - PadOptionsController * padController; - UIPopoverController *editorPopover; - - //Transparent view with a text - //and a pictogram for a hint. - HintView *hintView; - - //Small views with pictograms: hints. - PictView *panPic; - PictView *pinchPic; - PictView *doubleTapPic; - PictView *rotatePic; - PictView *singleTapPic; - - NSTimer *animationTimer; - unsigned currentFrame; - - ROOT::iOS::Pad *pad; - - //Depending on more, either parentView of - //scrollViews is/are parent(s) of padViews. - UIView *parentView; - UIScrollView *scrollViews[kTDNOfPads]; - PadView *padViews[kTDNOfPads]; - - //Transparent view with selected object. - SelectionView *selectionViews[kTDNOfPads]; - - UIPanGestureRecognizer *padPanGestures[kTDNOfPads]; - UITapGestureRecognizer *padTapGestures[kTDNOfPads]; - - unsigned activeView; - - CGSize oldSizes; - - ROOT::iOS::Demos::DemoBase *activeDemo; - - //Either zoom or selection. - ETutorialsMode appMode; - - BOOL activeAnimation; -} - -@property (nonatomic, retain) UIPopoverController *popoverController; - -- (void) showPanHint; -- (void) showPinchHint; -- (void) showDoubleTapHint; -- (void) showRotationHint; -- (void) showSingleTapHint; -- (void) handleDoubleTapPad : (UITapGestureRecognizer *)tap; - -@end - - - -@implementation DetailViewController - -//These are generated declarations. -@synthesize toolbar; -@synthesize popoverController; - -//This was "generated" by me. -@synthesize help; -@synthesize tabBar; - -#pragma mark - Managing the detail item - -//_________________________________________________________________ -- (void) initCPPObjects -{ - pad = new ROOT::iOS::Pad(640, 640); -} - -//_________________________________________________________________ -- (void) initMainViews -{ - const CGPoint padCenter = self.view.center; - CGRect padRect = CGRectMake(padCenter.x - 320.f, padCenter.y - 310.f, 640.f, 640.f); - - oldSizes.width = 640.f; - oldSizes.height = 640.f; - - parentView = [[UIView alloc] initWithFrame:padRect]; - parentView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - - [self.view addSubview:parentView]; - - //Trick with shadow and shadow path: - //http://nachbaur.com/blog/fun-shadow-effects-using-custom-calayer-shadowpaths - //Many thanks. - parentView.layer.shadowColor = [UIColor blackColor].CGColor; - parentView.layer.shadowOpacity = 0.7f; - parentView.layer.shadowOffset = CGSizeMake(10.f, 10.f); - UIBezierPath *path = [UIBezierPath bezierPathWithRect:parentView.bounds]; - parentView.layer.shadowPath = path.CGPath; - /// - padRect.origin.x = 0.f, padRect.origin.y = 0.f; - for (unsigned i = 0; i < 2; ++i) {// < kTDNOfPads - scrollViews[i] = [[UIScrollView alloc] initWithFrame:padRect]; - scrollViews[i].backgroundColor = [UIColor darkGrayColor]; - scrollViews[i].delegate = self; - padViews[i] = [[PadView alloc] initWithFrame : padRect forPad : pad]; - scrollViews[i].contentSize = padViews[i].frame.size; - [scrollViews[i] addSubview:padViews[i]]; - // - scrollViews[i].minimumZoomScale = 1.f; - scrollViews[i].maximumZoomScale = 1280.f / 640.f; - [scrollViews[i] setZoomScale:1.f]; - [parentView addSubview:scrollViews[i]]; - } - - parentView.hidden = YES; - // - activeView = 0; - - padRect = CGRectMake(padCenter.x - 320.f, padCenter.y - 310.f, 640.f, 640.f); - - for (unsigned i = 0; i < 2; ++i) { // < kTDNOfPads - selectionViews[i] = [[SelectionView alloc] initWithFrame:padRect]; - selectionViews[i].autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - [self.view addSubview:selectionViews[i]]; - selectionViews[i].hidden = YES; - selectionViews[i].opaque = NO; - } -} - -//_________________________________________________________________ -- (void) initHints -{ - //"Hint" is a semi-transparent view, which shows gesture icon and some textual description. - //Pictogramms. - CGRect pictRect = CGRectMake(670.f, 450.f, 50.f, 50.f); - pinchPic = [[PictView alloc] initWithFrame:pictRect andIcon:@"pinch_gesture_icon_small.png"]; - pinchPic.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - [self.view addSubview:pinchPic]; - UITapGestureRecognizer *pinchTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(showPinchHint)]; - [pinchPic addGestureRecognizer:pinchTap]; - pinchPic.hidden = YES; - - pictRect.origin.y = 520; - panPic = [[PictView alloc] initWithFrame:pictRect andIcon:@"pan_gesture_icon_small.png"]; - panPic.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - [self.view addSubview:panPic]; - UITapGestureRecognizer *panTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(showPanHint)]; - [panPic addGestureRecognizer:panTap]; - panPic.hidden = YES; - - pictRect.origin.y = 590; - doubleTapPic = [[PictView alloc] initWithFrame:pictRect andIcon:@"double_tap_gesture_icon_small.png"]; - doubleTapPic.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - [self.view addSubview:doubleTapPic]; - UITapGestureRecognizer *dtapTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(showDoubleTapHint)]; - [doubleTapPic addGestureRecognizer:dtapTap]; - doubleTapPic.hidden = YES; - - rotatePic = [[PictView alloc] initWithFrame:pictRect andIcon:@"rotate_icon_small.png"]; - rotatePic.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - [self.view addSubview:rotatePic]; - UITapGestureRecognizer *rotTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(showRotationHint)]; - [rotatePic addGestureRecognizer:rotTap]; - rotatePic.hidden = YES; - - singleTapPic = [[PictView alloc] initWithFrame:pictRect andIcon:@"single_tap_icon_small.png"]; - singleTapPic.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - [self.view addSubview:singleTapPic]; - UITapGestureRecognizer *singleTapTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(showSingleTapHint)]; - [singleTapPic addGestureRecognizer:singleTapTap]; - singleTapPic.hidden = YES; - - const CGPoint center = self.view.center; - CGRect rect = CGRectMake(center.x - 300.f, center.y - 290.f, 600.f, 600.f); - hintView = [[HintView alloc] initWithFrame:rect]; - hintView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - [self.view addSubview:hintView]; - UITapGestureRecognizer *hintTap = [[UITapGestureRecognizer alloc] initWithTarget:hintView action:@selector(handleTap:)]; - [hintView addGestureRecognizer:hintTap]; - hintView.hidden = YES; -} - -//_________________________________________________________________ -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; -} - -//_________________________________________________________________ -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; -} - -//_________________________________________________________________ -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; -} - -//_________________________________________________________________ -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear:animated]; -} - -//_________________________________________________________________ -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - return YES; -} - -#pragma mark - Split view support - -//_________________________________________________________________ -- (void)splitViewController:(UISplitViewController *)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController: (UIPopoverController *)pc -{ - barButtonItem.title = @"Tutorials"; - NSMutableArray *items = [[self.toolbar items] mutableCopy]; - [items insertObject:barButtonItem atIndex:0]; - [self.toolbar setItems:items animated:YES]; - self.popoverController = pc; -} - -//_________________________________________________________________ -- (void)splitViewController:(UISplitViewController *)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem -{ - // Called when the view is shown again in the split view, invalidating the button and popover controller. - NSMutableArray *items = [[self.toolbar items] mutableCopy]; - [items removeObjectAtIndex:0]; - [self.toolbar setItems:items animated:YES]; - self.popoverController = nil; -} - -//_________________________________________________________________ -- (void)viewDidLoad -{ - self.view.backgroundColor = [UIColor lightGrayColor]; - - [self initCPPObjects]; - [self initMainViews]; - [self initHints]; - - appMode = kTAZoom; - - UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTapPad:)]; - [parentView addGestureRecognizer:tapGesture]; - tapGesture.numberOfTapsRequired = 2; - - //Load a help view from a nib file. - [[NSBundle mainBundle] loadNibNamed:@"HelpView" owner:self options:nil]; - CGRect helpFrame = help.frame; - helpFrame.origin.x = self.view.center.x - helpFrame.size.width / 2; - helpFrame.origin.y = self.view.center.y - helpFrame.size.height / 2; - help.frame = helpFrame; - help.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - [self.view addSubview:help]; - - //Editor view and help view (created in a IB) are on top. - [self.view bringSubviewToFront:help]; - - //Shadow for editor. - tabBar.selectedItem = [tabBar.items objectAtIndex : 0]; - - [super viewDidLoad]; -} - -//_________________________________________________________________ -- (void)viewDidUnload -{ - [super viewDidUnload]; - - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; - self.popoverController = nil; -} - -#pragma mark - Memory management - -//_________________________________________________________________ -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - - // Release any cached data, images, etc that aren't in use. -} - -//_________________________________________________________________ -- (void)dealloc -{ - // - delete pad; - // -} - -//_________________________________________________________________ -- (void) prepareHints -{ - if (appMode == kTAZoom) { - panPic.hidden = NO; - pinchPic.hidden = NO; - doubleTapPic.hidden = NO; - - singleTapPic.hidden = YES; - rotatePic.hidden = YES; -// emptyPic.hidden = YES; - //Hide selection pictograms. - } else { - //Show selection or rotate pictogram. - - //Hide zoom mode's pictograms. - panPic.hidden = YES; - pinchPic.hidden = YES; - doubleTapPic.hidden = YES; - - rotatePic.hidden = !activeDemo->Supports3DRotation(); - singleTapPic.hidden = !rotatePic.hidden; - } -} - -//_________________________________________________________________ -- (void) setActiveDemo:(ROOT::iOS::Demos::DemoBase *)demo -{ - help.hidden = YES; - - if (demo != activeDemo) { - - selectionViews[0].hidden = YES; - selectionViews[1].hidden = YES; - - parentView.hidden = NO; - //Stop any animated demo (previously active). - if (animationTimer) { - [animationTimer invalidate]; - animationTimer = 0; - } - currentFrame = 0; - // - - //Prepare to make an animation: remove one view, show another. - activeDemo = demo; - [self prepareHints]; - - UIView * showView = 0; - UIView * hideView = 0; - - const unsigned hide = activeView; - const unsigned show = !hide; - activeView = show; - - if (appMode == kTAZoom) { - showView = scrollViews[show]; - hideView = scrollViews[hide]; - } else { - showView = padViews[show]; - hideView = padViews[hide]; - } - - //This is temporary hack. - [padViews[activeView] setProcessPan:activeDemo->Supports3DRotation()]; - [padViews[activeView] setProcessTap:!activeDemo->Supports3DRotation()]; - - //Remove old contents of pad, - //set pad's parameters (if required by demo) - //reset demo (if required), add demo's primitives to pad. - pad->Clear(); - activeDemo->AdjustPad(pad); - activeDemo->ResetDemo(); - activeDemo->PresentDemo(); - - //Repaint active view's content. - [padViews[activeView] setNeedsDisplay]; - - if (activeDemo->IsAnimated()) { - //Start timer for animated demo. - activeDemo->StartAnimation(); - animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 / 25 target:self selector:@selector(onTimer) userInfo:nil repeats:YES]; - } - - //Make an animation: hide one view (demo), show another one. - showView.hidden = NO; - hideView.hidden = YES; - // First create a CATransition object to describe the transition - CATransition *transition = [CATransition animation]; - // Animate over 3/4 of a second - transition.duration = 0.75; - // using the ease in/out timing function - transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; - // Now to set the type of transition. - transition.type = kCATransitionReveal; - transition.subtype = kCATransitionFromLeft; - // Finally, to avoid overlapping transitions we assign ourselves as the delegate for the animation and wait for the - // -animationDidStop:finished: message. When it comes in, we will flag that we are no longer transitioning. - //transitioning = YES; - transition.delegate = self; - // Next add it to the containerView's layer. This will perform the transition based on how we change its contents. - [parentView.layer addAnimation : transition forKey:nil]; - } -} - -//_________________________________________________________________ -- (void) dismissPopover -{ - [popoverController dismissPopoverAnimated : YES]; -} - -//_________________________________________________________________ -- (void) onTimer -{ - if (currentFrame == activeDemo->NumOfFrames()) { - [animationTimer invalidate]; - animationTimer = 0; - } else { - ++currentFrame; - activeDemo->NextStep(); - [padViews[activeView] setNeedsDisplay]; - } -} - -//_________________________________________________________________ -- (void) resizePadView:(unsigned)view -{ - UIScrollView *scroll = (UIScrollView *)padViews[view].superview; - CGRect oldRect = padViews[view].frame; - - if (abs(640.f - oldRect.size.width) < 0.01 && (abs(640.f - oldRect.size.height) < 0.01)) - return; - - CGRect padRect = CGRectMake(0.f, 0.f, 640.f, 640.f); - [padViews[view] removeFromSuperview]; - padViews[view] = [[PadView alloc] initWithFrame : padRect forPad : pad]; - [scroll addSubview:padViews[view]]; - - scroll.minimumZoomScale = 1.f; - scroll.maximumZoomScale = 2.f; - [scroll setZoomScale:1.f]; - scroll.contentSize = padRect.size; - scroll.contentOffset = CGPointMake(0.f, 0.f); - - oldSizes.width = 640.f; - oldSizes.height = 640.f; -} - -//_________________________________________________________________ --(void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag -{ - //After one view was hidden, resize it's scale to 1 and - //view itself to original size. - if (appMode == kTAZoom) { - unsigned inactiveView = activeView ? 0 : 1; - [self resizePadView : inactiveView]; - } -} - -#pragma mark - That's what I call action :) - -//_________________________________________________________________ -- (IBAction)zoomButtonPressed -{ - if (appMode == kTAZoom) - return; - - //Zoom mode was selected. - appMode = kTAZoom; - //The mode was kTASelect previously. - //Reparent pad views, now scrollview is a parent for a pad view. - for (unsigned i = 0; i < 2; ++i) { // < kTDNOfPads. - selectionViews[i].hidden = YES; - [padViews[i] removeGestureRecognizer : padPanGestures[i]]; - [padViews[i] removeGestureRecognizer : padTapGestures[i]]; - - padViews[i].hidden = NO; - [padViews[i] removeFromSuperview]; - [scrollViews[i] addSubview : padViews[i]]; - } - - if (activeDemo) { - scrollViews[activeView].hidden = NO; - [self prepareHints]; - } -} - -//_________________________________________________________________ -- (IBAction) selectButtonPressed -{ - if (appMode == kTASelect)// || !activeDemo) - return; - - appMode = kTASelect; - - //hide both scroll views, re-parent pad-views. - for (unsigned i = 0; i < 2; ++i) { // < kTDNOfPads - scrollViews[i].hidden = YES; - //1. Check, if views must be resized (unscaled). - [self resizePadView : i]; - - [padViews[i] removeFromSuperview]; - - padPanGestures[i] = [[UIPanGestureRecognizer alloc] initWithTarget:padViews[i] action:@selector(handlePanGesture:)]; - [padViews[i] addGestureRecognizer:padPanGestures[i]]; - - padTapGestures[i] = [[UITapGestureRecognizer alloc] initWithTarget:padViews[i] action:@selector(handleTapGesture:)]; - [padViews[i] addGestureRecognizer:padTapGestures[i]]; - - [padViews[i] setSelectionView:selectionViews[i]]; - - [parentView addSubview:padViews[i]]; - - if (activeDemo) //In case no demo was selected - nothing to show yet. - padViews[i].hidden = i == activeView ? NO : YES; - } - - if (activeDemo) { - [padViews[activeView] setProcessPan:activeDemo->Supports3DRotation()]; - [padViews[activeView] setProcessTap:!activeDemo->Supports3DRotation()]; - [self prepareHints]; - } -} - -//_________________________________________________________________ -- (IBAction) editButtonPressed : (id) sender -{ - if (editorPopover && editorPopover.popoverVisible) { - [editorPopover dismissPopoverAnimated : YES]; - return; - } else { - if (!padController) { - padController = [[PadOptionsController alloc] initWithNibName : @"PadOptionsController" bundle : nil]; - padController.contentSizeForViewInPopover = CGSizeMake(250.f, 650.f); - } - - if (!editorPopover) { - editorPopover = [[UIPopoverController alloc] initWithContentViewController : padController]; - editorPopover.popoverContentSize = CGSizeMake(250.f, 650.f); - } - - [editorPopover presentPopoverFromBarButtonItem : sender permittedArrowDirections:UIPopoverArrowDirectionAny animated : YES]; - [padController setView : padViews[activeView] andPad : pad]; - } -} - -//_________________________________________________________________ -- (IBAction) showHelp -{ - CATransition *transition = [CATransition animation]; - transition.duration = 0.25; - transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; - transition.type = kCATransitionReveal; - transition.subtype = kCATransitionFade; - help.hidden = !help.hidden; - [help.layer addAnimation:transition forKey:nil]; -} - -#pragma mark - UIScrollView's delegate. - -//_________________________________________________________________ -- (UIView *) viewForZoomingInScrollView : (UIScrollView *)scrollView -{ - if (scrollView == scrollViews[0]) - return padViews[0]; - - return padViews[1]; -} - -//_________________________________________________________________ -- (CGRect) centeredFrameForScrollView : (UIScrollView *)scroll andUIView : (UIView *)rView -{ - CGSize boundsSize = scroll.bounds.size; - CGRect frameToCenter = rView.frame; - // center horizontally - if (frameToCenter.size.width < boundsSize.width) - frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2; - else - frameToCenter.origin.x = 0; - // center vertically - if (frameToCenter.size.height < boundsSize.height) - frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2; - else - frameToCenter.origin.y = 0; - - return frameToCenter; -} - -//_________________________________________________________________ -- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale -{ - const CGPoint off = [scrollView contentOffset]; - CGRect oldRect = padViews[activeView].frame; - oldRect.origin.x = 0.f; - oldRect.origin.y = 0.f; - - if (abs(oldSizes.width - oldRect.size.width) < 0.01 && (abs(oldSizes.height - oldRect.size.height) < 0.01)) - return; - - oldSizes = oldRect.size; - - [padViews[activeView] removeFromSuperview]; - padViews[activeView] = [[PadView alloc] initWithFrame : oldRect forPad : pad]; - [scrollView addSubview:padViews[activeView]]; - - [scrollView setZoomScale:1.f]; - scrollView.contentSize = oldRect.size; - scrollView.contentOffset = off; - - scrollView.minimumZoomScale = 640.f / oldRect.size.width; - scrollView.maximumZoomScale = 1280.f / oldRect.size.width; -} - -//_________________________________________________________________ -- (void)scrollViewDidZoom:(UIScrollView *)scrollView -{ - padViews[activeView].frame = [self centeredFrameForScrollView:scrollView andUIView:padViews[activeView]]; -} - -#pragma mark - Tab bar delegate. - -//_________________________________________________________________ -- (void) tabBar : (UITabBar *) tb didSelectItem:(UITabBarItem *)item -{ - if (item.tag == 1) - [self zoomButtonPressed]; - else - [self selectButtonPressed]; -} - -#pragma mark - Tap gesture handler. - -//_________________________________________________________________ -- (void) handleDoubleTapPad:(UITapGestureRecognizer *)tap -{ - if (appMode != kTAZoom || !activeDemo) - return; - - if (oldSizes.width > 640.f) - [self resizePadView : activeView]; - else { - //Zoom to maximum. - oldSizes = CGSizeMake(1280.f, 1280.f); - CGRect newRect = CGRectMake(0.f, 0.f, 1280.f, 1280.f); - - [padViews[activeView] removeFromSuperview]; - - padViews[activeView] = [[PadView alloc] initWithFrame : newRect forPad : pad]; - [scrollViews[activeView] addSubview:padViews[activeView]]; - - [scrollViews[activeView] setZoomScale:1.f]; - scrollViews[activeView].contentSize = newRect.size; - - scrollViews[activeView].minimumZoomScale = 1.f; - scrollViews[activeView].maximumZoomScale = 1.f; - - const CGPoint tapXY = [tap locationInView : tap.view]; - scrollViews[activeView].contentOffset = CGPointMake(tapXY.x, tapXY.y); - } -} - -#pragma mark - Hints. - -//_________________________________________________________________ -- (void) showPinchHint -{ - [hintView setHintIcon : @"pinch_gesture_icon.png" hintText : @"Use a pinch gesture to zoom/unzoom a pad. Tap to close this hint."]; - [hintView setNeedsDisplay]; - hintView.hidden = NO; -} - -//_________________________________________________________________ -- (void) showPanHint -{ - [hintView setHintIcon : @"pan_gesture_icon.png" hintText : @"When a pad zoomed in, use a pan gesture to scroll a pad. Tap to close this hint."]; - [hintView setNeedsDisplay]; - hintView.hidden = NO; -} - -//_________________________________________________________________ -- (void) showDoubleTapHint -{ - [hintView setHintIcon : @"double_tap_gesture_icon.png" hintText : @"Use the double tap gesture to zoom/unzoom a pad. Tap to close this hint."]; - [hintView setNeedsDisplay]; - hintView.hidden = NO; -} - -//_________________________________________________________________ -- (void) showRotationHint -{ - [hintView setHintIcon:@"rotate_icon.png" hintText : @"You can rotate 3D object, using pan gesture. Tap to close this hint."]; - [hintView setNeedsDisplay]; - hintView.hidden = NO; -} - -//_________________________________________________________________ -- (void) showSingleTapHint -{ - [hintView setHintIcon:@"single_tap_icon.png" hintText : @"Use a single tap gesture to select pad's contents. Tap to close this hint."]; - [hintView setNeedsDisplay]; - hintView.hidden = NO; -} - -@end diff --git a/test/ios/Tutorials/Tutorials/HelpView.xib b/test/ios/Tutorials/Tutorials/HelpView.xib deleted file mode 100644 index 99955b0e2c3a8..0000000000000 --- a/test/ios/Tutorials/Tutorials/HelpView.xib +++ /dev/null @@ -1,548 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - YES - IBUITextView - IBUIButton - IBUIImageView - IBUIView - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 256 - - YES - - - 256 - {{0, 13}, {529, 93}} - - - - - 3 - MCAwAA - - YES - NO - IBIPadFramework - NO - NO - This is the very first ROOT's graphics demo program for iOS (iPad only at the moment). It shows several demos ("tutorials") and has some options. - 2 - - 2 - IBCocoaTouchFramework - - - Helvetica - Helvetica - 0 - 18 - - - Helvetica - 18 - 16 - - - - - 292 - {{83, 103}, {446, 60}} - - - - - 1 - MSAxIDEgMAA - - YES - 0.89999997615814209 - NO - IBIPadFramework - NO - NO - In "zoom" mode you can zoom/unzoom, scroll pad's contents, using pinch gesture or double tap gesture. - 2 - - 2 - IBCocoaTouchFramework - - - - - - - 292 - {{15, 109}, {65, 48}} - - - - - 3 - MQA - - NO - IBIPadFramework - - NSImage - zoom_mode_icon.png - - - - - 292 - {{20, 179}, {340, 98}} - - - - - YES - NO - IBIPadFramework - NO - NO - Gestures, which you can use in the current mode, are shown by pictograms. You can tap on a pictogram to read a hint. - - 2 - IBCocoaTouchFramework - - - - - - - 292 - {{346, 179}, {80, 80}} - - - - NO - IBIPadFramework - - NSImage - pinch_gesture_icon.png - - - - - 292 - {{449, 179}, {80, 80}} - - - - NO - IBIPadFramework - - NSImage - pan_gesture_icon.png - - - - - 292 - {{15, 293}, {71, 44}} - - - - - NO - IBIPadFramework - - NSImage - select_mode.png - - - - - 292 - {{94, 285}, {435, 100}} - - - - - YES - NO - IBIPadFramework - NO - NO - In selection mode, you can rotate 3D objects like lego or surface or pick axis/histograms (no editor in this demo). - 1 - - 2 - IBCocoaTouchFramework - - - - - - - 292 - {{201, 393}, {158, 58}} - - - - NO - IBIPadFramework - 0 - 0 - 1 - Hide - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - 3 - MC41AA - - - Helvetica-Bold - Helvetica - 2 - 15 - - - Helvetica-Bold - 15 - 16 - - - - {561, 471} - - - - - 0.89999997615814209 - 2 - - 3 - 3 - - IBIPadFramework - - - - - YES - - - help - - - - 13 - - - - showHelp - - - 7 - - 14 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 3 - - - YES - - - - - - - - - - - - - - 4 - - - - - 6 - - - - - 5 - - - - - 7 - - - - - 8 - - - - - 12 - - - - - 10 - - - Image View - - - 11 - - - - - 9 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 10.IBPluginDependency - 11.IBPluginDependency - 12.IBPluginDependency - 3.IBPluginDependency - 4.IBPluginDependency - 5.IBPluginDependency - 6.IBPluginDependency - 7.IBPluginDependency - 8.IBPluginDependency - 9.IBPluginDependency - - - YES - DetailViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 14 - - - - YES - - DetailViewController - UIViewController - - YES - - YES - editButtonPressed: - selectButtonPressed - showHelp - zoomButtonPressed - - - YES - id - id - id - id - - - - YES - - YES - editButtonPressed: - selectButtonPressed - showHelp - zoomButtonPressed - - - YES - - editButtonPressed: - id - - - selectButtonPressed - id - - - showHelp - id - - - zoomButtonPressed - id - - - - - YES - - YES - detailDescriptionLabel - help - tb - toolbar - - - YES - UILabel - UIView - UITabBar - UIToolbar - - - - YES - - YES - detailDescriptionLabel - help - tb - toolbar - - - YES - - detailDescriptionLabel - UILabel - - - help - UIView - - - tb - UITabBar - - - toolbar - UIToolbar - - - - - IBProjectSource - ./Classes/DetailViewController.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - pan_gesture_icon.png - pinch_gesture_icon.png - select_mode.png - zoom_mode_icon.png - - - YES - {80, 80} - {80, 80} - {43, 30} - {41, 30} - - - 933 - - diff --git a/test/ios/Tutorials/Tutorials/RootViewController.h b/test/ios/Tutorials/Tutorials/RootViewController.h deleted file mode 100644 index 247cec14376ed..0000000000000 --- a/test/ios/Tutorials/Tutorials/RootViewController.h +++ /dev/null @@ -1,7 +0,0 @@ -#import - -@interface RootViewController : UITableViewController - -@property (nonatomic, retain) IBOutlet DetailViewController *detailViewController; - -@end diff --git a/test/ios/Tutorials/Tutorials/RootViewController.mm b/test/ios/Tutorials/Tutorials/RootViewController.mm deleted file mode 100644 index f8428d23d941e..0000000000000 --- a/test/ios/Tutorials/Tutorials/RootViewController.mm +++ /dev/null @@ -1,167 +0,0 @@ -#import - -#import "DetailViewController.h" -#import "RootViewController.h" - -#import "DemoHelper.h" -#import "DemoBase.h" - -namespace { - -enum { - nROOTDemos = 6 -}; - -} - -@implementation RootViewController { - NSMutableArray *tutorialNames; - NSMutableArray *tutorialIcons; - - ROOT::iOS::Demos::DemoBase *demos[nROOTDemos]; -} - -@synthesize detailViewController; - -//_________________________________________________________________ -- (void)viewDidLoad -{ - NSString *filePath = [[NSBundle mainBundle] pathForResource : @"h2poly" ofType : @"root"]; - if (!ROOT::iOS::Demos::CreateTutorials(demos, [filePath cStringUsingEncoding : [NSString defaultCStringEncoding]])) { - NSLog(@"Failed to create demos"); - exit(1); - } - - tutorialNames = [[NSMutableArray alloc] init]; - [tutorialNames addObject:@"Hsimple"]; - [tutorialNames addObject:@"Surface"]; - [tutorialNames addObject:@"Polar graph"]; - [tutorialNames addObject:@"Lego"]; - [tutorialNames addObject:@"Exclusion graph"]; - [tutorialNames addObject:@"TH2Poly from file"]; - - tutorialIcons = [[NSMutableArray alloc] init]; - [tutorialIcons addObject:@"hsimple_icon_n.png"]; - [tutorialIcons addObject:@"surface_icon_n.png"]; - [tutorialIcons addObject:@"polar_icon_n.png"]; - [tutorialIcons addObject:@"lego_icon_n.png"]; - [tutorialIcons addObject:@"exclusion_icon_n.png"]; - [tutorialIcons addObject:@"h2poly_icon.png"]; - - //Set table view's color, row height, separator's color - //(I want separator to be invisible). - self.tableView.rowHeight = 72.f; - self.tableView.backgroundColor = [UIColor lightGrayColor]; - self.tableView.separatorColor = [UIColor lightGrayColor]; - - //This code was generated by ide. - [super viewDidLoad]; - - - self.clearsSelectionOnViewWillAppear = NO; - self.contentSizeForViewInPopover = CGSizeMake(320.0, 500.0);//Default height was 600., I've changed it to 500. -} - -//_________________________________________________________________ -- (void) viewWillAppear : (BOOL)animated -{ - [super viewWillAppear : animated]; -} - -//_________________________________________________________________ -- (void) viewDidAppear : (BOOL)animated -{ - [super viewDidAppear : animated]; -} - -//_________________________________________________________________ -- (void) viewWillDisappear : (BOOL)animated -{ - [super viewWillDisappear : animated]; -} - -//_________________________________________________________________ -- (void) viewDidDisappear : (BOOL)animated -{ - [super viewDidDisappear : animated]; -} - -//_________________________________________________________________ -- (BOOL) shouldAutorotateToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation -{ - return YES; -} - -//_________________________________________________________________ -- (NSInteger) numberOfSectionsInTableView : (UITableView *)tableView -{ - return 1; -} - -//_________________________________________________________________ -- (NSInteger) tableView : (UITableView *)tableView numberOfRowsInSection : (NSInteger)section -{ - return [tutorialNames count]; -} - -//_________________________________________________________________ -- (UITableViewCell *) tableView : (UITableView *)tableView cellForRowAtIndexPath : (NSIndexPath *)indexPath -{ - static NSString *CellIdentifier = @"Cell"; - - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier : CellIdentifier]; - if (cell == nil) - cell = [[UITableViewCell alloc] initWithStyle : UITableViewCellStyleDefault reuseIdentifier : CellIdentifier]; - - // Configure the cell. - const BOOL useDarkBackground = indexPath.row % 2; - NSString *backgroundImagePath = [[NSBundle mainBundle] pathForResource : useDarkBackground ? @"DarkBackground" : @"LightBackground" ofType : @"png"]; - - UIImage *backgroundImage = [[UIImage imageWithContentsOfFile : backgroundImagePath] stretchableImageWithLeftCapWidth : 0.f topCapHeight : 1.f]; - cell.backgroundView = [[UIImageView alloc] initWithImage : backgroundImage]; - cell.backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - cell.backgroundView.frame = cell.bounds; - - cell.textLabel.text = [tutorialNames objectAtIndex : indexPath.row]; - cell.imageView.image = [UIImage imageNamed : [tutorialIcons objectAtIndex : indexPath.row]]; - - return cell; -} - -//_________________________________________________________________ -- (void) tableView : (UITableView *)tableView didSelectRowAtIndexPath : (NSIndexPath *)indexPath -{ - [self.detailViewController dismissPopover]; - [self.detailViewController setActiveDemo : demos[indexPath.row]]; -} - -//_________________________________________________________________ -- (void) didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - // Relinquish ownership any cached data, images, etc that aren't in use. -} - -//_________________________________________________________________ -- (void) viewDidUnload -{ - // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand. - // For example: self.myOutlet = nil; -} - -//_________________________________________________________________ -- (void) dealloc -{ - for (unsigned i = 0; i < nROOTDemos; ++i) - delete demos[i]; -} - -//_________________________________________________________________ -- (void) tableView : (UITableView *)tableView willDisplayCell : (UITableViewCell *)cell forRowAtIndexPath : (NSIndexPath *)indexPath -{ - [[cell textLabel] setBackgroundColor : [UIColor clearColor]]; - [[cell detailTextLabel] setBackgroundColor : [UIColor clearColor]]; -} - -@end diff --git a/test/ios/Tutorials/Tutorials/Tutorials-Info.plist b/test/ios/Tutorials/Tutorials/Tutorials-Info.plist deleted file mode 100644 index 136b11117bf71..0000000000000 --- a/test/ios/Tutorials/Tutorials/Tutorials-Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - ${PRODUCT_NAME} - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleGetInfoString - - CFBundleIconFile - tutorials_app_icon.png - CFBundleIdentifier - ch.cern.ROOT1 - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - LSApplicationCategoryType - - LSRequiresIPhoneOS - - NSHumanReadableCopyright - - NSMainNibFile - MainWindow - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationPortrait - - - diff --git a/test/ios/Tutorials/Tutorials/Tutorials-Prefix.pch b/test/ios/Tutorials/Tutorials/Tutorials-Prefix.pch deleted file mode 100644 index d59a721d3e4ce..0000000000000 --- a/test/ios/Tutorials/Tutorials/Tutorials-Prefix.pch +++ /dev/null @@ -1,14 +0,0 @@ -// -// Prefix header for all source files of the 'Tutorials' target in the 'Tutorials' project -// - -#import - -#ifndef __IPHONE_3_0 -#warning "This project uses features only available in iPhone SDK 3.0 and later." -#endif - -#ifdef __OBJC__ - #import - #import -#endif diff --git a/test/ios/Tutorials/Tutorials/TutorialsAppDelegate.h b/test/ios/Tutorials/Tutorials/TutorialsAppDelegate.h deleted file mode 100644 index c7865fa16410b..0000000000000 --- a/test/ios/Tutorials/Tutorials/TutorialsAppDelegate.h +++ /dev/null @@ -1,15 +0,0 @@ -#import - -@class DetailViewController; -@class RootViewController; - -class TApplication; - -@interface TutorialsAppDelegate : NSObject - -@property (nonatomic, retain) IBOutlet UIWindow *window; -@property (nonatomic, retain) IBOutlet UISplitViewController *splitViewController; -@property (nonatomic, retain) IBOutlet RootViewController *rootViewController; -@property (nonatomic, retain) IBOutlet DetailViewController *detailViewController; - -@end diff --git a/test/ios/Tutorials/Tutorials/TutorialsAppDelegate.mm b/test/ios/Tutorials/Tutorials/TutorialsAppDelegate.mm deleted file mode 100644 index eb7dc1d93e927..0000000000000 --- a/test/ios/Tutorials/Tutorials/TutorialsAppDelegate.mm +++ /dev/null @@ -1,78 +0,0 @@ -#import "TutorialsAppDelegate.h" -#import "RootViewController.h" - -#import "TApplication.h" - -@implementation TutorialsAppDelegate { - TApplication *rootApp; -} - -@synthesize window; -@synthesize splitViewController; -@synthesize rootViewController; -@synthesize detailViewController; - -//_________________________________________________________________ -- (BOOL) application : (UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - // Override point for customization after application launch. - // Add the split view controller's view to the window and display. - rootApp = new TApplication("iosApp", 0, 0); - - self.window.rootViewController = self.splitViewController; - [self.window makeKeyAndVisible]; - - return YES; -} - -//_________________________________________________________________ -- (void)applicationWillResignActive:(UIApplication *)application -{ - /* - Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - */ -} - -//_________________________________________________________________ -- (void)applicationDidEnterBackground:(UIApplication *)application -{ - /* - Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - */ -} - -//_________________________________________________________________ -- (void)applicationWillEnterForeground:(UIApplication *)application -{ - /* - Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - */ -} - -//_________________________________________________________________ -- (void)applicationDidBecomeActive:(UIApplication *)application -{ - /* - Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - */ -} - -//_________________________________________________________________ -- (void)applicationWillTerminate:(UIApplication *)application -{ - /* - Called when the application is about to terminate. - Save data if appropriate. - See also applicationDidEnterBackground:. - */ -} - -//_________________________________________________________________ -- (void)dealloc -{ - delete rootApp; -} - -@end diff --git a/test/ios/Tutorials/Tutorials/en.lproj/DetailView.xib b/test/ios/Tutorials/Tutorials/en.lproj/DetailView.xib deleted file mode 100644 index 2493acef0d543..0000000000000 --- a/test/ios/Tutorials/Tutorials/en.lproj/DetailView.xib +++ /dev/null @@ -1,462 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - YES - IBUITabBar - IBUIBarButtonItem - IBUIToolbar - IBUIView - IBUITabBarItem - IBProxyObject - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 274 - - YES - - - 290 - {768, 44} - - - - NO - NO - IBIPadFramework - 1 - - YES - - Show editor - IBIPadFramework - 1 - - - - IBIPadFramework - - 5 - - - Help - IBIPadFramework - 1 - - - - - - - 266 - {{0, 955}, {768, 49}} - - - - 3 - MCAwAA - - NO - NO - IBIPadFramework - - YES - - 1 - Zoom - - NSImage - zoom_mode_icon.png - - IBIPadFramework - - - - 2 - Select and edit - - NSImage - select_mode.png - - IBIPadFramework - - - - - - {{0, 20}, {768, 1004}} - - - - - 3 - MQA - - NO - - 2 - - IBIPadFramework - - - - - YES - - - view - - - - 12 - - - - toolbar - - - - 65 - - - - tabBar - - - - 119 - - - - showHelp - - - - 110 - - - - delegate - - - - 114 - - - - editButtonPressed: - - - - 118 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 8 - - - YES - - - - - - - 63 - - - YES - - - - - - - - 108 - - - - - 109 - - - - - 111 - - - YES - - - - - - - 112 - - - - - 113 - - - - - 115 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 108.IBPluginDependency - 109.IBPluginDependency - 111.IBPluginDependency - 111.notes - 111.showNotes - 112.IBPluginDependency - 113.IBPluginDependency - 115.IBPluginDependency - 63.IBPluginDependency - 8.IBPluginDependency - - - YES - DetailViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - aa - - - YES - - YES - NSFont - NSParagraphStyle - - - YES - - Helvetica - 12 - 16 - - - 4 - - - - - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 119 - - - - YES - - DetailViewController - UIViewController - - YES - - YES - editButtonPressed: - selectButtonPressed - showHelp - zoomButtonPressed - - - YES - id - id - id - id - - - - YES - - YES - editButtonPressed: - selectButtonPressed - showHelp - zoomButtonPressed - - - YES - - editButtonPressed: - id - - - selectButtonPressed - id - - - showHelp - id - - - zoomButtonPressed - id - - - - - YES - - YES - help - tabBar - toolbar - - - YES - UIView - UITabBar - UIToolbar - - - - YES - - YES - help - tabBar - toolbar - - - YES - - help - UIView - - - tabBar - UITabBar - - - toolbar - UIToolbar - - - - - IBProjectSource - ./Classes/DetailViewController.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - select_mode.png - zoom_mode_icon.png - - - YES - {43, 30} - {41, 30} - - - 933 - - diff --git a/test/ios/Tutorials/Tutorials/en.lproj/InfoPlist.strings b/test/ios/Tutorials/Tutorials/en.lproj/InfoPlist.strings deleted file mode 100644 index 477b28ff8f86a..0000000000000 --- a/test/ios/Tutorials/Tutorials/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,2 +0,0 @@ -/* Localized versions of Info.plist keys */ - diff --git a/test/ios/Tutorials/Tutorials/en.lproj/MainWindow.xib b/test/ios/Tutorials/Tutorials/en.lproj/MainWindow.xib deleted file mode 100644 index 68d695b393145..0000000000000 --- a/test/ios/Tutorials/Tutorials/en.lproj/MainWindow.xib +++ /dev/null @@ -1,406 +0,0 @@ - - - - 800 - 10K540 - 1305 - 1038.36 - 461.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 300 - - - IBProxyObject - IBUINavigationController - IBUIViewController - IBUICustomObject - IBUISplitViewController - IBUIWindow - IBUITableViewController - IBUINavigationBar - IBUINavigationItem - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 292 - {768, 1024} - - - - 1 - MC4wMDUxMDIwNDA4MTYgMC4wMDUxMDIwNDA4MTYgMC4wMDUxMDIwNDA4MTYAA - - NO - NO - - 2 - - IBIPadFramework - YES - - - IBIPadFramework - - - - - 2 - - - 3 - 3 - - IBIPadFramework - YES - - - - 2 - - - 1 - 1 - - IBIPadFramework - NO - - - 256 - {0, 0} - YES - YES - IBIPadFramework - 1 - - - - - - Tutorials - IBIPadFramework - - - - 2 - - - 1 - 1 - - IBIPadFramework - NO - - - - - - - DetailView - - 1 - 1 - - IBIPadFramework - NO - - - - - - - - window - - - - 4 - - - - delegate - - - - 17 - - - - splitViewController - - - - 43 - - - - rootViewController - - - - 44 - - - - detailViewController - - - - 45 - - - - detailViewController - - - - 46 - - - - delegate - - - - 49 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - - - 3 - - - - - 37 - - - - - - - - - 38 - - - - - - - - - 39 - - - - - 40 - - - - - - - - 41 - - - - - 42 - - - - - - - UIApplication - UIResponder - {{190, 57}, {783, 799}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - TutorialsAppDelegate - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - {{794, 594}, {1024, 768}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - DetailViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - RootViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 49 - - - - - DetailViewController - UIViewController - - id - id - id - id - - - - editButtonPressed - id - - - selectButtonPressed - id - - - showHelp - id - - - zoomButtonPressed - id - - - - UILabel - UIView - UIView - UITabBar - UIToolbar - - - - detailDescriptionLabel - UILabel - - - editor - UIView - - - help - UIView - - - tb - UITabBar - - - toolbar - UIToolbar - - - - IBProjectSource - ./Classes/DetailViewController.h - - - - RootViewController - UITableViewController - - detailViewController - DetailViewController - - - detailViewController - - detailViewController - DetailViewController - - - - IBProjectSource - ./Classes/RootViewController.h - - - - TutorialsAppDelegate - NSObject - - DetailViewController - RootViewController - UISplitViewController - UIWindow - - - - detailViewController - DetailViewController - - - rootViewController - RootViewController - - - splitViewController - UISplitViewController - - - window - UIWindow - - - - IBProjectSource - ./Classes/TutorialsAppDelegate.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 300 - - diff --git a/test/ios/Tutorials/Tutorials/main.m b/test/ios/Tutorials/Tutorials/main.m deleted file mode 100644 index 8a6f93d9a6952..0000000000000 --- a/test/ios/Tutorials/Tutorials/main.m +++ /dev/null @@ -1,8 +0,0 @@ -#import - -int main(int argc, char *argv[]) -{ - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, nil); - } -} diff --git a/test/ios/Tutorials/h2poly.root b/test/ios/Tutorials/h2poly.root deleted file mode 100644 index c6502b16a7820..0000000000000 Binary files a/test/ios/Tutorials/h2poly.root and /dev/null differ diff --git a/test/stress.cxx b/test/stress.cxx index 9e5d317e7e744..f00ed33633180 100644 --- a/test/stress.cxx +++ b/test/stress.cxx @@ -357,7 +357,7 @@ void stress2() //Long64_t lastgood = 9789; // changes for new TFormula //Long64_t lastgood = 9797; // changes for TH1 v8 ROOT-9173 on 32-bits #ifdef R__HAS_DEFAULT_LZ4 - Long64_t lastgood = 11579; + Long64_t lastgood = 10733; if (last < lastgood - 200 || last > lastgood + 200 || comp < 1.5 || comp > 2.1) OK = kFALSE; #else diff --git a/test/stressGraphics.ref b/test/stressGraphics.ref index 00e034737b836..a40945127bbf4 100644 --- a/test/stressGraphics.ref +++ b/test/stressGraphics.ref @@ -25,20 +25,20 @@ Test# PS1Ref# PS1Err# PDFRef# PDFErr# GIFRef# GIFErr# JPGRef# JP 24 7813 300 23739 100 4662 2300 11085 6000 6973 3100 8081 300 25 28422 150 29391 100 5187 1400 14104 14800 7386 2800 14493 150 26 4545 150 14541 100 11094 1400 27602 14800 13094 2800 4467 150 - 27 6141 200 15967 100 14776 4200 39594 21600 19331 7000 6126 200 + 27 6141 200 15967 100 14776 4200 39594 21600 19331 7000 6596 500 28 9110 500 16737 200 9738 4200 21346 21600 10645 7000 8869 500 29 7419 500 15112 200 8113 4200 18872 21600 7928 7000 7296 500 30 17016 5500 18198 100 13764 3400 32434 17400 22157 5000 20823 5500 31 30615 8200 27494 150 29010 5900 50520 18200 35724 5400 36690 8200 - 32 3304592 100 712308 100 155478 32000 62688 19000 123056 7000 0 0 - 33 321963 5500 434394 1000 34942 8300 65532 27800 37314 12000 331505 5500 + 32 3304592 100 712308 500 155478 32000 62688 19000 123056 7000 0 0 + 33 321963 5500 434394 1100 34942 8300 65532 27800 37314 12000 331505 5500 34 36514 300 16815 200 25333 2200 47408 12700 33739 3700 36399 300 35 207729 750 87126 100 41853 6200 76094 38000 54717 11000 210497 800 36 401670 6500 156361 500 38898 10400 62719 34100 45592 14000 410114 6500 37 566142 5000 225206 750 43638 6300 65828 31800 53934 6500 573396 5000 - 38 3738751 35000 1292739 500 84139 3400 60580 9900 133547 3500 3783013 35000 + 38 3738751 35000 1292739 8000 84139 3400 60580 9900 133547 3500 3783013 35000 39 1456993 9000 853193 50000 54777 8600 38425 13500 91242 18100 1463263 7500 - 40 38312 200 56877 100 47205 3900 36524 11800 119641 8000 38121 200 + 40 38312 200 56877 250 47205 3900 36524 11800 119641 8000 38121 200 41 15025 3000 29289 500 34091 1500 42525 11300 33336 3900 14787 4000 42 254604 5000 376027 7000 34608 5000 55666 30400 46534 6500 259594 7000 43 4846 150 14075 100 24281 200 33239 600 25303 300 4877 150 diff --git a/test/stressHistogram.cxx b/test/stressHistogram.cxx index cd0917b38f8e5..35b3d38d257eb 100644 --- a/test/stressHistogram.cxx +++ b/test/stressHistogram.cxx @@ -3678,6 +3678,7 @@ bool testMerge1DLabelSame() h4->Fill(labels[i], 1.0); } + TList *list = new TList; list->Add(h2); list->Add(h3); @@ -3694,6 +3695,65 @@ bool testMerge1DLabelSame() return ret; } +bool testMerge1DLabelSameStatsBug() +{ + // Tests the merge with some equal labels method for 1D Histograms + // number of labels used = number of bins + // This test uses SetBinCOntent instead of Fill and ResetStats after to + // test th ebug in TH1::Merge reported in ROOT-9336 + + // since we do not set bin errors + // make sure we have not stored Sumw2 otherwise all bin errors + // will be zero. This needs to be done before constructing the histograms + bool globalSumw2 = TH1::GetDefaultSumw2(); + if (globalSumw2) TH1::SetDefaultSumw2(false); + + + TH1D* h1 = new TH1D("h1", "h1-Title", numberOfBins, minRange, maxRange); + TH1D* h2 = new TH1D("h2", "h2-Title", numberOfBins, minRange, maxRange); + TH1D* h3 = new TH1D("h3", "h3-Title", numberOfBins, minRange, maxRange); + TH1D* h4 = new TH1D("h4", "h4-Title", numberOfBins, minRange, maxRange); + + const char labels[10][5] = {"aaa","bbb","ccc","ddd","eee","fff","ggg","hhh","iii","lll"}; + + for (Int_t i = 0; i < numberOfBins; ++i) { + h1->GetXaxis()->SetBinLabel(i+1, labels[i]); + h2->GetXaxis()->SetBinLabel(i+1, labels[i]); + h3->GetXaxis()->SetBinLabel(i+1, labels[i]); + h4->GetXaxis()->SetBinLabel(i+1, labels[i]); + double val1 = r.Uniform(0,10); + double val2 = r.Uniform(0,10); + h2->SetBinContent(i, val1); + h3->SetBinContent(i, val2); + h4->SetBinContent(i, val1+val2); + } + + + TList *list = new TList; + list->Add(h2); + list->Add(h3); + + h1->SetCanExtend(TH1::kAllAxes); + + // reset the stats to get correct entries + // the reset was causing the histogram to be flagged as empty + // see bug ROOT-9336 + h2->ResetStats(); + h3->ResetStats(); + h4->ResetStats(); + + h1->Merge(list); + + bool ret = equals("MergeLabelSame1DStatsBug", h1, h4, cmpOptStats, 1E-10); + if (cleanHistos) delete h1; + if (cleanHistos) delete h2; + if (cleanHistos) delete h3; + + if (globalSumw2) TH1::SetDefaultSumw2(true); + + return ret; +} + bool testMerge2DLabelSame() { // Tests the merge with some equal labels method for 2D Histograms @@ -6573,16 +6633,9 @@ bool testH1BufferWeights() { h2->Fill(x,w); } - int pr = std::cout.precision(15); - double eps = TMath::Limits::Epsilon(); - - // Adjust the threshold on ARM64 bits. On this RISC architecture, - // there is a difference when incrementing the sumwx with variables - // saved in memory (in the histogram buffer) and passed as function - // arguments (Fill(x,w)). -#ifdef __aarch64__ - eps*=28; -#endif + // We use 30 epsilon below because some platforms (ARM64, x86_64) + // have rounding errors exceeding a few ulps and make the test fail. + double eps = 30 * std::numeric_limits::epsilon(); bool itest = false; @@ -6592,11 +6645,11 @@ bool testH1BufferWeights() { h2->GetStats(s2); std::vector snames = {"sumw","sumw2","sumwx","sumwx2"}; for (unsigned int i =0; i < snames.size(); ++i) { - itest = equals(s1[i],s2[i],eps ); - if (defaultEqualOptions & cmpOptDebug ) { - std::cout << "Statistics " << snames[i] << " = " << s1[i] << " " << s2[i] << " - " << itest << std::endl; - } - iret |= itest; + itest = equals(s1[i],s2[i],eps ); + if (defaultEqualOptions & cmpOptDebug ) { + std::cout << "Statistics " << snames[i] << " = " << s1[i] << " " << s2[i] << " - " << itest << std::endl; + } + iret |= itest; } // another fill will reset the histogram @@ -6613,15 +6666,13 @@ bool testH1BufferWeights() { iret |= equals("testh1bufferweight",h1,h2,cmpOptStats,eps); - std::cout.precision(pr); + std::cout.precision(15); if (cleanHistos) delete h1; if ( defaultEqualOptions & cmpOptPrint ) std::cout << "Buffer Weighted H1:\t" << (iret?"FAILED":"OK") << std::endl; - - return iret; } @@ -10061,7 +10112,8 @@ int stressHistogram() testMerge3DLabelAll, testMergeProf3DLabelAll, testMerge1DLabelAllDiff, testMergeProf1DLabelAllDiff, testMerge2DLabelAllDiff, testMergeProf2DLabelAllDiff, - testMerge3DLabelAllDiff, testMergeProf3DLabelAllDiff + testMerge3DLabelAllDiff, testMergeProf3DLabelAllDiff, + testMerge1DLabelSameStatsBug }; std::vector mergeDiffTestPointer = { testMerge1DDiff, testMergeProf1DDiff, testMerge2DDiff, testMergeProf2DDiff, diff --git a/test/stressMathCore.cxx b/test/stressMathCore.cxx index a4a9e17870246..6bd50920ba270 100644 --- a/test/stressMathCore.cxx +++ b/test/stressMathCore.cxx @@ -1366,7 +1366,7 @@ int testSMatrix(int ngen, bool testio=false) { typeName = "ROOT::Math::"+name0+ "," + Rep::name32() + ">"; - estSize = ngen* 4 * Dim + 10000; + estSize = ngen* 4 * Dim + 60158; scale = 0.1 / std::numeric_limits::epsilon(); fsize32 = a.testWrite(v1,typeName); iret |= a.check(name+" write",fsize32,estSize,scale); ir = a.testRead(v1); iret |= a.check(name+" read",ir,0); diff --git a/tmva/tmva/inc/TMVA/DNN/Architectures/Cpu.h b/tmva/tmva/inc/TMVA/DNN/Architectures/Cpu.h index 45ffe910de82a..2c14497eca0ce 100644 --- a/tmva/tmva/inc/TMVA/DNN/Architectures/Cpu.h +++ b/tmva/tmva/inc/TMVA/DNN/Architectures/Cpu.h @@ -396,9 +396,15 @@ class TCpu /** Perform the complete backward propagation step in a Pooling Layer. Based on the * winning idices stored in the index matrix, it just forwards the actiovation * gradients to the previous layer. */ - static void MaxPoolLayerBackward(std::vector> &activationGradientsBackward, - const std::vector> &activationGradients, - const std::vector> &indexMatrix, size_t batchSize, size_t depth, + static void MaxPoolLayerBackward(TCpuMatrix &activationGradientsBackward, + const TCpuMatrix &activationGradients, + const TCpuMatrix &indexMatrix, + size_t imgHeight, + size_t imgWidth, + size_t fltHeight, + size_t fltWidth, + size_t strideRows, + size_t strideCols, size_t nLocalViews); ///@} diff --git a/tmva/tmva/inc/TMVA/DNN/Architectures/Cpu/CpuMatrix.h b/tmva/tmva/inc/TMVA/DNN/Architectures/Cpu/CpuMatrix.h index 0bef3024eda7d..a298493b3c08f 100644 --- a/tmva/tmva/inc/TMVA/DNN/Architectures/Cpu/CpuMatrix.h +++ b/tmva/tmva/inc/TMVA/DNN/Architectures/Cpu/CpuMatrix.h @@ -25,7 +25,7 @@ #include "CpuBuffer.h" #include -#define DEBUG_TMVA_TCPUMATRIX +//#define DEBUG_TMVA_TCPUMATRIX #if defined(DEBUG_TMVA_TCPUMATRIX) #define PrintMatrix(mat, text) \ { \ diff --git a/tmva/tmva/inc/TMVA/DNN/Architectures/Cuda.h b/tmva/tmva/inc/TMVA/DNN/Architectures/Cuda.h index 0a17eed5db012..79c759a562e37 100644 --- a/tmva/tmva/inc/TMVA/DNN/Architectures/Cuda.h +++ b/tmva/tmva/inc/TMVA/DNN/Architectures/Cuda.h @@ -405,9 +405,15 @@ class TCuda /** Perform the complete backward propagation step in a Pooling Layer. Based on the * winning idices stored in the index matrix, it just forwards the actiovation * gradients to the previous layer. */ - static void MaxPoolLayerBackward(std::vector> &activationGradientsBackward, - const std::vector> &activationGradients, - const std::vector> &indexMatrix, size_t batchSize, size_t depth, + static void MaxPoolLayerBackward(TCudaMatrix &activationGradientsBackward, + const TCudaMatrix &activationGradients, + const TCudaMatrix &indexMatrix, + size_t imgHeight, + size_t imgWidth, + size_t fltHeight, + size_t fltWidth, + size_t strideRows, + size_t strideCols, size_t nLocalViews); ///@} diff --git a/tmva/tmva/inc/TMVA/DNN/Architectures/Cuda/CudaMatrix.h b/tmva/tmva/inc/TMVA/DNN/Architectures/Cuda/CudaMatrix.h index b6b84d78ef3e1..f4ed673d52675 100644 --- a/tmva/tmva/inc/TMVA/DNN/Architectures/Cuda/CudaMatrix.h +++ b/tmva/tmva/inc/TMVA/DNN/Architectures/Cuda/CudaMatrix.h @@ -165,11 +165,8 @@ class TCudaMatrix mat.Print(); } - void Zero() { - // to be checked - AFloat * p = GetDataPointer(); - for (size_t i = 0; i < GetNoElements(); ++i) - p[i] = 0; + void Zero() { + cudaMemset(GetDataPointer(), 0, sizeof(AFloat) * GetNoElements()); } diff --git a/tmva/tmva/inc/TMVA/DNN/Architectures/Reference.h b/tmva/tmva/inc/TMVA/DNN/Architectures/Reference.h index 294c1839a23ae..e8db2d847a667 100644 --- a/tmva/tmva/inc/TMVA/DNN/Architectures/Reference.h +++ b/tmva/tmva/inc/TMVA/DNN/Architectures/Reference.h @@ -427,9 +427,15 @@ class TReference /** Perform the complete backward propagation step in a Max Pooling Layer. Based on the * winning idices stored in the index matrix, it just forwards the actiovation * gradients to the previous layer. */ - static void MaxPoolLayerBackward(std::vector> &activationGradientsBackward, - const std::vector> &activationGradients, - const std::vector> &indexMatrix, size_t batchSize, size_t depth, + static void MaxPoolLayerBackward(TMatrixT &activationGradientsBackward, + const TMatrixT &activationGradients, + const TMatrixT &indexMatrix, + size_t imgHeight, + size_t imgWidth, + size_t fltHeight, + size_t fltWidth, + size_t strideRows, + size_t strideCol, size_t nLocalViews); ///@} //____________________________________________________________________________ diff --git a/tmva/tmva/inc/TMVA/DNN/CNN/ConvLayer.h b/tmva/tmva/inc/TMVA/DNN/CNN/ConvLayer.h index 73b6eda106636..1caa362ef3556 100644 --- a/tmva/tmva/inc/TMVA/DNN/CNN/ConvLayer.h +++ b/tmva/tmva/inc/TMVA/DNN/CNN/ConvLayer.h @@ -46,6 +46,19 @@ class TConvLayer : public VGeneralLayer { using Scalar_t = typename Architecture_t::Scalar_t; private: + bool inline isInteger(Scalar_t x) const { return x == floor(x); } + + /* Calculate the output dimension of the convolutional layer */ + size_t calculateDimension(size_t imgDim, size_t fltDim, size_t padding, size_t stride); + + /* Calculate the number of pixels in a single receptive field */ + size_t inline calculateNLocalViewPixels(size_t depth, size_t height, size_t width) { return depth * height * width; } + + /* Calculate the number of receptive fields in an image given the filter and image sizes */ + size_t calculateNLocalViews(size_t inputHeight, size_t filterHeight, size_t paddingHeight, size_t strideRows, + size_t inputWidth, size_t filterWidth, size_t paddingWidth, size_t strideCols); + +protected: size_t fFilterDepth; ///< The depth of the filter. size_t fFilterHeight; ///< The height of the filter. size_t fFilterWidth; ///< The width of the filter. @@ -53,14 +66,15 @@ class TConvLayer : public VGeneralLayer { size_t fStrideRows; ///< The number of row pixels to slid the filter each step. size_t fStrideCols; ///< The number of column pixels to slid the filter each step. - size_t fPaddingHeight; ///< The number of zero layers added top and bottom of the input. - size_t fPaddingWidth; ///< The number of zero layers left and right of the input. - size_t fNLocalViewPixels; ///< The number of pixels in one local image view. size_t fNLocalViews; ///< The number of local views in one image. Scalar_t fDropoutProbability; ///< Probability that an input is active. +private: + size_t fPaddingHeight; ///< The number of zero layers added top and bottom of the input. + size_t fPaddingWidth; ///< The number of zero layers left and right of the input. + std::vector fDerivatives; ///< First fDerivatives of the activations of this layer. std::vector fForwardIndices; ///< Vector of indices used for a fast Im2Col in forward pass @@ -71,11 +85,10 @@ class TConvLayer : public VGeneralLayer { ERegularization fReg; ///< The regularization method. Scalar_t fWeightDecay; ///< The weight decay. + public: /*! Constructor. */ - TConvLayer(size_t BatchSize, size_t InputDepth, size_t InputHeight, size_t InputWidth, size_t Depth, size_t Height, - size_t Width, size_t WeightsNRows, size_t WeightsNCols, size_t BiasesNRows, size_t BiasesNCols, - size_t OutputNSlices, size_t OutputNRows, size_t OutputNCols, EInitialization Init, size_t FilterDepth, + TConvLayer(size_t BatchSize, size_t InputDepth, size_t InputHeight, size_t InputWidth, size_t Depth, EInitialization Init, size_t FilterHeight, size_t FilterWidth, size_t StrideRows, size_t StrideCols, size_t PaddingHeight, size_t PaddingWidth, Scalar_t DropoutProbability, EActivationFunction f, ERegularization Reg, Scalar_t WeightDecay); @@ -145,23 +158,32 @@ class TConvLayer : public VGeneralLayer { //______________________________________________________________________________ template TConvLayer::TConvLayer(size_t batchSize, size_t inputDepth, size_t inputHeight, size_t inputWidth, - size_t depth, size_t height, size_t width, size_t weightsNRows, - size_t weightsNCols, size_t biasesNRows, size_t biasesNCols, - size_t outputNSlices, size_t outputNRows, size_t outputNCols, - EInitialization init, size_t filterDepth, size_t filterHeight, - size_t filterWidth, size_t strideRows, size_t strideCols, size_t paddingHeight, - size_t paddingWidth, Scalar_t dropoutProbability, EActivationFunction f, - ERegularization reg, Scalar_t weightDecay) - : VGeneralLayer(batchSize, inputDepth, inputHeight, inputWidth, depth, height, width, 1, - weightsNRows, weightsNCols, 1, biasesNRows, biasesNCols, outputNSlices, outputNRows, - outputNCols, init), - fFilterDepth(filterDepth), fFilterHeight(filterHeight), fFilterWidth(filterWidth), fStrideRows(strideRows), - fStrideCols(strideCols), fPaddingHeight(paddingHeight), fPaddingWidth(paddingWidth), - fNLocalViewPixels(filterDepth * filterHeight * filterWidth), fNLocalViews(height * width), - fDropoutProbability(dropoutProbability), fDerivatives(), fF(f), fReg(reg), fWeightDecay(weightDecay) + size_t depth, EInitialization init, size_t filterHeight, size_t filterWidth, + size_t strideRows, size_t strideCols, size_t paddingHeight, size_t paddingWidth, + Scalar_t dropoutProbability, EActivationFunction f, ERegularization reg, + Scalar_t weightDecay) + : VGeneralLayer(batchSize, inputDepth, inputHeight, inputWidth, depth, + calculateDimension(inputHeight, filterHeight, paddingHeight, strideRows), + calculateDimension(inputWidth, filterWidth, paddingWidth, strideCols), + 1, depth, calculateNLocalViewPixels(inputDepth, filterHeight, filterWidth), + 1, depth, 1, batchSize, depth, + calculateNLocalViews(inputHeight, filterHeight, paddingHeight, strideRows, + inputWidth, filterWidth, paddingWidth, strideCols), + init), + fFilterDepth(inputDepth), fFilterHeight(filterHeight), fFilterWidth(filterWidth), fStrideRows(strideRows), + fStrideCols(strideCols), fNLocalViewPixels(calculateNLocalViewPixels(inputDepth, filterHeight, filterWidth)), + fNLocalViews(calculateNLocalViews(inputHeight, filterHeight, paddingHeight, strideRows, + inputWidth, filterWidth, paddingWidth, strideCols)), + fDropoutProbability(dropoutProbability), fPaddingHeight(paddingHeight), fPaddingWidth(paddingWidth), + fDerivatives(), fF(f), fReg(reg), fWeightDecay(weightDecay) { - for (size_t i = 0; i < outputNSlices; i++) { - fDerivatives.emplace_back(outputNRows, outputNCols); + /** Each element in the vector is a `T_Matrix` representing an event, therefore `vec.size() == batchSize`. + * Cells in these matrices are distributed in the following manner: + * Each row represents a single feature map, therefore we have `nRows == depth`. + * Each column represents a single pixel in that feature map, therefore we have `nCols == nLocalViews`. + **/ + for (size_t i = 0; i < batchSize; i++) { + fDerivatives.emplace_back(depth, fNLocalViews); } } @@ -171,9 +193,9 @@ TConvLayer::TConvLayer(TConvLayer *layer) : VGeneralLayer(layer), fFilterDepth(layer->GetFilterDepth()), fFilterHeight(layer->GetFilterHeight()), fFilterWidth(layer->GetFilterWidth()), fStrideRows(layer->GetStrideRows()), fStrideCols(layer->GetStrideCols()), - fPaddingHeight(layer->GetPaddingHeight()), fPaddingWidth(layer->GetPaddingWidth()), fNLocalViewPixels(layer->GetNLocalViewPixels()), fNLocalViews(layer->GetNLocalViews()), - fDropoutProbability(layer->GetDropoutProbability()), fF(layer->GetActivationFunction()), + fDropoutProbability(layer->GetDropoutProbability()), fPaddingHeight(layer->GetPaddingHeight()), + fPaddingWidth(layer->GetPaddingWidth()), fF(layer->GetActivationFunction()), fReg(layer->GetRegularization()), fWeightDecay(layer->GetWeightDecay()) { size_t outputNSlices = (layer->GetDerivatives()).size(); @@ -193,9 +215,9 @@ template TConvLayer::TConvLayer(const TConvLayer &convLayer) : VGeneralLayer(convLayer), fFilterDepth(convLayer.fFilterDepth), fFilterHeight(convLayer.fFilterHeight), fFilterWidth(convLayer.fFilterWidth), fStrideRows(convLayer.fStrideRows), - fStrideCols(convLayer.fStrideCols), fPaddingHeight(convLayer.fPaddingHeight), - fPaddingWidth(convLayer.fPaddingWidth), fNLocalViewPixels(convLayer.fNLocalViewPixels), - fNLocalViews(convLayer.fNLocalViews), fDropoutProbability(convLayer.fDropoutProbability), fF(convLayer.fF), + fStrideCols(convLayer.fStrideCols), fNLocalViewPixels(convLayer.fNLocalViewPixels), + fNLocalViews(convLayer.fNLocalViews), fDropoutProbability(convLayer.fDropoutProbability), + fPaddingHeight(convLayer.fPaddingHeight), fPaddingWidth(convLayer.fPaddingWidth), fF(convLayer.fF), fReg(convLayer.fReg), fWeightDecay(convLayer.fWeightDecay) { size_t outputNSlices = convLayer.fDerivatives.size(); @@ -351,6 +373,28 @@ void TConvLayer::ReadWeightsFromXML(void *parent) this->ReadMatrixXML(parent,"Biases", this -> GetBiasesAt(0)); } +template +size_t TConvLayer::calculateDimension(size_t imgDim, size_t fltDim, size_t padding, size_t stride) +{ + Scalar_t dimension = ((imgDim - fltDim + 2 * padding) / stride) + 1; + if (!isInteger(dimension) || dimension <= 0) { + Fatal("calculateDimension", "Not compatible hyper parameters for layer - (imageDim, filterDim, padding, stride) %zu , %zu , %zu , %zu", + imgDim, fltDim, padding, stride); + } + + return (size_t)dimension; +} + +template +size_t TConvLayer::calculateNLocalViews(size_t inputHeight, size_t filterHeight, size_t paddingHeight, + size_t strideRows, size_t inputWidth, size_t filterWidth, + size_t paddingWidth, size_t strideCols) +{ + int height = calculateDimension(inputHeight, filterHeight, paddingHeight, strideRows); + int width = calculateDimension(inputWidth, filterWidth, paddingWidth, strideCols); + + return height * width; +} } // namespace CNN } // namespace DNN diff --git a/tmva/tmva/inc/TMVA/DNN/CNN/MaxPoolLayer.h b/tmva/tmva/inc/TMVA/DNN/CNN/MaxPoolLayer.h index 98ad5843e6bb1..3dded945554cb 100644 --- a/tmva/tmva/inc/TMVA/DNN/CNN/MaxPoolLayer.h +++ b/tmva/tmva/inc/TMVA/DNN/CNN/MaxPoolLayer.h @@ -29,7 +29,7 @@ #include "TMatrix.h" -#include "TMVA/DNN/GeneralLayer.h" +#include "TMVA/DNN/CNN/ConvLayer.h" #include "TMVA/DNN/Functions.h" #include @@ -43,38 +43,30 @@ namespace CNN { Generic Max Pooling Layer class. This generic Max Pooling Layer Class represents a pooling layer of - a CNN. It inherits all of the properties of the generic virtual base class - VGeneralLayer. In addition to that, it contains a matrix of winning units. + a CNN. It inherits all of the properties of the convolutional layer + TConvLayer, but it overrides the propagation methods. In a sense, max pooling + can be seen as non-linear convolution: a filter slides over the input and produces + one element as a function of the the elements within the receptive field. + In addition to that, it contains a matrix of winning units. The height and width of the weights and biases is set to 0, since this layer does not contain any weights. */ template -class TMaxPoolLayer : public VGeneralLayer { +class TMaxPoolLayer : public TConvLayer { + public: - using Matrix_t = typename Architecture_t::Matrix_t; - using Scalar_t = typename Architecture_t::Scalar_t; + using Matrix_t = typename Architecture_t::Matrix_t; + using Scalar_t = typename Architecture_t::Scalar_t; private: std::vector indexMatrix; ///< Matrix of indices for the backward pass. - size_t fFrameHeight; ///< The height of the frame. - size_t fFrameWidth; ///< The width of the frame. - - size_t fStrideRows; ///< The number of row pixels to slid the filter each step. - size_t fStrideCols; ///< The number of column pixels to slid the filter each step. - - size_t fNLocalViewPixels; ///< The number of pixels in one local image view. - size_t fNLocalViews; ///< The number of local views in one image. - - Scalar_t fDropoutProbability; ///< Probability that an input is active. - public: /*! Constructor. */ - TMaxPoolLayer(size_t BatchSize, size_t InputDepth, size_t InputHeight, size_t InputWidth, size_t Height, - size_t Width, size_t OutputNSlices, size_t OutputNRows, size_t OutputNCols, size_t FrameHeight, - size_t FrameWidth, size_t StrideRows, size_t StrideCols, Scalar_t DropoutProbability); + TMaxPoolLayer(size_t BatchSize, size_t InputDepth, size_t InputHeight, size_t InputWidth, size_t FilterHeight, + size_t FilterWidth, size_t StrideRows, size_t StrideCols, Scalar_t DropoutProbability); /*! Copy the max pooling layer provided as a pointer */ TMaxPoolLayer(TMaxPoolLayer *layer); @@ -104,7 +96,6 @@ class TMaxPoolLayer : public VGeneralLayer { /*! Read the information and the weights about the layer from XML node. */ virtual void ReadWeightsFromXML(void *parent); - /*! Prints the info about the layer. */ void Print() const; @@ -112,29 +103,18 @@ class TMaxPoolLayer : public VGeneralLayer { const std::vector &GetIndexMatrix() const { return indexMatrix; } std::vector &GetIndexMatrix() { return indexMatrix; } - size_t GetFrameHeight() const { return fFrameHeight; } - size_t GetFrameWidth() const { return fFrameWidth; } - - size_t GetStrideRows() const { return fStrideRows; } - size_t GetStrideCols() const { return fStrideCols; } - - size_t GetNLocalViewPixels() const { return fNLocalViewPixels; } - size_t GetNLocalViews() const { return fNLocalViews; } - - Scalar_t GetDropoutProbability() const { return fDropoutProbability; } }; //______________________________________________________________________________ template TMaxPoolLayer::TMaxPoolLayer(size_t batchSize, size_t inputDepth, size_t inputHeight, size_t inputWidth, - size_t height, size_t width, size_t outputNSlices, size_t outputNRows, - size_t outputNCols, size_t frameHeight, size_t frameWidth, - size_t strideRows, size_t strideCols, Scalar_t dropoutProbability) - : VGeneralLayer(batchSize, inputDepth, inputHeight, inputWidth, inputDepth, height, width, 0, 0, 0, - 0, 0, 0, outputNSlices, outputNRows, outputNCols, EInitialization::kZero), - indexMatrix(), fFrameHeight(frameHeight), fFrameWidth(frameWidth), fStrideRows(strideRows), - fStrideCols(strideCols), fNLocalViewPixels(inputDepth * frameHeight * frameWidth), fNLocalViews(height * width), - fDropoutProbability(dropoutProbability) + size_t filterHeight, size_t filterWidth, size_t strideRows, + size_t strideCols, Scalar_t dropoutProbability) + + : TConvLayer(batchSize, inputDepth, inputHeight, inputWidth, inputDepth, EInitialization::kZero, + filterHeight, filterWidth, strideRows, strideCols, 0, 0, dropoutProbability, + EActivationFunction::kIdentity, ERegularization::kNone, 0), + indexMatrix() { for (size_t i = 0; i < this->GetBatchSize(); i++) { indexMatrix.emplace_back(this->GetDepth(), this->GetNLocalViews()); @@ -144,10 +124,7 @@ TMaxPoolLayer::TMaxPoolLayer(size_t batchSize, size_t inputDepth //______________________________________________________________________________ template TMaxPoolLayer::TMaxPoolLayer(TMaxPoolLayer *layer) - : VGeneralLayer(layer), indexMatrix(), fFrameHeight(layer->GetFrameHeight()), - fFrameWidth(layer->GetFrameWidth()), fStrideRows(layer->GetStrideRows()), fStrideCols(layer->GetStrideCols()), - fNLocalViewPixels(layer->GetNLocalViewPixels()), fNLocalViews(layer->GetNLocalViews()), - fDropoutProbability(layer->GetDropoutProbability()) + : TConvLayer(layer), indexMatrix() { for (size_t i = 0; i < layer->GetBatchSize(); i++) { indexMatrix.emplace_back(layer->GetDepth(), layer->GetNLocalViews()); @@ -157,10 +134,7 @@ TMaxPoolLayer::TMaxPoolLayer(TMaxPoolLayer *laye //______________________________________________________________________________ template TMaxPoolLayer::TMaxPoolLayer(const TMaxPoolLayer &layer) - : VGeneralLayer(layer), indexMatrix(), fFrameHeight(layer.fFrameHeight), - fFrameWidth(layer.fFrameWidth), fStrideRows(layer.fStrideRows), fStrideCols(layer.fStrideCols), - fNLocalViewPixels(layer.fNLocalViewPixels), fNLocalViews(layer.fNLocalViews), - fDropoutProbability(layer.fDropoutProbability) + : TConvLayer(layer), indexMatrix() { for (size_t i = 0; i < layer.fBatchSize; i++) { indexMatrix.emplace_back(layer.fDepth, layer.fNLocalViews); @@ -184,7 +158,7 @@ auto TMaxPoolLayer::Forward(std::vector &input, bool a } Architecture_t::Downsample(this->GetOutputAt(i), indexMatrix[i], input[i], this->GetInputHeight(), - this->GetInputWidth(), this->GetFrameHeight(), this->GetFrameWidth(), + this->GetInputWidth(), this->GetFilterHeight(), this->GetFilterWidth(), this->GetStrideRows(), this->GetStrideCols()); } } @@ -196,8 +170,13 @@ auto TMaxPoolLayer::Backward(std::vector &gradients_ba std::vector & /*inp1*/, std::vector & /*inp2*/) -> void { - Architecture_t::MaxPoolLayerBackward(gradients_backward, this->GetActivationGradients(), indexMatrix, - this->GetBatchSize(), this->GetDepth(), this->GetNLocalViews()); + for (size_t i = 0; i < this->GetBatchSize(); i++) { + Architecture_t::MaxPoolLayerBackward(gradients_backward[i], this->GetActivationGradients()[i], + this->GetIndexMatrix()[i], + this->GetInputHeight(), this->GetInputWidth(), + this->GetFilterHeight(), this->GetFilterWidth(), + this->GetStrideRows(), this->GetStrideCols(), this->GetNLocalViews()); + } } //______________________________________________________________________________ @@ -209,8 +188,8 @@ auto TMaxPoolLayer::Print() const -> void std::cout << " H = " << this->GetHeight() << " , "; std::cout << " D = " << this->GetDepth() << " ) "; - std::cout << "\t Frame ( W = " << this->GetFrameWidth() << " , "; - std::cout << " H = " << this->GetFrameHeight() << " ) "; + std::cout << "\t Filter ( W = " << this->GetFilterWidth() << " , "; + std::cout << " H = " << this->GetFilterHeight() << " ) "; if (this->GetOutput().size() > 0) { std::cout << "\tOutput = ( " << this->GetOutput().size() << " , " << this->GetOutput()[0].GetNrows() << " , " << this->GetOutput()[0].GetNcols() << " ) "; @@ -225,8 +204,8 @@ void TMaxPoolLayer::AddWeightsXMLTo(void *parent) auto layerxml = gTools().xmlengine().NewChild(parent, 0, "MaxPoolLayer"); // write maxpool layer info - gTools().xmlengine().NewAttr(layerxml, 0, "FrameHeight", gTools().StringFromInt(this->GetFrameHeight())); - gTools().xmlengine().NewAttr(layerxml, 0, "FrameWidth", gTools().StringFromInt(this->GetFrameWidth())); + gTools().xmlengine().NewAttr(layerxml, 0, "FilterHeight", gTools().StringFromInt(this->GetFilterHeight())); + gTools().xmlengine().NewAttr(layerxml, 0, "FilterWidth", gTools().StringFromInt(this->GetFilterWidth())); gTools().xmlengine().NewAttr(layerxml, 0, "StrideRows", gTools().StringFromInt(this->GetStrideRows())); gTools().xmlengine().NewAttr(layerxml, 0, "StrideCols", gTools().StringFromInt(this->GetStrideCols())); diff --git a/tmva/tmva/inc/TMVA/DNN/DeepNet.h b/tmva/tmva/inc/TMVA/DNN/DeepNet.h index 400546ce343f3..884a90568a3d0 100644 --- a/tmva/tmva/inc/TMVA/DNN/DeepNet.h +++ b/tmva/tmva/inc/TMVA/DNN/DeepNet.h @@ -380,8 +380,8 @@ auto TDeepNet::calculateDimension(int imgDim, int fltDi { Scalar_t dimension = ((imgDim - fltDim + 2 * padding) / stride) + 1; if (!isInteger(dimension) || dimension <= 0) { - this->Print(); - int iLayer = fLayers.size(); + this->Print(); + int iLayer = fLayers.size(); Fatal("calculateDimension","Not compatible hyper parameters for layer %d - (imageDim, filterDim, padding, stride) %d , %d , %d , %d", iLayer, imgDim, fltDim, padding, stride); // std::cout << " calculateDimension - Not compatible hyper parameters (imgDim, fltDim, padding, stride)" @@ -405,16 +405,6 @@ TConvLayer *TDeepNet::AddConvLayer(size size_t inputDepth; size_t inputHeight; size_t inputWidth; - size_t height; - size_t width; - size_t filterDepth; - size_t weightsNRows = depth; - size_t weightsNCols; - size_t biasesNRows = depth; - size_t biasesNCols = 1; - size_t outputNSlices = this->GetBatchSize(); - size_t outputNRows = depth; - size_t outputNCols; EInitialization init = this->GetInitialization(); ERegularization reg = this->GetRegularization(); Scalar_t decay = this->GetWeightDecay(); @@ -430,19 +420,12 @@ TConvLayer *TDeepNet::AddConvLayer(size inputWidth = lastLayer->GetWidth(); } - height = calculateDimension(inputHeight, filterHeight, paddingHeight, strideRows); - width = calculateDimension(inputWidth, filterWidth, paddingWidth, strideCols); - - filterDepth = inputDepth; - weightsNCols = filterDepth * filterHeight * filterWidth; - outputNCols = height * width; // Create the conv layer TConvLayer *convLayer = new TConvLayer( - batchSize, inputDepth, inputHeight, inputWidth, depth, height, width, weightsNRows, weightsNCols, biasesNRows, - biasesNCols, outputNSlices, outputNRows, outputNCols, init, filterDepth, filterHeight, filterWidth, strideRows, - strideCols, paddingHeight, paddingWidth, dropoutProbability, f, reg, decay); + batchSize, inputDepth, inputHeight, inputWidth, depth, init, filterHeight, filterWidth, strideRows, + strideCols, paddingHeight, paddingWidth, dropoutProbability, f, reg, decay); fLayers.push_back(convLayer); return convLayer; @@ -465,11 +448,6 @@ TMaxPoolLayer *TDeepNet::AddMaxPoolLaye size_t inputDepth; size_t inputHeight; size_t inputWidth; - size_t height; - size_t width; - size_t outputNSlices = this->GetBatchSize(); - size_t outputNRows; - size_t outputNCols; if (fLayers.size() == 0) { inputDepth = this->GetInputDepth(); @@ -482,15 +460,9 @@ TMaxPoolLayer *TDeepNet::AddMaxPoolLaye inputWidth = lastLayer->GetWidth(); } - height = calculateDimension(inputHeight, frameHeight, 0, strideRows); - width = calculateDimension(inputWidth, frameWidth, 0, strideCols); - - outputNRows = inputDepth; - outputNCols = height * width; - TMaxPoolLayer *maxPoolLayer = new TMaxPoolLayer( - batchSize, inputDepth, inputHeight, inputWidth, height, width, outputNSlices, outputNRows, outputNCols, - frameHeight, frameWidth, strideRows, strideCols, dropoutProbability); + batchSize, inputDepth, inputHeight, inputWidth, frameHeight, frameWidth, + strideRows, strideCols, dropoutProbability); // But this creates a copy or what? fLayers.push_back(maxPoolLayer); diff --git a/tmva/tmva/inc/TMVA/MsgLogger.h b/tmva/tmva/inc/TMVA/MsgLogger.h index 2ddb8c128bb66..9cde1dbfb9da8 100644 --- a/tmva/tmva/inc/TMVA/MsgLogger.h +++ b/tmva/tmva/inc/TMVA/MsgLogger.h @@ -74,7 +74,7 @@ namespace TMVA { std::string GetPrintedSource() const; std::string GetFormattedSource() const; - static UInt_t GetMaxSourceSize() { return (UInt_t)fgMaxSourceSize; } + static UInt_t GetMaxSourceSize() { return static_cast(fgMaxSourceSize); } // Needed for copying MsgLogger& operator= ( const MsgLogger& parent ); diff --git a/tmva/tmva/src/DNN/Architectures/Cpu/Propagation.cxx b/tmva/tmva/src/DNN/Architectures/Cpu/Propagation.cxx index cacbf34bb2843..de30c4e9bd43e 100644 --- a/tmva/tmva/src/DNN/Architectures/Cpu/Propagation.cxx +++ b/tmva/tmva/src/DNN/Architectures/Cpu/Propagation.cxx @@ -556,25 +556,30 @@ void TCpu::Downsample(TCpuMatrix &A, TCpuMatrix &B, cons //____________________________________________________________________________ template -void TCpu::MaxPoolLayerBackward(std::vector> &activationGradientsBackward, - const std::vector> &activationGradients, - const std::vector> &indexMatrix, size_t batchSize, - size_t depth, size_t nLocalViews) +void TCpu::MaxPoolLayerBackward(TCpuMatrix &activationGradientsBackward, + const TCpuMatrix &activationGradients, + const TCpuMatrix &indexMatrix, + size_t /* imgHeight */, + size_t /* imgWidth */, + size_t /* fltHeight */, + size_t /* fltWidth */, + size_t /* strideRows */, + size_t /* strideCols */, + size_t nLocalViews) { - for (size_t i = 0; i < batchSize; i++) { - for (size_t j = 0; j < depth; j++) { + size_t depth = activationGradientsBackward.GetNrows(); - // initialize to zeros - for (size_t t = 0; t < (size_t)activationGradientsBackward[i].GetNcols(); t++) { - activationGradientsBackward[i](j, t) = 0; - } + for (size_t j = 0; j < depth; j++) { + // initialize to zeros + for (size_t t = 0; t < (size_t)activationGradientsBackward.GetNcols(); t++) { + activationGradientsBackward(j, t) = 0; + } - // set values - for (size_t k = 0; k < nLocalViews; k++) { - AFloat grad = activationGradients[i](j, k); - size_t winningIdx = indexMatrix[i](j, k); - activationGradientsBackward[i](j, winningIdx) += grad; - } + // set values + for (size_t k = 0; k < nLocalViews; k++) { + AFloat grad = activationGradients(j, k); + size_t winningIdx = indexMatrix(j, k); + activationGradientsBackward(j, winningIdx) += grad; } } } @@ -589,7 +594,7 @@ void TCpu::Reshape(TCpuMatrix &A, const TCpuMatrix &B) for (size_t i = 0; i < A.GetNrows(); i++) { for (size_t j = 0; j < A.GetNcols(); j++) { size_t nElem = i * nColsA + j; - A(i, j) = B(nElem / nColsB, (nElem - 1) % nColsB); + A(i, j) = B(nElem / nColsB, nElem % nColsB); } } } diff --git a/tmva/tmva/src/DNN/Architectures/Cuda/Kernels.cuh b/tmva/tmva/src/DNN/Architectures/Cuda/Kernels.cuh index b919d2fc75214..f8a6e5bd1ff6a 100644 --- a/tmva/tmva/src/DNN/Architectures/Cuda/Kernels.cuh +++ b/tmva/tmva/src/DNN/Architectures/Cuda/Kernels.cuh @@ -203,6 +203,105 @@ __device__ void ReduceSum(AFloat *result, AFloat * sdata) __syncthreads(); } +template +__device__ AFloat max(AFloat x, AFloat y) +{ + if (x < y) return y; + return x; +} + +//////////////////////////////////////////////////////////////////////////////////// +/// \brief Calculate the dimension of an output volume, given the sliding parameters +/// and the input shape. +/// \param[in] imgDim The size of the input tensor in a spatial dimension. +/// \param[in] fltDim The size of the sliding filter in the same dimension. +/// \param[in] padding Number of zeroes to pad the input with. +/// \param[in] stride Number of pixels the kernel is sliding in each iteration. +/// \returns The output dimension. +/// +/// Note that no checks are performed to assert validity of the input parameters. +/// We are allowed to assume them valid because those checks have already been +/// performed prior to the invocation of the kernel. +//////////////////////////////////////////////////////////////////////////////////// +__device__ int calculateDimension(int imgDim, int fltDim, int padding, int stride) +{ + // Parameters passed at this point are guaranteed to be valid - skip checks. + return ((imgDim - fltDim + 2 * padding) / stride) + 1; +} + +//////////////////////////////////////////////////////////////////////////////////// +/// \brief A kernel that re-arranges image regions of the input matrix \B, into +/// column vectors in matrix \A. +/// +/// \param[out] A The output matrix. Each row corresponds to a receptive field. +/// \param[in] B The input matrix. Each row corresponds to a row in the image view. +/// \param[in] depth The depth of the input tensor. +/// \param[in] imgHeight The height of the input tensor. +/// \param[in] imgWidth The output of the input tensor +/// \param[in] fltHeight Height of the filter. +/// \param[in] fltWidth Width of the filter. +/// \param[in] strideRows stride size in the horizontal dimension. +/// \param[in] strideCols stride size in the vertical dimension. +/// \param[in] zeroPaddingHeight The padding in the horizontal dimension. +/// \param[in] zeroPaddingWidth The padding in the vertical dimension. +/// +/// The kernel should be invoked with one thread per output element. Note that +/// matrices \A and \B have different shapes. Each thread in this kernel is +/// responsible for filling one cell of the output matrix \A. It does so by computing +/// the correct element to copy from the input matrix \B. We therefore never need to +/// block. When reading this kernel it is important to keep in mind that TCudaMatrix +/// objects are saved in column major order for compatibility with cuBLAS. +//////////////////////////////////////////////////////////////////////////////////// +template +__global__ void Im2Col(AFloat * A, + const AFloat * B, + int depth, + int imgHeight, + int imgWidth, + int fltHeight, + int fltWidth, + int strideRows, + int strideCols, + int zeroPaddingHeight, + int zeroPaddingWidth) +{ + // The row of the output matrix. + int i = blockDim.y * blockIdx.y + threadIdx.y; + + // The column of the output matrix. + int j = blockDim.x * blockIdx.x + threadIdx.x; + + // Number of column in matrix A. + int NLocalViewPixels = fltHeight * fltWidth * depth; + + // Number of rows in matrix A. + int NLocalViews = calculateDimension(imgWidth, fltWidth, zeroPaddingWidth, strideCols) * + calculateDimension(imgHeight, fltHeight, zeroPaddingHeight, strideRows); + + if (i >= NLocalViews || j >= NLocalViewPixels) return; + + int index = j * NLocalViews + i; + + int numSlidesPerRow = calculateDimension(imgWidth, fltWidth, zeroPaddingWidth, strideCols); + + // Which image channel of B? + int bz = j / (fltHeight * fltWidth); + + // Which row in matrix B? + int by = (i / numSlidesPerRow) * strideRows - zeroPaddingHeight + (j - bz * fltHeight * fltWidth) / fltWidth; + + // Which column in matrix B? + int bx = (i % numSlidesPerRow) * strideCols - zeroPaddingWidth + (j - bz * fltHeight * fltWidth) % fltWidth; + + if (bx < 0 || by < 0 || bx >= imgWidth || by >= imgHeight) { + // This is a padding element. + A[index] = 0; + } + else { + A[index] = B[(bx + by * imgWidth) * depth + bz]; + } +} + //____________________________________________________________________________ template __global__ void AddRowWise(AFloat * W, @@ -747,6 +846,203 @@ __global__ void Dropout(AFloat *A, } } +//____________________________________________________________________________ +////////////////////////////////////////////////////////////////////////////////////////////// +/// \brief Downsampling kernel used as the forward propagation step of a +/// Max-Pooling layer. +/// +/// \param[out] A The output matrix. Each row corresponds to a slice and each element +/// is the max within a receptive field. +/// \param[out] B The winning indices matrix. Each element is the index of the max element. +/// \param[in] C The input matrix. Each row is a slice. +/// \param[in] imgHeight The heigh of the input. +/// \param[in] imgWidth The output of the input. +/// \param[in] fltHeight Height of the kernel. +/// \param[in] fltWidth Width of the kernel. +/// \param[in] strideRows stride size in the horizontal dimension. +/// \param[in] strideCols stride size in the vertical dimension. +/// +/// Each output element is the maximum of the receptive field. The caller launches one thread +/// per output element in order to eliminate shared write access. +/////////////////////////////////////////////////////////////////////////////////////////////// +template +__global__ void Downsample(AFloat * output, AFloat * indexMatrix, const AFloat * input, int depth, int imgHeight, + int imgWidth, int fltHeight, int fltWidth, int strideRows, int strideCols) +{ + // The row of the output matrix. + int i = blockDim.y * blockIdx.y + threadIdx.y; + + // The column of the output matrix. + int j = blockDim.x * blockIdx.x + threadIdx.x; + + // Number of columns in matrix A. + int NLocalViews = calculateDimension(imgWidth, fltWidth, 0, strideCols) * + calculateDimension(imgHeight, fltHeight, 0, strideRows); + + if (i >= depth || j >= NLocalViews) return; + + int outputIndex = j * depth + i; + + int numSlidesPerRow = calculateDimension(imgWidth, fltWidth, 0, strideCols); + + int rowMin = (j / numSlidesPerRow) * strideRows; // First row of B that this thread should look at. + int colMin = (j % numSlidesPerRow) * strideCols; // First column of B that this thread should look at. + int bz = i; // Slice of B that this thread should look at. + + AFloat value = 0; + AFloat maxIndex = 0; + bool first = true; // The first element should write to `value` no matter what. + + for (size_t by = rowMin; by < rowMin + fltHeight; by++) { + for (size_t bx = colMin; bx < colMin + fltWidth; bx++) { + int inputIndex = (bx + by * imgWidth) * depth + bz; + if (input[inputIndex] > value || first) { + first = false; + maxIndex = bx + by * imgWidth; + value = input[inputIndex]; + } + } + } + indexMatrix[outputIndex] = maxIndex; + output[outputIndex] = value; + +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +/// \brief Back-propagate the gradients through a max-pooling layer. +/// +/// \param[out] gradientsBackward The gradients to be written. One gradient for each neuron at the layers's input. +/// \param[in] gradients The gradients coming from the next layer. One gradient for each receptive field. +/// \param[in] indexMatrix Winning indices. One index for each receptive field. +/// \param[in] depth The depth of the input tensor. +/// \param[in] imgHeight The height of the input tensor. +/// \param[in] imgWidth The output of the input tensor +/// \param[in] fltHeight Height of the filter. +/// \param[in] fltWidth Width of the filter. +/// \param[in] strideRows stride size in the horizontal dimension. +/// \param[in] strideCols stride size in the vertical dimension. +///////////////////////////////////////////////////////////////////////////////////////////////// +template +__global__ void MaxPoolBackward(AFloat * activationGradientsBackward, + const AFloat * activationGradients, + const AFloat * indexMatrix, + int depth, int imgHeight, int imgWidth, int fltHeight, int fltWidth, + int strideRows, int strideCols) +{ + int slice = blockDim.y * blockIdx.y + threadIdx.y; // row of the gradientsBackward matrix. + int j = blockDim.x * blockIdx.x + threadIdx.x; // column of the gradientsBackward matrix. + + if (slice >= depth || j >= imgHeight * imgWidth) return; + + int height = calculateDimension(imgHeight, fltHeight, 0, strideRows); + int width = calculateDimension(imgWidth, fltWidth, 0, strideCols); + + // Which gradientsBackward element should this thread write to? + int backRow = j % imgHeight; + int backCol = j / imgHeight; + + // Which gradient and indexMatrix elements should this thread read? + int nextRowMin = floor((backRow - fltHeight) / (AFloat)strideRows) + 1; + int nextColMin = floor((backCol - fltWidth) / (AFloat)strideCols) + 1; + + int outputIndex = 0; + AFloat grad = 0; + + // Iterate over all output elements that were the outcome of receptive fields I was part of. + for (int row = nextRowMin; row <= nextRowMin + fltHeight - strideRows; row++) { + for (int col = nextColMin; col <= nextColMin + fltWidth - strideCols; col++) { + + if (row >= height || col >= width || col < 0 || row < 0) continue; + + outputIndex = (row * width + col) * depth + slice; + + // Was I the winning index within this receptive field? + if (indexMatrix[outputIndex] == backCol + backRow * imgWidth) { + grad += activationGradients[outputIndex]; + } + } + } + activationGradientsBackward[(backCol + backRow * imgWidth) * depth + slice] = grad; +} + +template +__global__ void Reshape(AFloat * A, const AFloat * B, int nRowsA, int nColsA, int nRowsB, int nColsB) +{ + int i = blockDim.y * blockIdx.y + threadIdx.y; + int j = blockDim.x * blockIdx.x + threadIdx.x; + if (i >= nRowsA || j >= nColsA) return; + + size_t indexA = j * nRowsA + i; + + size_t nElem = i * nColsA + j; + size_t indexB = (nElem % nColsB) * nRowsB + nElem / nColsB; + + A[indexA] = B[indexB]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief Flatten an array of 2D-arrays into a single 2D-array. +/// +/// \param[out] A Output 2D-array saved in column major order. +/// \param[in] B Input array of 2D-arrays. Each element is a matrix to be concatenated. +/// \param[in] size Number of 2D-arrays in the input. +/// \param[in] nRows Number of rows in each matrix of the input. +/// \param[in] nCols Number of columns on each matrix of the input. +/// +/// B is a pointer to `size` raw `TCudaMatrix` pointers. Each of those contains +/// elements saved on column major order. However the concatenation is performed +/// row wise. Each thread writes a single output element by locating the +/// appropriate input index. +////////////////////////////////////////////////////////////////////////////////// +template +__global__ void Flatten(AFloat * A, const AFloat ** B, int size, int nRows, int nCols) +{ + int i = blockDim.y * blockIdx.y + threadIdx.y; + int j = blockDim.x * blockIdx.x + threadIdx.x; + + int nColsA = nRows * nCols; + if (i >= size || j >= nColsA) return; + + // Get a transposed view on matrix B[i]. + int row = j / nCols; + int col = j % nCols; + AFloat element = B[i][col * nRows + row]; + + size_t index = j * size + i; + A[index] = element; +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief Deflatten a 2D-array into an array of 2D-arrays. +/// +/// \param[out] A Output array of 2D-arrays, each of which is column-major. +/// \param[in] B Input 2D-array to be split into `size` parts. +/// \param[in] size Number of 2D-arrays in the output. +/// \param[in] nRows Number of rows in each matrix of the output. +/// \param[in] nCols Number of columns on each matrix of the output. +/// +/// A is a pointer to `size` raw `TCudaMatrix` pointers. Each of those will +/// contain elements saved on column major order. However the concatenation +/// is performed row wise. Each thread writes a single output element +/// by locating the appropriate input index. +////////////////////////////////////////////////////////////////////////////////// +template +__global__ void Deflatten(AFloat ** A, const AFloat * B, int size, int nRows, int nCols) +{ + int i = blockDim.y * blockIdx.y + threadIdx.y; + int j = blockDim.x * blockIdx.x + threadIdx.x; + + int nColsB = nRows * nCols; + if (i >= size || j >= nColsB) return; + + AFloat element = B[j * size + i]; + + // Get a transposed view on matrix A[i]. + int row = j / nCols; + int col = j % nCols; + A[i][col * nRows + row] = element; +} + } // namespace Cuda } // namespace DNN } // namespace TMVA diff --git a/tmva/tmva/src/DNN/Architectures/Cuda/Propagation.cu b/tmva/tmva/src/DNN/Architectures/Cuda/Propagation.cu index dbf129bee5a39..5deb25ac701e3 100644 --- a/tmva/tmva/src/DNN/Architectures/Cuda/Propagation.cu +++ b/tmva/tmva/src/DNN/Architectures/Cuda/Propagation.cu @@ -18,6 +18,7 @@ #include "TMVA/DNN/Architectures/Cuda.h" #include "TMVA/DNN/Architectures/Cuda/Device.h" #include "Kernels.cuh" +#include namespace TMVA { namespace DNN { @@ -139,6 +140,43 @@ void TCuda::Copy(std::vector> & B, } //____________________________________________________________________________ + +inline bool isInteger(double x) +{ + return x == floor(x); +} + +int calculateDimension(size_t imgDim, size_t fltDim, size_t padding, size_t stride) +{ + double dimension = ((imgDim - fltDim + 2 * padding) / stride) + 1; + if (!isInteger(dimension)) { + std::cout << "Not compatible hyper parameters" << std::endl; + std::exit(EXIT_FAILURE); + } + + return (size_t)dimension; +} + +/////////////////////////////////////////////////////////////////////////////////// +/// \brief A helper for image operations that rearranges image regions into +/// column vectors. +/// +/// \param[out] A The output matrix. Each row corresponds to a receptive field. +/// \param[in] B The input matrix. Each row corresponds to a row in the image view. +/// \param[in] imgHeight The heigh of the input. +/// \param[in] imgWidth The output of the input. +/// \param[in] fltHeight Height of the kernel. +/// \param[in] fltWidth Width of the kernel. +/// \param[in] strideRows stride size in the horizontal dimension. +/// \param[in] strideCols stride size in the vertical dimension. +/// \param[in] zeroPaddingHeight The padding in the horizontal dimension. +/// \param[in] zeroPaddingWidth The padding in the vertical dimension. +/// +/// This transformation allows us to express a 2D convolution as a matrix +/// multiplication. We can therefore harness the finely tuned GEMM +/// implementation of cuBLAS to achieve maximum performance. This function +/// can greatly speed-up propagation in TConvLayer. +/////////////////////////////////////////////////////////////////////////////////// template void TCuda::Im2col(TCudaMatrix &A, const TCudaMatrix &B, @@ -151,6 +189,16 @@ void TCuda::Im2col(TCudaMatrix &A, size_t zeroPaddingHeight, size_t zeroPaddingWidth) { + size_t depth = B.GetNrows(); + + dim3 blockDims = TDevice::BlockDims2D(); + dim3 gridDims = TDevice::GridDims2D(A); + cudaStream_t s = A.GetComputeStream(); + + ::TMVA::DNN::Cuda::Im2Col<<>>(A.GetDataPointer(), B.GetDataPointer(), depth, imgHeight, imgWidth, + fltHeight, fltWidth, strideRows, strideCols, + zeroPaddingHeight, zeroPaddingWidth); + } @@ -250,6 +298,26 @@ void TCuda::AddConvBiases(TCudaMatrix &output, //____________________________________________________________________________ +////////////////////////////////////////////////////////////////////////////////////////////// +/// \brief Downsampling function used as the forward propagation step of a +/// Max-Pooling layer. +/// +/// \param[out] A The output matrix. Each row corresponds to a slice and each element +/// is the max within a receptive field. +/// \param[out] B The winning indices matrix. Each element is the index of the max element. +/// \param[in] C The input matrix. Each row is a slice. +/// \param[in] imgHeight The heigh of the input. +/// \param[in] imgWidth The output of the input. +/// \param[in] fltHeight Height of the kernel. +/// \param[in] fltWidth Width of the kernel. +/// \param[in] strideRows stride size in the horizontal dimension. +/// \param[in] strideCols stride size in the vertical dimension. +/// +/// Each output element is the maximum of the receptive field. We also save the winning +/// indices to facilitate back-propagation - we need to know which input element influenced +/// the output and only apply the derivative correction to this particular element. +/// The slicing process is the same as in a convolutional layer, however padding is set to 0. +/////////////////////////////////////////////////////////////////////////////////////////////// template void TCuda::Downsample(TCudaMatrix &A, TCudaMatrix &B, @@ -261,26 +329,52 @@ void TCuda::Downsample(TCudaMatrix &A, size_t strideRows, size_t strideCols) { + size_t depth = C.GetNrows(); + dim3 blockDims = TDevice::BlockDims2D(); + dim3 gridDims = TDevice::GridDims2D(A); + cudaStream_t s = A.GetComputeStream(); + ::TMVA::DNN::Cuda::Downsample<<>>(A.GetDataPointer(), B.GetDataPointer(), + C.GetDataPointer(), depth, imgHeight, imgWidth, + fltHeight, fltWidth, strideRows, strideCols); } //____________________________________________________________________________ template -void TCuda::MaxPoolLayerBackward(std::vector> & activationGradientsBackward, - const std::vector> & activationGradients, - const std::vector> & indexMatrix, - size_t batchSize, - size_t depth, - size_t nLocalViews) +void TCuda::MaxPoolLayerBackward(TCudaMatrix & activationGradientsBackward, + const TCudaMatrix & activationGradients, + const TCudaMatrix & indexMatrix, + size_t imgHeight, + size_t imgWidth, + size_t fltHeight, + size_t fltWidth, + size_t strideRows, + size_t strideCols, + size_t /* nLocalViews */) { + size_t depth = activationGradientsBackward.GetNrows(); + dim3 blockDims = TDevice::BlockDims2D(); + dim3 gridDims = TDevice::GridDims2D(activationGradientsBackward); + cudaStream_t s = activationGradientsBackward.GetComputeStream(); + + ::TMVA::DNN::Cuda::MaxPoolBackward<<>>(activationGradientsBackward.GetDataPointer(), + activationGradients.GetDataPointer(), + indexMatrix.GetDataPointer(), + depth, imgHeight, imgWidth, fltHeight, fltWidth, + strideRows, strideCols); } //____________________________________________________________________________ template void TCuda::Reshape(TCudaMatrix &A, const TCudaMatrix &B) { - //TODO + dim3 blockDims = TDevice::BlockDims2D(); + dim3 gridDims = TDevice::GridDims2D(A); + cudaStream_t s = A.GetComputeStream(); + + ::TMVA::DNN::Cuda::Reshape<<>>(A.GetDataPointer(), B.GetDataPointer(), + A.GetNrows(), A.GetNcols(), B.GetNrows(), B.GetNcols()); } //______________________________________________________________________________ @@ -309,6 +403,21 @@ void TCuda::Rearrange(std::vector> &out, const std::ve } //____________________________________________________________________________ +//////////////////////////////////////////////////////////////////////////////// +/// \brief Flatten a vector of matrices into a single matrix. +/// +/// \param[out] A Output matrix. +/// \param[in] B Input vector. Each element is a matrix to be concatenated. +/// \param[in] size Number of matrices in the input vector. +/// \param[in] nRows Number of rows in each matrix of the input vector. +/// \param[in] nCols Number of columns on each matrix of the input vector. +/// +/// Each row in the output matrix is the concatenation of the same row in +/// each of the input matrices. Passing an std::vector to a CUDA kernel is +/// a non trivial task that requires manually allocating and copying to device +/// memory - details in comments within the function's body. Launching one +/// thread per output element. +////////////////////////////////////////////////////////////////////////////////// template void TCuda::Flatten(TCudaMatrix &A, const std::vector> &B, @@ -316,18 +425,77 @@ void TCuda::Flatten(TCudaMatrix &A, size_t nRows, size_t nCols) { + dim3 blockDims = TDevice::BlockDims2D(); + dim3 gridDims = TDevice::GridDims2D(A); + cudaStream_t s = A.GetComputeStream(); + + // Get raw pointers from a vector of matrices - this is more challenging than it sounds. + // + // Attention: While `TCudaMatrix.GetDataPointer() returns a pointer to device memory, + // std::vector (and its .data() raw pointer) resides on host memory. Therefore + // we need to manually copy these pointers to the device prior to invoking the kernel. + + const AFloat ** dB; // device pointer to device pointers.S + const AFloat ** hB = new const AFloat * [size]; // host pointer to device pointers. + + cudaMalloc(&dB, sizeof(AFloat *) * size); + + for(size_t i = 0; i < size; ++i) { + hB[i] = B[i].GetDataPointer(); + } + + cudaMemcpy(dB, hB, sizeof(AFloat *) * size, cudaMemcpyHostToDevice); + // Launch the kernel using our device pointers. + ::TMVA::DNN::Cuda::Flatten<<>>(A.GetDataPointer(), dB, size, nRows, nCols); } //____________________________________________________________________________ +//////////////////////////////////////////////////////////////////////////////// +/// \brief Deflatten a matrix into a vector of matrices. +/// +/// \param[out] A Output matrices. Each element will be a part of the input. +/// \param[in] B Input flat matrix. +/// \param[in] size Number of matrices in the output vector. +/// \param[in] nRows Number of rows in each matrix of the output vector. +/// \param[in] nCols Number of columns on each matrix of the output vector. +/// +/// Each row in the input matrix is the concatenation of the same row in +/// each of the output matrices. Passing an std::vector to a CUDA kernel is +/// a non trivial task that requires manually allocating and copying to device +/// memory - details in comments within the function's body. Launching one +/// thread per input element. +////////////////////////////////////////////////////////////////////////////////// template void TCuda::Deflatten(std::vector> &A, const TCudaMatrix &B, - size_t index, + size_t size, size_t nRows, size_t nCols) { + dim3 blockDims = TDevice::BlockDims2D(); + dim3 gridDims = TDevice::GridDims2D(B); + cudaStream_t s = B.GetComputeStream(); + + // Get raw pointers from a vector of matrices - this is more challenging than it sounds. + // + // Attention: While `TCudaMatrix.GetDataPointer() returns a pointer to device memory, + // std::vector (and its .data() raw pointer) resides on host memory. Therefore + // we need to manually copy these pointers to the device prior to invoking the kernel. + + AFloat ** dA; // device pointer to device pointers. + AFloat ** hA = new AFloat * [size]; // host pointer to device pointers. + + cudaMalloc(&dA, sizeof(AFloat *) * size); + + for(size_t i = 0; i < size; ++i) { + hA[i] = A[i].GetDataPointer(); + } + + cudaMemcpy(dA, hA, sizeof(AFloat *) * size, cudaMemcpyHostToDevice); + // Launch the kernel using our device pointers. + ::TMVA::DNN::Cuda::Deflatten<<>>(dA, B.GetDataPointer(), size, nRows, nCols); } } // namespace DNN diff --git a/tmva/tmva/src/DNN/Architectures/Reference/Propagation.cxx b/tmva/tmva/src/DNN/Architectures/Reference/Propagation.cxx index 88404efc12803..7adf1dc1acd6c 100644 --- a/tmva/tmva/src/DNN/Architectures/Reference/Propagation.cxx +++ b/tmva/tmva/src/DNN/Architectures/Reference/Propagation.cxx @@ -375,25 +375,26 @@ void TReference::Downsample(TMatrixT &A, TMatrixT &B, const //______________________________________________________________________________ template -void TReference::MaxPoolLayerBackward(std::vector> &activationGradientsBackward, - const std::vector> &activationGradients, - const std::vector> &indexMatrix, size_t batchSize, - size_t depth, size_t nLocalViews) +void TReference::MaxPoolLayerBackward(TMatrixT &activationGradientsBackward, + const TMatrixT &activationGradients, + const TMatrixT &indexMatrix, + size_t /* imgHeight */, size_t /* imgWidth */, size_t /* fltHeight */, + size_t /* fltWidth */, size_t /* strideRows */, size_t /* strideCols */, + size_t nLocalViews) { - for (size_t i = 0; i < batchSize; i++) { - for (size_t j = 0; j < depth; j++) { + size_t depth = activationGradientsBackward.GetNrows(); - // initialize to zeros - for (size_t t = 0; t < (size_t)activationGradientsBackward[i].GetNcols(); t++) { - activationGradientsBackward[i][j][t] = 0; - } + for (size_t j = 0; j < depth; j++) { + // initialize to zeros + for (size_t t = 0; t < (size_t)activationGradientsBackward.GetNcols(); t++) { + activationGradientsBackward[j][t] = 0; + } - // set values - for (size_t k = 0; k < nLocalViews; k++) { - AReal grad = activationGradients[i][j][k]; - size_t winningIdx = indexMatrix[i][j][k]; - activationGradientsBackward[i][j][winningIdx] = grad; - } + // set values + for (size_t k = 0; k < nLocalViews; k++) { + AReal grad = activationGradients[j][k]; + size_t winningIdx = indexMatrix[j][k]; + activationGradientsBackward[j][winningIdx] += grad; } } } @@ -408,7 +409,7 @@ void TReference::Reshape(TMatrixT &A, const TMatrixT &B) for (Int_t i = 0; i < A.GetNrows(); i++) { for (Int_t j = 0; j < A.GetNcols(); j++) { auto nElem = i * nColsA + j; - A(i, j) = B(nElem / nColsB, (nElem - 1) % nColsB); + A(i, j) = B(nElem / nColsB, nElem % nColsB); } } } diff --git a/tmva/tmva/src/DataSetFactory.cxx b/tmva/tmva/src/DataSetFactory.cxx index a7183f63f0c2a..6ac52a697fcdc 100644 --- a/tmva/tmva/src/DataSetFactory.cxx +++ b/tmva/tmva/src/DataSetFactory.cxx @@ -128,7 +128,6 @@ TMVA::DataSet* TMVA::DataSetFactory::CreateDataSet( TMVA::DataSetInfo& dsi, // build the first dataset from the data input DataSet * ds = BuildInitialDataSet( dsi, dataInput ); -#if 0 if (ds->GetNEvents() > 1) { CalcMinMax(ds,dsi); @@ -143,7 +142,6 @@ TMVA::DataSet* TMVA::DataSetFactory::CreateDataSet( TMVA::DataSetInfo& dsi, //Log() << kHEADER << Endl; Log() << kHEADER << Form("[%s] : ",dsi.GetName()) << " " << Endl << Endl; } -#endif return ds; } diff --git a/tmva/tmva/src/MethodBDT.cxx b/tmva/tmva/src/MethodBDT.cxx index 5bd6b9b58c3e1..27b89a85eeae3 100644 --- a/tmva/tmva/src/MethodBDT.cxx +++ b/tmva/tmva/src/MethodBDT.cxx @@ -377,7 +377,7 @@ void TMVA::MethodBDT::DeclareOptions() AddPreDefVal(TString("Exponential")); DeclareOptionRef(fBaggedBoost=kFALSE, "UseBaggedBoost","Use only a random subsample of all events for growing the trees in each boost iteration."); - DeclareOptionRef(fShrinkage=1.0, "Shrinkage", "Learning rate for GradBoost algorithm"); + DeclareOptionRef(fShrinkage = 1.0, "Shrinkage", "Learning rate for BoostType=Grad algorithm"); DeclareOptionRef(fAdaBoostBeta=.5, "AdaBoostBeta", "Learning rate for AdaBoost algorithm"); DeclareOptionRef(fRandomisedTrees,"UseRandomisedTrees","Determine at each node splitting the cut variable only as the best out of a random subset of variables (like in RandomForests)"); DeclareOptionRef(fUseNvars,"UseNvars","Size of the subset of variables used with RandomisedTree option"); @@ -547,9 +547,10 @@ void TMVA::MethodBDT::ProcessOptions() if (fBoostType=="Grad") { fPruneMethod = DecisionTree::kNoPruning; if (fNegWeightTreatment=="InverseBoostNegWeights"){ - Log() << kINFO << "the option *InverseBoostNegWeights* does not exist for BoostType=Grad --> change" << Endl; - Log() << kINFO << "to new default for GradBoost *Pray*" << Endl; - Log() << kDEBUG << "i.e. simply keep them as if which should work fine for Grad Boost" << Endl; + Log() << kINFO << "the option NegWeightTreatment=InverseBoostNegWeights does" + << " not exist for BoostType=Grad" << Endl; + Log() << kINFO << "--> change to new default NegWeightTreatment=Pray" << Endl; + Log() << kDEBUG << "i.e. simply keep them as if which should work fine for Grad Boost" << Endl; fNegWeightTreatment="Pray"; fNoNegWeightsInTraining=kFALSE; } @@ -1297,8 +1298,7 @@ void TMVA::MethodBDT::Train() if(DoMulticlass()){ if (fBoostType!="Grad"){ Log() << kFATAL << "Multiclass is currently only supported by gradient boost. " - << "Please change boost option accordingly (GradBoost)." - << Endl; + << "Please change boost option accordingly (BoostType=Grad)." << Endl; } UInt_t nClasses = DataInfo().GetNClasses(); diff --git a/tmva/tmva/src/MethodDL.cxx b/tmva/tmva/src/MethodDL.cxx index dac6332e00381..2bcfb57faa773 100644 --- a/tmva/tmva/src/MethodDL.cxx +++ b/tmva/tmva/src/MethodDL.cxx @@ -684,8 +684,8 @@ void MethodDL::ParseMaxPoolLayer(DNN::TDeepNet &deepNet TString delim) { - int frameHeight = 0; - int frameWidth = 0; + int filterHeight = 0; + int filterWidth = 0; int strideRows = 0; int strideCols = 0; @@ -697,15 +697,15 @@ void MethodDL::ParseMaxPoolLayer(DNN::TDeepNet &deepNet for (; token != nullptr; token = (TObjString *)nextToken()) { switch (idxToken) { - case 1: // frame height + case 1: // filter height { TString strFrmHeight(token->GetString()); - frameHeight = strFrmHeight.Atoi(); + filterHeight = strFrmHeight.Atoi(); } break; - case 2: // frame width + case 2: // filter width { TString strFrmWidth(token->GetString()); - frameWidth = strFrmWidth.Atoi(); + filterWidth = strFrmWidth.Atoi(); } break; case 3: // stride in rows { @@ -723,10 +723,11 @@ void MethodDL::ParseMaxPoolLayer(DNN::TDeepNet &deepNet // Add the Max pooling layer // TMaxPoolLayer *maxPoolLayer = - deepNet.AddMaxPoolLayer(frameHeight, frameWidth, strideRows, strideCols); + deepNet.AddMaxPoolLayer(filterHeight, filterWidth, strideRows, strideCols); // Add the same layer to fNet - if (fBuildNet) fNet->AddMaxPoolLayer(frameHeight, frameWidth, strideRows, strideCols); + if (fBuildNet) fNet->AddMaxPoolLayer(filterHeight, filterWidth, strideRows, strideCols); + //TMaxPoolLayer *copyMaxPoolLayer = new TMaxPoolLayer(*maxPoolLayer); @@ -1603,14 +1604,14 @@ void MethodDL::ReadWeightsFromXML(void * rootXML) else if (layerName == "MaxPoolLayer") { // read maxpool layer info - size_t frameHeight, frameWidth = 0; + size_t filterHeight, filterWidth = 0; size_t strideRows, strideCols = 0; - gTools().ReadAttr(layerXML, "FrameHeight", frameHeight); - gTools().ReadAttr(layerXML, "FrameWidth", frameWidth); + gTools().ReadAttr(layerXML, "FilterHeight", filterHeight); + gTools().ReadAttr(layerXML, "FilterWidth", filterWidth); gTools().ReadAttr(layerXML, "StrideRows", strideRows); gTools().ReadAttr(layerXML, "StrideCols", strideCols); - fNet->AddMaxPoolLayer(frameHeight, frameWidth, strideRows, strideCols); + fNet->AddMaxPoolLayer(filterHeight, filterWidth, strideRows, strideCols); } else if (layerName == "ReshapeLayer") { diff --git a/tmva/tmva/test/DNN/CNN/CMakeLists.txt b/tmva/tmva/test/DNN/CNN/CMakeLists.txt index 816bc36a60a8f..7c5223cd2cc57 100644 --- a/tmva/tmva/test/DNN/CNN/CMakeLists.txt +++ b/tmva/tmva/test/DNN/CNN/CMakeLists.txt @@ -8,8 +8,24 @@ find_package(ROOT REQUIRED) set(Libraries Core MathCore Matrix TMVA) + +#--- CUDA tests. --------------------------- if (CUDA_FOUND AND tmva-gpu) include_directories(${ROOT_INCLUDE_DIRS} ${CUDA_INCLUDE_DIRS}) +set(DNN_CUDA_LIBRARIES dnn_cuda ${CUDA_CUBLAS_LIBRARIES}) + +CUDA_ADD_EXECUTABLE(testIm2ColCuda TestIm2ColCuda.cxx) +target_link_libraries(testIm2ColCuda ${Libraries} ${DNN_CUDA_LIBRARIES}) +ROOT_ADD_TEST(TMVA-DNN-CNN-Im2ColCuda COMMAND testIm2ColCuda) + +CUDA_ADD_EXECUTABLE(testPoolingLayerCuda TestPoolingLayerCuda.cxx) +target_link_libraries(testPoolingLayerCuda ${Libraries} ${DNN_CUDA_LIBRARIES}) +ROOT_ADD_TEST(TMVA-DNN-CNN-PoolingLayerCuda COMMAND testPoolingLayerCuda) + +CUDA_ADD_EXECUTABLE(testReshapeCuda TestReshapeCuda.cxx) +target_link_libraries(testReshapeCuda ${Libraries} ${DNN_CUDA_LIBRARIES}) +ROOT_ADD_TEST(TMVA-DNN-CNN-ReshapeCuda COMMAND testReshapeCuda) + else() include_directories(${ROOT_INCLUDE_DIRS}) endif() @@ -17,11 +33,11 @@ endif() ROOT_EXECUTABLE(testIm2Col TestIm2Col.cxx LIBRARIES ${Libraries}) ROOT_ADD_TEST(TMVA-DNN-CNN-Im2Col COMMAND testIm2Col) -ROOT_EXECUTABLE(testDownsample TestDownsample.cxx LIBRARIES ${Libraries}) -ROOT_ADD_TEST(TMVA-DNN-CNN-Downsample COMMAND testDownsample) +ROOT_EXECUTABLE(testPoolingLayer TestPoolingLayer.cxx LIBRARIES ${Libraries}) +ROOT_ADD_TEST(TMVA-DNN-CNN-PoolingLayer COMMAND testPoolingLayer) -ROOT_EXECUTABLE(testFlatten TestFlatten.cxx LIBRARIES ${Libraries}) -ROOT_ADD_TEST(TMVA-DNN-CNN-testFlatten COMMAND testFlatten) +ROOT_EXECUTABLE(testReshape TestReshape.cxx LIBRARIES ${Libraries}) +ROOT_ADD_TEST(TMVA-DNN-CNN-Reshape COMMAND testReshape) ROOT_EXECUTABLE(testRotWeights TestRotateWeights.cxx LIBRARIES ${Libraries}) ROOT_ADD_TEST(TMVA-DNN-CNN-RotWeights COMMAND testRotWeights) @@ -42,7 +58,6 @@ ROOT_ADD_TEST(TMVA-DNN-CNN-RotWeights COMMAND testRotWeights) #ROOT_EXECUTABLE(testTensorDataLoader TestTensorDataLoader.cxx LIBRARIES ${Libraries}) #ROOT_ADD_TEST(TMVA-DNN-Tensor-Data-Loader COMMAND testTensorDataLoader) - #--- CPU tests. ---------------------------- if ((BLAS_FOUND OR mathmore) AND imt AND tmva-cpu) @@ -51,8 +66,8 @@ include_directories(SYSTEM ${TBB_INCLUDE_DIRS}) ROOT_EXECUTABLE(testIm2ColCpu TestIm2ColCpu.cxx LIBRARIES ${Libraries}) ROOT_ADD_TEST(TMVA-DNN-CNN-Im2Col-CPU COMMAND testIm2ColCpu) -ROOT_EXECUTABLE(testDownsampleCpu TestDownsampleCpu.cxx LIBRARIES ${Libraries}) -ROOT_ADD_TEST(TMVA-DNN-CNN-Downsample-CPU COMMAND testDownsampleCpu) +ROOT_EXECUTABLE(testPoolingLayerCpu TestPoolingLayerCpu.cxx LIBRARIES ${Libraries}) +ROOT_ADD_TEST(TMVA-DNN-CNN-PoolingLayer-CPU COMMAND testPoolingLayerCpu) ROOT_EXECUTABLE(testRotWeightsCpu TestRotateWeightsCpu.cxx LIBRARIES ${Libraries}) ROOT_ADD_TEST(TMVA-DNN-CNN-RotWeights-CPU COMMAND testRotWeightsCpu) @@ -66,6 +81,9 @@ ROOT_ADD_TEST(TMVA-DNN-CNN-Loss-CPU COMMAND testConvNetLossCpu) ROOT_EXECUTABLE(testConvNetPredCpu TestConvNetPredictionCpu.cxx LIBRARIES ${Libraries}) ROOT_ADD_TEST(TMVA-DNN-CNN-Pred-CPU COMMAND testConvNetPredCpu) +ROOT_EXECUTABLE(testReshapeCpu TestReshapeCpu.cxx LIBRARIES ${Libraries}) +ROOT_ADD_TEST(TMVA-DNN-CNN-Reshape-CPU COMMAND testReshapeCpu) + #-- need to be fixed #ROOT_EXECUTABLE(testTensorDataLoaderCpu TestTensorDataLoaderCpu.cxx LIBRARIES ${Libraries}) #ROOT_ADD_TEST(TMVA-DNN-Tensor-Data-Loader-CPU COMMAND testTensorDataLoaderCpu) @@ -76,7 +94,6 @@ ROOT_ADD_TEST(TMVA-DNN-CNN-Minimization-CPU COMMAND testDLMinimizationCpu) ROOT_EXECUTABLE(testConvBackpropagationCpu TestConvBackpropagation.cxx LIBRARIES ${Libraries}) ROOT_ADD_TEST(TMVA-DNN-CNN-Backpropagation-CPU COMMAND testConvBackpropagationCpu) - ROOT_EXECUTABLE(testMethodDLCpu TestMethodDL.cxx LIBRARIES ${Libraries}) ROOT_ADD_TEST(TMVA-DNN-CNN-MethodDL-CPU COMMAND testMethodDLCpu) diff --git a/tmva/tmva/test/DNN/CNN/TestConvNet.h b/tmva/tmva/test/DNN/CNN/TestConvNet.h index 07f064489615a..ba027b0aeae0f 100644 --- a/tmva/tmva/test/DNN/CNN/TestConvNet.h +++ b/tmva/tmva/test/DNN/CNN/TestConvNet.h @@ -133,11 +133,65 @@ auto testDownsample(const typename Architecture::Matrix_t &A, const typename Arc return true; } +/** Back propagate the activation gradients through the max-pooling layer and check whether the ++ * computed gradients are equal to the matrix A. */ +//______________________________________________________________________________ +template +auto testPoolingBackward(const typename Architecture::Matrix_t &input, const typename Architecture::Matrix_t &output, + const typename Architecture::Matrix_t &indexMatrix, size_t imgHeight, size_t imgWidth, + size_t fltHeight, size_t fltWidth, size_t strideRows, size_t strideCols, size_t nLocalViews, + double epsilon = 0.01) -> bool { + size_t depth = output.GetNrows(); + + typename Architecture::Matrix_t ABack(output.GetNrows(), output.GetNcols()); + Architecture::MaxPoolLayerBackward(ABack, input, indexMatrix, imgHeight, imgWidth, fltHeight, fltWidth, + strideRows, strideCols, nLocalViews); + + /* Needed to support double (almost) equality */ + auto almostEqual = [epsilon](double a, double b) { + // Using a magic EPSILON value (makes sense for the existing tests). + return fabs(a - b) < epsilon; + }; + + for (size_t d = 0; d < depth; d++) { + for (size_t i = 0; i < nLocalViews; i++) { + if (!almostEqual(ABack(d, i), output(d, i))) { + return false; + } + } + } + return true; +} + +/** Reshape the matrix A using the Reshape function and compare it to + * the result in matrix B. */ +//______________________________________________________________________________ +template +auto testReshape(const typename Architecture_t::Matrix_t &A, const typename Architecture_t::Matrix_t &B) -> bool +{ + + size_t m, n; + m = B.GetNrows(); + n = B.GetNcols(); + + typename Architecture_t::Matrix_t AReshaped(m, n); + Architecture_t::Reshape(AReshaped, A); + + for (size_t i = 0; i < m; i++) { + for (size_t j = 0; j < n; j++) { + if (AReshaped(i, j) != B(i, j)) { + return false; + } + } + } + return true; +} + /** Flatten the 3D tensor A using the Flatten function and compare it to * the result in the flat matrix B. */ //______________________________________________________________________________ -template -auto testFlatten(std::vector &A, const typename Architecture::Matrix_t &B, size_t size, +template +auto testFlatten(std::vector &A, const typename Architecture_t::Matrix_t &B, size_t size, size_t nRows, size_t nCols) -> bool { @@ -145,8 +199,8 @@ auto testFlatten(std::vector &A, const typename m = B.GetNrows(); n = B.GetNcols(); - typename Architecture::Matrix_t AFlat(m, n); - Architecture::Flatten(AFlat, A, size, nRows, nCols); + typename Architecture_t::Matrix_t AFlat(m, n); + Architecture_t::Flatten(AFlat, A, size, nRows, nCols); for (size_t i = 0; i < m; i++) { for (size_t j = 0; j < n; j++) { @@ -159,6 +213,31 @@ auto testFlatten(std::vector &A, const typename return true; } +/** Deflatten the 2D tensor A using the Deflatten function and compare it to + * the result in the 3D tensor B. */ +//______________________________________________________________________________ +template +auto testDeflatten(const typename Architecture_t::Matrix_t &A, const std::vector &B, + size_t size, size_t nRows, size_t nCols) -> bool +{ + std::vector AComputed; + for (size_t i = 0; i < size; i++) { + AComputed.emplace_back(nRows, nCols); + } + + Architecture_t::Deflatten(AComputed, A, size, nRows, nCols); + + for (size_t i = 0; i < size; i++) { + for (size_t j = 0; j < nRows; j++) { + for (size_t k = 0; k < nCols; k++) { + if (AComputed[i](j, k) != B[i](j, k)) return false; + } + } + } + + return true; +} + /*! Generate a conv net, perform forward pass */ //______________________________________________________________________________ template diff --git a/tmva/tmva/test/DNN/CNN/TestDownsample.cxx b/tmva/tmva/test/DNN/CNN/TestDownsample.cxx deleted file mode 100644 index 582b74cc21649..0000000000000 --- a/tmva/tmva/test/DNN/CNN/TestDownsample.cxx +++ /dev/null @@ -1,250 +0,0 @@ -// @(#)root/tmva/tmva/cnn:$Id$ -// Author: Vladimir Ilievski - -/********************************************************************************** - * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * - * Package: TMVA * - * Class : * - * Web : http://tmva.sourceforge.net * - * * - * Description: * - * Testing Downsample method * - * * - * Authors (alphabetical): * - * Vladimir Ilievski - CERN, Switzerland * - * * - * Copyright (c) 2005-2015: * - * CERN, Switzerland * - * U. of Victoria, Canada * - * MPI-K Heidelberg, Germany * - * U. of Bonn, Germany * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted according to the terms listed in LICENSE * - * (http://tmva.sourceforge.net/LICENSE) * - **********************************************************************************/ - - - -//////////////////////////////////////////////////////////////////// -// Testing the Downsample function // -//////////////////////////////////////////////////////////////////// - -#include -#include - -#include "TMVA/DNN/Architectures/Reference.h" -#include "TestConvNet.h" - -using namespace TMVA::DNN; -using namespace TMVA::DNN::CNN; -using Matrix_t = typename TReference::Matrix_t; - - -inline bool isInteger(double x) {return x == floor(x);} - -size_t calculateDimension(size_t imgDim, - size_t fltDim, - size_t padding, - size_t stride) -{ - double dimension = ((imgDim - fltDim + 2 * padding) / stride) + 1; - if(!isInteger(dimension)) { - std::cout << "Not compatible hyper parameters" << std::endl; - std::exit(EXIT_FAILURE); - } - - return (size_t) dimension; -} - - - -/************************************************************************* - * Test 1: - * depth = 2, image height = 4, image width = 5, - * frame depth = 2, filter height = 2, filter width = 2, - * stride rows = 2, stride cols = 1, - * zero-padding height = 0, zero-padding width = 0, - *************************************************************************/ - -void test1() -{ - - double imgTest1[][20] = - { - {166, 212, 213, 150, 114, - 119, 109, 115, 88, 144, - 227, 208, 208, 235, 57, - 57, 165, 250, 139, 76}, - - { 57, 255, 184, 162, 204, - 220, 11, 192, 183, 174, - 2, 153, 183, 175, 10, - 55, 123, 246, 138, 80} - }; - - - double answerTest1[][8] = - { - {212, 213, 213, 150, - 227, 250, 250, 235}, - - {255, 255, 192, 204, - 153, 246, 246, 175} - }; - - double answerIdxTest1[][8] = - { - { 1, 2, 2, 3, - 10, 17, 17, 13}, - - { 1, 1, 7, 4, - 11, 17, 17, 13} - }; - - size_t imgDepthTest1 = 2; - size_t imgHeightTest1 = 4; - size_t imgWidthTest1 = 5; - size_t fltHeightTest1 = 2; - size_t fltWidthTest1 = 2; - size_t strideRowsTest1 = 2; - size_t strideColsTest1 = 1; - - - Matrix_t A(imgDepthTest1, imgHeightTest1 * imgWidthTest1); - - for(size_t i = 0; i < (size_t) A.GetNrows(); i++){ - for(size_t j = 0; j < (size_t) A.GetNcols(); j++){ - A(i, j) = imgTest1[i][j]; - } - } - - - size_t height = calculateDimension(imgHeightTest1, fltHeightTest1, - 0, strideRowsTest1); - - size_t width = calculateDimension(imgWidthTest1, fltWidthTest1, - 0, strideColsTest1); - - - Matrix_t idx(imgDepthTest1, height * width); - Matrix_t B(imgDepthTest1, height * width); - - for(size_t i = 0; i < (size_t) B.GetNrows(); i++){ - for(size_t j = 0; j < (size_t) B.GetNcols(); j++){ - idx(i, j) = answerIdxTest1[i][j]; - B(i, j) = answerTest1[i][j]; - } - } - - - - bool status = testDownsample>(A, idx, B, - imgHeightTest1, imgWidthTest1, - fltHeightTest1, fltWidthTest1, - strideRowsTest1, strideColsTest1); - - if(status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} - -/************************************************************************* - * Test 1: - * depth = 1, image height = 6, image width = 6, - * frame depth = 1, filter height = 2, filter width = 3, - * stride rows = 1, stride cols = 3, - * zero-padding height = 0, zero-padding width = 0, - *************************************************************************/ - -void test2() -{ - - double imgTest2[][36] = - { - {200, 79, 69, 58, 98, 168, - 49, 230, 21, 141, 218, 38, - 72, 224, 14, 65, 147, 105, - 38, 27, 111, 160, 200, 48, - 109, 104, 153, 149, 233, 11, - 16, 91, 236, 183, 166, 155} - }; - - - double answerTest2[][10] = - { - {230, 218, - 230, 218, - 224, 200, - 153, 233, - 236, 233} - }; - - double answerIdxTest2[][10] = - { - { 7, 10, - 7, 10, - 13, 22, - 26, 28, - 32, 28} - }; - - size_t imgDepthTest2 = 1; - size_t imgHeightTest2 = 6; - size_t imgWidthTest2 = 6; - size_t fltHeightTest2 = 2; - size_t fltWidthTest2 = 3; - size_t strideRowsTest2 = 1; - size_t strideColsTest2 = 3; - - - Matrix_t A(imgDepthTest2, imgHeightTest2 * imgWidthTest2); - - for(size_t i = 0; i < (size_t) A.GetNrows(); i++){ - for(size_t j = 0; j < (size_t) A.GetNcols(); j++){ - A(i, j) = imgTest2[i][j]; - } - } - - - size_t height = calculateDimension(imgHeightTest2, fltHeightTest2, - 0, strideRowsTest2); - - size_t width = calculateDimension(imgWidthTest2, fltWidthTest2, - 0, strideColsTest2); - - - Matrix_t idx(imgDepthTest2, height * width); - Matrix_t B(imgDepthTest2, height * width); - - for(size_t i = 0; i < (size_t) B.GetNrows(); i++){ - for(size_t j = 0; j < (size_t) B.GetNcols(); j++){ - idx(i, j) = answerIdxTest2[i][j]; - B(i, j) = answerTest2[i][j]; - } - } - - - - bool status = testDownsample>(A, idx, B, - imgHeightTest2, imgWidthTest2, - fltHeightTest2, fltWidthTest2, - strideRowsTest2, strideColsTest2); - - if(status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} - - -int main(){ - std::cout << "Testing Downsample function:" << std::endl; - - std::cout << "Test 1: " << std::endl; - test1(); - - std::cout << "Test 2: " << std::endl; - test2(); -} diff --git a/tmva/tmva/test/DNN/CNN/TestDownsampleCpu.cxx b/tmva/tmva/test/DNN/CNN/TestDownsampleCpu.cxx deleted file mode 100644 index 4a685a9ec9e99..0000000000000 --- a/tmva/tmva/test/DNN/CNN/TestDownsampleCpu.cxx +++ /dev/null @@ -1,186 +0,0 @@ -// @(#)root/tmva/tmva/cnn:$Id$ -// Author: Vladimir Ilievski - -/********************************************************************************** - * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * - * Package: TMVA * - * Class : * - * Web : http://tmva.sourceforge.net * - * * - * Description: * - * Testing Downsample method on a CPU architecture * - * * - * Authors (alphabetical): * - * Vladimir Ilievski - CERN, Switzerland * - * * - * Copyright (c) 2005-2015: * - * CERN, Switzerland * - * U. of Victoria, Canada * - * MPI-K Heidelberg, Germany * - * U. of Bonn, Germany * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted according to the terms listed in LICENSE * - * (http://tmva.sourceforge.net/LICENSE) * - **********************************************************************************/ - -//////////////////////////////////////////////////////////////////// -// Testing the Downsample function // -//////////////////////////////////////////////////////////////////// - -#include -#include - -#include "TMVA/DNN/Architectures/Cpu.h" -#include "TestConvNet.h" - -using namespace TMVA::DNN; -using namespace TMVA::DNN::CNN; -using Matrix_t = typename TCpu::Matrix_t; - -inline bool isInteger(double x) -{ - return x == floor(x); -} - -size_t calculateDimension(size_t imgDim, size_t fltDim, size_t padding, size_t stride) -{ - double dimension = ((imgDim - fltDim + 2 * padding) / stride) + 1; - if (!isInteger(dimension)) { - std::cout << "Not compatible hyper parameters" << std::endl; - std::exit(EXIT_FAILURE); - } - - return (size_t)dimension; -} - -/************************************************************************* - * Test 1: - * depth = 2, image height = 4, image width = 5, - * frame depth = 2, filter height = 2, filter width = 2, - * stride rows = 2, stride cols = 1, - * zero-padding height = 0, zero-padding width = 0, - *************************************************************************/ - -void test1() -{ - - double imgTest1[][20] = { - {166, 212, 213, 150, 114, 119, 109, 115, 88, 144, 227, 208, 208, 235, 57, 57, 165, 250, 139, 76}, - - {57, 255, 184, 162, 204, 220, 11, 192, 183, 174, 2, 153, 183, 175, 10, 55, 123, 246, 138, 80}}; - - double answerTest1[][8] = {{212, 213, 213, 150, 227, 250, 250, 235}, - - {255, 255, 192, 204, 153, 246, 246, 175}}; - - double answerIdxTest1[][8] = {{1, 2, 2, 3, 10, 17, 17, 13}, - - {1, 1, 7, 4, 11, 17, 17, 13}}; - - size_t imgDepthTest1 = 2; - size_t imgHeightTest1 = 4; - size_t imgWidthTest1 = 5; - size_t fltHeightTest1 = 2; - size_t fltWidthTest1 = 2; - size_t strideRowsTest1 = 2; - size_t strideColsTest1 = 1; - - Matrix_t A(imgDepthTest1, imgHeightTest1 * imgWidthTest1); - - for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { - A(i, j) = imgTest1[i][j]; - } - } - - size_t height = calculateDimension(imgHeightTest1, fltHeightTest1, 0, strideRowsTest1); - - size_t width = calculateDimension(imgWidthTest1, fltWidthTest1, 0, strideColsTest1); - - Matrix_t idx(imgDepthTest1, height * width); - Matrix_t B(imgDepthTest1, height * width); - - for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { - idx(i, j) = answerIdxTest1[i][j]; - B(i, j) = answerTest1[i][j]; - } - } - - bool status = testDownsample>(A, idx, B, imgHeightTest1, imgWidthTest1, fltHeightTest1, fltWidthTest1, - strideRowsTest1, strideColsTest1); - - if (status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} - -/************************************************************************* - * Test 1: - * depth = 1, image height = 6, image width = 6, - * frame depth = 1, filter height = 2, filter width = 3, - * stride rows = 1, stride cols = 3, - * zero-padding height = 0, zero-padding width = 0, - *************************************************************************/ - -void test2() -{ - - double imgTest2[][36] = {{200, 79, 69, 58, 98, 168, 49, 230, 21, 141, 218, 38, 72, 224, 14, 65, 147, 105, - 38, 27, 111, 160, 200, 48, 109, 104, 153, 149, 233, 11, 16, 91, 236, 183, 166, 155}}; - - double answerTest2[][10] = {{230, 218, 230, 218, 224, 200, 153, 233, 236, 233}}; - - double answerIdxTest2[][10] = {{7, 10, 7, 10, 13, 22, 26, 28, 32, 28}}; - - size_t imgDepthTest2 = 1; - size_t imgHeightTest2 = 6; - size_t imgWidthTest2 = 6; - size_t fltHeightTest2 = 2; - size_t fltWidthTest2 = 3; - size_t strideRowsTest2 = 1; - size_t strideColsTest2 = 3; - - Matrix_t A(imgDepthTest2, imgHeightTest2 * imgWidthTest2); - - for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { - A(i, j) = imgTest2[i][j]; - } - } - - size_t height = calculateDimension(imgHeightTest2, fltHeightTest2, 0, strideRowsTest2); - - size_t width = calculateDimension(imgWidthTest2, fltWidthTest2, 0, strideColsTest2); - - Matrix_t idx(imgDepthTest2, height * width); - Matrix_t B(imgDepthTest2, height * width); - - for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { - idx(i, j) = answerIdxTest2[i][j]; - B(i, j) = answerTest2[i][j]; - } - } - - bool status = testDownsample>(A, idx, B, imgHeightTest2, imgWidthTest2, fltHeightTest2, fltWidthTest2, - strideRowsTest2, strideColsTest2); - - if (status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} - -int main() -{ - std::cout << "Testing Downsample function:" << std::endl; - - std::cout << "Test 1: " << std::endl; - test1(); - - std::cout << "Test 2: " << std::endl; - test2(); -} diff --git a/tmva/tmva/test/DNN/CNN/TestFlatten.cxx b/tmva/tmva/test/DNN/CNN/TestFlatten.cxx deleted file mode 100644 index e11205c19e7d3..0000000000000 --- a/tmva/tmva/test/DNN/CNN/TestFlatten.cxx +++ /dev/null @@ -1,113 +0,0 @@ -// @(#)root/tmva $Id$ -// Author: Vladimir Ilievski - -/********************************************************************************** - * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * - * Package: TMVA * - * Class : * - * Web : http://tmva.sourceforge.net * - * * - * Description: * - * Testing Flatten function for Reference backend * - * * - * Authors (alphabetical): * - * Vladimir Ilievski - CERN, Switzerland * - * * - * Copyright (c) 2005-2015: * - * CERN, Switzerland * - * U. of Victoria, Canada * - * MPI-K Heidelberg, Germany * - * U. of Bonn, Germany * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted according to the terms listed in LICENSE * - * (http://tmva.sourceforge.net/LICENSE) * - **********************************************************************************/ - -//////////////////////////////////////////////////////////////////// -// Testing the Flatten Function // -//////////////////////////////////////////////////////////////////// - -#include - -#include "TMVA/DNN/Architectures/Reference.h" -#include "TestConvNet.h" - -using namespace TMVA::DNN; -using namespace TMVA::DNN::CNN; -using Matrix_t = typename TReference::Matrix_t; - -/************************************************************************* - * Test 1: - * depth = 3, width = 5, height = 5 - *************************************************************************/ - -void test1() -{ - - double imgTest1[][5][5] = {{ - {158, 157, 22, 166, 179}, - {68, 179, 233, 110, 163}, - {168, 216, 76, 8, 102}, - {159, 163, 25, 78, 119}, - {116, 50, 206, 102, 247}, - }, - - {{187, 166, 121, 112, 136}, - {237, 30, 180, 7, 248}, - {52, 172, 146, 130, 92}, - {124, 244, 214, 175, 9}, - {80, 232, 139, 224, 237}}, - - {{53, 147, 103, 53, 110}, - {112, 222, 19, 156, 232}, - {81, 19, 188, 224, 220}, - {255, 190, 76, 219, 95}, - {245, 4, 217, 22, 22}}}; - - double answerTest1[][25] = {{158, 157, 22, 166, 179, 68, 179, 233, 110, 163, 168, 216, 76, - 8, 102, 159, 163, 25, 78, 119, 116, 50, 206, 102, 247}, - - {187, 166, 121, 112, 136, 237, 30, 180, 7, 248, 52, 172, 146, - 130, 92, 124, 244, 214, 175, 9, 80, 232, 139, 224, 237}, - - {53, 147, 103, 53, 110, 112, 222, 19, 156, 232, 81, 19, 188, - 224, 220, 255, 190, 76, 219, 95, 245, 4, 217, 22, 22}}; - - size_t sizeTest1 = 3; - size_t nRowsTest1 = 5; - size_t nColsTest1 = 5; - - std::vector A; - for (size_t i = 0; i < sizeTest1; i++) { - Matrix_t temp(nRowsTest1, nColsTest1); - for (size_t j = 0; j < nRowsTest1; j++) { - for (size_t k = 0; k < nColsTest1; k++) { - temp(j, k) = imgTest1[i][j][k]; - } - } - A.push_back(temp); - } - - Matrix_t B(sizeTest1, nRowsTest1 * nColsTest1); - for (size_t i = 0; i < sizeTest1; i++) { - for (size_t j = 0; j < nRowsTest1 * nColsTest1; j++) { - B(i, j) = answerTest1[i][j]; - } - } - - bool status = testFlatten>(A, B, sizeTest1, nRowsTest1, nColsTest1); - - if (status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} - -int main() -{ - std::cout << "Testing Flatten function:" << std::endl; - - std::cout << "Test 1: " << std::endl; - test1(); -} diff --git a/tmva/tmva/test/DNN/CNN/TestIm2Col.cxx b/tmva/tmva/test/DNN/CNN/TestIm2Col.cxx index 6e8a9a272ec5c..d5b31c3df1b87 100644 --- a/tmva/tmva/test/DNN/CNN/TestIm2Col.cxx +++ b/tmva/tmva/test/DNN/CNN/TestIm2Col.cxx @@ -29,266 +29,38 @@ //////////////////////////////////////////////////////////////////// #include -#include #include "TMVA/DNN/Architectures/Reference.h" -#include "TestConvNet.h" +#include "TestIm2Col.h" using namespace TMVA::DNN; using namespace TMVA::DNN::CNN; -using Matrix_t = typename TReference::Matrix_t; - -inline bool isInteger(double x) -{ - return x == floor(x); -} - -int calculateDimension(size_t imgDim, size_t fltDim, size_t padding, size_t stride) -{ - double dimension = ((imgDim - fltDim + 2 * padding) / stride) + 1; - if (!isInteger(dimension)) { - std::cout << "Not compatible hyper parameters" << std::endl; - std::exit(EXIT_FAILURE); - } - - return (size_t)dimension; -} - -/************************************************************************* - * Test 1: - * depth = 1, image height = 5, image width = 5, - * filter depth = 1, filter height = 2, filter width = 2, - * stride rows = 1, stride cols = 1, - * zero-padding height = 1, zero-padding width = 1, - *************************************************************************/ - -void test1() -{ - double imgTest1[][25] = {{244, 198, 134, 194, 86, 104, 156, 52, 126, 39, 56, 250, 68, - 247, 251, 93, 160, 61, 8, 81, 204, 113, 107, 206, 146} - - }; - - double answerTest1[][4] = {{0, 0, 0, 244}, {0, 0, 244, 198}, {0, 0, 198, 134}, {0, 0, 134, 194}, - {0, 0, 194, 86}, {0, 0, 86, 0}, {0, 244, 0, 104}, {244, 198, 104, 156}, - {198, 134, 156, 52}, {134, 194, 52, 126}, {194, 86, 126, 39}, {86, 0, 39, 0}, - {0, 104, 0, 56}, {104, 156, 56, 250}, {156, 52, 250, 68}, {52, 126, 68, 247}, - {126, 39, 247, 251}, {39, 0, 251, 0}, {0, 56, 0, 93}, {56, 250, 93, 160}, - {250, 68, 160, 61}, {68, 247, 61, 8}, {247, 251, 8, 81}, {251, 0, 81, 0}, - {0, 93, 0, 204}, {93, 160, 204, 113}, {160, 61, 113, 107}, {61, 8, 107, 206}, - {8, 81, 206, 146}, {81, 0, 146, 0}, {0, 204, 0, 0}, {204, 113, 0, 0}, - {113, 107, 0, 0}, {107, 206, 0, 0}, {206, 146, 0, 0}, {146, 0, 0, 0}}; - - size_t imgDepthTest1 = 1; - size_t imgHeightTest1 = 5; - size_t imgWidthTest1 = 5; - size_t fltHeightTest1 = 2; - size_t fltWidthTest1 = 2; - size_t strideRowsTest1 = 1; - size_t strideColsTest1 = 1; - size_t zeroPaddingHeightTest1 = 1; - size_t zeroPaddingWidthTest1 = 1; - - Matrix_t A(imgDepthTest1, imgHeightTest1 * imgWidthTest1); - - for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { - A(i, j) = imgTest1[i][j]; - } - } - - size_t height = calculateDimension(imgHeightTest1, fltHeightTest1, zeroPaddingHeightTest1, strideRowsTest1); - - size_t width = calculateDimension(imgWidthTest1, fltWidthTest1, zeroPaddingWidthTest1, strideColsTest1); - - Matrix_t B(height * width, imgDepthTest1 * fltHeightTest1 * fltWidthTest1); - - for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { - B(i, j) = answerTest1[i][j]; - } - } - - bool status = - testIm2col>(A, B, imgHeightTest1, imgWidthTest1, fltHeightTest1, fltWidthTest1, - strideRowsTest1, strideColsTest1, zeroPaddingHeightTest1, zeroPaddingWidthTest1); - - if (status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} - -/************************************************************************* - * Test 2: - * depth = 2, image height = 5, image width = 5, - * filter depth = 2, filter height = 2, filter width = 3, - * stride rows = 1, stride cols = 1, - * zero-padding height = 1, zero-padding width = 1, - *************************************************************************/ - -void test2() -{ - - // 2 x 5 x 5 image - double imgTest2[][25] = { - - {244, 198, 134, 194, 86, 104, 156, 52, 126, 39, 56, 250, 68, - 247, 251, 93, 160, 61, 8, 81, 204, 113, 107, 206, 146}, - - {205, 136, 184, 196, 42, 157, 10, 62, 201, 46, 250, 78, 43, - 185, 82, 95, 218, 128, 104, 71, 118, 215, 228, 199, 52} - - }; - - double answerTest2[][12] = {{0, 0, 0, 0, 244, 198, 0, 0, 0, 0, 205, 136}, - {0, 0, 0, 244, 198, 134, 0, 0, 0, 205, 136, 184}, - {0, 0, 0, 198, 134, 194, 0, 0, 0, 136, 184, 196}, - {0, 0, 0, 134, 194, 86, 0, 0, 0, 184, 196, 42}, - {0, 0, 0, 194, 86, 0, 0, 0, 0, 196, 42, 0}, - {0, 244, 198, 0, 104, 156, 0, 205, 136, 0, 157, 10}, - {244, 198, 134, 104, 156, 52, 205, 136, 184, 157, 10, 62}, - {198, 134, 194, 156, 52, 126, 136, 184, 196, 10, 62, 201}, - {134, 194, 86, 52, 126, 39, 184, 196, 42, 62, 201, 46}, - {194, 86, 0, 126, 39, 0, 196, 42, 0, 201, 46, 0}, - {0, 104, 156, 0, 56, 250, 0, 157, 10, 0, 250, 78}, - {104, 156, 52, 56, 250, 68, 157, 10, 62, 250, 78, 43}, - {156, 52, 126, 250, 68, 247, 10, 62, 201, 78, 43, 185}, - {52, 126, 39, 68, 247, 251, 62, 201, 46, 43, 185, 82}, - {126, 39, 0, 247, 251, 0, 201, 46, 0, 185, 82, 0}, - {0, 56, 250, 0, 93, 160, 0, 250, 78, 0, 95, 218}, - {56, 250, 68, 93, 160, 61, 250, 78, 43, 95, 218, 128}, - {250, 68, 247, 160, 61, 8, 78, 43, 185, 218, 128, 104}, - {68, 247, 251, 61, 8, 81, 43, 185, 82, 128, 104, 71}, - {247, 251, 0, 8, 81, 0, 185, 82, 0, 104, 71, 0}, - {0, 93, 160, 0, 204, 113, 0, 95, 218, 0, 118, 215}, - {93, 160, 61, 204, 113, 107, 95, 218, 128, 118, 215, 228}, - {160, 61, 8, 113, 107, 206, 218, 128, 104, 215, 228, 199}, - {61, 8, 81, 107, 206, 146, 128, 104, 71, 228, 199, 52}, - {8, 81, 0, 206, 146, 0, 104, 71, 0, 199, 52, 0}, - {0, 204, 113, 0, 0, 0, 0, 118, 215, 0, 0, 0}, - {204, 113, 107, 0, 0, 0, 118, 215, 228, 0, 0, 0}, - {113, 107, 206, 0, 0, 0, 215, 228, 199, 0, 0, 0}, - {107, 206, 146, 0, 0, 0, 228, 199, 52, 0, 0, 0}, - {206, 146, 0, 0, 0, 0, 199, 52, 0, 0, 0, 0}}; - - size_t imgDepthTest2 = 2; - size_t imgHeightTest2 = 5; - size_t imgWidthTest2 = 5; - size_t fltHeightTest2 = 2; - size_t fltWidthTest2 = 3; - size_t strideRowsTest2 = 1; - size_t strideColsTest2 = 1; - size_t zeroPaddingHeightTest2 = 1; - size_t zeroPaddingWidthTest2 = 1; - - Matrix_t A(imgDepthTest2, imgHeightTest2 * imgWidthTest2); - - for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { - A(i, j) = imgTest2[i][j]; - } - } - - size_t height = calculateDimension(imgHeightTest2, fltHeightTest2, zeroPaddingHeightTest2, strideRowsTest2); - - size_t width = calculateDimension(imgWidthTest2, fltWidthTest2, zeroPaddingWidthTest2, strideColsTest2); - - Matrix_t B(height * width, imgDepthTest2 * fltHeightTest2 * fltWidthTest2); - - for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { - B(i, j) = answerTest2[i][j]; - } - } - - bool status = - testIm2col>(A, B, imgHeightTest2, imgWidthTest2, fltHeightTest2, fltWidthTest2, - strideRowsTest2, strideColsTest2, zeroPaddingHeightTest2, zeroPaddingWidthTest2); - - if (status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} - -/************************************************************************* - * Test 3: - * depth = 3, image height = 2, image width = 3, - * filter depth = 3, filter height = 3, filter width = 2, - * stride rows = 3, stride cols = 1, - * zero-padding height = 2, zero-padding width = 1, - *************************************************************************/ - -void test3() -{ - - // 3 x 2 x 3 image - double imgTest3[][6] = {{235, 213, 185, 144, 235, 212}, - - {158, 168, 116, 68, 159, 157}, - - {240, 135, 195, 252, 36, 77}}; - - double answerTest3[][18] = {{0, 0, 0, 0, 0, 235, 0, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 240}, - {0, 0, 0, 0, 235, 213, 0, 0, 0, 0, 158, 168, 0, 0, 0, 0, 240, 135}, - {0, 0, 0, 0, 213, 185, 0, 0, 0, 0, 168, 116, 0, 0, 0, 0, 135, 195}, - {0, 0, 0, 0, 185, 0, 0, 0, 0, 0, 116, 0, 0, 0, 0, 0, 195, 0}, - {0, 144, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 252, 0, 0, 0, 0}, - {144, 235, 0, 0, 0, 0, 68, 159, 0, 0, 0, 0, 252, 36, 0, 0, 0, 0}, - {235, 212, 0, 0, 0, 0, 159, 157, 0, 0, 0, 0, 36, 77, 0, 0, 0, 0}, - {212, 0, 0, 0, 0, 0, 157, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0}}; - - size_t imgDepthTest3 = 3; - size_t imgHeightTest3 = 2; - size_t imgWidthTest3 = 3; - size_t fltHeightTest3 = 3; - size_t fltWidthTest3 = 2; - size_t strideRowsTest3 = 3; - size_t strideColsTest3 = 1; - size_t zeroPaddingHeightTest3 = 2; - size_t zeroPaddingWidthTest3 = 1; - - Matrix_t A(imgDepthTest3, imgHeightTest3 * imgWidthTest3); - - for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { - A(i, j) = imgTest3[i][j]; - } - } - - size_t height = calculateDimension(imgHeightTest3, fltHeightTest3, zeroPaddingHeightTest3, strideRowsTest3); - - size_t width = calculateDimension(imgWidthTest3, fltWidthTest3, zeroPaddingWidthTest3, strideColsTest3); - - Matrix_t B(height * width, imgDepthTest3 * fltHeightTest3 * fltWidthTest3); - - for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { - B(i, j) = answerTest3[i][j]; - } - } - - bool status = - testIm2col>(A, B, imgHeightTest3, imgWidthTest3, fltHeightTest3, fltWidthTest3, - strideRowsTest3, strideColsTest3, zeroPaddingHeightTest3, zeroPaddingWidthTest3); - - if (status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} int main() { + using Scalar_t = Double_t; std::cout << "Testing Im2Col function:" << std::endl; + bool status = true; + std::cout << "Test 1: " << std::endl; - test1(); + status &= test1>(); + if (!status) { + std::cerr << "ERROR - test1 failed " << std::endl; + return -1; + } std::cout << "Test 2: " << std::endl; - test2(); + status &= test2>(); + if (!status) { + std::cerr << "ERROR - test2 failed " << std::endl; + return -1; + } std::cout << "Test 3: " << std::endl; - test3(); + status &= test3>(); + if (!status) { + std::cerr << "ERROR - test3 failed " << std::endl; + return -1; + } } diff --git a/tmva/tmva/test/DNN/CNN/TestIm2Col.h b/tmva/tmva/test/DNN/CNN/TestIm2Col.h new file mode 100644 index 0000000000000..ba45efccf282a --- /dev/null +++ b/tmva/tmva/test/DNN/CNN/TestIm2Col.h @@ -0,0 +1,280 @@ +// +// Created by manos on 18-5-18. +// + +#ifndef ROOT_TESTIM2COL_H +#define ROOT_TESTIM2COL_H + +/********************************************************************************** + * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * + * Package: TMVA * + * Class : * + * Web : http://tmva.sourceforge.net * + * * + * Description: * + * Testing Im2Col method * + * * + * Authors (alphabetical): * + * Vladimir Ilievsky - CERN, Switzerland * + * Manos Stergiadis - CERN, Switzerland * + * * + * Copyright (c) 2005-2015: * + * CERN, Switzerland * + * U. of Victoria, Canada * + * MPI-K Heidelberg, Germany * + * U. of Bonn, Germany * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted according to the terms listed in LICENSE * + * (http://tmva.sourceforge.net/LICENSE) * + **********************************************************************************/ + +//////////////////////////////////////////////////////////////////// +// Testing the method Im2col // +//////////////////////////////////////////////////////////////////// + +#include +#include + +#include "TestConvNet.h" + +using namespace TMVA::DNN; +using namespace TMVA::DNN::CNN; + +inline bool isInteger(double x) +{ + return x == floor(x); +} + +int calculateDimension(size_t imgDim, size_t fltDim, size_t padding, size_t stride) +{ + double dimension = ((imgDim - fltDim + 2 * padding) / stride) + 1; + if (!isInteger(dimension)) { + std::cout << "Not compatible hyper parameters" << std::endl; + std::exit(EXIT_FAILURE); + } + + return (size_t)dimension; +} + +/************************************************************************* + * Test 1: + * depth = 1, image height = 5, image width = 5, + * filter depth = 1, filter height = 2, filter width = 2, + * stride rows = 1, stride cols = 1, + * zero-padding height = 1, zero-padding width = 1, + *************************************************************************/ +template +bool test1() +{ + using Matrix_t = typename Architecture::Matrix_t; + + double imgTest1[][25] = {{244, 198, 134, 194, 86, 104, 156, 52, 126, 39, 56, 250, 68, + 247, 251, 93, 160, 61, 8, 81, 204, 113, 107, 206, 146} + + }; + + double answerTest1[][4] = {{0, 0, 0, 244}, {0, 0, 244, 198}, {0, 0, 198, 134}, {0, 0, 134, 194}, + {0, 0, 194, 86}, {0, 0, 86, 0}, {0, 244, 0, 104}, {244, 198, 104, 156}, + {198, 134, 156, 52}, {134, 194, 52, 126}, {194, 86, 126, 39}, {86, 0, 39, 0}, + {0, 104, 0, 56}, {104, 156, 56, 250}, {156, 52, 250, 68}, {52, 126, 68, 247}, + {126, 39, 247, 251}, {39, 0, 251, 0}, {0, 56, 0, 93}, {56, 250, 93, 160}, + {250, 68, 160, 61}, {68, 247, 61, 8}, {247, 251, 8, 81}, {251, 0, 81, 0}, + {0, 93, 0, 204}, {93, 160, 204, 113}, {160, 61, 113, 107}, {61, 8, 107, 206}, + {8, 81, 206, 146}, {81, 0, 146, 0}, {0, 204, 0, 0}, {204, 113, 0, 0}, + {113, 107, 0, 0}, {107, 206, 0, 0}, {206, 146, 0, 0}, {146, 0, 0, 0}}; + + size_t imgDepthTest1 = 1; + size_t imgHeightTest1 = 5; + size_t imgWidthTest1 = 5; + size_t fltHeightTest1 = 2; + size_t fltWidthTest1 = 2; + size_t strideRowsTest1 = 1; + size_t strideColsTest1 = 1; + size_t zeroPaddingHeightTest1 = 1; + size_t zeroPaddingWidthTest1 = 1; + + Matrix_t A(imgDepthTest1, imgHeightTest1 * imgWidthTest1); + + for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { + for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { + A(i, j) = imgTest1[i][j]; + } + } + + size_t height = calculateDimension(imgHeightTest1, fltHeightTest1, zeroPaddingHeightTest1, strideRowsTest1); + + size_t width = calculateDimension(imgWidthTest1, fltWidthTest1, zeroPaddingWidthTest1, strideColsTest1); + + Matrix_t B(height * width, imgDepthTest1 * fltHeightTest1 * fltWidthTest1); + + for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { + for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { + B(i, j) = answerTest1[i][j]; + } + } + + bool status = + testIm2col(A, B, imgHeightTest1, imgWidthTest1, fltHeightTest1, fltWidthTest1, + strideRowsTest1, strideColsTest1, zeroPaddingHeightTest1, zeroPaddingWidthTest1); + + return status; +} + +/************************************************************************* + * Test 2: + * depth = 2, image height = 5, image width = 5, + * filter depth = 2, filter height = 2, filter width = 3, + * stride rows = 1, stride cols = 1, + * zero-padding height = 1, zero-padding width = 1, + *************************************************************************/ +template +bool test2() +{ + using Matrix_t = typename Architecture::Matrix_t; + + // 2 x 5 x 5 image + double imgTest2[][25] = { + + {244, 198, 134, 194, 86, 104, 156, 52, 126, 39, 56, 250, 68, + 247, 251, 93, 160, 61, 8, 81, 204, 113, 107, 206, 146}, + + {205, 136, 184, 196, 42, 157, 10, 62, 201, 46, 250, 78, 43, + 185, 82, 95, 218, 128, 104, 71, 118, 215, 228, 199, 52} + + }; + + double answerTest2[][12] = {{0, 0, 0, 0, 244, 198, 0, 0, 0, 0, 205, 136}, + {0, 0, 0, 244, 198, 134, 0, 0, 0, 205, 136, 184}, + {0, 0, 0, 198, 134, 194, 0, 0, 0, 136, 184, 196}, + {0, 0, 0, 134, 194, 86, 0, 0, 0, 184, 196, 42}, + {0, 0, 0, 194, 86, 0, 0, 0, 0, 196, 42, 0}, + {0, 244, 198, 0, 104, 156, 0, 205, 136, 0, 157, 10}, + {244, 198, 134, 104, 156, 52, 205, 136, 184, 157, 10, 62}, + {198, 134, 194, 156, 52, 126, 136, 184, 196, 10, 62, 201}, + {134, 194, 86, 52, 126, 39, 184, 196, 42, 62, 201, 46}, + {194, 86, 0, 126, 39, 0, 196, 42, 0, 201, 46, 0}, + {0, 104, 156, 0, 56, 250, 0, 157, 10, 0, 250, 78}, + {104, 156, 52, 56, 250, 68, 157, 10, 62, 250, 78, 43}, + {156, 52, 126, 250, 68, 247, 10, 62, 201, 78, 43, 185}, + {52, 126, 39, 68, 247, 251, 62, 201, 46, 43, 185, 82}, + {126, 39, 0, 247, 251, 0, 201, 46, 0, 185, 82, 0}, + {0, 56, 250, 0, 93, 160, 0, 250, 78, 0, 95, 218}, + {56, 250, 68, 93, 160, 61, 250, 78, 43, 95, 218, 128}, + {250, 68, 247, 160, 61, 8, 78, 43, 185, 218, 128, 104}, + {68, 247, 251, 61, 8, 81, 43, 185, 82, 128, 104, 71}, + {247, 251, 0, 8, 81, 0, 185, 82, 0, 104, 71, 0}, + {0, 93, 160, 0, 204, 113, 0, 95, 218, 0, 118, 215}, + {93, 160, 61, 204, 113, 107, 95, 218, 128, 118, 215, 228}, + {160, 61, 8, 113, 107, 206, 218, 128, 104, 215, 228, 199}, + {61, 8, 81, 107, 206, 146, 128, 104, 71, 228, 199, 52}, + {8, 81, 0, 206, 146, 0, 104, 71, 0, 199, 52, 0}, + {0, 204, 113, 0, 0, 0, 0, 118, 215, 0, 0, 0}, + {204, 113, 107, 0, 0, 0, 118, 215, 228, 0, 0, 0}, + {113, 107, 206, 0, 0, 0, 215, 228, 199, 0, 0, 0}, + {107, 206, 146, 0, 0, 0, 228, 199, 52, 0, 0, 0}, + {206, 146, 0, 0, 0, 0, 199, 52, 0, 0, 0, 0}}; + + size_t imgDepthTest2 = 2; + size_t imgHeightTest2 = 5; + size_t imgWidthTest2 = 5; + size_t fltHeightTest2 = 2; + size_t fltWidthTest2 = 3; + size_t strideRowsTest2 = 1; + size_t strideColsTest2 = 1; + size_t zeroPaddingHeightTest2 = 1; + size_t zeroPaddingWidthTest2 = 1; + + Matrix_t A(imgDepthTest2, imgHeightTest2 * imgWidthTest2); + + for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { + for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { + A(i, j) = imgTest2[i][j]; + } + } + + size_t height = calculateDimension(imgHeightTest2, fltHeightTest2, zeroPaddingHeightTest2, strideRowsTest2); + + size_t width = calculateDimension(imgWidthTest2, fltWidthTest2, zeroPaddingWidthTest2, strideColsTest2); + + Matrix_t B(height * width, imgDepthTest2 * fltHeightTest2 * fltWidthTest2); + + for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { + for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { + B(i, j) = answerTest2[i][j]; + } + } + + bool status = + testIm2col(A, B, imgHeightTest2, imgWidthTest2, fltHeightTest2, fltWidthTest2, + strideRowsTest2, strideColsTest2, zeroPaddingHeightTest2, zeroPaddingWidthTest2); + + return status; +} + +/************************************************************************* + * Test 3: + * depth = 3, image height = 2, image width = 3, + * filter depth = 3, filter height = 3, filter width = 2, + * stride rows = 3, stride cols = 1, + * zero-padding height = 2, zero-padding width = 1, + *************************************************************************/ +template +bool test3() +{ + using Matrix_t = typename Architecture::Matrix_t; + + // 3 x 2 x 3 image + double imgTest3[][6] = {{235, 213, 185, 144, 235, 212}, + + {158, 168, 116, 68, 159, 157}, + + {240, 135, 195, 252, 36, 77}}; + + double answerTest3[][18] = {{0, 0, 0, 0, 0, 235, 0, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 240}, + {0, 0, 0, 0, 235, 213, 0, 0, 0, 0, 158, 168, 0, 0, 0, 0, 240, 135}, + {0, 0, 0, 0, 213, 185, 0, 0, 0, 0, 168, 116, 0, 0, 0, 0, 135, 195}, + {0, 0, 0, 0, 185, 0, 0, 0, 0, 0, 116, 0, 0, 0, 0, 0, 195, 0}, + {0, 144, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 252, 0, 0, 0, 0}, + {144, 235, 0, 0, 0, 0, 68, 159, 0, 0, 0, 0, 252, 36, 0, 0, 0, 0}, + {235, 212, 0, 0, 0, 0, 159, 157, 0, 0, 0, 0, 36, 77, 0, 0, 0, 0}, + {212, 0, 0, 0, 0, 0, 157, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0}}; + + size_t imgDepthTest3 = 3; + size_t imgHeightTest3 = 2; + size_t imgWidthTest3 = 3; + size_t fltHeightTest3 = 3; + size_t fltWidthTest3 = 2; + size_t strideRowsTest3 = 3; + size_t strideColsTest3 = 1; + size_t zeroPaddingHeightTest3 = 2; + size_t zeroPaddingWidthTest3 = 1; + + Matrix_t A(imgDepthTest3, imgHeightTest3 * imgWidthTest3); + + for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { + for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { + A(i, j) = imgTest3[i][j]; + } + } + + size_t height = calculateDimension(imgHeightTest3, fltHeightTest3, zeroPaddingHeightTest3, strideRowsTest3); + + size_t width = calculateDimension(imgWidthTest3, fltWidthTest3, zeroPaddingWidthTest3, strideColsTest3); + + Matrix_t B(height * width, imgDepthTest3 * fltHeightTest3 * fltWidthTest3); + + for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { + for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { + B(i, j) = answerTest3[i][j]; + } + } + + bool status = + testIm2col(A, B, imgHeightTest3, imgWidthTest3, fltHeightTest3, fltWidthTest3, + strideRowsTest3, strideColsTest3, zeroPaddingHeightTest3, zeroPaddingWidthTest3); + + return status; +} + +#endif //ROOT_TESTIM2COL_H diff --git a/tmva/tmva/test/DNN/CNN/TestIm2ColCpu.cxx b/tmva/tmva/test/DNN/CNN/TestIm2ColCpu.cxx index 0757a24401ac4..5a46445c5d2f3 100644 --- a/tmva/tmva/test/DNN/CNN/TestIm2ColCpu.cxx +++ b/tmva/tmva/test/DNN/CNN/TestIm2ColCpu.cxx @@ -29,266 +29,39 @@ //////////////////////////////////////////////////////////////////// #include -#include #include "TMVA/DNN/Architectures/Cpu.h" -#include "TestConvNet.h" +#include "TestIm2Col.h" using namespace TMVA::DNN; using namespace TMVA::DNN::CNN; -using Matrix_t = typename TCpu::Matrix_t; -inline bool isInteger(double x) -{ - return x == floor(x); -} - -int calculateDimension(size_t imgDim, size_t fltDim, size_t padding, size_t stride) -{ - double dimension = ((imgDim - fltDim + 2 * padding) / stride) + 1; - if (!isInteger(dimension)) { - std::cout << "Not compatible hyper parameters" << std::endl; - std::exit(EXIT_FAILURE); - } - - return (size_t)dimension; -} - -/************************************************************************* - * Test 1: - * depth = 1, image height = 5, image width = 5, - * filter depth = 1, filter height = 2, filter width = 2, - * stride rows = 1, stride cols = 1, - * zero-padding height = 1, zero-padding width = 1, - *************************************************************************/ - -void test1() -{ - double imgTest1[][25] = {{244, 198, 134, 194, 86, 104, 156, 52, 126, 39, 56, 250, 68, - 247, 251, 93, 160, 61, 8, 81, 204, 113, 107, 206, 146} - - }; - - double answerTest1[][4] = {{0, 0, 0, 244}, {0, 0, 244, 198}, {0, 0, 198, 134}, {0, 0, 134, 194}, - {0, 0, 194, 86}, {0, 0, 86, 0}, {0, 244, 0, 104}, {244, 198, 104, 156}, - {198, 134, 156, 52}, {134, 194, 52, 126}, {194, 86, 126, 39}, {86, 0, 39, 0}, - {0, 104, 0, 56}, {104, 156, 56, 250}, {156, 52, 250, 68}, {52, 126, 68, 247}, - {126, 39, 247, 251}, {39, 0, 251, 0}, {0, 56, 0, 93}, {56, 250, 93, 160}, - {250, 68, 160, 61}, {68, 247, 61, 8}, {247, 251, 8, 81}, {251, 0, 81, 0}, - {0, 93, 0, 204}, {93, 160, 204, 113}, {160, 61, 113, 107}, {61, 8, 107, 206}, - {8, 81, 206, 146}, {81, 0, 146, 0}, {0, 204, 0, 0}, {204, 113, 0, 0}, - {113, 107, 0, 0}, {107, 206, 0, 0}, {206, 146, 0, 0}, {146, 0, 0, 0}}; - - size_t imgDepthTest1 = 1; - size_t imgHeightTest1 = 5; - size_t imgWidthTest1 = 5; - size_t fltHeightTest1 = 2; - size_t fltWidthTest1 = 2; - size_t strideRowsTest1 = 1; - size_t strideColsTest1 = 1; - size_t zeroPaddingHeightTest1 = 1; - size_t zeroPaddingWidthTest1 = 1; - - Matrix_t A(imgDepthTest1, imgHeightTest1 * imgWidthTest1); - - for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { - A(i, j) = imgTest1[i][j]; - } - } - - size_t height = calculateDimension(imgHeightTest1, fltHeightTest1, zeroPaddingHeightTest1, strideRowsTest1); - - size_t width = calculateDimension(imgWidthTest1, fltWidthTest1, zeroPaddingWidthTest1, strideColsTest1); - - Matrix_t B(height * width, imgDepthTest1 * fltHeightTest1 * fltWidthTest1); - - for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { - B(i, j) = answerTest1[i][j]; - } - } - - bool status = - testIm2col>(A, B, imgHeightTest1, imgWidthTest1, fltHeightTest1, fltWidthTest1, strideRowsTest1, - strideColsTest1, zeroPaddingHeightTest1, zeroPaddingWidthTest1); - - if (status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} - -/************************************************************************* - * Test 2: - * depth = 2, image height = 5, image width = 5, - * filter depth = 2, filter height = 2, filter width = 3, - * stride rows = 1, stride cols = 1, - * zero-padding height = 1, zero-padding width = 1, - *************************************************************************/ - -void test2() -{ - - // 2 x 5 x 5 image - double imgTest2[][25] = { - - {244, 198, 134, 194, 86, 104, 156, 52, 126, 39, 56, 250, 68, - 247, 251, 93, 160, 61, 8, 81, 204, 113, 107, 206, 146}, - - {205, 136, 184, 196, 42, 157, 10, 62, 201, 46, 250, 78, 43, - 185, 82, 95, 218, 128, 104, 71, 118, 215, 228, 199, 52} - - }; - - double answerTest2[][12] = {{0, 0, 0, 0, 244, 198, 0, 0, 0, 0, 205, 136}, - {0, 0, 0, 244, 198, 134, 0, 0, 0, 205, 136, 184}, - {0, 0, 0, 198, 134, 194, 0, 0, 0, 136, 184, 196}, - {0, 0, 0, 134, 194, 86, 0, 0, 0, 184, 196, 42}, - {0, 0, 0, 194, 86, 0, 0, 0, 0, 196, 42, 0}, - {0, 244, 198, 0, 104, 156, 0, 205, 136, 0, 157, 10}, - {244, 198, 134, 104, 156, 52, 205, 136, 184, 157, 10, 62}, - {198, 134, 194, 156, 52, 126, 136, 184, 196, 10, 62, 201}, - {134, 194, 86, 52, 126, 39, 184, 196, 42, 62, 201, 46}, - {194, 86, 0, 126, 39, 0, 196, 42, 0, 201, 46, 0}, - {0, 104, 156, 0, 56, 250, 0, 157, 10, 0, 250, 78}, - {104, 156, 52, 56, 250, 68, 157, 10, 62, 250, 78, 43}, - {156, 52, 126, 250, 68, 247, 10, 62, 201, 78, 43, 185}, - {52, 126, 39, 68, 247, 251, 62, 201, 46, 43, 185, 82}, - {126, 39, 0, 247, 251, 0, 201, 46, 0, 185, 82, 0}, - {0, 56, 250, 0, 93, 160, 0, 250, 78, 0, 95, 218}, - {56, 250, 68, 93, 160, 61, 250, 78, 43, 95, 218, 128}, - {250, 68, 247, 160, 61, 8, 78, 43, 185, 218, 128, 104}, - {68, 247, 251, 61, 8, 81, 43, 185, 82, 128, 104, 71}, - {247, 251, 0, 8, 81, 0, 185, 82, 0, 104, 71, 0}, - {0, 93, 160, 0, 204, 113, 0, 95, 218, 0, 118, 215}, - {93, 160, 61, 204, 113, 107, 95, 218, 128, 118, 215, 228}, - {160, 61, 8, 113, 107, 206, 218, 128, 104, 215, 228, 199}, - {61, 8, 81, 107, 206, 146, 128, 104, 71, 228, 199, 52}, - {8, 81, 0, 206, 146, 0, 104, 71, 0, 199, 52, 0}, - {0, 204, 113, 0, 0, 0, 0, 118, 215, 0, 0, 0}, - {204, 113, 107, 0, 0, 0, 118, 215, 228, 0, 0, 0}, - {113, 107, 206, 0, 0, 0, 215, 228, 199, 0, 0, 0}, - {107, 206, 146, 0, 0, 0, 228, 199, 52, 0, 0, 0}, - {206, 146, 0, 0, 0, 0, 199, 52, 0, 0, 0, 0}}; - - size_t imgDepthTest2 = 2; - size_t imgHeightTest2 = 5; - size_t imgWidthTest2 = 5; - size_t fltHeightTest2 = 2; - size_t fltWidthTest2 = 3; - size_t strideRowsTest2 = 1; - size_t strideColsTest2 = 1; - size_t zeroPaddingHeightTest2 = 1; - size_t zeroPaddingWidthTest2 = 1; - - Matrix_t A(imgDepthTest2, imgHeightTest2 * imgWidthTest2); - - for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { - A(i, j) = imgTest2[i][j]; - } - } - - size_t height = calculateDimension(imgHeightTest2, fltHeightTest2, zeroPaddingHeightTest2, strideRowsTest2); - - size_t width = calculateDimension(imgWidthTest2, fltWidthTest2, zeroPaddingWidthTest2, strideColsTest2); - - Matrix_t B(height * width, imgDepthTest2 * fltHeightTest2 * fltWidthTest2); - - for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { - B(i, j) = answerTest2[i][j]; - } - } - - bool status = - testIm2col>(A, B, imgHeightTest2, imgWidthTest2, fltHeightTest2, fltWidthTest2, strideRowsTest2, - strideColsTest2, zeroPaddingHeightTest2, zeroPaddingWidthTest2); - - if (status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} - -/************************************************************************* - * Test 3: - * depth = 3, image height = 2, image width = 3, - * filter depth = 3, filter height = 3, filter width = 2, - * stride rows = 3, stride cols = 1, - * zero-padding height = 2, zero-padding width = 1, - *************************************************************************/ - -void test3() -{ - - // 3 x 2 x 3 image - double imgTest3[][6] = {{235, 213, 185, 144, 235, 212}, - - {158, 168, 116, 68, 159, 157}, - - {240, 135, 195, 252, 36, 77}}; - - double answerTest3[][18] = {{0, 0, 0, 0, 0, 235, 0, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 240}, - {0, 0, 0, 0, 235, 213, 0, 0, 0, 0, 158, 168, 0, 0, 0, 0, 240, 135}, - {0, 0, 0, 0, 213, 185, 0, 0, 0, 0, 168, 116, 0, 0, 0, 0, 135, 195}, - {0, 0, 0, 0, 185, 0, 0, 0, 0, 0, 116, 0, 0, 0, 0, 0, 195, 0}, - {0, 144, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 252, 0, 0, 0, 0}, - {144, 235, 0, 0, 0, 0, 68, 159, 0, 0, 0, 0, 252, 36, 0, 0, 0, 0}, - {235, 212, 0, 0, 0, 0, 159, 157, 0, 0, 0, 0, 36, 77, 0, 0, 0, 0}, - {212, 0, 0, 0, 0, 0, 157, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0}}; - - size_t imgDepthTest3 = 3; - size_t imgHeightTest3 = 2; - size_t imgWidthTest3 = 3; - size_t fltHeightTest3 = 3; - size_t fltWidthTest3 = 2; - size_t strideRowsTest3 = 3; - size_t strideColsTest3 = 1; - size_t zeroPaddingHeightTest3 = 2; - size_t zeroPaddingWidthTest3 = 1; - - Matrix_t A(imgDepthTest3, imgHeightTest3 * imgWidthTest3); - - for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { - A(i, j) = imgTest3[i][j]; - } - } - - size_t height = calculateDimension(imgHeightTest3, fltHeightTest3, zeroPaddingHeightTest3, strideRowsTest3); - - size_t width = calculateDimension(imgWidthTest3, fltWidthTest3, zeroPaddingWidthTest3, strideColsTest3); - - Matrix_t B(height * width, imgDepthTest3 * fltHeightTest3 * fltWidthTest3); - - for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { - for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { - B(i, j) = answerTest3[i][j]; - } - } - - bool status = - testIm2col>(A, B, imgHeightTest3, imgWidthTest3, fltHeightTest3, fltWidthTest3, strideRowsTest3, - strideColsTest3, zeroPaddingHeightTest3, zeroPaddingWidthTest3); - - if (status) - std::cout << "Test passed!" << std::endl; - else - std::cout << "Test not passed!" << std::endl; -} int main() { + using Scalar_t = Double_t; std::cout << "Testing Im2Col function:" << std::endl; + bool status = true; + std::cout << "Test 1: " << std::endl; - test1(); + status &= test1>(); + if (!status) { + std::cerr << "ERROR - test1 failed " << std::endl; + return -1; + } std::cout << "Test 2: " << std::endl; - test2(); + status &= test2>(); + if (!status) { + std::cerr << "ERROR - test2 failed " << std::endl; + return -1; + } std::cout << "Test 3: " << std::endl; - test3(); + status &= test3>(); + if (!status) { + std::cerr << "ERROR - test3 failed " << std::endl; + return -1; + } } diff --git a/tmva/tmva/test/DNN/CNN/TestIm2ColCuda.cxx b/tmva/tmva/test/DNN/CNN/TestIm2ColCuda.cxx new file mode 100644 index 0000000000000..2f5e8f0ef8301 --- /dev/null +++ b/tmva/tmva/test/DNN/CNN/TestIm2ColCuda.cxx @@ -0,0 +1,64 @@ +/********************************************************************************** + * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * + * Package: TMVA * + * Class : * + * Web : http://tmva.sourceforge.net * + * * + * Description: * + * Testing Im2Col method on the GPU * + * * + * Authors (alphabetical): * + * Manos Stergiadis - CERN, Switzerland * + * * + * Copyright (c) 2005-2015: * + * CERN, Switzerland * + * U. of Victoria, Canada * + * MPI-K Heidelberg, Germany * + * U. of Bonn, Germany * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted according to the terms listed in LICENSE * + * (http://tmva.sourceforge.net/LICENSE) * + **********************************************************************************/ + +//////////////////////////////////////////////////////////////////// +// Concrete instantiation of the generic Im2Col test for // +// CUDA architectures. // +//////////////////////////////////////////////////////////////////// +#include + +#include "TMVA/DNN/Architectures/Cuda.h" +#include "TestIm2Col.h" + +using namespace TMVA::DNN; +using namespace TMVA::DNN::CNN; + + +int main() +{ + using Scalar_t = Double_t; + std::cout << "Testing Im2Col function on the GPU:" << std::endl; + + bool status = true; + + std::cout << "Test 1: " << std::endl; + status &= test1>(); + if (!status) { + std::cerr << "ERROR - test1 failed " << std::endl; + return -1; + } + + std::cout << "Test 2: " << std::endl; + status &= test2>(); + if (!status) { + std::cerr << "ERROR - test2 failed " << std::endl; + return -1; + } + + std::cout << "Test 3: " << std::endl; + status &= test3>(); + if (!status) { + std::cerr << "ERROR - test3 failed " << std::endl; + return -1; + } +} \ No newline at end of file diff --git a/tmva/tmva/test/DNN/CNN/TestPoolingLayer.cxx b/tmva/tmva/test/DNN/CNN/TestPoolingLayer.cxx new file mode 100644 index 0000000000000..6f883588810d6 --- /dev/null +++ b/tmva/tmva/test/DNN/CNN/TestPoolingLayer.cxx @@ -0,0 +1,72 @@ +// @(#)root/tmva/tmva/cnn:$Id$ +// Author: Manos Stergiadis + +/********************************************************************************** + * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * + * Package: TMVA * + * Class : * + * Web : http://tmva.sourceforge.net * + * * + * Description: * + * Testing the Pooling Layer on a CPU architecture * + * * + * Authors (alphabetical): * + * Vladimir Ilievski - CERN, Switzerland * + * * + * Copyright (c) 2005-2015: * + * CERN, Switzerland * + * U. of Victoria, Canada * + * MPI-K Heidelberg, Germany * + * U. of Bonn, Germany * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted according to the terms listed in LICENSE * + * (http://tmva.sourceforge.net/LICENSE) * + **********************************************************************************/ + +//////////////////////////////////////////////////////////////////// +// Testing the Downsample function // +//////////////////////////////////////////////////////////////////// + +#include +#include + +#include "TMVA/DNN/Architectures/Reference.h" +#include "TestPoolingLayer.h" + +int main() +{ + using Scalar_t = Double_t; + + std::cout << "Testing Downsample on the GPU:" << std::endl; + + bool status = true; + + std::cout << "Test Forward-Propagation 1: " << std::endl; + status &= testDownsample1>(); + if (!status) { + std::cerr << "ERROR - Forward-Propagation 1 failed " << std::endl; + return -1; + } + + std::cout << "Test Forward-Propagation 2: " << std::endl; + status &= testDownsample2>(); + if (!status) { + std::cerr << "ERROR - Forward-Propagation 2 failed " << std::endl; + return -1; + } + + std::cout << "Test Back-propagation: " << std::endl; + status &= testBackward1>(); + if (!status) { + std::cerr << "ERROR - Back-propagation failed " << std::endl; + return -1; + } + + std::cout << "Test Back-propagation: " << std::endl; + status &= testBackward2>(); + if (!status) { + std::cerr << "ERROR - Back-propagation failed " << std::endl; + return -1; + } +} \ No newline at end of file diff --git a/tmva/tmva/test/DNN/CNN/TestPoolingLayer.h b/tmva/tmva/test/DNN/CNN/TestPoolingLayer.h new file mode 100644 index 0000000000000..3a156d8cfa9b1 --- /dev/null +++ b/tmva/tmva/test/DNN/CNN/TestPoolingLayer.h @@ -0,0 +1,342 @@ +// @(#)root/tmva/tmva/cnn:$Id$ +// Author: Manos Stergiadis + +#ifndef ROOT_TESTPOOLINGLAYER_H +#define ROOT_TESTPOOLINGLAYER_H + +/********************************************************************************** + * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * + * Package: TMVA * + * Class : * + * Web : http://tmva.sourceforge.net * + * * + * Description: * + * Testing the Pooling layer in an architecture agnostic manner. * + * * + * Authors (alphabetical): * + * Manos Stergiadis - CERN, Switzerland * + * * + * Copyright (c) 2005-2015: * + * CERN, Switzerland * + * U. of Victoria, Canada * + * MPI-K Heidelberg, Germany * + * U. of Bonn, Germany * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted according to the terms listed in LICENSE * + * (http://tmva.sourceforge.net/LICENSE) * + **********************************************************************************/ + +//////////////////////////////////////////////////////////////////// +// Testing the Max Pooling Layer // +//////////////////////////////////////////////////////////////////// + +#include +#include + +#include "TestConvNet.h" + +using namespace TMVA::DNN; +using namespace TMVA::DNN::CNN; + + +inline bool isInteger(double x) +{ + return x == floor(x); +} + +size_t calculateDimension(size_t imgDim, size_t fltDim, size_t stride) +{ + double dimension = ((imgDim - fltDim) / stride) + 1; + if (!isInteger(dimension)) { + std::cout << "Not compatible hyper parameters" << std::endl; + std::exit(EXIT_FAILURE); + } + + return (size_t)dimension; +} + +/************************************************************************* + * Test 1: + * depth = 2, image height = 4, image width = 5, + * frame depth = 2, filter height = 2, filter width = 2, + * stride rows = 2, stride cols = 1, + * zero-padding height = 0, zero-padding width = 0, + *************************************************************************/ +template +bool testDownsample1() +{ + using Matrix_t = typename Architecture::Matrix_t; + + double imgTest1[][20] = { + {166, 212, 213, 150, 114, 119, 109, 115, 88, 144, 227, 208, 208, 235, 57, 57, 165, 250, 139, 76}, + + {57, 255, 184, 162, 204, 220, 11, 192, 183, 174, 2, 153, 183, 175, 10, 55, 123, 246, 138, 80}}; + + double answerTest1[][8] = {{212, 213, 213, 150, 227, 250, 250, 235}, + + {255, 255, 192, 204, 153, 246, 246, 175}}; + + double answerIdxTest1[][8] = {{1, 2, 2, 3, 10, 17, 17, 13}, + + {1, 1, 7, 4, 11, 17, 17, 13}}; + + size_t imgDepthTest1 = 2; + size_t imgHeightTest1 = 4; + size_t imgWidthTest1 = 5; + size_t fltHeightTest1 = 2; + size_t fltWidthTest1 = 2; + size_t strideRowsTest1 = 2; + size_t strideColsTest1 = 1; + + Matrix_t A(imgDepthTest1, imgHeightTest1 * imgWidthTest1); + + for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { + for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { + A(i, j) = imgTest1[i][j]; + } + } + + size_t height = calculateDimension(imgHeightTest1, fltHeightTest1, strideRowsTest1); + + size_t width = calculateDimension(imgWidthTest1, fltWidthTest1, strideColsTest1); + + Matrix_t idx(imgDepthTest1, height * width); + Matrix_t B(imgDepthTest1, height * width); + + for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { + for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { + idx(i, j) = answerIdxTest1[i][j]; + B(i, j) = answerTest1[i][j]; + } + } + + bool status = testDownsample(A, idx, B, imgHeightTest1, imgWidthTest1, fltHeightTest1, fltWidthTest1, + strideRowsTest1, strideColsTest1); + + return status; +} + +/************************************************************************* + * Test 1: + * depth = 1, image height = 6, image width = 6, + * frame depth = 1, filter height = 2, filter width = 3, + * stride rows = 1, stride cols = 3, + * zero-padding height = 0, zero-padding width = 0, + *************************************************************************/ +template +bool testDownsample2() +{ + using Matrix_t = typename Architecture::Matrix_t; + + double imgTest2[][36] = {{200, 79, 69, 58, 98, 168, 49, 230, 21, 141, 218, 38, 72, 224, 14, 65, 147, 105, + 38, 27, 111, 160, 200, 48, 109, 104, 153, 149, 233, 11, 16, 91, 236, 183, 166, 155}}; + + double answerTest2[][10] = {{230, 218, 230, 218, 224, 200, 153, 233, 236, 233}}; + + double answerIdxTest2[][10] = {{7, 10, 7, 10, 13, 22, 26, 28, 32, 28}}; + + size_t imgDepthTest2 = 1; + size_t imgHeightTest2 = 6; + size_t imgWidthTest2 = 6; + size_t fltHeightTest2 = 2; + size_t fltWidthTest2 = 3; + size_t strideRowsTest2 = 1; + size_t strideColsTest2 = 3; + + Matrix_t A(imgDepthTest2, imgHeightTest2 * imgWidthTest2); + + for (size_t i = 0; i < (size_t)A.GetNrows(); i++) { + for (size_t j = 0; j < (size_t)A.GetNcols(); j++) { + A(i, j) = imgTest2[i][j]; + } + } + + size_t height = calculateDimension(imgHeightTest2, fltHeightTest2, strideRowsTest2); + + size_t width = calculateDimension(imgWidthTest2, fltWidthTest2, strideColsTest2); + + Matrix_t idx(imgDepthTest2, height * width); + Matrix_t B(imgDepthTest2, height * width); + + for (size_t i = 0; i < (size_t)B.GetNrows(); i++) { + for (size_t j = 0; j < (size_t)B.GetNcols(); j++) { + idx(i, j) = answerIdxTest2[i][j]; + B(i, j) = answerTest2[i][j]; + } + } + + bool status = testDownsample(A, idx, B, imgHeightTest2, imgWidthTest2, fltHeightTest2, fltWidthTest2, + strideRowsTest2, strideColsTest2); + + return status; +} + +/************************************************************************* + * Test BackWard 1: + * depth = 1, image height = 6, image width = 6, + * frame depth = 1, filter height = 2, filter width = 3, + * stride rows = 1, stride cols = 3, + * zero-padding height = 0, zero-padding width = 0, + *************************************************************************/ +template +bool testBackward1() { + + using Matrix_t = typename Architecture::Matrix_t; + + /* Activations of the previous layer. These will be computed by the backward pass. */ + double expected[][36] = + { + { + 0, 0, 0, 0, 0, 0, + 0, 21.0, 0, 0, -3.6, 0, + 0, 12.0, 0, 0, 0, 0, + 0, 0, 0, 0, -6.0, 0, + 0, 0, 21.0, 0, 12.0, 0, + 0, 0, -3.0, 0, 0, 0 + } + }; + + /* Activation gradients, coming from the next layer. These will be back-propagated. */ + double next[][10] = + { + {15.0, -6.6, + 6.0, 3.0, + 12.0, -6.0, + 21.0, -9.0, + -3.0, 21.0} + }; + + double index[][10] = + { + {7, 10, + 7, 10, + 13, 22, + 26, 28, + 32, 28} + }; + + size_t depth = 1; + size_t inHeight = 6; + size_t inWidth = 6; + size_t frameHeight = 2; + size_t frameWidth = 3; + size_t strideRows = 1; + size_t strideCols = 3; + + Matrix_t A(depth, inHeight * inWidth); + printf("Filling A with the expected values\n"); + for (size_t i = 0; i < depth; i++) { + for (size_t j = 0; j < inHeight * inWidth; j++) { + A(i, j) = expected[i][j]; + } + } + + /* Fill the activation gradients */ + size_t height = calculateDimension(inHeight, frameHeight, strideRows); + size_t width = calculateDimension(inWidth, frameWidth, strideCols); + + Matrix_t idx(depth, height * width); + Matrix_t B(depth, height * width); + printf("filling matrices B and idx\n"); + for (size_t i = 0; i < depth; i++) { + for (size_t j = 0; j < height * width; j++) { + idx(i, j) = index[i][j]; + B(i, j) = next[i][j]; + } + } + + + bool status = testPoolingBackward(B, A, idx, inHeight, inWidth, frameHeight, + frameWidth, strideRows, strideCols, height * width); + return status; +} + +/************************************************************************* +// * Test Backward 2: +// * depth = 2, image height = 4, image width = 5, +// * frame depth = 2, filter height = 2, filter width = 2, +// * stride rows = 2, stride cols = 1, +// * zero-padding height = 0, zero-padding width = 0, +// *************************************************************************/ +template +bool testBackward2() { + + using Matrix_t = typename Architecture::Matrix_t; + + /* Activations of the previous layer. These will be computed by the backward pass. */ + double expected[][20] = + { + { + 0.0, 15.0, -0.5, 3.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, + 12.0, 0.0, 0.0, -9.0, 0.0, + 0.0, 0.0, -2.0, 0.0, 0.0 + }, + { + 0.0, 0.5, 0.0, 0.0, -12.0, + 0.0, 0.0, 3.5, 0.0, 0.0, + 0.0, 5.5, 0.0, -3.5, 0.0, + 0.0, 0.0, 5.0, 0.0, 0.0 + } + }; + + /* Activation gradients, coming from the next layer. These will be back-propagated. */ + double next[][8] = + { + { + 15, -6.5, 6.0, 3.0, + 12, 2.5, -4.5, -9.0 + }, + { + -0.5, 1.0, 3.5, -12.0, + 5.5, -2.0, 7.0, -3.5 + } + }; + + double index[][10] = + { + { + 1, 2, 2, 3, + 10, 17, 17, 13 + }, + { + 1, 1, 7, 4, + 11, 17, 17, 13 + } + }; + + size_t depth = 2; + size_t inHeight = 4; + size_t inWidth = 5; + size_t frameHeight = 2; + size_t frameWidth = 2; + size_t strideRows = 2; + size_t strideCols = 1; + + Matrix_t A(depth, inHeight * inWidth); + for (size_t i = 0; i < depth; i++) { + for (size_t j = 0; j < inHeight * inWidth; j++) { + A(i, j) = expected[i][j]; + } + } + + /* Fill the activation gradients */ + size_t height = calculateDimension(inHeight, frameHeight, strideRows); + size_t width = calculateDimension(inWidth, frameWidth, strideCols); + + Matrix_t idx(depth, height * width); + Matrix_t B(depth, height * width); + for (size_t i = 0; i < depth; i++) { + for (size_t j = 0; j < height * width; j++) { + idx(i, j) = index[i][j]; + B(i, j) = next[i][j]; + } + } + + bool status = testPoolingBackward(B, A, idx, inHeight, inWidth, frameHeight, + frameWidth, strideRows, strideCols, height * width); + return status; +} + +#endif //ROOT_TESTPOOLINGLAYER_H diff --git a/tmva/tmva/test/DNN/CNN/TestPoolingLayerCpu.cxx b/tmva/tmva/test/DNN/CNN/TestPoolingLayerCpu.cxx new file mode 100644 index 0000000000000..cf40df630471e --- /dev/null +++ b/tmva/tmva/test/DNN/CNN/TestPoolingLayerCpu.cxx @@ -0,0 +1,72 @@ +// @(#)root/tmva/tmva/cnn:$Id$ +// Author: Manos Stergiadis + +/********************************************************************************** + * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * + * Package: TMVA * + * Class : * + * Web : http://tmva.sourceforge.net * + * * + * Description: * + * Testing the Pooling Layer on a CPU architecture * + * * + * Authors (alphabetical): * + * Manos Stergiadis - CERN, Switzerland * + * * + * Copyright (c) 2005-2015: * + * CERN, Switzerland * + * U. of Victoria, Canada * + * MPI-K Heidelberg, Germany * + * U. of Bonn, Germany * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted according to the terms listed in LICENSE * + * (http://tmva.sourceforge.net/LICENSE) * + **********************************************************************************/ + +//////////////////////////////////////////////////////////////////// +// Testing the Downsample function // +//////////////////////////////////////////////////////////////////// + +#include +#include + +#include "TMVA/DNN/Architectures/Cpu.h" +#include "TestPoolingLayer.h" + +int main() +{ + using Scalar_t = Double_t; + + std::cout << "Testing Downsample on the CPU:" << std::endl; + + bool status = true; + + std::cout << "Test Forward-Propagation 1: " << std::endl; + status &= testDownsample1>(); + if (!status) { + std::cerr << "ERROR - Forward-Propagation 1 failed " << std::endl; + return -1; + } + + std::cout << "Test Forward-Propagation 2: " << std::endl; + status &= testDownsample2>(); + if (!status) { + std::cerr << "ERROR - Forward-Propagation 2 failed " << std::endl; + return -1; + } + + std::cout << "Test Back-propagation 1: " << std::endl; + status &= testBackward1>(); + if (!status) { + std::cerr << "ERROR - Back-propagation failed " << std::endl; + return -1; + } + + std::cout << "Test Back-propagation 2: " << std::endl; + status &= testBackward2>(); + if (!status) { + std::cerr << "ERROR - Back-propagation failed " << std::endl; + return -1; + } +} \ No newline at end of file diff --git a/tmva/tmva/test/DNN/CNN/TestPoolingLayerCuda.cxx b/tmva/tmva/test/DNN/CNN/TestPoolingLayerCuda.cxx new file mode 100644 index 0000000000000..bdd940a4f6445 --- /dev/null +++ b/tmva/tmva/test/DNN/CNN/TestPoolingLayerCuda.cxx @@ -0,0 +1,73 @@ +// @(#)root/tmva/tmva/cnn:$Id$ +// Author: Manos Stergiadis + +/********************************************************************************** + * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * + * Package: TMVA * + * Class : * + * Web : http://tmva.sourceforge.net * + * * + * Description: * + * Testing the Pooling Layer on a CPU architecture * + * * + * Authors (alphabetical): * + * Manos Stergiadis - CERN, Switzerland * + * * + * Copyright (c) 2005-2015: * + * CERN, Switzerland * + * U. of Victoria, Canada * + * MPI-K Heidelberg, Germany * + * U. of Bonn, Germany * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted according to the terms listed in LICENSE * + * (http://tmva.sourceforge.net/LICENSE) * + **********************************************************************************/ + +//////////////////////////////////////////////////////////////////// +// Testing the Downsample function // +//////////////////////////////////////////////////////////////////// + +#include +#include + +#include "TMVA/DNN/Architectures/Cuda.h" +#include "TestPoolingLayer.h" + + +int main() +{ + using Scalar_t = Double_t; + + std::cout << "Testing Downsample on the GPU:" << std::endl; + + bool status = true; + + std::cout << "Test Forward-Propagation 1: " << std::endl; + status &= testDownsample1>(); + if (!status) { + std::cerr << "ERROR - Forward-Propagation 1 failed " << std::endl; + return -1; + } + + std::cout << "Test Forward-Propagation 2: " << std::endl; + status &= testDownsample2>(); + if (!status) { + std::cerr << "ERROR - Forward-Propagation 2 failed " << std::endl; + return -1; + } + + std::cout << "Test Back-propagation: " << std::endl; + status &= testBackward1>(); + if (!status) { + std::cerr << "ERROR - Back-propagation failed " << std::endl; + return -1; + } + + std::cout << "Test Back-propagation: " << std::endl; + status &= testBackward2>(); + if (!status) { + std::cerr << "ERROR - Back-propagation failed " << std::endl; + return -1; + } +} \ No newline at end of file diff --git a/tmva/tmva/test/DNN/CNN/TestReshape.cxx b/tmva/tmva/test/DNN/CNN/TestReshape.cxx new file mode 100644 index 0000000000000..a104861ec4d2c --- /dev/null +++ b/tmva/tmva/test/DNN/CNN/TestReshape.cxx @@ -0,0 +1,68 @@ +// @(#)root/tmva $Id$ +// Author: Vladimir Ilievski + +/********************************************************************************** + * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * + * Package: TMVA * + * Class : * + * Web : http://tmva.sourceforge.net * + * * + * Description: * + * Testing Flatten function for Reference backend * + * * + * Authors (alphabetical): * + * Vladimir Ilievski - CERN, Switzerland * + * * + * Copyright (c) 2005-2015: * + * CERN, Switzerland * + * U. of Victoria, Canada * + * MPI-K Heidelberg, Germany * + * U. of Bonn, Germany * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted according to the terms listed in LICENSE * + * (http://tmva.sourceforge.net/LICENSE) * + **********************************************************************************/ + +//////////////////////////////////////////////////////////////////// +// Testing Flatten/Deflatten on the Reference architecture // +//////////////////////////////////////////////////////////////////// + +#include + +#include "TMVA/DNN/Architectures/Reference.h" +#include "TestReshape.h" + +using namespace TMVA::DNN; +using namespace TMVA::DNN::CNN; +using Matrix_t = typename TReference::Matrix_t; + + +int main() +{ + using Scalar_t = Double_t; + std::cout << "Testing Flatten/Deflatten on the Reference architecture:" << std::endl; + + bool status = true; + + std::cout << "Test Reshape: " << std::endl; + status &= testReshape>(); + if (!status) { + std::cerr << "ERROR - testReshape failed " << std::endl; + return 1; + } + + std::cout << "Test Flatten: " << std::endl; + status &= testFlatten>(); + if (!status) { + std::cerr << "ERROR - testFlatten failed " << std::endl; + return 1; + } + + std::cout << "Test Deflatten: " << std::endl; + status &= testDeflatten>(); + if (!status) { + std::cerr << "ERROR - testDeflatten failed " << std::endl; + return 1; + } +} diff --git a/tmva/tmva/test/DNN/CNN/TestReshape.h b/tmva/tmva/test/DNN/CNN/TestReshape.h new file mode 100644 index 0000000000000..d9ecf02f0d5c6 --- /dev/null +++ b/tmva/tmva/test/DNN/CNN/TestReshape.h @@ -0,0 +1,203 @@ +// @(#)root/tmva $Id$ +// Author: Manos Stergiadis + +/********************************************************************************** + * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * + * Package: TMVA * + * Class : * + * Web : http://tmva.sourceforge.net * + * * + * Description: * + * Testing Flatten function for every architecture using templates * + * * + * Authors (alphabetical): * + * Manos Stergiadis +#include "TestConvNet.h" + +using namespace TMVA::DNN; +using namespace TMVA::DNN::CNN; + +///////////////////////////////////////////////////////////////////////// +/// Test Reshape: +/// Input Shape: (3, 5) +/// Output Shape: (5, 3) +///////////////////////////////////////////////////////////////////////// +template +bool testReshape() +{ + using Matrix_t = typename Architecture_t::Matrix_t; + + double input[][5] = {{158, 157, 22, 166, 179}, + { 68, 179, 233, 110, 163}, + {168, 216, 76, 8, 102}}; + + size_t nRowsA = 3; + size_t nColsA = 5; + Matrix_t A(nRowsA, nColsA); + for (size_t i = 0; i < nRowsA; i++) { + for (size_t j = 0; j < nColsA; j++) { + A(i, j) = input[i][j]; + } + } + + double expected[][3] = {{158, 157, 22}, + {166, 179, 68}, + {179, 233, 110}, + {163, 168, 216}, + { 76, 8, 102}}; + + size_t nRowsB = 5; + size_t nColsB = 3; + Matrix_t B(nRowsB, nColsB); + for (size_t i = 0; i < nRowsB; i++) { + for (size_t j = 0; j < nColsB; j++) { + B(i, j) = expected[i][j]; + } + } + + return testReshape(A, B); +} + +/************************************************************************* + * Test 1: + * depth = 3, width = 5, height = 5 + *************************************************************************/ +template +bool testFlatten() +{ + using Matrix_t = typename Architecture_t::Matrix_t; + + double input[][5][5] = {{{158, 157, 22, 166, 179}, + {68, 179, 233, 110, 163}, + {168, 216, 76, 8, 102}, + {159, 163, 25, 78, 119}, + {116, 50, 206, 102, 247}, + }, + + {{187, 166, 121, 112, 136}, + {237, 30, 180, 7, 248}, + {52, 172, 146, 130, 92}, + {124, 244, 214, 175, 9}, + {80, 232, 139, 224, 237}}, + + {{53, 147, 103, 53, 110}, + {112, 222, 19, 156, 232}, + {81, 19, 188, 224, 220}, + {255, 190, 76, 219, 95}, + {245, 4, 217, 22, 22}}}; + + double expected[][25] = {{158, 157, 22, 166, 179, 68, 179, 233, 110, 163, 168, 216, 76, + 8, 102, 159, 163, 25, 78, 119, 116, 50, 206, 102, 247}, + + {187, 166, 121, 112, 136, 237, 30, 180, 7, 248, 52, 172, 146, + 130, 92, 124, 244, 214, 175, 9, 80, 232, 139, 224, 237}, + + { 53, 147, 103, 53, 110, 112, 222, 19, 156, 232, 81, 19, 188, + 224, 220, 255, 190, 76, 219, 95, 245, 4, 217, 22, 22}}; + + size_t size = 3; + size_t nRows = 5; + size_t nCols = 5; + + std::vector A; + for (size_t i = 0; i < size; i++) { + Matrix_t temp(nRows, nCols); + for (size_t j = 0; j < nRows; j++) { + for (size_t k = 0; k < nCols; k++) { + temp(j, k) = input[i][j][k]; + } + } + A.push_back(temp); + } + + Matrix_t B(size, nRows * nCols); + for (size_t i = 0; i < size; i++) { + for (size_t j = 0; j < nRows * nCols; j++) { + B(i, j) = expected[i][j]; + } + } + + return testFlatten(A, B, size, nRows, nCols); +} + +/************************************************************************* + * Test 1: + * depth = 3, width = 5, height = 5 + *************************************************************************/ +template +bool testDeflatten() +{ + using Matrix_t = typename Architecture_t::Matrix_t; + + double input[][25] = {{158, 157, 22, 166, 179, 68, 179, 233, 110, 163, 168, 216, 76, + 8, 102, 159, 163, 25, 78, 119, 116, 50, 206, 102, 247}, + + {187, 166, 121, 112, 136, 237, 30, 180, 7, 248, 52, 172, 146, + 130, 92, 124, 244, 214, 175, 9, 80, 232, 139, 224, 237}, + + { 53, 147, 103, 53, 110, 112, 222, 19, 156, 232, 81, 19, 188, + 224, 220, 255, 190, 76, 219, 95, 245, 4, 217, 22, 22}}; + + double expected[][5][5] = {{{158, 157, 22, 166, 179}, + {68, 179, 233, 110, 163}, + {168, 216, 76, 8, 102}, + {159, 163, 25, 78, 119}, + {116, 50, 206, 102, 247}, + }, + + {{187, 166, 121, 112, 136}, + {237, 30, 180, 7, 248}, + {52, 172, 146, 130, 92}, + {124, 244, 214, 175, 9}, + {80, 232, 139, 224, 237}}, + + {{53, 147, 103, 53, 110}, + {112, 222, 19, 156, 232}, + {81, 19, 188, 224, 220}, + {255, 190, 76, 219, 95}, + {245, 4, 217, 22, 22}}}; + + size_t size = 3; + size_t nRows = 5; + size_t nCols = 5; + + Matrix_t A(size, nRows * nCols); + for (size_t i = 0; i < size; i++) { + for (size_t j = 0; j < nRows * nCols; j++) { + A(i, j) = input[i][j]; + } + } + + std::vector B; + for (size_t i = 0; i < size; i++) { + Matrix_t temp(nRows, nCols); + for (size_t j = 0; j < nRows; j++) { + for (size_t k = 0; k < nCols; k++) { + temp(j, k) = expected[i][j][k]; + } + } + B.push_back(temp); + } + + return testDeflatten(A, B, size, nRows, nCols); + +} + +#endif //ROOT_TESTFLATTEN_H diff --git a/tmva/tmva/test/DNN/CNN/TestReshapeCpu.cxx b/tmva/tmva/test/DNN/CNN/TestReshapeCpu.cxx new file mode 100644 index 0000000000000..d3817ded6758d --- /dev/null +++ b/tmva/tmva/test/DNN/CNN/TestReshapeCpu.cxx @@ -0,0 +1,70 @@ +// @(#)root/tmva $Id$ +// Author: Manos Stergiadis + +/********************************************************************************** + * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * + * Package: TMVA * + * Class : * + * Web : http://tmva.sourceforge.net * + * * + * Description: * + * Testing Flatten function for Reference backend * + * * + * Authors (alphabetical): * + * Manos Stergiadis - CERN, Switzerland * + * * + * Copyright (c) 2005-2015: * + * CERN, Switzerland * + * U. of Victoria, Canada * + * MPI-K Heidelberg, Germany * + * U. of Bonn, Germany * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted according to the terms listed in LICENSE * + * (http://tmva.sourceforge.net/LICENSE) * + **********************************************************************************/ + +//////////////////////////////////////////////////////////////////// +// Testing Flatten/Deflatten on the CPU architecture // +//////////////////////////////////////////////////////////////////// + +#include + +#include "TMVA/DNN/Architectures/Cpu.h" +#include "TestReshape.h" + +using namespace TMVA::DNN; +using namespace TMVA::DNN::CNN; +using Matrix_t = typename TCpu::Matrix_t; + + +int main() +{ + using Scalar_t = Double_t; + std::cout << "Testing Flatten/Deflatten on the CPU architecture:" << std::endl; + + bool status = true; + + std::cout << "Test Reshape: " << std::endl; + status &= testReshape>(); + if (!status) { + std::cerr << "ERROR - testReshape failed " << std::endl; + return 1; + } + + std::cout << "Test Flatten: " << std::endl; + status &= testFlatten>(); + if (!status) { + std::cerr << "ERROR - testFlatten failed " << std::endl; + return 1; + } + + std::cout << "Test Deflatten: " << std::endl; + status &= testDeflatten>(); + if (!status) { + std::cerr << "ERROR - testDeflatten failed " << std::endl; + return 1; + } + +} + diff --git a/tmva/tmva/test/DNN/CNN/TestReshapeCuda.cxx b/tmva/tmva/test/DNN/CNN/TestReshapeCuda.cxx new file mode 100644 index 0000000000000..e8c65a911fe1d --- /dev/null +++ b/tmva/tmva/test/DNN/CNN/TestReshapeCuda.cxx @@ -0,0 +1,61 @@ +// @(#)root/tmva $Id$ +// Author: Manos Stergiadis + +/********************************************************************************** + * Project: TMVA - a Root-integrated toolkit for multivariate data analysis * + * Package: TMVA * + * Class : * + * Web : http://tmva.sourceforge.net * + * * + * Description: * + * Testing Flatten function for Reference backend * + * * + * Authors (alphabetical): * + * Manos Stergiadis >(); + if (!status) { + std::cerr << "ERROR - testReshape failed " << std::endl; + return 1; + } + + std::cout << "Test Flatten: " << std::endl; + status &= testFlatten>(); + if (!status) { + std::cerr << "ERROR - testFlatten failed " << std::endl; + return 1; + } + + std::cout << "Test Deflatten: " << std::endl; + status &= testDeflatten>(); + if (!status) { + std::cerr << "ERROR - testDeflatten failed " << std::endl; + return 1; + } +} diff --git a/tmva/tmva/test/DNN/TestMinimization.h b/tmva/tmva/test/DNN/TestMinimization.h index 3e883ad75f427..53b8eb6d4e628 100644 --- a/tmva/tmva/test/DNN/TestMinimization.h +++ b/tmva/tmva/test/DNN/TestMinimization.h @@ -21,6 +21,7 @@ #include "TMatrix.h" #include "TMVA/DNN/Minimizers.h" #include "TMVA/DNN/Net.h" +#include "TRandom3.h" #include "Utility.h" using namespace TMVA::DNN; @@ -44,10 +45,12 @@ template TMatrixT XTrain(nSamples, nFeatures), YTrain(nSamples, 1), WTrain(nSamples, 1), XTest(batchSize, nFeatures), YTest(batchSize, 1), WTest(nSamples, 1), K(nFeatures, 1); + TRandom3 rng{7101}; + // Use random K to generate linear mapping. - randomMatrix(K); - randomMatrix(XTrain); - randomMatrix(XTest); + randomMatrix(K, 0., 1., rng); + randomMatrix(XTrain, 0., 1., rng); + randomMatrix(XTest, 0., 1., rng); YTrain.Mult(XTrain, K); YTest.Mult(XTest, K); @@ -55,6 +58,7 @@ template fillMatrix(WTest, 1.0); Net_t net(batchSize, nFeatures, ELossFunction::kMeanSquaredError); + Architecture::SetRandomSeed(7102); net.AddLayer(8, EActivationFunction::kIdentity); net.AddLayer(8, EActivationFunction::kIdentity); net.AddLayer(1, EActivationFunction::kIdentity); @@ -98,11 +102,13 @@ auto testMinimizationWeights() -> typename Architecture::Scalar_t Y1(nSamples, 1), Y2(nSamples, 1), YTrain(2 * nSamples, 1), W1(nSamples, 1), W2(nSamples, 1), W(2 * nSamples, 1), XTest(batchSize, nFeatures), YTest(batchSize, 1), WTest(batchSize, 1), K1(nFeatures, 1), K2(nFeatures, 1); + TRandom3 rng{7101}; + // Training data from two different linear mappings. - randomMatrix(K1); - randomMatrix(K2); - randomMatrix(X1); - randomMatrix(X2); + randomMatrix(K1, 0., 1., rng); + randomMatrix(K2, 0., 1., rng); + randomMatrix(X1, 0., 1., rng); + randomMatrix(X2, 0., 1., rng); Y1.Mult(X1, K1); Y2.Mult(X2, K2); XTrain.SetSub(0, 0, X1); @@ -116,11 +122,12 @@ auto testMinimizationWeights() -> typename Architecture::Scalar_t W.SetSub(nSamples, 0, W2); // Test data from only the first mapping; - randomMatrix(XTest); + randomMatrix(XTest, 0., 1., rng); YTest.Mult(XTest, K2); WTest = 1.0; Net_t net(batchSize, nFeatures, ELossFunction::kMeanSquaredError); + Architecture::SetRandomSeed(7102); net.AddLayer(8, EActivationFunction::kIdentity); net.AddLayer(8, EActivationFunction::kIdentity); net.AddLayer(1, EActivationFunction::kIdentity); @@ -160,24 +167,26 @@ template TMatrixT XTrain(nSamples, nFeatures), YTrain(nSamples, 1), WTrain(nSamples, 1), XTest(batchSize, nFeatures), YTest(batchSize, 1), WTest(nSamples, 1), W(nFeatures, 1); - randomMatrix(W); - randomMatrix(XTrain); - randomMatrix(XTest); + TRandom3 rng{7101}; + + randomMatrix(W, 0., 1., rng); + randomMatrix(XTrain, 0., 1., rng); + randomMatrix(XTest, 0., 1., rng); YTrain.Mult(XTrain, W); YTest.Mult(XTest, W); fillMatrix(WTrain, 1.0); fillMatrix(WTest, 1.0); - auto ur = [](Scalar_t /*x*/) { - TRandom rand(clock()); - return rand.Uniform(); + auto ur = [&rng](Scalar_t /*x*/) { + return rng.Uniform(); }; applyMatrix(WTrain, ur); applyMatrix(WTest, ur); Net_t net(batchSize, nFeatures, ELossFunction::kMeanSquaredError); + Architecture::SetRandomSeed(7102); net.AddLayer(8, EActivationFunction::kIdentity); net.AddLayer(8, EActivationFunction::kIdentity); net.AddLayer(1, EActivationFunction::kIdentity); diff --git a/tmva/tmva/test/DNN/Utility.h b/tmva/tmva/test/DNN/Utility.h index 1f19cdd386557..99d35ac008566 100644 --- a/tmva/tmva/test/DNN/Utility.h +++ b/tmva/tmva/test/DNN/Utility.h @@ -321,18 +321,15 @@ void fillMatrix(AMatrix &X, AReal x) /*! Fill matrix with random, Gaussian-distributed values. */ //______________________________________________________________________________ template -void randomMatrix(AMatrix &X, double mean = 0.0, double sigma = 1.0) +void randomMatrix(AMatrix &X, double mean = 0.0, double sigma = 1.0, + TRandom & rand = *gRandom) { - // use default ROOT generator - TRandom & rand = *gRandom; - size_t m = X.GetNrows(); size_t n = X.GetNcols(); for (size_t i = 0; i < m; ++i) for (size_t j = 0; j < n; ++j) X(i,j) = rand.Gaus(mean, sigma); - } /*! Fill matrix with random, uniform-distributed values in [-1, 1] */ diff --git a/tmva/tmva/test/TestRandomGenerator.cxx b/tmva/tmva/test/TestRandomGenerator.cxx index c8f0f50ee5fe0..02f941d7f26cb 100644 --- a/tmva/tmva/test/TestRandomGenerator.cxx +++ b/tmva/tmva/test/TestRandomGenerator.cxx @@ -10,6 +10,7 @@ #include "TMVA/Tools.h" // Stdlib +#include #include // External diff --git a/tmva/tmvagui/src/mvaeffs.cxx b/tmva/tmvagui/src/mvaeffs.cxx index a5f61274a4e2a..8e41f2bfae7f5 100644 --- a/tmva/tmvagui/src/mvaeffs.cxx +++ b/tmva/tmvagui/src/mvaeffs.cxx @@ -512,7 +512,16 @@ void TMVA::mvaeffs(TString dataset, TString fin , { TMVAGlob::Initialize( useTMVAStyle ); - StatDialogMVAEffs* gGui = new StatDialogMVAEffs(dataset,gClient->GetRoot(), 1000, 1000); + TGClient * graphicsClient = TGClient::Instance(); + if (graphicsClient == nullptr) { + // When including mvaeffs in a stand-alone macro, the graphics subsystem + // is not initialised and `TGClient::Instance` is a nullptr. + graphicsClient = new TGClient(); + } + + StatDialogMVAEffs* gGui = new StatDialogMVAEffs(dataset, + graphicsClient->GetRoot(), 1000, 1000); + TFile* file = TMVAGlob::OpenFile( fin ); gGui->ReadHistograms(file); diff --git a/tree/dataframe/inc/LinkDef.h b/tree/dataframe/inc/LinkDef.h index f12fc53286d34..be19222aac01e 100644 --- a/tree/dataframe/inc/LinkDef.h +++ b/tree/dataframe/inc/LinkDef.h @@ -22,6 +22,7 @@ #pragma link C++ class ROOT::Detail::RDF::RFilterBase-; #pragma link C++ class ROOT::Detail::RDF::RJittedFilter-; #pragma link C++ class ROOT::Detail::RDF::RCustomColumnBase-; +#pragma link C++ class ROOT::Detail::RDF::RJittedCustomColumn-; #pragma link C++ class ROOT::Internal::RDF::CountHelper-; #pragma link C++ class ROOT::Detail::RDF::RRangeBase-; #pragma link C++ class ROOT::Detail::RDF::RLoopManager-; @@ -35,6 +36,22 @@ #pragma link C++ class ROOT::RDF::RTrivialDS-; #pragma link C++ class ROOT::RDF::RRootDS-; #pragma link C++ class ROOT::RDF::RCsvDS-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue>-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue>-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue>-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue>-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue>-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue>-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue>-; +#pragma link C++ class ROOT::Internal::RDF::TColumnValue>-; #endif diff --git a/tree/dataframe/inc/ROOT/RDFActionHelpers.hxx b/tree/dataframe/inc/ROOT/RDFActionHelpers.hxx index fa8040978ce71..1c944d730169f 100644 --- a/tree/dataframe/inc/ROOT/RDFActionHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDFActionHelpers.hxx @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,7 @@ #include "ROOT/TBufferMerger.hxx" // for SnapshotHelper #include "ROOT/RCutFlowReport.hxx" #include "ROOT/RDFUtils.hxx" +#include "ROOT/RMakeUnique.hxx" #include "ROOT/RSnapshotOptions.hxx" #include "ROOT/TThreadedObject.hxx" #include "ROOT/TypeTraits.hxx" @@ -48,9 +50,18 @@ namespace Detail { namespace RDF { template -class RActionImpl { +class RActionImpl +{ public: - void InitSlot(TTreeReader *r, unsigned int slot) { static_cast(*this).InitTask(r, slot); } + // call Helper::FinalizeTask if present, do nothing otherwise + template + auto CallFinalizeTask(unsigned int slot) -> decltype(&T::FinalizeTask, void()) + { + static_cast(this)->FinalizeTask(slot); + } + + template + void CallFinalizeTask(unsigned int, Args...) {} }; } // namespace RDF @@ -61,11 +72,12 @@ namespace RDF { using namespace ROOT::TypeTraits; using namespace ROOT::VecOps; using namespace ROOT::RDF; +using namespace ROOT::Detail::RDF; using Hist_t = ::TH1D; template -class ForeachSlotHelper { +class ForeachSlotHelper : public RActionImpl> { F fCallable; public: @@ -74,7 +86,7 @@ public: ForeachSlotHelper(ForeachSlotHelper &&) = default; ForeachSlotHelper(const ForeachSlotHelper &) = delete; - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} template void Exec(unsigned int slot, Args &&... args) @@ -89,7 +101,7 @@ public: void Finalize() { /* noop */} }; -class CountHelper { +class CountHelper : public RActionImpl { const std::shared_ptr fResultCount; std::vector fCounts; @@ -98,7 +110,7 @@ public: CountHelper(const std::shared_ptr &resultCount, const unsigned int nSlots); CountHelper(CountHelper &&) = default; CountHelper(const CountHelper &) = delete; - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot); void Initialize() { /* noop */} void Finalize(); @@ -106,7 +118,7 @@ public: }; template -class ReportHelper { +class ReportHelper : public RActionImpl> { const std::shared_ptr fReport; // Here we have a weak pointer since we need to keep track of the validity // of the proxied node. It can happen that the user does not trigger the @@ -121,7 +133,7 @@ public: : fReport(report), fProxiedWPtr(pp), fReturnEmptyReport(emptyRep){}; ReportHelper(ReportHelper &&) = default; ReportHelper(const ReportHelper &) = delete; - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int /* slot */) {} void Initialize() { /* noop */} void Finalize() @@ -132,7 +144,7 @@ public: } }; -class FillHelper { +class FillHelper : public RActionImpl { // this sets a total initial size of 16 MB for the buffers (can increase) static constexpr unsigned int fgTotalBufSize = 2097152; using BufEl_t = double; @@ -154,7 +166,7 @@ public: FillHelper(const std::shared_ptr &h, const unsigned int nSlots); FillHelper(FillHelper &&) = default; FillHelper(const FillHelper &) = delete; - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot, double v); void Exec(unsigned int slot, double v, double w); @@ -204,7 +216,7 @@ extern template void FillHelper::Exec(unsigned int, const std::vector &, const std::vector &); template -class FillTOHelper { +class FillTOHelper : public RActionImpl> { std::unique_ptr> fTo; public: @@ -220,7 +232,7 @@ public: } } - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot, double x0) // 1D histos { @@ -320,7 +332,7 @@ public: // Case 1.: The column is not an RVec, the collection is not a vector // No optimisations, no transformations: just copies. template -class TakeHelper { +class TakeHelper : public RActionImpl> { std::vector> fColls; public: @@ -334,7 +346,7 @@ public: TakeHelper(TakeHelper &&) = default; TakeHelper(const TakeHelper &) = delete; - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot, T &v) { fColls[slot]->emplace_back(v); } @@ -357,7 +369,7 @@ public: // Case 2.: The column is not an RVec, the collection is a vector // Optimisations, no transformations: just copies. template -class TakeHelper> { +class TakeHelper> : public RActionImpl>> { std::vector>> fColls; public: @@ -374,7 +386,7 @@ public: TakeHelper(TakeHelper &&) = default; TakeHelper(const TakeHelper &) = delete; - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot, T &v) { fColls[slot]->emplace_back(v); } @@ -400,7 +412,7 @@ public: // Case 3.: The column is a RVec, the collection is not a vector // No optimisations, transformations from RVecs to vectors template -class TakeHelper, COLL> { +class TakeHelper, COLL> : public RActionImpl, COLL>> { std::vector> fColls; public: @@ -414,7 +426,7 @@ public: TakeHelper(TakeHelper &&) = default; TakeHelper(const TakeHelper &) = delete; - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot, RVec av) { fColls[slot]->emplace_back(av.begin(), av.end()); } @@ -435,7 +447,8 @@ public: // Case 4.: The column is an RVec, the collection is a vector // Optimisations, transformations from RVecs to vectors template -class TakeHelper, std::vector> { + class TakeHelper, std::vector> + : public RActionImpl, std::vector>> { std::vector>>> fColls; public: @@ -452,7 +465,7 @@ public: TakeHelper(TakeHelper &&) = default; TakeHelper(const TakeHelper &) = delete; - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot, RVec av) { fColls[slot]->emplace_back(av.begin(), av.end()); } @@ -474,7 +487,7 @@ public: }; template -class MinHelper { +class MinHelper : public RActionImpl> { const std::shared_ptr fResultMin; std::vector fMins; @@ -487,7 +500,7 @@ public: void Exec(unsigned int slot, ResultType v) { fMins[slot] = std::min(v, fMins[slot]); } - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} template ::value, int>::type = 0> void Exec(unsigned int slot, const T &vs) @@ -516,7 +529,7 @@ public: // extern template void MinHelper::Exec(unsigned int, const std::vector &); template -class MaxHelper { +class MaxHelper : public RActionImpl> { const std::shared_ptr fResultMax; std::vector fMaxs; @@ -528,7 +541,7 @@ public: { } - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot, ResultType v) { fMaxs[slot] = std::max(v, fMaxs[slot]); } template ::value, int>::type = 0> @@ -559,7 +572,7 @@ public: // extern template void MaxHelper::Exec(unsigned int, const std::vector &); template -class SumHelper { +class SumHelper : public RActionImpl> { const std::shared_ptr fResultSum; std::vector fSums; @@ -571,7 +584,7 @@ public: { } - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot, ResultType v) { fSums[slot] += v; } template ::value, int>::type = 0> @@ -592,7 +605,7 @@ public: ResultType &PartialUpdate(unsigned int slot) { return fSums[slot]; } }; -class MeanHelper { +class MeanHelper : public RActionImpl { const std::shared_ptr fResultMean; std::vector fCounts; std::vector fSums; @@ -602,7 +615,7 @@ public: MeanHelper(const std::shared_ptr &meanVPtr, const unsigned int nSlots); MeanHelper(MeanHelper &&) = default; MeanHelper(const MeanHelper &) = delete; - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot, double v); template ::value, int>::type = 0> @@ -627,6 +640,43 @@ extern template void MeanHelper::Exec(unsigned int, const std::vector &); extern template void MeanHelper::Exec(unsigned int, const std::vector &); extern template void MeanHelper::Exec(unsigned int, const std::vector &); +class StdDevHelper : public RActionImpl { + // Number of subsets of data + const unsigned int fNSlots; + const std::shared_ptr fResultStdDev; + // Number of element for each slot + std::vector fCounts; + // Mean of each slot + std::vector fMeans; + // Squared distance from the mean + std::vector fDistancesfromMean; + +public: + StdDevHelper(const std::shared_ptr &meanVPtr, const unsigned int nSlots); + StdDevHelper(StdDevHelper &&) = default; + StdDevHelper(const StdDevHelper &) = delete; + void InitTask(TTreeReader *, unsigned int) {} + void Exec(unsigned int slot, double v); + + template ::value, int>::type = 0> + void Exec(unsigned int slot, const T &vs) + { + for (auto &&v : vs) { + Exec(slot, v); + } + } + + void Initialize() { /* noop */} + + void Finalize(); +}; + +extern template void StdDevHelper::Exec(unsigned int, const std::vector &); +extern template void StdDevHelper::Exec(unsigned int, const std::vector &); +extern template void StdDevHelper::Exec(unsigned int, const std::vector &); +extern template void StdDevHelper::Exec(unsigned int, const std::vector &); +extern template void StdDevHelper::Exec(unsigned int, const std::vector &); + /// Helper function for SnapshotHelper and SnapshotHelperMT. It creates new branches for the output TTree of a Snapshot. template void SetBranchesHelper(TTree * /*inputTree*/, TTree &outputTree, const std::string & /*validName*/, @@ -669,7 +719,7 @@ void SetBranchesHelper(TTree *inputTree, TTree &outputTree, const std::string &v /// Helper object for a single-thread Snapshot action template -class SnapshotHelper { +class SnapshotHelper : public RActionImpl> { const std::string fFileName; const std::string fDirName; const std::string fTreeName; @@ -679,7 +729,7 @@ class SnapshotHelper { bool fIsFirstEvent{true}; const ColumnNames_t fInputBranchNames; // This contains the resolved aliases const ColumnNames_t fOutputBranchNames; - TTree *fInputTree = nullptr; // Current input tree. Set at initialization time (`InitSlot`) + TTree *fInputTree = nullptr; // Current input tree. Set at initialization time (`InitTask`) public: SnapshotHelper(std::string_view filename, std::string_view dirname, std::string_view treename, @@ -692,7 +742,7 @@ public: SnapshotHelper(const SnapshotHelper &) = delete; SnapshotHelper(SnapshotHelper &&) = default; - void InitSlot(TTreeReader *r, unsigned int /* slot */) + void InitTask(TTreeReader *r, unsigned int /* slot */) { if (!r) // empty source, nothing to do return; @@ -741,18 +791,23 @@ public: void Finalize() { - ::TDirectory::TContext ctxt(fOutputFile->GetDirectory(fDirName.c_str())); - fOutputTree->Write(); + if (fOutputFile && fOutputTree) { + ::TDirectory::TContext ctxt(fOutputFile->GetDirectory(fDirName.c_str())); + fOutputTree->Write(); + } else { + Warning("Snapshot", "A lazy Snapshot action was booked but never triggered."); + } + } }; /// Helper object for a multi-thread Snapshot action template -class SnapshotHelperMT { +class SnapshotHelperMT : public RActionImpl> { const unsigned int fNSlots; std::unique_ptr fMerger; // must use a ptr because TBufferMerger is not movable std::vector> fOutputFiles; - std::vector fOutputTrees; // ROOT will own/manage these TTrees, must not delete + std::vector>> fOutputTrees; std::vector fIsFirstEvent; // vector is evil const std::string fFileName; // name of the output file name const std::string fDirName; // name of TFile subdirectory in which output must be written (possibly empty) @@ -760,30 +815,27 @@ class SnapshotHelperMT { const RSnapshotOptions fOptions; // struct holding options to pass down to TFile and TTree in this action const ColumnNames_t fInputBranchNames; // This contains the resolved aliases const ColumnNames_t fOutputBranchNames; - std::vector fInputTrees; // Current input trees. Set at initialization time (`InitSlot`) + std::vector fInputTrees; // Current input trees. Set at initialization time (`InitTask`) public: using ColumnTypes_t = TypeList; SnapshotHelperMT(const unsigned int nSlots, std::string_view filename, std::string_view dirname, std::string_view treename, const ColumnNames_t &vbnames, const ColumnNames_t &bnames, const RSnapshotOptions &options) - : fNSlots(nSlots), fOutputFiles(fNSlots), fOutputTrees(fNSlots, nullptr), fIsFirstEvent(fNSlots, 1), - fFileName(filename), fDirName(dirname), fTreeName(treename), fOptions(options), fInputBranchNames(vbnames), + : fNSlots(nSlots), fOutputFiles(fNSlots), fOutputTrees(fNSlots), fIsFirstEvent(fNSlots, 1), fFileName(filename), + fDirName(dirname), fTreeName(treename), fOptions(options), fInputBranchNames(vbnames), fOutputBranchNames(ReplaceDotWithUnderscore(bnames)), fInputTrees(fNSlots) { } SnapshotHelperMT(const SnapshotHelperMT &) = delete; SnapshotHelperMT(SnapshotHelperMT &&) = default; - void InitSlot(TTreeReader *r, unsigned int slot) + void InitTask(TTreeReader *r, unsigned int slot) { ::TDirectory::TContext c; // do not let tasks change the thread-local gDirectory - if (!fOutputTrees[slot]) { + if (!fOutputFiles[slot]) { // first time this thread executes something, let's create a TBufferMerger output directory fOutputFiles[slot] = fMerger->GetFile(); - } else { - // this thread is now re-executing the task, let's flush the current contents of the TBufferMergerFile - fOutputFiles[slot]->Write(); } TDirectory *treeDirectory = fOutputFiles[slot].get(); if (!fDirName.empty()) { @@ -791,20 +843,32 @@ public: } // re-create output tree as we need to create its branches again, with new input variables // TODO we could instead create the output tree and its branches, change addresses of input variables in each task - fOutputTrees[slot] = new TTree(fTreeName.c_str(), fTreeName.c_str(), fOptions.fSplitLevel, /*dir=*/treeDirectory); - fOutputTrees[slot]->ResetBit(kMustCleanup); // do not mingle with the thread-unsafe gListOfCleanups + fOutputTrees[slot].emplace( + std::make_unique(fTreeName.c_str(), fTreeName.c_str(), fOptions.fSplitLevel, /*dir=*/treeDirectory)); if (fOptions.fAutoFlush) - fOutputTrees[slot]->SetAutoFlush(fOptions.fAutoFlush); + fOutputTrees[slot].top()->SetAutoFlush(fOptions.fAutoFlush); if (r) { // not an empty-source RDF fInputTrees[slot] = r->GetTree(); // AddClone guarantees that if the input file changes the branches of the output tree are updated with the new - // addresses of the branch values - fInputTrees[slot]->AddClone(fOutputTrees[slot]); + // addresses of the branch values. We need this in case of friend trees with different cluster granularity + // than the main tree. + // FIXME: AddClone might result in many many (safe) warnings printed by TTree::CopyAddresses, see ROOT-9487. + const auto friendsListPtr = fInputTrees[slot]->GetListOfFriends(); + if (friendsListPtr && friendsListPtr->GetEntries() > 0) + fInputTrees[slot]->AddClone(fOutputTrees[slot].top().get()); } fIsFirstEvent[slot] = 1; // reset first event flag for this slot } + void FinalizeTask(unsigned int slot) + { + if (fOutputTrees[slot].top()->GetEntries() > 0) + fOutputFiles[slot]->Write(); + // clear now to avoid concurrent destruction of output trees and input tree (which has them listed as fClones) + fOutputTrees[slot].pop(); + } + void Exec(unsigned int slot, BranchTypes &... values) { if (fIsFirstEvent[slot]) { @@ -812,9 +876,9 @@ public: SetBranches(slot, values..., ind_t()); fIsFirstEvent[slot] = 0; } - fOutputTrees[slot]->Fill(); - auto entries = fOutputTrees[slot]->GetEntries(); - auto autoFlush = fOutputTrees[slot]->GetAutoFlush(); + fOutputTrees[slot].top()->Fill(); + auto entries = fOutputTrees[slot].top()->GetEntries(); + auto autoFlush = fOutputTrees[slot].top()->GetAutoFlush(); if ((autoFlush > 0) && (entries % autoFlush == 0)) fOutputFiles[slot]->Write(); } @@ -823,7 +887,7 @@ public: void SetBranches(unsigned int slot, BranchTypes &... values, std::index_sequence /*dummy*/) { // hack to call TTree::Branch on all variadic template arguments - int expander[] = {(SetBranchesHelper(fInputTrees[slot], *fOutputTrees[slot], fInputBranchNames[S], + int expander[] = {(SetBranchesHelper(fInputTrees[slot], *fOutputTrees[slot].top(), fInputBranchNames[S], fOutputBranchNames[S], &values), 0)..., 0}; @@ -839,16 +903,24 @@ public: void Finalize() { + auto fileWritten = false; for (auto &file : fOutputFiles) { - if (file) + if (file) { file->Write(); + fileWritten = true; + } + } + + if (!fileWritten) { + Warning("Snapshot", "A lazy Snapshot action was booked but never triggered."); } } + }; template ::value> -class AggregateHelper { +class AggregateHelper : public RActionImpl> { Acc fAggregate; Merge fMerge; const std::shared_ptr fResult; @@ -863,7 +935,7 @@ public: AggregateHelper(AggregateHelper &&) = default; AggregateHelper(const AggregateHelper &) = delete; - void InitSlot(TTreeReader *, unsigned int) {} + void InitTask(TTreeReader *, unsigned int) {} template ::type = 0> void Exec(unsigned int slot, const T &value) diff --git a/tree/dataframe/inc/ROOT/RDFInterface.hxx b/tree/dataframe/inc/ROOT/RDFInterface.hxx index 137334e6c94aa..3e85a0163f7bf 100644 --- a/tree/dataframe/inc/ROOT/RDFInterface.hxx +++ b/tree/dataframe/inc/ROOT/RDFInterface.hxx @@ -58,31 +58,16 @@ class TH2D; class TH3D; class TProfile2D; class TProfile; -namespace ROOT { -namespace Detail { -namespace RDF { -namespace TCCHelperTypes { -struct TNothing; -struct TSlot; -struct TSlotAndEntry; -} // namespace TCCHelperTypes -} // namespace RDF -} // namespace Detail -} // namespace ROOT +// Windows requires a forward decl of printValue to accept it as a valid friend function in RInterface namespace ROOT { - -// forward declarations class RDataFrame; - -} // namespace ROOT - +} namespace cling { -std::string printValue(ROOT::RDataFrame *tdf); // For a nice printing at the prompt +std::string printValue(ROOT::RDataFrame *tdf); } namespace ROOT { - namespace RDF { namespace RDFDetail = ROOT::Detail::RDF; namespace RDFInternal = ROOT::Internal::RDF; @@ -111,6 +96,7 @@ class RInterface { ColumnNames_t fValidCustomColumns; ///< Names of columns `Define`d for this branch of the functional graph. /// Non-owning pointer to a data-source object. Null if no data-source. RLoopManager has ownership of the object. RDataSource *const fDataSource = nullptr; + std::shared_ptr fBranchNames; ///< Cache of the chain columns names public: //////////////////////////////////////////////////////////////////////////// @@ -129,8 +115,7 @@ public: /// \brief Only enabled when building a RInterface template ::value, int>::type = 0> RInterface(const std::shared_ptr &proxied) - : fProxiedPtr(proxied), fImplWeakPtr(proxied->GetSharedPtr()), fValidCustomColumns(), - fDataSource(proxied->GetDataSource()) + : fProxiedPtr(proxied), fImplWeakPtr(proxied), fValidCustomColumns(), fDataSource(proxied->GetDataSource()) { AddDefaultColumns(); } @@ -162,15 +147,14 @@ public: auto loopManager = GetLoopManager(); using ColTypes_t = typename TTraits::CallableTraits::arg_types; constexpr auto nColumns = ColTypes_t::list_size; - const auto validColumnNames = - RDFInternal::GetValidatedColumnNames(*loopManager, nColumns, columns, fValidCustomColumns, fDataSource); + const auto validColumnNames = GetValidatedColumnNames(nColumns, columns); if (fDataSource) RDFInternal::DefineDataSourceColumns(validColumnNames, *loopManager, *fDataSource, std::make_index_sequence(), ColTypes_t()); using F_t = RDFDetail::RFilter; auto FilterPtr = std::make_shared(std::move(f), validColumnNames, *fProxiedPtr, name); loopManager->Book(FilterPtr); - return RInterface(FilterPtr, fImplWeakPtr, fValidCustomColumns, fDataSource); + return RInterface(FilterPtr, fImplWeakPtr, fValidCustomColumns, fBranchNames, fDataSource); } //////////////////////////////////////////////////////////////////////////// @@ -221,14 +205,15 @@ public: auto upcastNode = RDFInternal::UpcastNode(fProxiedPtr); RInterface upcastInterface(upcastNode, fImplWeakPtr, - fValidCustomColumns, fDataSource); + fValidCustomColumns, fBranchNames, fDataSource); const auto prevNodeTypeName = upcastInterface.GetNodeTypeName(); const auto jittedFilter = std::make_shared(df.get(), name); RDFInternal::BookFilterJit(jittedFilter.get(), upcastNode.get(), prevNodeTypeName, name, expression, aliasMap, branches, customColumns, tree, fDataSource, df->GetID()); df->Book(jittedFilter); - return RInterface(jittedFilter, fImplWeakPtr, fValidCustomColumns, fDataSource); + return RInterface(jittedFilter, fImplWeakPtr, fValidCustomColumns, + fBranchNames, fDataSource); } // clang-format off @@ -254,7 +239,7 @@ public: template ::value, int>::type = 0> RInterface Define(std::string_view name, F expression, const ColumnNames_t &columns = {}) { - return DefineImpl(name, std::move(expression), columns); + return DefineImpl(name, std::move(expression), columns); } // clang-format on @@ -282,7 +267,7 @@ public: template RInterface DefineSlot(std::string_view name, F expression, const ColumnNames_t &columns = {}) { - return DefineImpl(name, std::move(expression), columns); + return DefineImpl(name, std::move(expression), columns); } // clang-format on @@ -311,7 +296,7 @@ public: template RInterface DefineSlotEntry(std::string_view name, F expression, const ColumnNames_t &columns = {}) { - return DefineImpl(name, std::move(expression), columns); + return DefineImpl(name, std::move(expression), columns); } // clang-format on @@ -334,7 +319,8 @@ public: RDFInternal::BookDefineJit(name, expression, *lm, fDataSource); - RInterface newInterface(fProxiedPtr, fImplWeakPtr, fValidCustomColumns, fDataSource); + RInterface newInterface(fProxiedPtr, fImplWeakPtr, fValidCustomColumns, + fBranchNames, fDataSource); newInterface.fValidCustomColumns.emplace_back(name); return newInterface; } @@ -357,11 +343,10 @@ public: // If the alias name is a column name, there is a problem RDFInternal::CheckCustomColumn(alias, loopManager->GetTree(), fValidCustomColumns, dsColumnNames); - const auto validColumnName = RDFInternal::GetValidatedColumnNames(*loopManager, 1, {std::string(columnName)}, - fValidCustomColumns, fDataSource)[0]; + const auto validColumnName = GetValidatedColumnNames(1, {std::string(columnName)})[0]; loopManager->AddColumnAlias(std::string(alias), validColumnName); - RInterface newInterface(fProxiedPtr, fImplWeakPtr, fValidCustomColumns, fDataSource); + RInterface newInterface(fProxiedPtr, fImplWeakPtr, fValidCustomColumns, fBranchNames, fDataSource); newInterface.fValidCustomColumns.emplace_back(alias); return newInterface; } @@ -410,7 +395,7 @@ public: std::stringstream snapCall; auto upcastNode = RDFInternal::UpcastNode(fProxiedPtr); RInterface> upcastInterface(fProxiedPtr, fImplWeakPtr, - fValidCustomColumns, fDataSource); + fValidCustomColumns, fBranchNames, fDataSource); // build a string equivalent to // "(RInterface*)(this)->Snapshot(treename,filename,*(ColumnNames_t*)(&columnList), options)" // on Windows, to prefix the hexadecimal value of a pointer with '0x', @@ -419,10 +404,11 @@ public: << std::showbase << (size_t)&upcastInterface << ")->Snapshot<"; const auto &customCols = df->GetCustomColumnNames(); - const auto dontCovertVector = false; - for (auto &c : columnList) { + const auto dontConvertVector = false; + const auto validCols = GetValidatedColumnNames(columnList.size(), columnList); + for (auto &c : validCols) { const auto isCustom = std::find(customCols.begin(), customCols.end(), c) != customCols.end(); - snapCall << RDFInternal::ColumnName2ColumnTypeName(c, nsID, tree, fDataSource, isCustom, dontCovertVector) + snapCall << RDFInternal::ColumnName2ColumnTypeName(c, nsID, tree, fDataSource, isCustom, dontConvertVector) << ", "; }; if (!columnList.empty()) @@ -517,7 +503,9 @@ public: std::stringstream snapCall; auto upcastNode = RDFInternal::UpcastNode(fProxiedPtr); RInterface> upcastInterface(fProxiedPtr, fImplWeakPtr, - fValidCustomColumns, fDataSource); + fValidCustomColumns, + fBranchNames, + fDataSource); // build a string equivalent to // "(RInterface*)(this)->Cache(*(ColumnNames_t*)(&columnList))" // on Windows, to prefix the hexadecimal value of a pointer with '0x', @@ -578,7 +566,8 @@ public: using Range_t = RDFDetail::RRange; auto RangePtr = std::make_shared(begin, end, stride, *fProxiedPtr); df->Book(RangePtr); - RInterface> tdf_r(RangePtr, fImplWeakPtr, fValidCustomColumns, fDataSource); + RInterface> tdf_r(RangePtr, fImplWeakPtr, fValidCustomColumns, + fBranchNames, fDataSource); return tdf_r; } @@ -634,8 +623,7 @@ public: auto loopManager = GetLoopManager(); using ColTypes_t = TypeTraits::RemoveFirstParameter_t::arg_types>; constexpr auto nColumns = ColTypes_t::list_size; - const auto validColumnNames = - RDFInternal::GetValidatedColumnNames(*loopManager, nColumns, columns, fValidCustomColumns, fDataSource); + const auto validColumnNames = GetValidatedColumnNames(nColumns, columns); if (fDataSource) RDFInternal::DefineDataSourceColumns(validColumnNames, *loopManager, *fDataSource, std::make_index_sequence(), ColTypes_t()); @@ -725,8 +713,7 @@ public: { auto loopManager = GetLoopManager(); const auto columns = column.empty() ? ColumnNames_t() : ColumnNames_t({std::string(column)}); - const auto validColumnNames = - RDFInternal::GetValidatedColumnNames(*loopManager, 1, columns, fValidCustomColumns, fDataSource); + const auto validColumnNames = GetValidatedColumnNames(1, columns); if (fDataSource) RDFInternal::DefineDataSourceColumns(validColumnNames, *loopManager, *fDataSource, std::make_index_sequence<1>(), TTraits::TypeList()); @@ -766,7 +753,7 @@ public: if (h->GetXaxis()->GetXmax() == h->GetXaxis()->GetXmin()) RDFInternal::HistoUtils<::TH1D>::SetCanExtendAllAxes(*h); - return CreateAction(userColumns, h); + return CreateAction(userColumns, h); } template @@ -796,7 +783,7 @@ public: ROOT::Internal::RDF::RIgnoreErrorLevelRAII iel(kError); h = model.GetHistogram(); } - return CreateAction(userColumns, h); + return CreateAction(userColumns, h); } //////////////////////////////////////////////////////////////////////////// @@ -858,7 +845,7 @@ public: const auto userColumns = RDFInternal::AtLeastOneEmptyString(columnViews) ? ColumnNames_t() : ColumnNames_t(columnViews.begin(), columnViews.end()); - return CreateAction(userColumns, h); + return CreateAction(userColumns, h); } //////////////////////////////////////////////////////////////////////////// @@ -891,7 +878,7 @@ public: const auto userColumns = RDFInternal::AtLeastOneEmptyString(columnViews) ? ColumnNames_t() : ColumnNames_t(columnViews.begin(), columnViews.end()); - return CreateAction(userColumns, h); + return CreateAction(userColumns, h); } template @@ -930,7 +917,7 @@ public: const auto userColumns = RDFInternal::AtLeastOneEmptyString(columnViews) ? ColumnNames_t() : ColumnNames_t(columnViews.begin(), columnViews.end()); - return CreateAction(userColumns, h); + return CreateAction(userColumns, h); } //////////////////////////////////////////////////////////////////////////// @@ -965,7 +952,7 @@ public: const auto userColumns = RDFInternal::AtLeastOneEmptyString(columnViews) ? ColumnNames_t() : ColumnNames_t(columnViews.begin(), columnViews.end()); - return CreateAction(userColumns, h); + return CreateAction(userColumns, h); } template @@ -1002,7 +989,7 @@ public: const auto userColumns = RDFInternal::AtLeastOneEmptyString(columnViews) ? ColumnNames_t() : ColumnNames_t(columnViews.begin(), columnViews.end()); - return CreateAction(userColumns, h); + return CreateAction(userColumns, h); } //////////////////////////////////////////////////////////////////////////// @@ -1036,7 +1023,7 @@ public: const auto userColumns = RDFInternal::AtLeastOneEmptyString(columnViews) ? ColumnNames_t() : ColumnNames_t(columnViews.begin(), columnViews.end()); - return CreateAction(userColumns, h); + return CreateAction(userColumns, h); } template @@ -1076,7 +1063,7 @@ public: const auto userColumns = RDFInternal::AtLeastOneEmptyString(columnViews) ? ColumnNames_t() : ColumnNames_t(columnViews.begin(), columnViews.end()); - return CreateAction(userColumns, h); + return CreateAction(userColumns, h); } //////////////////////////////////////////////////////////////////////////// @@ -1112,7 +1099,7 @@ public: const auto userColumns = RDFInternal::AtLeastOneEmptyString(columnViews) ? ColumnNames_t() : ColumnNames_t(columnViews.begin(), columnViews.end()); - return CreateAction(userColumns, h); + return CreateAction(userColumns, h); } template @@ -1144,7 +1131,7 @@ public: if (!RDFInternal::HistoUtils::HasAxisLimits(*h)) { throw std::runtime_error("The absence of axes limits is not supported yet."); } - return CreateAction(columnList, h); + return CreateAction(columnList, h); } //////////////////////////////////////////////////////////////////////////// @@ -1165,7 +1152,7 @@ public: if (!RDFInternal::HistoUtils::HasAxisLimits(*h)) { throw std::runtime_error("The absence of axes limits is not supported yet."); } - return CreateAction(bl, h, bl.size()); + return CreateAction(bl, h, bl.size()); } //////////////////////////////////////////////////////////////////////////// @@ -1185,7 +1172,7 @@ public: const auto userColumns = columnName.empty() ? ColumnNames_t() : ColumnNames_t({std::string(columnName)}); using RetType_t = RDFDetail::MinReturnType_t; auto minV = std::make_shared(std::numeric_limits::max()); - return CreateAction(userColumns, minV); + return CreateAction(userColumns, minV); } //////////////////////////////////////////////////////////////////////////// @@ -1205,7 +1192,7 @@ public: const auto userColumns = columnName.empty() ? ColumnNames_t() : ColumnNames_t({std::string(columnName)}); using RetType_t = RDFDetail::MaxReturnType_t; auto maxV = std::make_shared(std::numeric_limits::lowest()); - return CreateAction(userColumns, maxV); + return CreateAction(userColumns, maxV); } //////////////////////////////////////////////////////////////////////////// @@ -1223,7 +1210,25 @@ public: { const auto userColumns = columnName.empty() ? ColumnNames_t() : ColumnNames_t({std::string(columnName)}); auto meanV = std::make_shared(0); - return CreateAction(userColumns, meanV); + return CreateAction(userColumns, meanV); + } + + //////////////////////////////////////////////////////////////////////////// + /// \brief Return the unbiased standard deviation of processed column values (*lazy action*) + /// \tparam T The type of the branch/column. + /// \param[in] columnName The name of the branch/column to be treated. + /// + /// If T is not specified, RDataFrame will infer it from the data and just-in-time compile the correct + /// template specialization of this method. + /// + /// This action is *lazy*: upon invocation of this method the calculation is + /// booked but not executed. See RResultPtr documentation. + template + RResultPtr StdDev(std::string_view columnName = "") + { + const auto userColumns = columnName.empty() ? ColumnNames_t() : ColumnNames_t({std::string(columnName)}); + auto stdDeviationV = std::make_shared(0); + return CreateAction(userColumns, stdDeviationV); } // clang-format off @@ -1246,7 +1251,7 @@ public: { const auto userColumns = columnName.empty() ? ColumnNames_t() : ColumnNames_t({std::string(columnName)}); auto sumV = std::make_shared>(initValue); - return CreateAction(userColumns, sumV); + return CreateAction(userColumns, sumV); } // clang-format on @@ -1352,8 +1357,7 @@ public: auto loopManager = GetLoopManager(); const auto columns = columnName.empty() ? ColumnNames_t() : ColumnNames_t({std::string(columnName)}); constexpr auto nColumns = ArgTypes::list_size; - const auto validColumnNames = - RDFInternal::GetValidatedColumnNames(*loopManager, 1, columns, fValidCustomColumns, fDataSource); + const auto validColumnNames = GetValidatedColumnNames(1, columns); if (fDataSource) RDFInternal::DefineDataSourceColumns(validColumnNames, *loopManager, *fDataSource, std::make_index_sequence(), ArgTypes()); @@ -1426,6 +1430,8 @@ public: template RResultPtr Book(Helper &&h, const ColumnNames_t &columns = {}) { + RDFInternal::CheckTypesAndPars(sizeof...(ColumnTypes), columns.size()); + // TODO add more static sanity checks on Helper using AH = RDFDetail::RActionImpl; static_assert(std::is_base_of::value && std::is_convertible::value, @@ -1441,20 +1447,19 @@ public: private: void AddDefaultColumns() { - auto lm = GetLoopManager(); ColumnNames_t validColNames = {}; // Entry number column const auto entryColName = "tdfentry_"; auto entryColGen = [](unsigned int, ULong64_t entry) { return entry; }; - DefineImpl(entryColName, std::move(entryColGen), - {}); + DefineImpl(entryColName, + std::move(entryColGen), {}); fValidCustomColumns.emplace_back(entryColName); // Slot number column const auto slotColName = "tdfslot_"; auto slotColGen = [](unsigned int slot) { return slot; }; - DefineImpl(slotColName, std::move(slotColGen), {}); + DefineImpl(slotColName, std::move(slotColGen), {}); fValidCustomColumns.emplace_back(slotColName); } @@ -1523,48 +1528,46 @@ private: inline static std::string GetNodeTypeName(); // Type was specified by the user, no need to infer it - template ::value, int>::type = 0> RResultPtr CreateAction(const ColumnNames_t &columns, const std::shared_ptr &r) { auto lm = GetLoopManager(); constexpr auto nColumns = sizeof...(BranchTypes); - const auto selectedCols = - RDFInternal::GetValidatedColumnNames(*lm, nColumns, columns, fValidCustomColumns, fDataSource); + const auto selectedCols = GetValidatedColumnNames(nColumns, columns); if (fDataSource) RDFInternal::DefineDataSourceColumns(selectedCols, *lm, *fDataSource, std::make_index_sequence(), RDFInternal::TypeList()); const auto nSlots = lm->GetNSlots(); auto actionPtr = - RDFInternal::BuildAndBook(selectedCols, r, nSlots, *lm, *fProxiedPtr, (ActionType *)nullptr); + RDFInternal::BuildAndBook(selectedCols, r, nSlots, *lm, *fProxiedPtr, ActionTag{}); return MakeResultPtr(r, lm, actionPtr); } // User did not specify type, do type inference // This version of CreateAction has a `nColumns` optional argument. If present, the number of required columns for // this action is taken equal to nColumns, otherwise it is assumed to be sizeof...(BranchTypes) - template ::value, int>::type = 0> RResultPtr CreateAction(const ColumnNames_t &columns, const std::shared_ptr &r, const int nColumns = -1) { auto lm = GetLoopManager(); auto realNColumns = (nColumns > -1 ? nColumns : sizeof...(BranchTypes)); - const auto validColumnNames = - RDFInternal::GetValidatedColumnNames(*lm, realNColumns, columns, fValidCustomColumns, fDataSource); + const auto validColumnNames = GetValidatedColumnNames(realNColumns, columns); const unsigned int nSlots = lm->GetNSlots(); const auto &customColumns = lm->GetCustomColumnNames(); auto tree = lm->GetTree(); auto rOnHeap = RDFInternal::MakeSharedOnHeap(r); auto upcastNode = RDFInternal::UpcastNode(fProxiedPtr); RInterface> upcastInterface( - upcastNode, fImplWeakPtr, fValidCustomColumns, fDataSource); + upcastNode, fImplWeakPtr, fValidCustomColumns, fBranchNames, fDataSource); auto resultProxyAndActionPtrPtr = MakeResultPtr(r, lm); auto &resultProxy = resultProxyAndActionPtrPtr.first; auto actionPtrPtrOnHeap = RDFInternal::MakeSharedOnHeap(resultProxyAndActionPtrPtr.second); auto toJit = RDFInternal::JitBuildAndBook(validColumnNames, upcastInterface.GetNodeTypeName(), upcastNode.get(), - typeid(std::shared_ptr), typeid(ActionType), rOnHeap, tree, + typeid(std::shared_ptr), typeid(ActionTag), rOnHeap, tree, nSlots, customColumns, fDataSource, actionPtrPtrOnHeap, lm->GetID()); lm->ToJit(toJit); return resultProxy; @@ -1580,13 +1583,12 @@ private: using ArgTypes_t = typename TTraits::CallableTraits::arg_types; using ColTypesTmp_t = typename RDFInternal::RemoveFirstParameterIf< - std::is_same::value, ArgTypes_t>::type; + std::is_same::value, ArgTypes_t>::type; using ColTypes_t = typename RDFInternal::RemoveFirstTwoParametersIf< - std::is_same::value, ColTypesTmp_t>::type; + std::is_same::value, ColTypesTmp_t>::type; constexpr auto nColumns = ColTypes_t::list_size; - const auto validColumnNames = - RDFInternal::GetValidatedColumnNames(*loopManager, nColumns, columns, fValidCustomColumns, fDataSource); + const auto validColumnNames = GetValidatedColumnNames(nColumns, columns); if (fDataSource) RDFInternal::DefineDataSourceColumns(validColumnNames, *loopManager, *fDataSource, std::make_index_sequence(), ColTypes_t()); @@ -1605,7 +1607,7 @@ private: loopManager->Book(std::make_shared(name, std::move(expression), validColumnNames, loopManager.get())); loopManager->AddCustomColumnName(name); - RInterface newInterface(fProxiedPtr, fImplWeakPtr, fValidCustomColumns, fDataSource); + RInterface newInterface(fProxiedPtr, fImplWeakPtr, fValidCustomColumns, fBranchNames, fDataSource); newInterface.fValidCustomColumns.emplace_back(name); return newInterface; } @@ -1634,19 +1636,18 @@ private: /// since there are no copies, the address of the value passed by reference /// is the address pointing to the storage of the read/created object in/by /// the TTreeReaderValue/TemporaryBranch - template + template RResultPtr> SnapshotImpl(std::string_view treename, std::string_view filename, const ColumnNames_t &columnList, const RSnapshotOptions &options) { - RDFInternal::CheckSnapshot(sizeof...(BranchTypes), columnList.size()); + RDFInternal::CheckTypesAndPars(sizeof...(ColumnTypes), columnList.size()); auto lm = GetLoopManager(); - auto validCols = - RDFInternal::GetValidatedColumnNames(*lm, columnList.size(), columnList, fValidCustomColumns, fDataSource); + const auto validCols = GetValidatedColumnNames(columnList.size(), columnList); if (fDataSource) - RDFInternal::DefineDataSourceColumns(validCols, *lm, *fDataSource, std::index_sequence_for(), - TTraits::TypeList()); + RDFInternal::DefineDataSourceColumns(validCols, *lm, *fDataSource, std::index_sequence_for(), + TTraits::TypeList()); const std::string fullTreename(treename); // split name into directory and treename if needed @@ -1661,13 +1662,13 @@ private: std::shared_ptr actionPtr; if (!ROOT::IsImplicitMTEnabled()) { // single-thread snapshot - using Helper_t = RDFInternal::SnapshotHelper; - using Action_t = RDFInternal::RAction>; + using Helper_t = RDFInternal::SnapshotHelper; + using Action_t = RDFInternal::RAction>; actionPtr.reset(new Action_t(Helper_t(filename, dirname, treename, validCols, columnList, options), validCols, *fProxiedPtr)); } else { // multi-thread snapshot - using Helper_t = RDFInternal::SnapshotHelperMT; + using Helper_t = RDFInternal::SnapshotHelperMT; using Action_t = RDFInternal::RAction; actionPtr.reset( new Action_t(Helper_t(lm->GetNSlots(), filename, dirname, treename, validCols, columnList, options), @@ -1680,7 +1681,13 @@ private: ::TDirectory::TContext ctxt; // Now we mimic a constructor for the RDataFrame. We cannot invoke it here // since this would introduce a cyclic headers dependency. - auto snapshotRDF = std::make_shared>(std::make_shared(nullptr, validCols)); + + // Keep these two statements separated to work-around an ABI incompatibility + // between clang (and thus cling) and gcc in the way std::forward is handled. + // See https://sft.its.cern.ch/jira/browse/ROOT-9236 for more detail. + auto rlm_ptr = std::make_shared(nullptr, validCols); + auto snapshotRDF = std::make_shared>(rlm_ptr); + auto chain = std::make_shared(fullTreename.c_str()); chain->Add(std::string(filename).c_str()); snapshotRDF->fProxiedPtr->SetTree(chain); @@ -1706,7 +1713,7 @@ private: // We share bits and pieces with snapshot. De facto this is a snapshot // in memory! - RDFInternal::CheckSnapshot(sizeof...(BranchTypes), columnList.size()); + RDFInternal::CheckTypesAndPars(sizeof...(BranchTypes), columnList.size()); if (fDataSource) { auto lm = GetLoopManager(); RDFInternal::DefineDataSourceColumns(columnList, *lm, *fDataSource, s, TTraits::TypeList()); @@ -1735,12 +1742,29 @@ protected: } RInterface(const std::shared_ptr &proxied, const std::weak_ptr &impl, - const ColumnNames_t &validColumns, RDataSource *ds) - : fProxiedPtr(proxied), fImplWeakPtr(impl), fValidCustomColumns(validColumns), fDataSource(ds) + const ColumnNames_t &validColumns, const std::shared_ptr &datasetColumns, + RDataSource *ds) + : fProxiedPtr(proxied), fImplWeakPtr(impl), fValidCustomColumns(validColumns), + fDataSource(ds), fBranchNames(datasetColumns) { } const std::shared_ptr &GetProxiedPtr() const { return fProxiedPtr; } + + /// Prepare the call to the GetValidatedColumnNames routine, making sure that GetBranchNames, + /// which is expensive in terms of runtime, is called at most once. + ColumnNames_t GetValidatedColumnNames(const unsigned int nColumns, const ColumnNames_t &columns) + { + auto loopManager = GetLoopManager(); + auto tree = loopManager->GetTree(); + if (tree && !fBranchNames) { + fBranchNames = std::make_shared(RDFInternal::GetBranchNames(*tree)); + } + return RDFInternal::GetValidatedColumnNames(*loopManager, nColumns, columns, + (tree ? *fBranchNames : ColumnNames_t{}), + fValidCustomColumns, fDataSource); + } + }; template <> diff --git a/tree/dataframe/inc/ROOT/RDFInterfaceUtils.hxx b/tree/dataframe/inc/ROOT/RDFInterfaceUtils.hxx index d000871f55213..3be1da219e9c6 100644 --- a/tree/dataframe/inc/ROOT/RDFInterfaceUtils.hxx +++ b/tree/dataframe/inc/ROOT/RDFInterfaceUtils.hxx @@ -70,18 +70,18 @@ public: // clang-format off /// This namespace defines types to be used for tag dispatching in RInterface. -namespace ActionTypes { -// they cannot just be forward declared: we need concrete types for jitting and to use them with TClass::GetClass -struct Histo1D {}; -struct Histo2D {}; -struct Histo3D {}; -struct Profile1D {}; -struct Profile2D {}; -struct Min {}; -struct Max {}; -struct Sum {}; -struct Mean {}; -struct Fill {}; +namespace ActionTags { +struct Histo1D{}; +struct Histo2D{}; +struct Histo3D{}; +struct Profile1D{}; +struct Profile2D{}; +struct Min{}; +struct Max{}; +struct Sum{}; +struct Mean{}; +struct Fill{}; +struct StdDev{}; } // clang-format on @@ -115,9 +115,9 @@ struct HistoUtils { }; // Generic filling (covers Histo2D, Histo3D, Profile1D and Profile2D actions, with and without weights) -template +template RActionBase *BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr &h, - const unsigned int nSlots, RLoopManager &loopManager, PrevNodeType &prevNode, ActionType *) + const unsigned int nSlots, RLoopManager &loopManager, PrevNodeType &prevNode, ActionTag) { using Helper_t = FillTOHelper; using Action_t = RAction>; @@ -129,7 +129,7 @@ RActionBase *BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr RActionBase *BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h, const unsigned int nSlots, - RLoopManager &loopManager, PrevNodeType &prevNode, ActionTypes::Histo1D *) + RLoopManager &loopManager, PrevNodeType &prevNode, ActionTags::Histo1D) { auto hasAxisLimits = HistoUtils<::TH1D>::HasAxisLimits(*h); @@ -155,7 +155,7 @@ RActionBase *BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> template RActionBase * BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr &minV, const unsigned int nSlots, - RLoopManager &loopManager, PrevNodeType &prevNode, ActionTypes::Min *) + RLoopManager &loopManager, PrevNodeType &prevNode, ActionTags::Min) { using Helper_t = MinHelper; using Action_t = RAction>; @@ -168,7 +168,7 @@ BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr &m template RActionBase * BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr &maxV, const unsigned int nSlots, - RLoopManager &loopManager, PrevNodeType &prevNode, ActionTypes::Max *) + RLoopManager &loopManager, PrevNodeType &prevNode, ActionTags::Max) { using Helper_t = MaxHelper; using Action_t = RAction>; @@ -181,7 +181,7 @@ BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr &m template RActionBase * BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr &sumV, const unsigned int nSlots, - RLoopManager &loopManager, PrevNodeType &prevNode, ActionTypes::Sum *) + RLoopManager &loopManager, PrevNodeType &prevNode, ActionTags::Sum) { using Helper_t = SumHelper; using Action_t = RAction>; @@ -193,7 +193,7 @@ BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr &s // Mean action template RActionBase *BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr &meanV, const unsigned int nSlots, - RLoopManager &loopManager, PrevNodeType &prevNode, ActionTypes::Mean *) + RLoopManager &loopManager, PrevNodeType &prevNode, ActionTags::Mean) { using Helper_t = MeanHelper; using Action_t = RAction>; @@ -201,6 +201,19 @@ RActionBase *BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr loopManager.Book(action); return action.get(); } + +// Standard Deviation action +template +RActionBase *BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr &stdDeviationV, const unsigned int nSlots, + RLoopManager &loopManager, PrevNodeType &prevNode, ActionTags::StdDev) +{ + using Helper_t = StdDevHelper; + using Action_t = RAction>; + auto action = std::make_shared(Helper_t(stdDeviationV, nSlots), bl, prevNode); + loopManager.Book(action); + return action.get(); +} + /****** end BuildAndBook ******/ template @@ -250,7 +263,8 @@ std::shared_ptr UpcastNode(const std::shared_ptr ptr std::shared_ptr UpcastNode(const std::shared_ptr ptr); ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns, - const ColumnNames_t &validCustomColumns, RDataSource *ds); + const ColumnNames_t &datasetColumns, const ColumnNames_t &validCustomColumns, + RDataSource *ds); std::vector FindUndefinedDSColumns(const ColumnNames_t &requestedCols, const ColumnNames_t &definedDSCols); @@ -260,7 +274,7 @@ void DefineDSColumnHelper(std::string_view name, RLoopManager &lm, RDataSource & { auto readers = ds.GetColumnReaders(name); auto getValue = [readers](unsigned int slot) { return *readers[slot]; }; - using NewCol_t = RCustomColumn; + using NewCol_t = RCustomColumn; lm.Book(std::make_shared(name, std::move(getValue), ColumnNames_t{}, &lm, /*isDSColumn=*/true)); lm.AddCustomColumnName(name); lm.AddDataSourceColumn(name); @@ -302,9 +316,10 @@ void JitFilterHelper(F &&f, const ColumnNames_t &cols, std::string_view name, RJ } template -void JitDefineHelper(F &&f, const ColumnNames_t &cols, std::string_view name, RLoopManager *lm) +void JitDefineHelper(F &&f, const ColumnNames_t &cols, std::string_view name, RLoopManager *lm, + RJittedCustomColumn &jittedCustomCol) { - using NewCol_t = RCustomColumn; + using NewCol_t = RCustomColumn; using ColTypes_t = typename TTraits::CallableTraits::arg_types; constexpr auto nColumns = ColTypes_t::list_size; @@ -312,11 +327,11 @@ void JitDefineHelper(F &&f, const ColumnNames_t &cols, std::string_view name, RL if (ds) RDFInternal::DefineDataSourceColumns(cols, *lm, *ds, std::make_index_sequence(), ColTypes_t()); - lm->Book(std::make_shared(name, std::move(f), cols, lm)); + jittedCustomCol.SetCustomColumn(std::make_unique(name, std::move(f), cols, lm)); } /// Convenience function invoked by jitted code to build action nodes at runtime -template +template void CallBuildAndBook(PrevNodeType &prevNode, const ColumnNames_t &bl, const unsigned int nSlots, const std::shared_ptr *rOnHeap, const std::shared_ptr *actionPtrPtrOnHeap) @@ -329,7 +344,7 @@ void CallBuildAndBook(PrevNodeType &prevNode, const ColumnNames_t &bl, const uns if (ds) DefineDataSourceColumns(bl, loopManager, *ds, std::make_index_sequence(), ColTypes_t()); RActionBase *actionPtr = - BuildAndBook(bl, *rOnHeap, nSlots, loopManager, prevNode, (ActionType *)nullptr); + BuildAndBook(bl, *rOnHeap, nSlots, loopManager, prevNode, ActionTag{}); **actionPtrPtrOnHeap = actionPtr; delete rOnHeap; delete actionPtrPtrOnHeap; @@ -412,14 +427,14 @@ void CheckAggregate(T) /////////////////////////////////////////////////////////////////////////////// /// Check as many template parameters were passed as the number of column names, throw if this is not the case. -void CheckSnapshot(unsigned int nTemplateParams, unsigned int nColumnNames); +void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames); /// Return local BranchNames or default BranchNames according to which one should be used const ColumnNames_t SelectColumns(unsigned int nArgs, const ColumnNames_t &bl, const ColumnNames_t &defBl); /// Check whether column names refer to a valid branch of a TTree or have been `Define`d. Return invalid column names. -ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, TTree *tree, const ColumnNames_t &definedCols, - const ColumnNames_t &dataSourceColumns); +ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const ColumnNames_t &datasetColumns, + const ColumnNames_t &definedCols, const ColumnNames_t &dataSourceColumns); bool IsInternalColumn(std::string_view colName); diff --git a/tree/dataframe/inc/ROOT/RDFNodes.hxx b/tree/dataframe/inc/ROOT/RDFNodes.hxx index d62bc363d644f..9b70ed643607b 100644 --- a/tree/dataframe/inc/ROOT/RDFNodes.hxx +++ b/tree/dataframe/inc/ROOT/RDFNodes.hxx @@ -11,60 +11,53 @@ #ifndef ROOT_RDFNODES #define ROOT_RDFNODES -#ifndef NDEBUG -#include "TError.h" -#endif -#include "ROOT/RIntegerSequence.hxx" -#include "ROOT/TypeTraits.hxx" #include "ROOT/RCutFlowReport.hxx" #include "ROOT/RDataSource.hxx" #include "ROOT/RDFNodesUtils.hxx" #include "ROOT/RDFUtils.hxx" +#include "ROOT/RIntegerSequence.hxx" #include "ROOT/RVec.hxx" -#include "ROOT/TSpinMutex.hxx" +#include "ROOT/TRWSpinLock.hxx" +#include "ROOT/TypeTraits.hxx" +#include "TError.h" #include "TTreeReaderArray.h" #include "TTreeReaderValue.h" -#include "TError.h" +#include // std::vector substitute in case of vector +#include +#include #include #include // std::accumulate (FillReport), std::iota (TSlotStack) +#include #include +#include #include -#include -#include -#include // std::vector substitute in case of vector -#include +#include namespace ROOT { namespace Internal { namespace RDF { class RActionBase; -// This is an helper class to allow to pick a slot without resorting to a map +// This is an helper class to allow to pick a slot resorting to a map // indexed by thread ids. // WARNING: this class does not work as a regular stack. The size is // fixed at construction time and no blocking is foreseen. class TSlotStack { private: - unsigned int &GetCount() - { - TTHREAD_TLS(unsigned int) count = 0U; - return count; - } - unsigned int &GetIndex() - { - TTHREAD_TLS(unsigned int) index = UINT_MAX; - return index; - } + unsigned int &GetCount(); + unsigned int &GetIndex(); unsigned int fCursor; std::vector fBuf; - ROOT::TSpinMutex fMutex; + ROOT::TRWSpinLock fRWLock; public: TSlotStack() = delete; TSlotStack(unsigned int size) : fCursor(size), fBuf(size) { std::iota(fBuf.begin(), fBuf.end(), 0U); } void ReturnSlot(unsigned int slotNumber); unsigned int GetSlot(); + std::map fCountMap; + std::map fIndexMap; }; } // ns RDF } // ns Internal @@ -86,7 +79,7 @@ class RRangeBase; using RangeBasePtr_t = std::shared_ptr; using RangeBaseVec_t = std::vector; -class RLoopManager : public std::enable_shared_from_this { +class RLoopManager { using RDataSource = ROOT::RDF::RDataSource; enum class ELoopType { kROOTFiles, kROOTFilesMT, kNoFiles, kNoFilesMT, kDataSource, kDataSourceMT }; @@ -168,7 +161,7 @@ class RLoopManager : public std::enable_shared_from_this { void InitNodes(); void CleanUpNodes(); void CleanUpTask(unsigned int slot); - void JitActions(); + void BuildJittedNodes(); void EvalChildrenCounts(); unsigned int GetNextID() const; @@ -181,7 +174,6 @@ public: void Run(); RLoopManager *GetLoopManagerUnchecked(); - std::shared_ptr GetSharedPtr() { return shared_from_this(); } const ColumnNames_t &GetDefaultColumnNames() const; const ColumnNames_t &GetCustomColumnNames() const { return fCustomColumnNames; }; TTree *GetTree() const; @@ -240,12 +232,15 @@ TTree branch or from a temporary column respectively. RDataFrame nodes can store tuples of TColumnValues and retrieve an updated value for the column via the `Get` method. **/ -template ::value> +template class TColumnValue { + + using MustUseRVec_t = IsRVec_t; + // ColumnValue_t is the type of the column or the type of the elements of an array column - using ColumnValue_t = typename std::conditional, T>::type; - using TreeReader_t = - typename std::conditional, TTreeReaderValue>::type; + using ColumnValue_t = typename std::conditional, T>::type; + using TreeReader_t = typename std::conditional, + TTreeReaderValue>::type; /// TColumnValue has a slightly different behaviour whether the column comes from a TTreeReader, a RDataFrame Define /// or a RDataSource. It stores which it is as an enum. @@ -255,20 +250,21 @@ class TColumnValue { /// The slot this value belongs to. Only needed when querying custom column values, it is set in `SetTmpColumn`. unsigned int fSlot = std::numeric_limits::max(); - // Each element of the following data members will be in use by a _single task_. - // The vectors are used as very small stacks (1-2 elements typically) that fill in case of interleaved task execution - // i.e. when more than one task needs readers in this worker thread. + // Each element of the following stacks will be in use by a _single task_. + // Each task will push one element when it starts and pop it when it ends. + // Stacks will typically be very small (1-2 elements typically) and will only grow over size 1 in case of interleaved + // task execution i.e. when more than one task needs readers in this worker thread. /// Owning ptrs to a TTreeReaderValue or TTreeReaderArray. Only used for Tree columns. - std::vector> fTreeReaders; + std::stack> fTreeReaders; /// Non-owning ptrs to the value of a custom column. - std::vector fCustomValuePtrs; + std::stack fCustomValuePtrs; /// Non-owning ptrs to the value of a data-source column. - std::vector fDSValuePtrs; + std::stack fDSValuePtrs; /// Non-owning ptrs to the node responsible for the custom column. Needed when querying custom values. - std::vector fCustomColumns; + std::stack fCustomColumns; /// Enumerator for the different properties of the branch storage in memory - enum class EStorageType : char { kContiguous, kUnknown, kSparse}; + enum class EStorageType : char { kContiguous, kUnknown, kSparse }; /// Signal whether we ever checked that the branch we are reading with a TTreeReaderArray stores array elements /// in contiguous memory. Only used when T == RVec. EStorageType fStorageType = EStorageType::kUnknown; @@ -277,44 +273,64 @@ class TColumnValue { bool fCopyWarningPrinted = false; public: - static constexpr bool fgMustUseRVec = MustUseRVec; - - TColumnValue() = default; + TColumnValue(){}; void SetTmpColumn(unsigned int slot, RCustomColumnBase *tmpColumn); void MakeProxy(TTreeReader *r, const std::string &bn) { fColumnKind = EColumnKind::kTree; - fTreeReaders.emplace_back(new TreeReader_t(*r, bn.c_str())); + fTreeReaders.emplace(new TreeReader_t(*r, bn.c_str())); } /// This overload is used to return scalar quantities (i.e. types that are not read into a RVec) - template ::fgMustUseRVec, int>::type = 0> + template ::MustUseRVec_t::value, int>::type = 0> T &Get(Long64_t entry); /// This overload is used to return arrays (i.e. types that are read into a RVec). /// In this case the returned T is always a RVec. - template ::fgMustUseRVec, int>::type = 0> + template ::MustUseRVec_t::value, int>::type = 0> T &Get(Long64_t entry); void Reset() { switch (fColumnKind) { - case EColumnKind::kTree: fTreeReaders.pop_back(); break; + case EColumnKind::kTree: fTreeReaders.pop(); break; case EColumnKind::kCustomColumn: - fCustomColumns.pop_back(); - fCustomValuePtrs.pop_back(); + fCustomColumns.pop(); + fCustomValuePtrs.pop(); break; case EColumnKind::kDataSource: - fCustomColumns.pop_back(); - fDSValuePtrs.pop_back(); + fCustomColumns.pop(); + fDSValuePtrs.pop(); break; case EColumnKind::kInvalid: throw std::runtime_error("ColumnKind not set for this TColumnValue"); } } }; +// Some extern instaniations to speed-up compilation/interpretation time +// These are not active if c++17 is enabled because of a bug in our clang +// See ROOT-9499. +#if __cplusplus < 201703L +extern template class TColumnValue; +extern template class TColumnValue; +extern template class TColumnValue; +extern template class TColumnValue; +extern template class TColumnValue; +extern template class TColumnValue; +extern template class TColumnValue; +extern template class TColumnValue; +extern template class TColumnValue>; +extern template class TColumnValue>; +extern template class TColumnValue>; +extern template class TColumnValue>; +extern template class TColumnValue>; +extern template class TColumnValue>; +extern template class TColumnValue>; +extern template class TColumnValue>; +#endif + template struct TRDFValueTuple { }; @@ -353,7 +369,7 @@ public: virtual void Initialize() = 0; virtual void InitSlot(TTreeReader *r, unsigned int slot) = 0; virtual void TriggerChildrenCount() = 0; - virtual void ClearValueReaders(unsigned int slot) = 0; + virtual void FinalizeSlot(unsigned int) = 0; /// This method is invoked to update a partial result during the event loop, right before passing the result to a /// user-defined callback registered via RResultPtr::RegisterCallback virtual void *PartialUpdate(unsigned int slot) = 0; @@ -385,7 +401,7 @@ public: { InitRDFValues(slot, fValues[slot], r, fBranches, fLoopManager->GetCustomColumnNames(), fLoopManager->GetBookedColumns(), TypeInd_t()); - fHelper.InitSlot(r, slot); + fHelper.InitTask(r, slot); } void Run(unsigned int slot, Long64_t entry) final @@ -404,11 +420,16 @@ public: void TriggerChildrenCount() final { fPrevData.IncrChildrenCount(); } - virtual void ClearValueReaders(unsigned int slot) final { ResetRDFValueTuple(fValues[slot], TypeInd_t()); } + void FinalizeSlot(unsigned int slot) final + { + ClearValueReaders(slot); + fHelper.CallFinalizeTask(slot); + } + + void ClearValueReaders(unsigned int slot) { ResetRDFValueTuple(fValues[slot], TypeInd_t()); } /// This method is invoked to update a partial result during the event loop, right before passing the result to a /// user-defined callback registered via RResultPtr::RegisterCallback - /// TODO the PartialUpdateImpl trick can go away once all action helpers will implement PartialUpdate void *PartialUpdate(unsigned int slot) final { return PartialUpdateImpl(slot); } private: @@ -434,8 +455,6 @@ protected: RLoopManager *fLoopManager; ///< A raw pointer to the RLoopManager at the root of this functional graph. It is only /// guaranteed to contain a valid address during an event loop. const std::string fName; - unsigned int fNChildren{0}; ///< number of nodes of the functional graph hanging from this object - unsigned int fNStopsReceived{0}; ///< number of times that a children node signaled to stop processing entries. const unsigned int fNSlots; ///< number of thread slots used by this node, inherited from parent node. const bool fIsDataSourceColumn; ///< does the custom column refer to a data-source column? (or a user-define column?) std::vector fLastCheckedEntry; @@ -447,35 +466,55 @@ public: virtual void InitSlot(TTreeReader *r, unsigned int slot) = 0; virtual void *GetValuePtr(unsigned int slot) = 0; virtual const std::type_info &GetTypeId() const = 0; - RLoopManager *GetLoopManagerUnchecked() const; std::string GetName() const; virtual void Update(unsigned int slot, Long64_t entry) = 0; virtual void ClearValueReaders(unsigned int slot) = 0; bool IsDataSourceColumn() const { return fIsDataSourceColumn; } - void InitNode(); + virtual void InitNode(); +}; + +/// A wrapper around a concrete RCustomColumn, which forwards all calls to it +/// RJittedCustomColumn is a placeholder that is put in the collection of custom columns in place of a RCustomColumn +/// that will be just-in-time compiled. Jitted code will assign the concrete RCustomColumn to this RJittedCustomColumn +/// before the event-loop starts. +class RJittedCustomColumn : public RCustomColumnBase +{ + std::unique_ptr fConcreteCustomColumn = nullptr; + +public: + RJittedCustomColumn(RLoopManager &lm, std::string_view name) + : RCustomColumnBase(&lm, name, lm.GetNSlots(), /*isDSColumn=*/false) {} + + void SetCustomColumn(std::unique_ptr c) { fConcreteCustomColumn = std::move(c); } + + void InitSlot(TTreeReader *r, unsigned int slot) final; + void *GetValuePtr(unsigned int slot) final; + const std::type_info &GetTypeId() const final; + void Update(unsigned int slot, Long64_t entry) final; + void ClearValueReaders(unsigned int slot) final; + void InitNode() final; }; // clang-format off -namespace TCCHelperTypes { -struct TNothing; -struct TSlot; -struct TSlotAndEntry; +namespace CustomColExtraArgs { +struct None{}; +struct Slot{}; +struct SlotAndEntry{}; } // clang-format on -template +template class RCustomColumn final : public RCustomColumnBase { // shortcuts - using TNothing = TCCHelperTypes::TNothing; - using TSlot = TCCHelperTypes::TSlot; - using TSlotAndEntry = TCCHelperTypes::TSlotAndEntry; - using UHT_t = UPDATE_HELPER_TYPE; + using NoneTag = CustomColExtraArgs::None; + using SlotTag = CustomColExtraArgs::Slot; + using SlotAndEntryTag = CustomColExtraArgs::SlotAndEntry; // other types using FunParamTypes_t = typename CallableTraits::arg_types; - using BranchTypesTmp_t = - typename RDFInternal::RemoveFirstParameterIf::value, FunParamTypes_t>::type; - using ColumnTypes_t = typename RDFInternal::RemoveFirstTwoParametersIf::value, - BranchTypesTmp_t>::type; + using ColumnTypesTmp_t = + RDFInternal::RemoveFirstParameterIf_t::value, FunParamTypes_t>; + using ColumnTypes_t = + RDFInternal::RemoveFirstTwoParametersIf_t::value, ColumnTypesTmp_t>; using TypeInd_t = std::make_index_sequence; using ret_type = typename CallableTraits::ret_type; // Avoid instantiating vector as `operator[]` returns temporaries in that case. Use std::deque instead. @@ -492,9 +531,7 @@ public: RCustomColumn(std::string_view name, F &&expression, const ColumnNames_t &bl, RLoopManager *lm, bool isDSColumn = false) : RCustomColumnBase(lm, name, lm->GetNSlots(), isDSColumn), fExpression(std::move(expression)), fBranches(bl), - fLastResults(fNSlots), fValues(fNSlots) - { - } + fLastResults(fNSlots), fValues(fNSlots) {} RCustomColumn(const RCustomColumn &) = delete; RCustomColumn &operator=(const RCustomColumn &) = delete; @@ -511,7 +548,7 @@ public: { if (entry != fLastCheckedEntry[slot]) { // evaluate this filter, cache the result - UpdateHelper(slot, entry, TypeInd_t(), ColumnTypes_t(), (UPDATE_HELPER_TYPE *)nullptr); + UpdateHelper(slot, entry, TypeInd_t(), ColumnTypes_t(), ExtraArgsTag{}); fLastCheckedEntry[slot] = entry; } } @@ -522,8 +559,7 @@ public: } template - void UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence, TypeList, - TCCHelperTypes::TNothing *) + void UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence, TypeList, NoneTag) { fLastResults[slot] = fExpression(std::get(fValues[slot]).Get(entry)...); // silence "unused parameter" warnings in gcc @@ -532,8 +568,7 @@ public: } template - void UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence, TypeList, - TCCHelperTypes::TSlot *) + void UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence, TypeList, SlotTag) { fLastResults[slot] = fExpression(slot, std::get(fValues[slot]).Get(entry)...); // silence "unused parameter" warnings in gcc @@ -542,8 +577,8 @@ public: } template - void UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence, TypeList, - TCCHelperTypes::TSlotAndEntry *) + void + UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence, TypeList, SlotAndEntryTag) { fLastResults[slot] = fExpression(slot, entry, std::get(fValues[slot]).Get(entry)...); // silence "unused parameter" warnings in gcc @@ -589,7 +624,7 @@ public: virtual void TriggerChildrenCount() = 0; virtual void ResetReportCount() { - assert(!fName.empty()); // this method is to only be called on named filters + R__ASSERT(!fName.empty()); // this method is to only be called on named filters // fAccepted and fRejected could be different than 0 if this is not the first event-loop run using this filter std::fill(fAccepted.begin(), fAccepted.end(), 0); std::fill(fRejected.begin(), fRejected.end(), 0); @@ -601,8 +636,6 @@ public: /// A wrapper around a concrete RFilter, which forwards all calls to it /// RJittedFilter is the type of the node returned by jitted Filter calls: the concrete filter can be created and set /// at a later time, from jitted code. -// FIXME after switching to the new ownership model, RJittedFilter should avoid inheriting from RFilterBase and -// overriding all of its methods: it can just implement them, and RFilterBase's can go back to have non-virtual methods class RJittedFilter final : public RFilterBase { std::unique_ptr fConcreteFilter = nullptr; @@ -611,18 +644,18 @@ public: void SetFilter(std::unique_ptr f); - void InitSlot(TTreeReader *r, unsigned int slot) override final; - bool CheckFilters(unsigned int slot, Long64_t entry) override final; - void Report(ROOT::RDF::RCutFlowReport &) const override final; - void PartialReport(ROOT::RDF::RCutFlowReport &) const override final; - void FillReport(ROOT::RDF::RCutFlowReport &) const override final; - void IncrChildrenCount() override final; - void StopProcessing() override final; - void ResetChildrenCount() override final; - void TriggerChildrenCount() override final; - void ResetReportCount() override final; - void ClearValueReaders(unsigned int slot) override final; - void InitNode() override final; + void InitSlot(TTreeReader *r, unsigned int slot) final; + bool CheckFilters(unsigned int slot, Long64_t entry) final; + void Report(ROOT::RDF::RCutFlowReport &) const final; + void PartialReport(ROOT::RDF::RCutFlowReport &) const final; + void FillReport(ROOT::RDF::RCutFlowReport &) const final; + void IncrChildrenCount() final; + void StopProcessing() final; + void ResetChildrenCount() final; + void TriggerChildrenCount() final; + void ResetReportCount() final; + void ClearValueReaders(unsigned int slot) final; + void InitNode() final; }; template @@ -703,7 +736,7 @@ public: void TriggerChildrenCount() final { - assert(!fName.empty()); // this method is to only be called on named filters + R__ASSERT(!fName.empty()); // this method is to only be called on named filters fPrevData.IncrChildrenCount(); } @@ -820,21 +853,23 @@ public: namespace Internal { namespace RDF { -template -void TColumnValue::SetTmpColumn(unsigned int slot, ROOT::Detail::RDF::RCustomColumnBase *customColumn) +template +void TColumnValue::SetTmpColumn(unsigned int slot, ROOT::Detail::RDF::RCustomColumnBase *customColumn) { - fCustomColumns.emplace_back(customColumn); - if (customColumn->GetTypeId() != typeid(T)) + fCustomColumns.emplace(customColumn); + // Here we compare names and not typeinfos since they may come from two different contexts: a compiled + // and a jitted one. + if (0 != strcmp(customColumn->GetTypeId().name(), typeid(T).name())) throw std::runtime_error( std::string("TColumnValue: type specified for column \"" + customColumn->GetName() + "\" is ") + - typeid(T).name() + " but temporary column has type " + customColumn->GetTypeId().name()); + TypeID2TypeName(typeid(T)) + " but temporary column has type " + TypeID2TypeName(customColumn->GetTypeId())); if (customColumn->IsDataSourceColumn()) { fColumnKind = EColumnKind::kDataSource; - fDSValuePtrs.emplace_back(static_cast(customColumn->GetValuePtr(slot))); + fDSValuePtrs.emplace(static_cast(customColumn->GetValuePtr(slot))); } else { fColumnKind = EColumnKind::kCustomColumn; - fCustomValuePtrs.emplace_back(static_cast(customColumn->GetValuePtr(slot))); + fCustomValuePtrs.emplace(static_cast(customColumn->GetValuePtr(slot))); } fSlot = slot; } @@ -842,25 +877,25 @@ void TColumnValue::SetTmpColumn(unsigned int slot, ROOT::Detail::RDF::RCus // This method is executed inside the event-loop, many times per entry // If need be, the if statement can be avoided using thunks // (have both branches inside functions and have a pointer to the branch to be executed) -template -template ::fgMustUseRVec, int>::type> -T &TColumnValue::Get(Long64_t entry) +template +template ::MustUseRVec_t::value, int>::type> +T &TColumnValue::Get(Long64_t entry) { if (fColumnKind == EColumnKind::kTree) { - return *(fTreeReaders.back()->Get()); + return *(fTreeReaders.top()->Get()); } else { - fCustomColumns.back()->Update(fSlot, entry); - return fColumnKind == EColumnKind::kCustomColumn ? *fCustomValuePtrs.back() : **fDSValuePtrs.back(); + fCustomColumns.top()->Update(fSlot, entry); + return fColumnKind == EColumnKind::kCustomColumn ? *fCustomValuePtrs.top() : **fDSValuePtrs.top(); } } /// This overload is used to return arrays (i.e. types that are read into a RVec) -template -template ::fgMustUseRVec, int>::type> -T &TColumnValue::Get(Long64_t entry) +template +template ::MustUseRVec_t::value, int>::type> +T &TColumnValue::Get(Long64_t entry) { if (fColumnKind == EColumnKind::kTree) { - auto &readerArray = *fTreeReaders.back(); + auto &readerArray = *fTreeReaders.top(); // We only use TTreeReaderArrays to read columns that users flagged as type `RVec`, so we need to check // that the branch stores the array as contiguous memory that we can actually wrap in an `RVec`. // Currently we need the first entry to have been loaded to perform the check @@ -887,12 +922,12 @@ T &TColumnValue::Get(Long64_t entry) swap(fRVec, emptyVec); } } else { - // The storage is not contiguous or we don't know yet: we cannot but copy into the tvec +// The storage is not contiguous or we don't know yet: we cannot but copy into the tvec #ifndef NDEBUG if (!fCopyWarningPrinted) { - Warning("TColumnValue::Get", - "Branch %s hangs from a non-split branch. For this reason, it cannot be accessed via a RVec. A copy is being performed in order to properly read the content.", - readerArray.GetBranchName()); + Warning("TColumnValue::Get", "Branch %s hangs from a non-split branch. A copy is being performed in order " + "to properly read the content.", + readerArray.GetBranchName()); fCopyWarningPrinted = true; } #else @@ -910,8 +945,8 @@ T &TColumnValue::Get(Long64_t entry) return fRVec; } else { - fCustomColumns.back()->Update(fSlot, entry); - return fColumnKind == EColumnKind::kCustomColumn ? *fCustomValuePtrs.back() : **fDSValuePtrs.back(); + fCustomColumns.top()->Update(fSlot, entry); + return fColumnKind == EColumnKind::kCustomColumn ? *fCustomValuePtrs.top() : **fDSValuePtrs.top(); } } diff --git a/tree/dataframe/inc/ROOT/RDFUtils.hxx b/tree/dataframe/inc/ROOT/RDFUtils.hxx index 6fa55cd3fdc44..cd62c727270be 100644 --- a/tree/dataframe/inc/ROOT/RDFUtils.hxx +++ b/tree/dataframe/inc/ROOT/RDFUtils.hxx @@ -83,6 +83,9 @@ struct RemoveFirstParameterIf { using type = RemoveFirstParameter_t; }; +template +using RemoveFirstParameterIf_t = typename RemoveFirstParameterIf::type; + template struct RemoveFirstTwoParametersIf { using type = TypeList; @@ -94,6 +97,9 @@ struct RemoveFirstTwoParametersIf { using type = typename RemoveFirstParameterIf::type; }; +template +using RemoveFirstTwoParametersIf_t = typename RemoveFirstTwoParametersIf::type; + /// Detect whether a type is an instantiation of RVec template struct IsRVec_t : public std::false_type {}; diff --git a/tree/dataframe/src/RCsvDS.cxx b/tree/dataframe/src/RCsvDS.cxx index c22784764cc63..54527805fef6e 100644 --- a/tree/dataframe/src/RCsvDS.cxx +++ b/tree/dataframe/src/RCsvDS.cxx @@ -75,6 +75,7 @@ important to check both how much memory is available and the size of the CSV fil #include #include #include +#include #include #include @@ -421,7 +422,7 @@ bool RCsvDS::SetEntry(unsigned int slot, ULong64_t entry) void RCsvDS::SetNSlots(unsigned int nSlots) { - assert(0U == fNSlots && "Setting the number of slots even if the number of slots is different from zero."); + R__ASSERT(0U == fNSlots && "Setting the number of slots even if the number of slots is different from zero."); fNSlots = nSlots; diff --git a/tree/dataframe/src/RDFActionHelpers.cxx b/tree/dataframe/src/RDFActionHelpers.cxx index 4bed933a8ceb7..cd0ed70ae1321 100644 --- a/tree/dataframe/src/RDFActionHelpers.cxx +++ b/tree/dataframe/src/RDFActionHelpers.cxx @@ -163,6 +163,63 @@ template void MeanHelper::Exec(unsigned int, const std::vector &); template void MeanHelper::Exec(unsigned int, const std::vector &); template void MeanHelper::Exec(unsigned int, const std::vector &); +StdDevHelper::StdDevHelper(const std::shared_ptr &meanVPtr, const unsigned int nSlots) + : fNSlots(nSlots), fResultStdDev(meanVPtr), fCounts(nSlots, 0), fMeans(nSlots, 0), fDistancesfromMean(nSlots, 0) +{ +} + +void StdDevHelper::Exec(unsigned int slot, double v) +{ + // Applies the Welford's algorithm to the stream of values received by the thread + auto count = ++fCounts[slot]; + auto delta = v - fMeans[slot]; + auto mean = fMeans[slot] + delta / count; + auto delta2 = v - mean; + auto distance = fDistancesfromMean[slot] + delta * delta2; + + fCounts[slot] = count; + fMeans[slot] = mean; + fDistancesfromMean[slot] = distance; +} + +void StdDevHelper::Finalize() +{ + // Evaluates and merges the partial result of each set of data to get the overall standard deviation. + double totalElements = 0; + for (auto c : fCounts) { + totalElements += c; + } + if (totalElements == 0 || totalElements == 1) { + //Std deviation is not defined for 1 element. + *fResultStdDev = 0; + return; + } + + double overallMean = 0; + for (unsigned int i = 0; i < fNSlots; ++i) { + overallMean += fCounts[i] * fMeans[i]; + } + overallMean = overallMean / totalElements; + + double variance = 0; + for (unsigned int i = 0; i < fNSlots; ++i) { + if (fCounts[i] == 0) { + continue; + } + auto setVariance = fDistancesfromMean[i] / (fCounts[i]); + variance += (fCounts[i]) * (setVariance + std::pow((fMeans[i] - overallMean), 2)); + } + + variance = variance / (totalElements - 1); + *fResultStdDev = std::sqrt(variance); +} + +template void StdDevHelper::Exec(unsigned int, const std::vector &); +template void StdDevHelper::Exec(unsigned int, const std::vector &); +template void StdDevHelper::Exec(unsigned int, const std::vector &); +template void StdDevHelper::Exec(unsigned int, const std::vector &); +template void StdDevHelper::Exec(unsigned int, const std::vector &); + } // end NS RDF } // end NS Internal } // end NS ROOT diff --git a/tree/dataframe/src/RDFInterfaceUtils.cxx b/tree/dataframe/src/RDFInterfaceUtils.cxx index 30a73c6dbde60..9964d2f5325ff 100644 --- a/tree/dataframe/src/RDFInterfaceUtils.cxx +++ b/tree/dataframe/src/RDFInterfaceUtils.cxx @@ -232,10 +232,10 @@ void CheckCustomColumn(std::string_view definedCol, TTree *treePtr, const Column } } -void CheckSnapshot(unsigned int nTemplateParams, unsigned int nColumnNames) +void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames) { if (nTemplateParams != nColumnNames) { - std::string err_msg = "The number of template parameters specified for the snapshot is "; + std::string err_msg = "The number of template parameters specified is "; err_msg += std::to_string(nTemplateParams); err_msg += " while "; err_msg += std::to_string(nColumnNames); @@ -271,17 +271,14 @@ SelectColumns(unsigned int nRequiredNames, const ColumnNames_t &names, const Col } } -ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, TTree *tree, const ColumnNames_t &definedCols, - const ColumnNames_t &dataSourceColumns) +ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const ColumnNames_t &datasetColumns, + const ColumnNames_t &definedCols, const ColumnNames_t &dataSourceColumns) { ColumnNames_t unknownColumns; for (auto &column : requiredCols) { - if (tree != nullptr) { - const auto branchNames = GetBranchNames(*tree); - const auto isBranch = std::find(branchNames.begin(), branchNames.end(), column) != branchNames.end(); - if (isBranch) - continue; - } + const auto isBranch = std::find(datasetColumns.begin(), datasetColumns.end(), column) != datasetColumns.end(); + if (isBranch) + continue; const auto isCustomColumn = std::find(definedCols.begin(), definedCols.end(), column) != definedCols.end(); if (isCustomColumn) continue; @@ -571,6 +568,8 @@ void BookDefineJit(std::string_view name, std::string_view expression, RLoopMana TryToJitExpression(dotlessExpr, varNames, usedColTypes, hasReturnStmt); + const auto jittedCustomColumn = std::make_shared(lm, name); + const auto definelambda = BuildLambdaString(dotlessExpr, varNames, usedColTypes, hasReturnStmt); const auto lambdaName = "eval_" + std::string(name); const auto ns = "__tdf" + std::to_string(namespaceID); @@ -594,9 +593,11 @@ void BookDefineJit(std::string_view name, std::string_view expression, RLoopMana if (!usedBranches.empty()) defineInvocation.seekp(-2, defineInvocation.cur); // remove the last ", defineInvocation << "}, \"" << name << "\", reinterpret_cast(" - << PrettyPrintAddr(&lm) << "));"; + << PrettyPrintAddr(&lm) << "), *reinterpret_cast(" + << PrettyPrintAddr(jittedCustomColumn.get()) << "));"; lm.AddCustomColumnName(name); + lm.Book(jittedCustomColumn); lm.ToJit(defineInvocation.str()); } @@ -705,11 +706,12 @@ std::shared_ptr UpcastNode(const std::shared_ptr p /// * check that selected column names refer to valid branches, custom columns or datasource columns (throw if not) /// Return the list of selected column names. ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns, - const ColumnNames_t &validCustomColumns, RDataSource *ds) + const ColumnNames_t &datasetColumns, const ColumnNames_t &validCustomColumns, + RDataSource *ds) { const auto &defaultColumns = lm.GetDefaultColumnNames(); auto selectedColumns = SelectColumns(nColumns, columns, defaultColumns); - const auto unknownColumns = FindUnknownColumns(selectedColumns, lm.GetTree(), validCustomColumns, + const auto unknownColumns = FindUnknownColumns(selectedColumns, datasetColumns, validCustomColumns, ds ? ds->GetColumnNames() : ColumnNames_t{}); if (!unknownColumns.empty()) { diff --git a/tree/dataframe/src/RDFNodes.cxx b/tree/dataframe/src/RDFNodes.cxx index 0831208590c47..3015edd82dd4d 100644 --- a/tree/dataframe/src/RDFNodes.cxx +++ b/tree/dataframe/src/RDFNodes.cxx @@ -20,7 +20,6 @@ #include "ROOT/TThreadExecutor.hxx" #endif #include -#include #include #include #include @@ -32,6 +31,7 @@ #include #include "RtypesCore.h" // Long64_t +#include "TError.h" #include "TInterpreter.h" #include "TROOT.h" // IsImplicitMTEnabled #include "TTreeReader.h" @@ -52,15 +52,34 @@ RActionBase::RActionBase(RLoopManager *implPtr, const unsigned int nSlots) : fLo { } +// Some extern instaniations to speed-up compilation/interpretation time +// These are not active if c++17 is enabled because of a bug in our clang +// See ROOT-9499. +#if __cplusplus < 201703L +template class TColumnValue; +template class TColumnValue; +template class TColumnValue; +template class TColumnValue; +template class TColumnValue; +template class TColumnValue; +template class TColumnValue; +template class TColumnValue; +template class TColumnValue>; +template class TColumnValue>; +template class TColumnValue>; +template class TColumnValue>; +template class TColumnValue>; +template class TColumnValue>; +template class TColumnValue>; +template class TColumnValue>; +#endif } // end NS RDF } // end NS Internal } // end NS ROOT -RCustomColumnBase::RCustomColumnBase(RLoopManager *implPtr, std::string_view name, const unsigned int nSlots, +RCustomColumnBase::RCustomColumnBase(RLoopManager *lm, std::string_view name, const unsigned int nSlots, const bool isDSColumn) - : fLoopManager(implPtr), fName(name), fNSlots(nSlots), fIsDataSourceColumn(isDSColumn) -{ -} + : fLoopManager(lm), fName(name), fNSlots(nSlots), fIsDataSourceColumn(isDSColumn) {} // pin vtable. Work around cling JIT issue. RCustomColumnBase::~RCustomColumnBase() = default; @@ -70,14 +89,45 @@ std::string RCustomColumnBase::GetName() const return fName; } -RLoopManager *RCustomColumnBase::GetLoopManagerUnchecked() const +void RCustomColumnBase::InitNode() { - return fLoopManager; + fLastCheckedEntry = std::vector(fNSlots, -1); } -void RCustomColumnBase::InitNode() +void RJittedCustomColumn::InitSlot(TTreeReader *r, unsigned int slot) { - fLastCheckedEntry = std::vector(fNSlots, -1); + R__ASSERT(fConcreteCustomColumn != nullptr); + fConcreteCustomColumn->InitSlot(r, slot); +} + +void *RJittedCustomColumn::GetValuePtr(unsigned int slot) +{ + R__ASSERT(fConcreteCustomColumn != nullptr); + return fConcreteCustomColumn->GetValuePtr(slot); +} + +const std::type_info &RJittedCustomColumn::GetTypeId() const +{ + R__ASSERT(fConcreteCustomColumn != nullptr); + return fConcreteCustomColumn->GetTypeId(); +} + +void RJittedCustomColumn::Update(unsigned int slot, Long64_t entry) +{ + R__ASSERT(fConcreteCustomColumn != nullptr); + fConcreteCustomColumn->Update(slot, entry); +} + +void RJittedCustomColumn::ClearValueReaders(unsigned int slot) +{ + R__ASSERT(fConcreteCustomColumn != nullptr); + fConcreteCustomColumn->ClearValueReaders(slot); +} + +void RJittedCustomColumn::InitNode() +{ + R__ASSERT(fConcreteCustomColumn != nullptr); + fConcreteCustomColumn->InitNode(); } RFilterBase::RFilterBase(RLoopManager *implPtr, std::string_view name, const unsigned int nSlots) @@ -188,19 +238,51 @@ void RJittedFilter::InitNode() fConcreteFilter->InitNode(); } +unsigned int &TSlotStack::GetCount() +{ + const auto tid = std::this_thread::get_id(); + { + ROOT::TRWSpinLockReadGuard rg(fRWLock); + auto it = fCountMap.find(tid); + if (fCountMap.end() != it) + return it->second; + } + + { + ROOT::TRWSpinLockWriteGuard rg(fRWLock); + return (fCountMap[tid] = 0U); + } +} +unsigned int &TSlotStack::GetIndex() +{ + const auto tid = std::this_thread::get_id(); + + { + ROOT::TRWSpinLockReadGuard rg(fRWLock); + if (fIndexMap.end() != fIndexMap.find(tid)) + return fIndexMap[tid]; + } + + { + ROOT::TRWSpinLockWriteGuard rg(fRWLock); + return (fIndexMap[tid] = std::numeric_limits::max()); + } +} + void TSlotStack::ReturnSlot(unsigned int slotNumber) { auto &index = GetIndex(); auto &count = GetCount(); - assert(count > 0U && "TSlotStack has a reference count relative to an index which will become negative."); + R__ASSERT(count > 0U && "TSlotStack has a reference count relative to an index which will become negative."); count--; if (0U == count) { - index = UINT_MAX; - std::lock_guard guard(fMutex); + index = std::numeric_limits::max(); + ROOT::TRWSpinLockWriteGuard guard(fRWLock); fBuf[fCursor++] = slotNumber; - assert(fCursor <= fBuf.size() && "TSlotStack assumes that at most a fixed number of values can be present in the " - "stack. fCursor is greater than the size of the internal buffer. This violates " - "such assumption."); + R__ASSERT(fCursor <= fBuf.size() && + "TSlotStack assumes that at most a fixed number of values can be present in the " + "stack. fCursor is greater than the size of the internal buffer. This violates " + "such assumption."); } } @@ -209,11 +291,12 @@ unsigned int TSlotStack::GetSlot() auto &index = GetIndex(); auto &count = GetCount(); count++; - if (UINT_MAX != index) + if (std::numeric_limits::max() != index) return index; - std::lock_guard guard(fMutex); - assert(fCursor > 0 && "TSlotStack assumes that a value can be always obtained. In this case fCursor is <=0 and this " - "violates such assumption."); + ROOT::TRWSpinLockWriteGuard guard(fRWLock); + R__ASSERT(fCursor > 0 && + "TSlotStack assumes that a value can be always obtained. In this case fCursor is <=0 and this " + "violates such assumption."); index = fBuf[--fCursor]; return index; } @@ -327,7 +410,7 @@ void RLoopManager::RunTreeReader() /// Run event loop over data accessed through a DataSource, in sequence. void RLoopManager::RunDataSource() { - assert(fDataSource != nullptr); + R__ASSERT(fDataSource != nullptr); fDataSource->Initialise(); auto ranges = fDataSource->GetEntryRanges(); while (!ranges.empty()) { @@ -351,7 +434,7 @@ void RLoopManager::RunDataSource() void RLoopManager::RunDataSourceMT() { #ifdef R__USE_IMT - assert(fDataSource != nullptr); + R__ASSERT(fDataSource != nullptr); TSlotStack slotStack(fNSlots); ROOT::TThreadExecutor pool; @@ -458,7 +541,7 @@ void RLoopManager::CleanUpNodes() void RLoopManager::CleanUpTask(unsigned int slot) { for (auto &ptr : fBookedActions) - ptr->ClearValueReaders(slot); + ptr->FinalizeSlot(slot); for (auto &ptr : fBookedFilters) ptr->ClearValueReaders(slot); for (auto &pair : fBookedCustomColumns) @@ -466,7 +549,7 @@ void RLoopManager::CleanUpTask(unsigned int slot) } /// Jit all actions that required runtime column type inference, and clean the `fToJit` member variable. -void RLoopManager::JitActions() +void RLoopManager::BuildJittedNodes() { auto error = TInterpreter::EErrorCode::kNoError; gInterpreter->Calc(fToJit.c_str(), &error); @@ -504,7 +587,7 @@ unsigned int RLoopManager::GetNextID() const void RLoopManager::Run() { if (!fToJit.empty()) - JitActions(); + BuildJittedNodes(); InitNodes(); diff --git a/tree/dataframe/src/RDataFrame.cxx b/tree/dataframe/src/RDataFrame.cxx index e7cd76ddc7ca5..ac20d6bb993e9 100644 --- a/tree/dataframe/src/RDataFrame.cxx +++ b/tree/dataframe/src/RDataFrame.cxx @@ -19,7 +19,7 @@ /** * \class ROOT::RDataFrame * \ingroup dataframe -* \brief ROOT's RDataFrame offers a high level interface for analyses of data stored in `TTree`s. +* \brief ROOT's RDataFrame offers a high level interface for analyses of data stored in `TTree`s, CSV's and other data formats. In addition, multi-threading and other low-level optimisations allow users to exploit all the resources available on their machines completely transparently.
@@ -28,28 +28,32 @@ Skip to the [class reference](#reference) or keep reading for the user guide. In a nutshell: ~~~{.cpp} ROOT::EnableImplicitMT(); // Tell ROOT you want to go parallel -ROOT::RDataFrame d("myTree", "file.root"); // Interface to TTree and TChain +ROOT::RDataFrame d("myTree", "file_*.root"); // Interface to TTree and TChain auto myHisto = d.Histo1D("Branch_A"); // This happens in parallel! myHisto->Draw(); ~~~ Calculations are expressed in terms of a type-safe *functional chain of actions and transformations*, `RDataFrame` takes care of their execution. The implementation automatically puts in place several low level optimisations such as -multi-thread parallelisation and caching. The namespace containing the RDataFrame is ROOT. +multi-thread parallelisation and caching. \htmlonly DOI \endhtmlonly -## Cheat sheet -These are the operations which can be performed with RDataFrame - -Here is a quick overview of what actions are present and what they do. Each one is described in more detail in the -reference guide. +## Table of Contents +- [Cheat sheet](#cheatsheet) +- [Introduction](#introduction) +- [Crash course](#crash-course) +- [More features](#more-features) +- [Transformations](#transformations) -- manipulating data +- [Actions](#actions) -- getting results +- [Parallel execution](#parallel-execution) -- how to use it and common pitfalls +- [Class reference](#reference) -- most methods are implemented in the RInterface base class -In the following, whenever we say an action "returns" something, we always mean it returns a smart pointer to it. Also -note that all actions are only executed for events that pass all preceding filters. +## Cheat sheet +These are the operations which can be performed with RDataFrame ### Transformations Transformations are a way to manipulated the data. @@ -63,9 +67,16 @@ Transformations are a way to manipulated the data. | [Range](classROOT_1_1RDF_1_1RInterface.html#a1b36b7868831de2375e061bb06cfc225) | Creates a node that filters entries based on range of entries | ### Actions -Actions are a way to get a result out of the data. +Actions are a way to produce a result out of the data. Each one is described in more detail in the reference guide. + +In the following, whenever we say an action "returns" something, we always mean it returns a smart pointer to it. Also +note that all actions are only executed for events that pass all preceding filters. + +Lazy actions only trigger the event loop when one of the results is accessed for the first time, making it easy to +produce several different results in one event loop. Instant actions trigger the event loop instantly. + -| **Lazy actions** | **Description** | +| **Lazy action** | **Description** | |------------------|-----------------| | [Aggregate](classROOT_1_1RDF_1_1RInterface.html#ae540b00addc441f9b504cbae0ef0a24d) | Execute a user-defined accumulation operation on the processed column values. | | [Book](classROOT_1_1RDF_1_1RInterface.html#a9b2f61f3333d1669e57055b9ae8be9d9) | Book execution of a custom action using a user-defined helper object. | @@ -82,7 +93,7 @@ Actions are a way to get a result out of the data. | [Sum](classROOT_1_1RDF_1_1RInterface.html#a61d03407459120df6749af43ed506891) | Return the sum of the values in the column. If the type of the column is inferred, the return type is `double`, the type of the column otherwise. | | [Take](classROOT_1_1RDF_1_1RInterface.html#a4fd694773a2931b6b07737ddcd1e73b4) | Extract a column from the dataset as a collection of values. If the type of the column is a C-style array, the type stored in the return container is a `ROOT::VecOps::RVec` to guarantee the lifetime of the data involved. | -| **Instant actions** | **Description** | +| **Instant action** | **Description** | |---------------------|-----------------| | [Foreach](classROOT_1_1RDF_1_1RInterface.html#ad2822a7ccb8a9afdf3e5b2ea321886ca) | Execute a user-defined function on each entry. Users are responsible for the thread-safety of this lambda when executing with implicit multi-threading enabled. | | [ForeachSlot](classROOT_1_1RDF_1_1RInterface.html#a3650ca30aae1ccd0d92bf3d680314129) | Same as `Foreach`, but the user-defined function must take an extra `unsigned int slot` as its first parameter. `slot` will take a different value, `0` to `nThreads - 1`, for each thread of execution. This is meant as a helper in writing thread-safe `Foreach` actions when using `RDataFrame` after `ROOT::EnableImplicitMT()`. `ForeachSlot` works just as well with single-thread execution: in that case `slot` will always be `0`. | @@ -91,22 +102,12 @@ Actions are a way to get a result out of the data. ### Other Operations -| **Operations** | **Description** | +| **Operation** | **Description** | |---------------------|-----------------| | [Alias](classROOT_1_1RDF_1_1RInterface.html#a31ca327e4a192dcc05a4aac240e1a725) | Introduce an alias for a particular column name | | [GetColumnNames](classROOT_1_1RDF_1_1RInterface.html#a951fe60b74d3a9fda37df59fd1dac186) | Get all the available columns of the dataset | - -## Table of Contents -- [Introduction](#introduction) -- [Crash course](#crash-course) -- [More features](#more-features) -- [Transformations](#transformations) -- manipulating data -- [Actions](#actions) -- getting results -- [Parallel execution](#parallel-execution) -- how to use it and common pitfalls -- [Class reference](#reference) -- most methods are implemented in the RInterface base class - ## Introduction Users define their analysis as a sequence of operations to be performed on the data-frame object; the framework takes care of the management of the loop over entries as well as low-level details such as I/O and parallelisation. diff --git a/tree/dataframe/src/RRootDS.cxx b/tree/dataframe/src/RRootDS.cxx index 2b92500a506fa..f2c063b2b9121 100644 --- a/tree/dataframe/src/RRootDS.cxx +++ b/tree/dataframe/src/RRootDS.cxx @@ -2,6 +2,7 @@ #include #include #include +#include #include // For the gROOTMutex #include // For the R__LOCKGUARD #include @@ -127,7 +128,7 @@ bool RRootDS::SetEntry(unsigned int slot, ULong64_t entry) void RRootDS::SetNSlots(unsigned int nSlots) { - assert(0U == fNSlots && "Setting the number of slots even if the number of slots is different from zero."); + R__ASSERT(0U == fNSlots && "Setting the number of slots even if the number of slots is different from zero."); fNSlots = nSlots; diff --git a/tree/dataframe/src/RTrivialDS.cxx b/tree/dataframe/src/RTrivialDS.cxx index c2aed42899230..abe1e41e3fd05 100644 --- a/tree/dataframe/src/RTrivialDS.cxx +++ b/tree/dataframe/src/RTrivialDS.cxx @@ -2,6 +2,7 @@ #include #include #include +#include namespace ROOT { @@ -61,7 +62,7 @@ bool RTrivialDS::SetEntry(unsigned int slot, ULong64_t entry) void RTrivialDS::SetNSlots(unsigned int nSlots) { - assert(0U == fNSlots && "Setting the number of slots even if the number of slots is different from zero."); + R__ASSERT(0U == fNSlots && "Setting the number of slots even if the number of slots is different from zero."); fNSlots = nSlots; fCounter.resize(fNSlots); diff --git a/tree/dataframe/test/CMakeLists.txt b/tree/dataframe/test/CMakeLists.txt index e21ac5b346aa1..59e5a43af5a29 100644 --- a/tree/dataframe/test/CMakeLists.txt +++ b/tree/dataframe/test/CMakeLists.txt @@ -19,7 +19,7 @@ ROOT_ADD_GTEST(dataframe_vecops dataframe_vecops.cxx LIBRARIES ROOTDataFrame) ROOT_ADD_GTEST(dataframe_resptr dataframe_resptr.cxx LIBRARIES ROOTDataFrame) ROOT_ADD_GTEST(datasource_more datasource_more.cxx LIBRARIES ROOTDataFrame) -ROOT_ADD_GTEST(datasource_root datasource_root.cxx LIBRARIES ROOTDataFrame) +#ROOT_ADD_GTEST(datasource_root datasource_root.cxx LIBRARIES ROOTDataFrame) ROOT_ADD_GTEST(datasource_trivial datasource_trivial.cxx LIBRARIES ROOTDataFrame) configure_file(RCsvDS_test_headers.csv . COPYONLY) configure_file(RCsvDS_test_noheaders.csv . COPYONLY) diff --git a/tree/dataframe/test/dataframe_nodes.cxx b/tree/dataframe/test/dataframe_nodes.cxx index 3975c3b2c3d35..388fdae37675a 100644 --- a/tree/dataframe/test/dataframe_nodes.cxx +++ b/tree/dataframe/test/dataframe_nodes.cxx @@ -32,36 +32,17 @@ TEST(RDataFrameNodes, TSlotStackGetOneTooMuch) t.join(); }; - ASSERT_DEATH(theTest(), "TSlotStack assumes that a value can be always obtained."); + EXPECT_DEATH(theTest(), "TSlotStack assumes that a value can be always obtained."); } TEST(RDataFrameNodes, TSlotStackPutBackTooMany) { - std::mutex m; - auto theTest = [&m]() { - unsigned int n(2); - ROOT::Internal::RDF::TSlotStack s(n); - - std::vector ts; - - for (unsigned int i = 0; i < 2; ++i) { - ts.emplace_back([&s, &m]() { - std::lock_guard lg(m); - s.GetSlot(); - }); - } - for (unsigned int i = 0; i < 2; ++i) { - ts.emplace_back([&s, &m, i]() { - std::lock_guard lg(m); - s.ReturnSlot(i); - }); - } - - for (auto &&t : ts) - t.join(); + auto theTest = []() { + ROOT::Internal::RDF::TSlotStack s(1); + s.ReturnSlot(0); }; - ASSERT_DEATH(theTest(), "TSlotStack has a reference count relative to an index which will become negative"); + EXPECT_DEATH(theTest(), "TSlotStack has a reference count relative to an index which will become negative"); } #endif diff --git a/tree/dataframe/test/dataframe_resptr.cxx b/tree/dataframe/test/dataframe_resptr.cxx index 9fef6e54fcf3b..7c45f016d0caa 100644 --- a/tree/dataframe/test/dataframe_resptr.cxx +++ b/tree/dataframe/test/dataframe_resptr.cxx @@ -45,11 +45,11 @@ TEST(RResultPtr, ImplConv) return (int)1; }).Histo1D("i"); - EXPECT_TRUE(m); + EXPECT_TRUE(m != nullptr); EXPECT_FALSE(hasRun); *m; - EXPECT_TRUE(m); + EXPECT_TRUE(m != nullptr); EXPECT_TRUE(hasRun); } diff --git a/tree/dataframe/test/dataframe_simple.cxx b/tree/dataframe/test/dataframe_simple.cxx index 2bdbd36ee3960..67c1cbfb9513d 100644 --- a/tree/dataframe/test/dataframe_simple.cxx +++ b/tree/dataframe/test/dataframe_simple.cxx @@ -14,6 +14,7 @@ #include #include #include +#include using namespace ROOT; using namespace ROOT::RDF; @@ -513,6 +514,113 @@ TEST_P(RDFSimpleTests, BookCustomAction) EXPECT_EQ(*maxSlot, nWorkers-1); } +class StdDevTestHelper { +private: + std::default_random_engine fGenerator; + std::normal_distribution fDistribution; + std::vector samples; + +public: + void GenerateNumbers(int n) + { + std::vector numbers; + for (int i = 0; i < n; ++i) + numbers.push_back(fDistribution(fGenerator)); + samples = numbers; + } + + double stdDevFromDefinition() + { + // Calculating the Variance using the definition + int nSamples = samples.size(); + double mean = 0; + for (int i = 0; i < nSamples; ++i) { + mean += samples[i]; + } + mean = mean / nSamples; + + double varianceRight = 0; + + for (int i = 0; i < nSamples; ++i) { + varianceRight += std::pow((samples[i] - mean), 2); + } + varianceRight = varianceRight / (nSamples - 1); + return std::sqrt(varianceRight); + } + + double stdDevFromWelford() + { + ROOT::RDataFrame d(samples.size()); + return *d.DefineSlotEntry("x", + [this](unsigned int slot, ULong64_t entry) { + (void)slot; + return samples[entry]; + }) + .StdDev("x"); + } +}; + +TEST_P(RDFSimpleTests, StandardDeviation) +{ + RDataFrame rd1(8); + auto stdDev = rd1.StdDev("tdfentry_"); + EXPECT_DOUBLE_EQ(*stdDev, 2.4494897427831779); +} + +TEST_P(RDFSimpleTests, StandardDeviationPrecision) +{ + const int maxNSamples = 100; + const int step = 10; + const int nTrials = 1; + + StdDevTestHelper helper; + + for (int j = 2; j < maxNSamples; j += step) { + for (int i = 0; i < nTrials; ++i) { + auto varianceFromDef = helper.stdDevFromDefinition(); + auto varianceFromWel = helper.stdDevFromWelford(); + EXPECT_DOUBLE_EQ(varianceFromDef, varianceFromWel); + helper.GenerateNumbers(j); + } + } +} + +TEST_P(RDFSimpleTests, StandardDeviationCollections) +{ + RDataFrame tdf(3); + auto stdDev = tdf.Define("vector", + []() { + std::vector v(3); + v[0] = 0; + v[1] = 1; + v[2] = 2; + return v; + }) + .StdDev>("vector"); + EXPECT_DOUBLE_EQ(*stdDev, 0.86602540378443871); +} + +TEST_P(RDFSimpleTests, StandardDeviationZero) +{ + RDataFrame rd1(8); + auto stdDev = rd1.Define("b1", []() { return 0; }).StdDev("b1"); + EXPECT_DOUBLE_EQ(*stdDev, 0); +} + +TEST_P(RDFSimpleTests, StandardDeviationOne) +{ + RDataFrame rd1(1); + auto stdDev = rd1.Define("b1", []() { return 1; }).StdDev("b1"); + EXPECT_DOUBLE_EQ(*stdDev, 0); +} + +TEST_P(RDFSimpleTests, StandardDeviationEmpty) +{ + RDataFrame rd1(0); + auto stdDev = rd1.Define("b1", []() { return 0; }).StdDev("b1"); + EXPECT_DOUBLE_EQ(*stdDev, 0); +} + // run single-thread tests INSTANTIATE_TEST_CASE_P(Seq, RDFSimpleTests, ::testing::Values(false)); diff --git a/tree/dataframe/test/dataframe_snapshot.cxx b/tree/dataframe/test/dataframe_snapshot.cxx index 4002fa042db94..be178a6daa776 100644 --- a/tree/dataframe/test/dataframe_snapshot.cxx +++ b/tree/dataframe/test/dataframe_snapshot.cxx @@ -470,6 +470,15 @@ TEST(RDFSnapshotMore, Lazy) gSystem->Unlink(fname1); } +TEST(RDFSnapshotMore, LazyNotTriggered) +{ + { + auto d = ROOT::RDataFrame(1); + ROOT::RDF::RSnapshotOptions opts; + opts.fLazy = true; + d.Snapshot("t", "foo.root", {"tdfentry_"}, opts); + } +} /********* MULTI THREAD TESTS ***********/ #ifdef R__USE_IMT @@ -601,5 +610,63 @@ TEST(RDFSnapshotMore, TreeWithFriendsMT) gSystem->Unlink(outfname); } +TEST(RDFSnapshotMore, JittedSnapshotAndAliasedColumns) +{ + ROOT::RDataFrame df(1); + const auto fname = "out_aliasedcustomcolumn.root"; + // aliasing a custom column + auto df2 = df.Define("x", [] { return 42; }).Alias("y", "x").Snapshot("t", fname, "y"); // must be jitted! + EXPECT_EQ(df2->GetColumnNames(), std::vector({"y", "y.y"})); + EXPECT_EQ(df2->Take("y")->at(0), 42); + + // aliasing a column from a file + const auto fname2 = "out_aliasedcustomcolumn2.root"; + df2->Alias("z", "y").Snapshot("t", fname2, "z"); + + gSystem->Unlink(fname); + gSystem->Unlink(fname2); +} + + +TEST(RDFSnapshotMore, LazyNotTriggeredMT) +{ + ROOT::EnableImplicitMT(4); + const auto fname = "lazynottriggeredmt.root"; + { + auto d = ROOT::RDataFrame(8); + ROOT::RDF::RSnapshotOptions opts; + opts.fLazy = true; + d.Snapshot("t", fname, {"tdfentry_"}, opts); + } + + gSystem->Unlink(fname); + ROOT::DisableImplicitMT(); +} + +TEST(RDFSnapshotMore, EmptyBuffersMT) +{ + const auto fname = "emptybuffersmt.root"; + const auto treename = "t"; + ROOT::EnableImplicitMT(4); + ROOT::RDataFrame d(10); + auto dd = d.DefineSlot("x", [](unsigned int s) { return s == 3 ? 0 : 1; }) + .Filter([](int x) { return x == 0; }, {"x"}, "f"); + auto r = dd.Report(); + dd.Snapshot(treename, fname, {"x"}); + + // check test sanity + const auto passed = r->At("f").GetPass(); + EXPECT_GT(passed, 0u); + + // check result + TFile f(fname); + TTree *t = nullptr; + f.GetObject(treename, t); + EXPECT_EQ(t->GetListOfBranches()->GetEntries(), 1); + EXPECT_EQ(t->GetEntries(), Long64_t(passed)); + + ROOT::DisableImplicitMT(); + gSystem->Unlink(fname); +} #endif // R__USE_IMT diff --git a/tree/dataframe/test/dataframe_utils.cxx b/tree/dataframe/test/dataframe_utils.cxx index 2aefa0aba6e34..afd7a7059b47a 100644 --- a/tree/dataframe/test/dataframe_utils.cxx +++ b/tree/dataframe/test/dataframe_utils.cxx @@ -4,6 +4,8 @@ #include "gtest/gtest.h" +namespace RDFInt = ROOT::Internal::RDF; + // Thanks clang-format... TEST(RDataFrameUtils, DeduceAllPODsFromTmpColumns) { @@ -70,7 +72,7 @@ TEST(RDataFrameUtils, DeduceAllPODsFromColumns) {"vararrint.a", "ROOT::VecOps::RVec"}}; for (auto &nameType : nameTypes) { - auto typeName = ROOT::Internal::RDF::ColumnName2ColumnTypeName(nameType.first, /*nsID=*/0, &t, /*ds=*/nullptr, + auto typeName = RDFInt::ColumnName2ColumnTypeName(nameType.first, /*nsID=*/0, &t, /*ds=*/nullptr, /*custom=*/false); EXPECT_STREQ(nameType.second, typeName.c_str()); } @@ -98,7 +100,7 @@ TEST(RDataFrameUtils, DeduceTypeOfBranchesWithCustomTitle) {"vararrint.a", "ROOT::VecOps::RVec"}}; for (auto &nameType : nameTypes) { - auto typeName = ROOT::Internal::RDF::ColumnName2ColumnTypeName(nameType.first, /*nsID=*/0, &t, /*ds=*/nullptr, + auto typeName = RDFInt::ColumnName2ColumnTypeName(nameType.first, /*nsID=*/0, &t, /*ds=*/nullptr, /*custom=*/false); EXPECT_STREQ(nameType.second, typeName.c_str()); } @@ -108,14 +110,14 @@ TEST(RDataFrameUtils, CheckNonExistingCustomColumnNullTree) { // CheckCustomColumn(std::string_view definedCol, TTree *treePtr, const ColumnNames_t &customCols, // const ColumnNames_t &dataSourceColumns) - ROOT::Internal::RDF::CheckCustomColumn("Bla", nullptr, {"a", "b"}, {}); + RDFInt::CheckCustomColumn("Bla", nullptr, {"a", "b"}, {}); } TEST(RDataFrameUtils, CheckExistingCustomColumnNullTree) { int ret = 1; try { - ROOT::Internal::RDF::CheckCustomColumn("a", nullptr, {"a", "b"}, {}); + RDFInt::CheckCustomColumn("a", nullptr, {"a", "b"}, {}); } catch (const std::runtime_error &e) { ret = 0; } @@ -130,7 +132,7 @@ TEST(RDataFrameUtils, CheckExistingCustomColumn) int ret = 1; try { - ROOT::Internal::RDF::CheckCustomColumn("a", &t, {"b"}, {}); + RDFInt::CheckCustomColumn("a", &t, {"b"}, {}); } catch (const std::runtime_error &e) { ret = 0; } @@ -145,18 +147,18 @@ TEST(RDataFrameUtils, CheckExistingCustomColumnDataSource) int ret = 1; try { - ROOT::Internal::RDF::CheckCustomColumn("c", &t, {"b"}, {"c"}); + RDFInt::CheckCustomColumn("c", &t, {"b"}, {"c"}); } catch (const std::runtime_error &e) { ret = 0; } EXPECT_EQ(0, ret); } -TEST(RDataFrameUtils, CheckSnapshot) +TEST(RDataFrameUtils, CheckTypesAndPars) { int ret = 1; try { - ROOT::Internal::RDF::CheckSnapshot(5, 4); + RDFInt::CheckTypesAndPars(5, 4); } catch (const std::runtime_error &e) { ret = 0; } @@ -167,7 +169,7 @@ TEST(RDataFrameUtils, SelectColumnsNNamesDiffersRequiredNames) { int ret = 1; try { - ROOT::Internal::RDF::SelectColumns(3, {"a", "b"}, {}); + RDFInt::SelectColumns(3, {"a", "b"}, {}); } catch (const std::runtime_error &e) { ret = 0; } @@ -178,7 +180,7 @@ TEST(RDataFrameUtils, SelectColumnsTooFewRequiredNames) { int ret = 1; try { - ROOT::Internal::RDF::SelectColumns(3, {}, {"bla"}); + RDFInt::SelectColumns(3, {}, {"bla"}); } catch (const std::runtime_error &e) { ret = 0; } @@ -187,8 +189,8 @@ TEST(RDataFrameUtils, SelectColumnsTooFewRequiredNames) TEST(RDataFrameUtils, SelectColumnsCheckNames) { - ROOT::Internal::RDF::ColumnNames_t cols{"a", "b", "c"}; - auto ncols = ROOT::Internal::RDF::SelectColumns(2, {}, cols); + RDFInt::ColumnNames_t cols{"a", "b", "c"}; + auto ncols = RDFInt::SelectColumns(2, {}, cols); EXPECT_STREQ("a", ncols[0].c_str()); EXPECT_STREQ("b", ncols[1].c_str()); } @@ -199,7 +201,7 @@ TEST(RDataFrameUtils, FindUnknownColumns) TTree t("t", "t"); t.Branch("a", &i); - auto ncols = ROOT::Internal::RDF::FindUnknownColumns({"a", "b", "c", "d"}, &t, {"b"}, {}); + auto ncols = RDFInt::FindUnknownColumns({"a", "b", "c", "d"}, RDFInt::GetBranchNames(t), {"b"}, {}); EXPECT_STREQ("c", ncols[0].c_str()); EXPECT_STREQ("d", ncols[1].c_str()); } @@ -210,7 +212,7 @@ TEST(RDataFrameUtils, FindUnknownColumnsWithDataSource) TTree t("t", "t"); t.Branch("a", &i); - auto ncols = ROOT::Internal::RDF::FindUnknownColumns({"a", "b", "c", "d"}, &t, {"b"}, {"c"}); + auto ncols = RDFInt::FindUnknownColumns({"a", "b", "c", "d"}, RDFInt::GetBranchNames(t), {"b"}, {"c"}); EXPECT_EQ(ncols.size(), 1u); EXPECT_STREQ("d", ncols[0].c_str()); } @@ -226,7 +228,7 @@ TEST(RDataFrameUtils, FindUnknownColumnsNestedNames) DummyStruct s{1, 2}; t.Branch("s", &s, "a/I:b/I"); - auto unknownCols = ROOT::Internal::RDF::FindUnknownColumns({"s.a", "s.b", "s", "s.", ".s", "_asd_"}, &t, {}, {}); + auto unknownCols = RDFInt::FindUnknownColumns({"s.a", "s.b", "s", "s.", ".s", "_asd_"}, RDFInt::GetBranchNames(t), {}, {}); const auto trueUnknownCols = std::vector({"s", "s.", ".s", "_asd_"}); EXPECT_EQ(unknownCols, trueUnknownCols); } @@ -253,6 +255,6 @@ TEST(RDataFrameUtils, FindUnknownColumnsFriendTrees) t1.AddFriend(&t2); t1.AddFriend(&t4); - auto ncols = ROOT::Internal::RDF::FindUnknownColumns({"c2", "c3", "c4"}, &t1, {}, {}); + auto ncols = RDFInt::FindUnknownColumns({"c2", "c3", "c4"}, RDFInt::GetBranchNames(t1), {}, {}); EXPECT_EQ(ncols.size(), 0u) << "Cannot find column in friend trees."; } diff --git a/tree/tree/inc/TBranchElement.h b/tree/tree/inc/TBranchElement.h index 501029aa12d78..760628c54944b 100644 --- a/tree/tree/inc/TBranchElement.h +++ b/tree/tree/inc/TBranchElement.h @@ -38,8 +38,7 @@ class TVirtualCollectionIterators; class TVirtualCollectionPtrIterators; class TVirtualArray; -namespace TStreamerInfoActions { class TActionSequence; } - +#include "TStreamerInfoActions.h" class TBranchElement : public TBranch { @@ -90,8 +89,9 @@ class TBranchElement : public TBranch { TStreamerInfo *fInfo; /// fIDs; ///SetWriteMode(); } - buf->ResetMap(); + if (!TestBit(kDoNotUseBufferMap)) { + buf->ResetMap(); + } Int_t lnew = 0; Int_t nbytes = 0; diff --git a/tree/tree/src/TBranchElement.cxx b/tree/tree/src/TBranchElement.cxx index e0a850c92319e..c9f4c691e6d7b 100644 --- a/tree/tree/src/TBranchElement.cxx +++ b/tree/tree/src/TBranchElement.cxx @@ -148,6 +148,7 @@ TBranchElement::TBranchElement() , fObject(0) , fOnfileObject(0) , fInit(kFALSE) +, fInInitInfo(kFALSE) , fInitOffsets(kFALSE) , fTargetClass() , fCurrentClass() @@ -192,6 +193,7 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TStreamerInfo* si , fObject(0) , fOnfileObject(0) , fInit(kTRUE) +, fInInitInfo(kFALSE) , fInitOffsets(kFALSE) , fTargetClass(fClassName) , fCurrentClass() @@ -234,6 +236,7 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TStreamerInfo , fObject(0) , fOnfileObject(0) , fInit(kTRUE) +, fInInitInfo(kFALSE) , fInitOffsets(kFALSE) , fTargetClass( fClassName ) , fCurrentClass() @@ -646,6 +649,9 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TClonesArray* clo , fClassName("TClonesArray") , fParentName() , fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo()) +, fInit(kTRUE) +, fInInitInfo(kFALSE) +, fInitOffsets(kFALSE) , fTargetClass( fClassName ) , fCurrentClass() , fParentClass() @@ -670,6 +676,9 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TClonesArray* , fClassName("TClonesArray") , fParentName() , fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo()) +, fInit(kTRUE) +, fInInitInfo(kFALSE) +, fInitOffsets(kFALSE) , fTargetClass( fClassName ) , fCurrentClass() , fParentClass() @@ -789,6 +798,9 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TVirtualCollectio : TBranch() , fClassName(cont->GetCollectionClass()->GetName()) , fParentName() +, fInit(kTRUE) +, fInInitInfo(kFALSE) +, fInitOffsets(kFALSE) , fTargetClass( fClassName ) , fCurrentClass() , fParentClass() @@ -812,6 +824,9 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TVirtualColle : TBranch() , fClassName(cont->GetCollectionClass()->GetName()) , fParentName() +, fInit(kTRUE) +, fInInitInfo(kFALSE) +, fInitOffsets(kFALSE) , fTargetClass( fClassName ) , fCurrentClass() , fParentClass() @@ -1883,94 +1898,212 @@ char* TBranchElement::GetAddress() const return fAddress; } -//////////////////////////////////////////////////////////////////////////////// -/// Init the streamer info for the branch class, try to compensate for class -/// code unload/reload and schema evolution. -void TBranchElement::InitInfo() +// For a mother branch of type 3 or 4, find the 'correct' StreamerInfo for the +// content of the collection by find a sub-branch corresponding to a direct data member +// of the containee class (valueClass) +// Default to the current StreamerInfo if none are found. +TStreamerInfo *TBranchElement::FindOnfileInfo(TClass *valueClass, const TObjArray &branches) const { - if (!fInfo) { - // We did not already have streamer info, so now we must find it. - TClass* cl = fBranchClass.GetClass(); + TStreamerInfo *localInfo = nullptr; + + // Search for the correct version. + for(auto subbe : TRangeDynCast( branches )) { + if (!subbe->fInfo) + subbe->SetupInfo(); + if (valueClass == subbe->fInfo->GetClass()) { // Use GetInfo to provoke its creation. + localInfo = subbe->fInfo; + break; + } + } + if (!localInfo) { + // This is likely sub-optimal as we really should call GetFile but it is non-const. + auto file = fDirectory ? fDirectory->GetFile() : nullptr; + if (file && file->GetSeekInfo()) { + localInfo = (TStreamerInfo*)file->GetStreamerInfoCache()->FindObject(valueClass->GetName()); + if (localInfo) { + if (valueClass->IsVersioned()) { + localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion()); + } else { + localInfo = (TStreamerInfo*)valueClass->FindStreamerInfo(localInfo->GetCheckSum()); + if (localInfo) { + // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo). + localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion()); + } + } + } + } + } + if (!localInfo) + localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(); + return localInfo; +} - //------------------------------------------------------------------------ - // Check if we're dealing with the name change - ////////////////////////////////////////////////////////////////////////// +namespace { + static void GatherArtificialElements(const TObjArray &branches, TStreamerInfoActions::TIDs &ids, TString prefix, TStreamerInfo *info, Int_t offset) { + size_t ndata = info->GetNelement(); + for (size_t i =0; i < ndata; ++i) { + TStreamerElement *nextel = info->GetElement(i); - TClass* targetClass = 0; - if( fTargetClass.GetClassName()[0] ) { - targetClass = fTargetClass; - if (!targetClass && GetCollectionProxy()) { - // We are in the case where the branch holds a custom collection - // proxy but the dictionary is not loaded, calling - // GetCollectionProxy had the side effect of creating the TClass - // corresponding to this emulated collection. - targetClass = fTargetClass; - } - if ( !targetClass ) { - Error( "InitInfo", "The target class dictionary is not present!" ); - return; - } - } else { - targetClass = cl; + if (nextel->GetType() == TStreamerInfo::kCacheDelete + || nextel->GetType() == TStreamerInfo::kCacheNew) { + continue; } - if (cl) { - //--------------------------------------------------------------------- - // Get the streamer info for given version - /////////////////////////////////////////////////////////////////////// - { - if ( (cl->Property() & kIsAbstract) && cl == targetClass) { - TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this); - if (parent && parent != this && !parent->GetClass()->IsLoaded() ) { - // Our parent's class is emulated and we represent an abstract class. - // and the target class has not been set explicilty. - TString target = cl->GetName(); - target += "@@emulated"; - fTargetClass.SetName(target); - - if (!fTargetClass) { - cl->GetStreamerInfoAbstractEmulated(fClassVersion); - } - targetClass = fTargetClass; - } + TString ename = prefix + nextel->GetName(); + + if (ename[0]=='*') + ename.Remove(0,1); + + Ssiz_t pos; + while ((pos = ename.Last('[')) != TString::kNPOS) { + ename = ename.Remove(pos); + } + + if (nextel->IsA() == TStreamerArtificial::Class() + && branches.FindObject(ename) == nullptr) { + + ids.push_back(i); + ids.back().fElement = nextel; + ids.back().fInfo = info; + } + + if (nextel->CannotSplit()) + continue; + + TClass *elementClass = nextel->GetClassPointer(); + TBranchElement *be = (TBranchElement*)branches.FindObject(ename); + if (elementClass && (!be || be->GetType() == -2)) { + TStreamerInfo *nextinfo = nullptr; + + // nextinfo_version = .... + auto search = be ? be->GetListOfBranches() : &branches; + TVirtualArray *onfileObject = nullptr; + for(auto subbe : TRangeDynCast( *search )) { + + if (elementClass == subbe->GetInfo()->GetClass()) { // Use GetInfo to provoke its creation. + nextinfo = subbe->GetInfo(); + onfileObject = subbe->GetOnfileObject(); + break; } - if( targetClass != cl ) { - fInfo = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fClassVersion ); - } else { - fInfo = (TStreamerInfo*)cl->GetStreamerInfo(fClassVersion); + } + if (!nextinfo) { + nextinfo = (TStreamerInfo *)elementClass->GetStreamerInfo(); + if (elementClass->GetCollectionProxy() && elementClass->GetCollectionProxy()->GetValueClass()) { + nextinfo = (TStreamerInfo *)elementClass->GetCollectionProxy()->GetValueClass()->GetStreamerInfo(); // NOTE: need to find the right version } } + ids.emplace_back(nextinfo, offset + nextel->GetOffset()); + ids.back().fNestedIDs->fOnfileObject = onfileObject; + GatherArtificialElements(branches, ids.back().fNestedIDs->fIDs, ename + ".", nextinfo, offset + nextel->GetOffset()); + if (ids.back().fNestedIDs->fIDs.empty()) + ids.pop_back(); + } + } +}; +} // Anonymous namespace. - // FIXME: Check that the found streamer info checksum matches our branch class checksum here. - // Check to see if the class code was unloaded/reloaded - // since we were created. - R__LOCKGUARD(gInterpreterMutex); - if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) { - // Try to compensate for a class that got unloaded on us. - // Search through the streamer infos by checksum - // and take the first match. - - TStreamerInfo* info; - if( targetClass != cl ) - info = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fCheckSum ); - else { - info = (TStreamerInfo*)cl->FindStreamerInfo( fCheckSum ); - if (info) { - // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo). - info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion()); + +//////////////////////////////////////////////////////////////////////////////// +/// Set the value of fInfo. This is part one of InitInfo. +/// To be used as: +/// if (!fInfo) +/// SetupInfo(); +/// It would only be used within InitInfo (and its callees) + +void TBranchElement::SetupInfo() +{ + // We did not already have streamer info, so now we must find it. + TClass* cl = fBranchClass.GetClass(); + + //------------------------------------------------------------------------ + // Check if we're dealing with the name change + ////////////////////////////////////////////////////////////////////////// + + TClass* targetClass = 0; + if( fTargetClass.GetClassName()[0] ) { + targetClass = fTargetClass; + if (!targetClass && GetCollectionProxy()) { + // We are in the case where the branch holds a custom collection + // proxy but the dictionary is not loaded, calling + // GetCollectionProxy had the side effect of creating the TClass + // corresponding to this emulated collection. + targetClass = fTargetClass; + } + if ( !targetClass ) { + Error( "InitInfo", "The target class dictionary is not present!" ); + return; + } + } else { + targetClass = cl; + } + if (cl) { + //--------------------------------------------------------------------- + // Get the streamer info for given version + /////////////////////////////////////////////////////////////////////// + + { + if ( (cl->Property() & kIsAbstract) && cl == targetClass) { + TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this); + if (parent && parent != this && !parent->GetClass()->IsLoaded() ) { + // Our parent's class is emulated and we represent an abstract class. + // and the target class has not been set explicilty. + TString target = cl->GetName(); + target += "@@emulated"; + fTargetClass.SetName(target); + + if (!fTargetClass) { + cl->GetStreamerInfoAbstractEmulated(fClassVersion); } + targetClass = fTargetClass; } - if( info ) { - fInfo = info; - // We no longer reset the class version so that in case the user is passing us later - // the address of a class that require (another) Conversion we can find the proper - // StreamerInfo. - // fClassVersion = fInfo->GetClassVersion(); + } + if( targetClass != cl ) { + fInfo = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fClassVersion ); + } else { + fInfo = (TStreamerInfo*)cl->GetStreamerInfo(fClassVersion); + } + } + + // FIXME: Check that the found streamer info checksum matches our branch class checksum here. + // Check to see if the class code was unloaded/reloaded + // since we were created. + R__LOCKGUARD(gInterpreterMutex); + if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) { + // Try to compensate for a class that got unloaded on us. + // Search through the streamer infos by checksum + // and take the first match. + + TStreamerInfo* info; + if( targetClass != cl ) + info = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fCheckSum ); + else { + info = (TStreamerInfo*)cl->FindStreamerInfo( fCheckSum ); + if (info) { + // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo). + info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion()); } } + if( info ) { + fInfo = info; + // We no longer reset the class version so that in case the user is passing us later + // the address of a class that require (another) Conversion we can find the proper + // StreamerInfo. + // fClassVersion = fInfo->GetClassVersion(); + } } } +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Init the streamer info for the branch class, try to compensate for class +/// code unload/reload and schema evolution. + +void TBranchElement::InitInfo() +{ + if (!fInfo) + SetupInfo(); // // Fixup cached streamer info if necessary. @@ -1984,12 +2117,87 @@ void TBranchElement::InitInfo() Error("InitInfo","StreamerInfo is not compiled."); } + // return immediately if we are called recursively. + if (fInInitInfo) + return; + fInInitInfo = kTRUE; if (!fInit) { // We were read in from a file, figure out what our fID should be, // schema evolution must be considered. // // Force our fID to be the id of the first streamer element that matches our name. // + auto SetOnfileObject = [this](TStreamerInfo *info) { + Int_t arrlen = 1; + if (fType==31 || fType==41) { + TLeaf *leaf = (TLeaf*)fLeaves.At(0); + if (leaf) { + arrlen = leaf->GetMaximum(); + } + } + Bool_t toplevel = (fType == 3 || fType == 4 || (fType == 0 && fID == -2)); + Bool_t seenExisting = kFALSE; + + fOnfileObject = new TVirtualArray( info->GetElement(0)->GetClassPointer(), arrlen ); + // Propage this to all the other branch of this type. + TObjArray *branches = toplevel ? GetListOfBranches() : GetMother()->GetSubBranch(this)->GetListOfBranches(); + Int_t nbranches = branches->GetEntriesFast(); + TBranchElement *lastbranch = this; + + TClass *currentClass = fBranchClass; + auto currentVersion = fClassVersion; + if (toplevel) { + // Note: Fragile/wrong when using conversion StreamerInfo? + currentClass = info->GetClass(); + currentVersion = info->GetClassVersion(); + } + + for (Int_t i = 0; i < nbranches; ++i) { + TBranchElement* subbranch = (TBranchElement*)branches->At(i); + Bool_t match = kFALSE; + if (this != subbranch) { + + if (!subbranch->fInfo) + subbranch->SetupInfo(); + + if (subbranch->fInfo == info) + match = kTRUE; + else if (subbranch->fInfo == nullptr && subbranch->fBranchClass == currentClass) { + if (!toplevel) { + if (subbranch->fCheckSum == fCheckSum) + match = kTRUE; + } else { + if (!subbranch->fBranchClass->IsForeign() && subbranch->fClassVersion == currentVersion) + match = kTRUE; + else if (subbranch->fCheckSum == info->GetCheckSum()) { + match = kTRUE; + } + } + } + } + if (match) { + if (subbranch->fOnfileObject && subbranch->fOnfileObject != fOnfileObject) { + if (seenExisting) { + Error("SetOnfileObject (lambda)", "2 distincts fOnfileObject are in the hierarchy of %s for type %s", + toplevel ? GetName() : GetMother()->GetSubBranch(this)->GetName(), info->GetName()); + } else { + delete fOnfileObject; + fOnfileObject = subbranch->fOnfileObject; + seenExisting = kTRUE; + } + } + subbranch->fOnfileObject = fOnfileObject; + lastbranch = subbranch; + } + } + if (toplevel) { + SetBit(kOwnOnfileObj); + if (lastbranch != this) + lastbranch->ResetBit(kOwnOnfileObj); + } else { + lastbranch->SetBit(kOwnOnfileObj); + } + }; if (GetID() > -1) { // We are *not* a top-level branch. std::string s(GetName()); @@ -2004,7 +2212,7 @@ void TBranchElement::InitInfo() TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(), offset); if (elt && offset!=TStreamerInfo::kMissing) { size_t ndata = fInfo->GetNelement(); - fIDs.clear(); + fNewIDs.clear(); for (size_t i = 0; i < ndata; ++i) { if (fInfo->GetElement(i) == elt) { if (elt->TestBit (TStreamerElement::kCache) @@ -2017,10 +2225,16 @@ void TBranchElement::InitInfo() // ReadLeaves). // fID = i+1; fID = i; - if (elt->TestBit(TStreamerElement::kRepeat)) { - fIDs.push_back(fID+1); - } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) { - fIDs.push_back(fID+1); + if (fType != 2) { + if (elt->TestBit(TStreamerElement::kRepeat)) { + fNewIDs.push_back(fID+1); + fNewIDs.back().fElement = fInfo->GetElement(i+1); + fNewIDs.back().fInfo = fInfo; + } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) { + fNewIDs.push_back(fID+1); + fNewIDs.back().fElement = fInfo->GetElement(i+1); + fNewIDs.back().fInfo = fInfo; + } } } else { fID = i; @@ -2031,8 +2245,21 @@ void TBranchElement::InitInfo() break; } } - for (size_t i = fID+1+(fIDs.size()); i < ndata; ++i) { + for (size_t i = fID+1+(fNewIDs.size()); i < ndata; ++i) { TStreamerElement *nextel = fInfo->GetElement(i); + + std::string ename = nextel->GetName(); + if (ename[0] == '*') + ename = ename.substr(1); + + while ((pos = ename.rfind('[')) != std::string::npos) { + ename = ename.substr(0, pos); + } + + if (s != ename) { + // We moved on to the next set + break; + } // Add all (and only) the Artificial Elements that follows this StreamerInfo. // fprintf(stderr,"%s/%d[%zu] passing trhough %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName()); if (fType==31||fType==41) { @@ -2052,16 +2279,18 @@ void TBranchElement::InitInfo() } if (nextel->IsA() != TStreamerArtificial::Class() || nextel->GetType() == TStreamerInfo::kCacheDelete ) { - break; + continue; } // NOTE: We should verify that the rule's source are 'before' // or 'at' this branch. // fprintf(stderr,"%s/%d[%zu] pushd %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName()); - fIDs.push_back(i); + fNewIDs.push_back(i); + fNewIDs.back().fElement = nextel; + fNewIDs.back().fInfo = fInfo; } } else if (elt && offset==TStreamerInfo::kMissing) { // Still re-assign fID properly. - fIDs.clear(); + fNewIDs.clear(); size_t ndata = fInfo->GetNelement(); for (size_t i = 0; i < ndata; ++i) { if (fInfo->GetElement(i) == elt) { @@ -2071,34 +2300,43 @@ void TBranchElement::InitInfo() } } else { // We have not even found the element .. this is strange :( - // fIDs.clear(); + // fNewIDs.clear(); // fID = -3; // SetBit(kDoNotProcess); } if (fOnfileObject==0 && (fType==31 || fType==41 || (0 <= fType && fType <=2) ) && fInfo->GetNelement() && fInfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew) { - Int_t arrlen = 1; - if (fType==31 || fType==41) { - TLeaf *leaf = (TLeaf*)fLeaves.At(0); - if (leaf) { - arrlen = leaf->GetMaximum(); - } - } - fOnfileObject = new TVirtualArray( fInfo->GetElement(0)->GetClassPointer(), arrlen ); - // Propage this to all the other branch of this type. - TObjArray *branches = GetMother()->GetSubBranch(this)->GetListOfBranches(); - Int_t nbranches = branches->GetEntriesFast(); - TBranchElement *lastbranch = this; - for (Int_t i = 0; i < nbranches; ++i) { - TBranchElement* subbranch = (TBranchElement*)branches->At(i); - if (this!=subbranch && subbranch->fBranchClass == fBranchClass && subbranch->fCheckSum == fCheckSum) { - subbranch->fOnfileObject = fOnfileObject; - lastbranch = subbranch; - } + SetOnfileObject(fInfo); + } + } + if (fType == 3 || fType == 4 || (fType == 0 && fID == -2)) { + // Need to add the rule targetting transient members. + TStreamerInfo *localInfo = fInfo; + if (fType == 3 || fType == 4) { + // Don't we have real version information? + // Not unless there is a subbranch with a non-split element of the class. + // Search for the correct version. + localInfo = FindOnfileInfo(fClonesClass, fBranches); + } + + TString prefix(GetName()); + if (prefix[prefix.Length()-1] != '.') { + if (fType == 3 || fType == 4) { + prefix += "."; + } else { + prefix = ""; } - lastbranch->SetBit(kOwnOnfileObj); } + fNewIDs.clear(); + + GatherArtificialElements(fBranches, fNewIDs, prefix, localInfo, 0); + + if (!fNewIDs.empty() && fOnfileObject == nullptr && localInfo->GetElement(0)->GetType() == TStreamerInfo::kCacheNew) + { + SetOnfileObject(localInfo); + } + } fInit = kTRUE; @@ -2112,6 +2350,7 @@ void TBranchElement::InitInfo() } SetReadLeavesPtr(); SetFillLeavesPtr(); + fInInitInfo = kFALSE; } } @@ -2320,6 +2559,45 @@ Int_t TBranchElement::GetEntry(Long64_t entry, Int_t getall) } break; } + if (!TestBit(kDecomposedObj) && fReadActionSequence && !fReadActionSequence->fActions.empty()) { + if (fType == 3) { + // Apply the unattached rules; by definition they do not need any + // input from a buffer. + TBufferFile b(TBufferFile::kRead, 1); + + auto ndata = GetNdata(); + + TClonesArray* clones = (TClonesArray*) fObject; + if (clones->IsZombie()) { + return -1; + } + R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata); + + char **arr = (char **)clones->GetObjectRef(); + char **end = arr + fNdata; + + b.ApplySequenceVecPtr(*fReadActionSequence,arr,end); + } else if (fType == 4) { + // Apply the unattached rules; by definition they do not need any + // input from a buffer. + TBufferFile b(TBufferFile::kRead, 1); + + auto ndata = GetNdata(); + + R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata); + TVirtualCollectionProxy *proxy = GetCollectionProxy(); + TVirtualCollectionProxy::TPushPop helper(proxy, fObject); + + TVirtualCollectionIterators *iter = fIterators; + b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd); + } else { + // Apply the unattached rules; by definition they do not need any + // input from a buffer. + TBufferFile b(TBufferFile::kRead, 1); + R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata); + b.ApplySequence(*fReadActionSequence, fObject); + } + } } else { // -- Terminal branch. if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) { @@ -3263,6 +3541,15 @@ void TBranchElement::InitializeOffsets() } } } + const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty(); + if (fReadActionSequence && isSplitNode) { + TBranchElement *parent = dynamic_cast(GetMother()->GetSubBranch(this)); + auto index = parent->fBranches.IndexOf(this); + if (index >= 0) { + fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] ); + } + } + fInitOffsets = kTRUE; } @@ -3327,6 +3614,19 @@ Bool_t TBranchElement::IsMissingCollection() const //////////////////////////////////////////////////////////////////////////////// /// Print branch parameters. +static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions::TIDs &ids) +{ + for(auto &cursor : ids) { + auto id = cursor.fElemID; + if (id >= 0) + info->GetElement(id)->ls(); + else if (cursor.fNestedIDs) { + Printf(" With subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset); + PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs); + } + } +} + void TBranchElement::Print(Option_t* option) const { Int_t nbranches = fBranches.GetEntriesFast(); @@ -3356,10 +3656,29 @@ void TBranchElement::Print(Option_t* option) const if (strncmp(option,"debugInfo",strlen("debugInfo"))==0) { Printf("Branch %s uses:",GetName()); if (fID>=0) { - GetInfoImp()->GetElement(fID)->ls(); - for(UInt_t i=0; i< fIDs.size(); ++i) { - GetInfoImp()->GetElement(fIDs[i])->ls(); + // GetInfoImp()->GetElement(fID)->ls(); + // for(UInt_t i=0; i< fIDs.size(); ++i) { + // GetInfoImp()->GetElement(fIDs[i])->ls(); + // } + TStreamerInfo *localInfo = GetInfoImp(); + if (fType == 3 || fType == 4) { + // Search for the correct version. + localInfo = FindOnfileInfo(fClonesClass, fBranches); + } + Printf(" With new ids:"); + if (fType != 3 && fType != 4) + localInfo->GetElement(fID)->ls(); + PrintElements(localInfo, fNewIDs); + Printf(" with read actions:"); + if (fReadActionSequence) fReadActionSequence->Print(option); + Printf(" with write actions:"); + if (fFillActionSequence) fFillActionSequence->Print(option); + } else if (!fNewIDs.empty() && GetInfoImp()) { + TStreamerInfo *localInfo = GetInfoImp(); + if (fType == 3 || fType == 4) { + localInfo = (TStreamerInfo *)fClonesClass->GetStreamerInfo(); } + PrintElements(localInfo, fNewIDs); Printf(" with read actions:"); if (fReadActionSequence) fReadActionSequence->Print(option); Printf(" with write actions:"); @@ -3863,15 +4182,6 @@ void TBranchElement::ReadLeavesCollectionSplitPtrMember(TBuffer& b) // R__ASSERT(0); TVirtualCollectionPtrIterators *iter = fBranchCount->fPtrIterators; b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd); - - // char **arr = (char **)proxy->At(0); - // char **end = arr + proxy->Size(); - // fReadActionSequence->ReadBufferVecPtr(b,arr,end); - - // info->ReadBufferSTLPtrs(b, proxy, fNdata, fID, fOffset); - // for(UInt_t ii=0; ii < fIDs.size(); ++ii) { - // info->ReadBufferSTLPtrs(b, proxy, fNdata, fIDs[ii], fOffset); - // } } //////////////////////////////////////////////////////////////////////////////// @@ -5035,9 +5345,40 @@ void TBranchElement::SetOffset(Int_t offset) fOffset = offset; } + //////////////////////////////////////////////////////////////////////////////// /// Set the sequence of actions needed to read the data out of the buffer. +void TBranchElement::SetActionSequence(TClass *originalClass, TStreamerInfo *localInfo, TStreamerInfoActions::TActionSequence::SequenceGetter_t create, TStreamerInfoActions::TActionSequence *&actionSequence) +{ + // A 'split' node does not store data itself (it has not associated baskets) + const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty(); + + if (!isSplitNode) { + fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence. + } + if (actionSequence) delete actionSequence; + auto original = create(localInfo, GetCollectionProxy(), originalClass); + + actionSequence = original->CreateSubSequence(fNewIDs, fOffset, create); + + if (!isSplitNode) + fNewIDs.erase(fNewIDs.begin()); + else { + // fObject has the address of the sub-object but the streamer action have + // offset relative to the parent. + TBranchElement *parent = dynamic_cast(GetMother()->GetSubBranch(this)); + if (fInitOffsets) { + auto index = parent->fBranches.IndexOf(this); + if (index >= 0) { + fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] ); + } + } // else it will be done by InitOffsets + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set the sequence of actions needed to read the data out of the buffer. void TBranchElement::SetReadActionSequence() { if (fInfo == 0) { @@ -5045,40 +5386,42 @@ void TBranchElement::SetReadActionSequence() return; } - // Get the action sequence we need to copy for reading. - TStreamerInfoActions::TActionSequence *original = 0; - TStreamerInfoActions::TActionSequence *transient = 0; + TStreamerInfoActions::TActionSequence::SequenceGetter_t create = nullptr; + TClass *originalClass = nullptr; + TStreamerInfo *localInfo = fInfo; if (fType == 41) { if( fSplitLevel >= TTree::kSplitCollectionOfPointers && fBranchCount->fSTLtype == ROOT::kSTLvector) { - original = fInfo->GetReadMemberWiseActions(kTRUE); + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionGetter; } else { TVirtualStreamerInfo *info = GetInfoImp(); if (GetParentClass() == info->GetClass()) { if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) { - original = GetCollectionProxy()->GetConversionReadMemberWiseActions(fBranchClass.GetClass(), fClassVersion); + originalClass = fBranchClass; + create = TStreamerInfoActions::TActionSequence::ConversionReadMemberWiseActionsViaProxyGetter; } else { - original = GetCollectionProxy()->GetReadMemberWiseActions(fClassVersion); + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsViaProxyGetter; } } else if (GetCollectionProxy()) { // Base class and embedded objects. - - transient = TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(info,*GetCollectionProxy()); - original = transient; + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionCreator; } } } else if (fType == 31) { - original = fInfo->GetReadMemberWiseActions(kTRUE); + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionGetter; } else if (0<=fType && fType<=2) { // Note: this still requires the ObjectWise sequence to not be optimized! - original = fInfo->GetReadMemberWiseActions(kFALSE); + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsGetter; + } else if ( fType == 4 && !fNewIDs.empty()) { + localInfo = FindOnfileInfo(fClonesClass, fBranches); + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionCreator; + } else if ( fType == 3 && !fNewIDs.empty()) { + localInfo = FindOnfileInfo(fClonesClass, fBranches); + create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionGetter; } - if (original) { - fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence. - if (fReadActionSequence) delete fReadActionSequence; - fReadActionSequence = original->CreateSubSequence(fIDs,fOffset); - fIDs.erase(fIDs.begin()); + + if (create) { + SetActionSequence(originalClass, localInfo, create, fReadActionSequence); } - delete transient; } //////////////////////////////////////////////////////////////////////////////// @@ -5143,41 +5486,42 @@ void TBranchElement::SetFillActionSequence() return; } - // Get the action sequence we need to copy for reading. - TStreamerInfoActions::TActionSequence *original = 0; - TStreamerInfoActions::TActionSequence *transient = 0; + TStreamerInfoActions::TActionSequence::SequenceGetter_t create = nullptr; + TClass *originalClass = nullptr; + TStreamerInfo *localInfo = fInfo; if (fType == 41) { if( fSplitLevel >= TTree::kSplitCollectionOfPointers && fBranchCount->fSTLtype == ROOT::kSTLvector) { - original = fInfo->GetWriteMemberWiseActions(kTRUE); + create = TStreamerInfoActions::TActionSequence::WriteMemberWiseActionsCollectionGetter; } else { TVirtualStreamerInfo *info = GetInfoImp(); if (GetParentClass() == info->GetClass()) { - //if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) { - // original = GetCollectionProxy()->GetConversionWriteMemberWiseActions(fBranchClass.GetClass()); - //} else { - original = GetCollectionProxy()->GetWriteMemberWiseActions(); - //} + // if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) { + // originalClass = fBranchClass; + // create = TStreamerInfoActions::TActionSequence::ConversionWriteMemberWiseActionsViaProxyGetter; + // } else { + create = TStreamerInfoActions::TActionSequence::WriteMemberWiseActionsViaProxyGetter; + // } } else if (GetCollectionProxy()) { // Base class and embedded objects. - - transient = TStreamerInfoActions::TActionSequence::CreateWriteMemberWiseActions(info,*GetCollectionProxy()); - original = transient; + create = TStreamerInfoActions::TActionSequence::WriteMemberWiseActionsCollectionCreator; } } } else if (fType == 31) { - original = fInfo->GetWriteMemberWiseActions(kTRUE); + create = TStreamerInfoActions::TActionSequence::WriteMemberWiseActionsCollectionGetter; } else if (0<=fType && fType<=2) { // Note: this still requires the ObjectWise sequence to not be optimized! - original = fInfo->GetWriteMemberWiseActions(kFALSE); - } - if (original) { - fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence. - if (fFillActionSequence) delete fFillActionSequence; - fFillActionSequence = original->CreateSubSequence(fIDs,fOffset); - fIDs.erase(fIDs.begin()); + create = TStreamerInfoActions::TActionSequence::WriteMemberWiseActionsGetter; + } else if ( fType == 4 && !fNewIDs.empty()) { + localInfo = FindOnfileInfo(fClonesClass, fBranches); + create = TStreamerInfoActions::TActionSequence::WriteMemberWiseActionsCollectionCreator; + } else if ( fType == 3 && !fNewIDs.empty()) { + localInfo = FindOnfileInfo(fClonesClass, fBranches); + create = TStreamerInfoActions::TActionSequence::WriteMemberWiseActionsCollectionGetter; } - delete transient; + if (create) { + SetActionSequence(originalClass, localInfo, create, fFillActionSequence); + } } //////////////////////////////////////////////////////////////////////////////// @@ -5356,6 +5700,7 @@ void TBranchElement::Streamer(TBuffer& R__b) fLeaves.Add(leaf); fTree->GetListOfLeaves()->Add(leaf); } + // SetReadLeavesPtr(); } else { @@ -5442,6 +5787,113 @@ void TBranchElement::Streamer(TBuffer& R__b) } } + +//////////////////////////////////////////////////////////////////////////////// +/// Split class cl into sub-branches of this branch. +/// +/// This version of Unroll was formerly embedded in TTree::BronchExec +/// It is moved here so we can make sure to call SetReadActionSequence. + +void TBranchElement::Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, char* objptr, Int_t bufsize, Int_t splitlevel) +{ + // + // Do we have a final dot in our name? + // + + // Note: The branch constructor which takes a folder as input + // creates top-level branch names with dots in them to + // indicate the folder hierarchy. + char* dot = (char*) strchr(name, '.'); + Int_t nch = strlen(name); + Bool_t dotlast = kFALSE; + if (nch && (name[nch-1] == '.')) { + dotlast = kTRUE; + } + + // Loop on all public data members of the class and its base classes and create branches for each one. + TObjArray* blist = this->GetListOfBranches(); + TIter next(sinfo->GetElements()); + TStreamerElement* element = 0; + TString bname; + for (Int_t id = 0; (element = (TStreamerElement*) next()); ++id) { + if (element->IsA() == TStreamerArtificial::Class()) { + continue; + } + if (element->TestBit(TStreamerElement::kRepeat)) { + continue; + } + if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) { + continue; + } + char* pointer = (char*) (objptr + element->GetOffset()); + // FIXME: This is not good enough, an STL container can be + // a base, and the test will fail. + // See TBranchElement::InitializeOffsets() for the + // correct test. + Bool_t isBase = (element->IsA() == TStreamerBase::Class()); + if (isBase) { + TClass* clbase = element->GetClassPointer(); + if ((clbase == TObject::Class()) && cl->CanIgnoreTObjectStreamer()) { + // Note: TStreamerInfo::Compile() leaves this element + // out of the optimized info, although it does + // exists in the non-compiled and non-optimized info. + // FIXME: The test that TStreamerInfo::Compile() uses + // is element->GetType() < 0, so that is what + // we should do as well. + continue; + } + if (clbase->GetListOfRealData()->GetSize() == 0) { + // Do not create a branch for empty bases. + continue; + } + } + if (dot) { + if (dotlast) { + bname.Form("%s%s", name, element->GetFullName()); + } else { + // FIXME: We are in the case where we have a top-level + // branch name that was created by the branch + // constructor which takes a folder as input. + // The internal dots in the name are in place of + // of the original slashes and represent the + // folder hierarchy. + if (isBase) { + // FIXME: This is very strange, this is the only case where + // we create a branch for a base class that does + // not have the base class name in the branch name. + // FIXME: This is also quite bad since classes with two + // or more base classes end up with sub-branches + // that have the same name. + bname = name; + } else { + bname.Form("%s.%s", name, element->GetFullName()); + } + } + } else { + // Note: For a base class element, this results in the branchname + // being the name of the base class. + bname.Form("%s", element->GetFullName()); + } + + if( splitlevel > TTree::kSplitCollectionOfPointers && element->GetClass() && + element->GetClass()->GetCollectionProxy() && + element->GetClass()->GetCollectionProxy()->HasPointers() ) + { + TBranchSTL* brSTL = new TBranchSTL(this, bname, element->GetClass()->GetCollectionProxy(), bufsize, splitlevel-1, sinfo, id ); + blist->Add(brSTL); + } + else + { + TBranchElement* bre = new TBranchElement(this, bname, sinfo, id, pointer, bufsize, splitlevel - 1); + bre->SetParentClass(cl); + blist->Add(bre); + } + } + // Now that we know that this branch is split, let's redo the actions. + SetReadActionSequence(); + SetFillActionSequence(); +} + //////////////////////////////////////////////////////////////////////////////// /// Split class cl into sub-branches of this branch. /// @@ -5672,6 +6124,11 @@ Int_t TBranchElement::Unroll(const char* name, TClass* clParent, TClass* cl, cha } } + if (!fBranches.IsEmpty()) { + // Refresh this branch's action now that we know whether it is split or not. + SetReadActionSequence(); + SetFillActionSequence(); + } return 1; } diff --git a/tree/tree/src/TTree.cxx b/tree/tree/src/TTree.cxx index 8e9b66be1404d..4d2202dc9bd32 100644 --- a/tree/tree/src/TTree.cxx +++ b/tree/tree/src/TTree.cxx @@ -2425,20 +2425,6 @@ TBranch* TTree::BronchExec(const char* name, const char* classname, void* addr, return 0; } - // - // Do we have a final dot in our name? - // - - // Note: The branch constructor which takes a folder as input - // creates top-level branch names with dots in them to - // indicate the folder hierarchy. - char* dot = (char*) strchr(name, '.'); - Int_t nch = strlen(name); - Bool_t dotlast = kFALSE; - if (nch && (name[nch-1] == '.')) { - dotlast = kTRUE; - } - // // Create a dummy top level branch object. // @@ -2455,85 +2441,7 @@ TBranch* TTree::BronchExec(const char* name, const char* classname, void* addr, // if (splitlevel%kSplitCollectionOfPointers > 0) { - // Loop on all public data members of the class and its base classes and create branches for each one. - TObjArray* blist = branch->GetListOfBranches(); - TIter next(sinfo->GetElements()); - TStreamerElement* element = 0; - TString bname; - for (id = 0; (element = (TStreamerElement*) next()); ++id) { - if (element->IsA() == TStreamerArtificial::Class()) { - continue; - } - if (element->TestBit(TStreamerElement::kRepeat)) { - continue; - } - if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) { - continue; - } - char* pointer = (char*) (objptr + element->GetOffset()); - // FIXME: This is not good enough, an STL container can be - // a base, and the test will fail. - // See TBranchElement::InitializeOffsets() for the - // correct test. - Bool_t isBase = (element->IsA() == TStreamerBase::Class()); - if (isBase) { - TClass* clbase = element->GetClassPointer(); - if ((clbase == TObject::Class()) && cl->CanIgnoreTObjectStreamer()) { - // Note: TStreamerInfo::Compile() leaves this element - // out of the optimized info, although it does - // exists in the non-compiled and non-optimized info. - // FIXME: The test that TStreamerInfo::Compile() uses - // is element->GetType() < 0, so that is what - // we should do as well. - continue; - } - if (clbase->GetListOfRealData()->GetSize() == 0) { - // Do not create a branch for empty bases. - continue; - } - } - if (dot) { - if (dotlast) { - bname.Form("%s%s", name, element->GetFullName()); - } else { - // FIXME: We are in the case where we have a top-level - // branch name that was created by the branch - // constructor which takes a folder as input. - // The internal dots in the name are in place of - // of the original slashes and represent the - // folder hierarchy. - if (isBase) { - // FIXME: This is very strange, this is the only case where - // we create a branch for a base class that does - // not have the base class name in the branch name. - // FIXME: This is also quite bad since classes with two - // or more base classes end up with sub-branches - // that have the same name. - bname = name; - } else { - bname.Form("%s.%s", name, element->GetFullName()); - } - } - } else { - // Note: For a base class element, this results in the branchname - // being the name of the base class. - bname.Form("%s", element->GetFullName()); - } - - if( splitlevel > kSplitCollectionOfPointers && element->GetClass() && - element->GetClass()->GetCollectionProxy() && - element->GetClass()->GetCollectionProxy()->HasPointers() ) - { - TBranchSTL* brSTL = new TBranchSTL( branch, bname, element->GetClass()->GetCollectionProxy(), bufsize, splitlevel-1, sinfo, id ); - blist->Add(brSTL); - } - else - { - TBranchElement* bre = new TBranchElement(branch, bname, sinfo, id, pointer, bufsize, splitlevel - 1); - bre->SetParentClass(cl); - blist->Add(bre); - } - } + branch->Unroll(name, cl, sinfo, objptr, bufsize, splitlevel); } // @@ -5451,13 +5359,10 @@ Int_t TTree::GetEntry(Long64_t entry, Int_t getall) }; #ifdef R__USE_IMT - // At most one parallel read with a single branch - unsigned int nSortedBranches(2); - if (nSortedBranches > 1 && ROOT::IsImplicitMTEnabled() && fIMTEnabled && !TTreeCacheUnzip::IsParallelUnzip()) { - if (fSortedBranches.empty()) { - InitializeBranchLists(true); - nSortedBranches = fSortedBranches.size(); - } + const auto nBranches = GetListOfBranches()->GetEntries(); + if (nBranches > 1 && ROOT::IsImplicitMTEnabled() && fIMTEnabled && !TTreeCacheUnzip::IsParallelUnzip()) { + if (fSortedBranches.empty()) + InitializeBranchLists(true); // Count branches are processed first and sequentially for (auto branch : fSeqBranches) { @@ -9308,7 +9213,7 @@ void TTree::UseCurrentStyle() //////////////////////////////////////////////////////////////////////////////// /// Write this object to the current directory. For more see TObject::Write -/// Write calls TTree::FlushBaskets before writing the tree. +/// If option & kFlushBasket, call FlushBasket before writing the tree. Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize) const { diff --git a/tree/tree/src/TTreeCache.cxx b/tree/tree/src/TTreeCache.cxx index 5f01df48bb945..779b956768e98 100644 --- a/tree/tree/src/TTreeCache.cxx +++ b/tree/tree/src/TTreeCache.cxx @@ -1185,8 +1185,21 @@ Bool_t TTreeCache::FillBuffer() fEntryCurrentMax = fEntryCurrent; TTree::TClusterIterator clusterIter = tree->GetClusterIterator(entry); - fEntryCurrent = clusterIter(); - fEntryNext = clusterIter.GetNextEntry(); + + auto entryCurrent = clusterIter(); + auto entryNext = clusterIter.GetNextEntry(); + + if (entryNext < fEntryMin || fEntryMax < entryCurrent) { + // There is no overlap betweent the cluster we found [entryCurrent, entryNext[ + // and the authorized range [fEntryMin, fEntryMax] + // so we have nothing to do + return kFALSE; + } + + fEntryCurrent = entryCurrent; + fEntryNext = entryNext; + + auto firstClusterEnd = fEntryNext; if (showMore || gDebug > 6) Info("FillBuffer", "Looking at cluster spanning from %lld to %lld", fEntryCurrent, fEntryNext); diff --git a/tree/treeplayer/inc/ROOT/TTreeProcessorMT.hxx b/tree/treeplayer/inc/ROOT/TTreeProcessorMT.hxx index 595532547cf49..4ac58dc44cd2f 100644 --- a/tree/treeplayer/inc/ROOT/TTreeProcessorMT.hxx +++ b/tree/treeplayer/inc/ROOT/TTreeProcessorMT.hxx @@ -1,5 +1,5 @@ // @(#)root/thread:$Id$ -// Author: Enric Tejedor, CERN 12/09/2016 +// Authors: Enric Tejedor, Enrico Guiraud CERN 05/06/2018 /************************************************************************* * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers. * @@ -20,6 +20,7 @@ #include "TError.h" #include "TEntryList.h" #include "TFriendElement.h" +#include "ROOT/RMakeUnique.hxx" #include "ROOT/TThreadedObject.hxx" #include @@ -47,257 +48,131 @@ the threaded object. namespace ROOT { namespace Internal { - /// A cluster of entries as seen by TTreeView - struct TreeViewCluster { - Long64_t startEntry; - Long64_t endEntry; + /// A cluster of entries + struct EntryCluster { + Long64_t start; + Long64_t end; }; + /// Names, aliases, and file names of a TTree's or TChain's friends + using NameAlias = std::pair; + struct FriendInfo { + /// Pairs of names and aliases of friend trees/chains + std::vector fFriendNames; + /// Names of the files where each friend is stored. fFriendFileNames[i] is the list of files for friend with + /// name fFriendNames[i] + std::vector> fFriendFileNames; + }; + + // EntryClusters and number of entries per file + using ClustersAndEntries = std::pair>, std::vector>; + ClustersAndEntries MakeClusters(const std::string &treename, const std::vector &filenames); + class TTreeView { private: - typedef std::pair NameAlias; + using TreeReaderEntryListPair = std::pair, std::unique_ptr>; // NOTE: fFriends must come before fChain to be deleted after it, see ROOT-9281 for more details std::vector> fFriends; ///< Friends of the tree/chain std::unique_ptr fChain; ///< Chain on which to operate - std::vector fFileNames; ///< Names of the files - std::string fTreeName; ///< Name of the tree - TEntryList fEntryList; ///< Entry numbers to be processed std::vector fLoadedEntries; /// fFriendNames; ///< pairs of the friends of the tree/chain - std::vector> fFriendFileNames; ///< Names of the files where friends are stored //////////////////////////////////////////////////////////////////////////////// - /// Initialize TTreeView. - void Init() + /// Construct fChain, also adding friends if needed and injecting knowledge of offsets if available. + void MakeChain(const std::string &treeName, const std::vector &fileNames, + const FriendInfo &friendInfo, const std::vector &nEntries, + const std::vector> &friendEntries) { - // If the tree name is empty, look for a tree in the file - if (fTreeName.empty()) { - ::TDirectory::TContext ctxt(gDirectory); - std::unique_ptr f(TFile::Open(fFileNames[0].c_str())); - TIter next(f->GetListOfKeys()); - while (TKey *key = (TKey*)next()) { - const char *className = key->GetClassName(); - if (strcmp(className, "TTree") == 0) { - fTreeName = key->GetName(); - break; - } - } - if (fTreeName.empty()) { - auto msg = "Cannot find any tree in file " + fFileNames[0]; - throw std::runtime_error(msg); - } - } + const std::vector &friendNames = friendInfo.fFriendNames; + const std::vector> &friendFileNames = friendInfo.fFriendFileNames; - fChain.reset(new TChain(fTreeName.c_str())); - for (auto &fn : fFileNames) { - fChain->Add(fn.c_str()); + fChain.reset(new TChain(treeName.c_str())); + const auto nFiles = fileNames.size(); + for (auto i = 0u; i < nFiles; ++i) { + fChain->Add(fileNames[i].c_str(), nEntries[i]); } fChain->ResetBit(TObject::kMustCleanup); - auto friendNum = 0u; - for (auto &na : fFriendNames) { - auto &name = na.first; - auto &alias = na.second; + fFriends.clear(); + const auto nFriends = friendNames.size(); + for (auto i = 0u; i < nFriends; ++i) { + const auto &friendName = friendNames[i]; + const auto &name = friendName.first; + const auto &alias = friendName.second; // Build a friend chain - TChain *frChain = new TChain(name.c_str()); - auto &fileNames = fFriendFileNames[friendNum]; - for (auto &fn : fileNames) - frChain->Add(fn.c_str()); + auto frChain = std::make_unique(name.c_str()); + const auto nFileNames = friendFileNames[i].size(); + for (auto j = 0u; j < nFileNames; ++j) + frChain->Add(friendFileNames[i][j].c_str(), friendEntries[i][j]); // Make it friends with the main chain - fFriends.emplace_back(frChain); - fChain->AddFriend(frChain, alias.c_str()); - - ++friendNum; + fChain->AddFriend(frChain.get(), alias.c_str()); + fFriends.emplace_back(std::move(frChain)); } } - //////////////////////////////////////////////////////////////////////////////// - /// Get and store the names, aliases and file names of the friends of the tree. - void StoreFriends(const TTree &tree, bool isTree) + TreeReaderEntryListPair MakeReaderWithEntryList(TEntryList &globalList, Long64_t start, Long64_t end) { - auto friends = tree.GetListOfFriends(); - if (!friends) - return; - - for (auto fr : *friends) { - auto frTree = static_cast(fr)->GetTree(); - - // Check if friend tree has an alias - auto realName = frTree->GetName(); - auto alias = tree.GetFriendAlias(frTree); - if (alias) { - fFriendNames.emplace_back(std::make_pair(realName, std::string(alias))); - } else { - fFriendNames.emplace_back(std::make_pair(realName, "")); - } - - // Store the file names of the friend tree - fFriendFileNames.emplace_back(); - auto &fileNames = fFriendFileNames.back(); - if (isTree) { - auto f = frTree->GetCurrentFile(); - fileNames.emplace_back(f->GetName()); - } else { - auto frChain = static_cast(frTree); - for (auto f : *(frChain->GetListOfFiles())) { - fileNames.emplace_back(f->GetTitle()); - } - } - } + // TEntryList and SetEntriesRange do not work together (the former has precedence). + // We need to construct a TEntryList that contains only those entry numbers in our desired range. + auto localList = std::make_unique(); + Long64_t entry = globalList.GetEntry(0); + do { + if (entry >= end) + break; + else if (entry >= start) + localList->Enter(entry); + } while ((entry = globalList.Next()) >= 0); + + auto reader = std::make_unique(fChain.get(), localList.get()); + return std::make_pair(std::move(reader), std::move(localList)); } - public: - ////////////////////////////////////////////////////////////////////////// - /// Constructor based on a file name. - /// \param[in] fn Name of the file containing the tree to process. - /// \param[in] tn Name of the tree to process. If not provided, - /// the implementation will automatically search for a - /// tree in the file. - TTreeView(std::string_view fn, std::string_view tn) : fTreeName(tn) + std::unique_ptr MakeReader(Long64_t start, Long64_t end) { - fFileNames.emplace_back(fn); - Init(); + auto reader = std::make_unique(fChain.get()); + fChain->LoadTree(start - 1); + reader->SetEntriesRange(start, end); + return reader; } - ////////////////////////////////////////////////////////////////////////// - /// Constructor based on a collection of file names. - /// \param[in] fns Collection of file names containing the tree to process. - /// \param[in] tn Name of the tree to process. If not provided, - /// the implementation will automatically search for a - /// tree in the collection of files. - TTreeView(const std::vector& fns, std::string_view tn) : fTreeName(tn) - { - if (fns.size() > 0) { - for (auto& fn : fns) - fFileNames.emplace_back(fn); - Init(); - } - else { - auto msg = "The provided list of file names is empty, cannot process tree " + fTreeName; - throw std::runtime_error(msg); - } - } - - ////////////////////////////////////////////////////////////////////////// - /// Constructor based on a TTree. - /// \param[in] tree Tree or chain of files containing the tree to process. - TTreeView(TTree& tree) : fTreeName(tree.GetName()) - { - static const TClassRef clRefTChain("TChain"); - if (clRefTChain == tree.IsA()) { - TObjArray* filelist = dynamic_cast(tree).GetListOfFiles(); - if (filelist->GetEntries() > 0) { - for (auto f : *filelist) - fFileNames.emplace_back(f->GetTitle()); - StoreFriends(tree, false); - Init(); - } - else { - auto msg = "The provided chain of files is empty, cannot process tree " + fTreeName; - throw std::runtime_error(msg); - } - } - else { - TFile *f = tree.GetCurrentFile(); - if (f) { - fFileNames.emplace_back(f->GetName()); - StoreFriends(tree, true); - Init(); - } - else { - auto msg = "The specified TTree is not linked to any file, in-memory-only trees are not supported. Cannot process tree " + fTreeName; - throw std::runtime_error(msg); - } - } - } - - ////////////////////////////////////////////////////////////////////////// - /// Constructor based on a TTree and a TEntryList. - /// \param[in] tree Tree or chain of files containing the tree to process. - /// \param[in] entries List of entry numbers to process. - TTreeView(TTree& tree, TEntryList& entries) : TTreeView(tree) - { - Long64_t numEntries = entries.GetN(); - for (Long64_t i = 0; i < numEntries; ++i) { - fEntryList.Enter(entries.GetEntry(i)); - } - } - - ////////////////////////////////////////////////////////////////////////// - /// Copy constructor. - /// \param[in] view Object to copy. - TTreeView(const TTreeView &view) : fTreeName(view.fTreeName), fEntryList(view.fEntryList) - { - for (auto& fn : view.fFileNames) - fFileNames.emplace_back(fn); - - for (auto &fn : view.fFriendNames) - fFriendNames.emplace_back(fn); - - for (auto &ffn : view.fFriendFileNames) { - fFriendFileNames.emplace_back(); - auto &fileNames = fFriendFileNames.back(); - for (auto &name : ffn) { - fileNames.emplace_back(name); - } - } + public: + TTreeView() {} - Init(); - } + // no-op, we don't want to copy the local TChains + TTreeView(const TTreeView &) {} ////////////////////////////////////////////////////////////////////////// /// Get a TTreeReader for the current tree of this view. - using TreeReaderEntryListPair = std::pair, std::unique_ptr>; - TreeReaderEntryListPair GetTreeReader(Long64_t start, Long64_t end) + TreeReaderEntryListPair GetTreeReader(Long64_t start, Long64_t end, const std::string &treeName, + const std::vector &fileNames, const FriendInfo &friendInfo, + TEntryList entryList, const std::vector &nEntries, + const std::vector> &friendEntries) { + const bool usingLocalEntries = friendInfo.fFriendNames.empty() && entryList.GetN() == 0; + if (fChain == nullptr || (usingLocalEntries && fileNames[0] != fChain->GetListOfFiles()->At(0)->GetTitle())) + MakeChain(treeName, fileNames, friendInfo, nEntries, friendEntries); + std::unique_ptr reader; - std::unique_ptr elist; - if (fEntryList.GetN() > 0) { - // TEntryList and SetEntriesRange do not work together (the former has precedence). - // We need to construct a TEntryList that contains only those entry numbers - // in our desired range. - elist.reset(new TEntryList); - Long64_t entry = fEntryList.GetEntry(0); - do { - if (entry >= start && entry < end) // TODO can quit this loop early when entry >= end - elist->Enter(entry); - } while ((entry = fEntryList.Next()) >= 0); - - reader.reset(new TTreeReader(fChain.get(), elist.get())); + std::unique_ptr localList; + if (entryList.GetN() > 0) { + std::tie(reader, localList) = MakeReaderWithEntryList(entryList, start, end); } else { - // If no TEntryList is involved we can safely set the range in the reader - reader.reset(new TTreeReader(fChain.get())); - fChain->LoadTree(start - 1); - reader->SetEntriesRange(start, end); + reader = MakeReader(start, end); } - return std::make_pair(std::move(reader), std::move(elist)); - } - - ////////////////////////////////////////////////////////////////////////// - /// Get the filenames for this view. - const std::vector &GetFileNames() const - { - return fFileNames; - } - - ////////////////////////////////////////////////////////////////////////// - /// Get the name of the tree of this view. - std::string GetTreeName() const - { - return fTreeName; + // we need to return the entry list too, as it needs to be in scope as long as the reader is + return std::make_pair(std::move(reader), std::move(localList)); } ////////////////////////////////////////////////////////////////////////// /// Push a new loaded entry to the stack. - void PushLoadedEntry(Long64_t entry) { fLoadedEntries.push_back(entry); } + void PushTaskFirstEntry(Long64_t entry) { fLoadedEntries.push_back(entry); } ////////////////////////////////////////////////////////////////////////// /// Restore the tree of the previous loaded entry, if any. - void RestoreLoadedEntry() + void PopTaskFirstEntry() { fLoadedEntries.pop_back(); if (fLoadedEntries.size() > 0) { @@ -307,20 +182,26 @@ namespace ROOT { }; } // End of namespace Internal - class TTreeProcessorMT { private: + const std::vector fFileNames; ///< Names of the files + const std::string fTreeName; ///< Name of the tree + /// User-defined selection of entry numbers to be processed, empty if none was provided + const TEntryList fEntryList; + const Internal::FriendInfo fFriendInfo; + ROOT::TThreadedObject treeView; /// MakeClusters(); + Internal::FriendInfo GetFriendInfo(TTree &tree); + std::string FindTreeName(); + public: TTreeProcessorMT(std::string_view filename, std::string_view treename = ""); - TTreeProcessorMT(const std::vector& filenames, std::string_view treename = ""); - TTreeProcessorMT(TTree& tree); - TTreeProcessorMT(TTree& tree, TEntryList& entries); - - void Process(std::function func); + TTreeProcessorMT(const std::vector &filenames, std::string_view treename = ""); + TTreeProcessorMT(TTree &tree, const TEntryList &entries); + TTreeProcessorMT(TTree &tree); + void Process(std::function func); }; } // End of namespace ROOT diff --git a/tree/treeplayer/src/TTreeProcessorMT.cxx b/tree/treeplayer/src/TTreeProcessorMT.cxx index 9bcb0d9d82607..da3e923a152f0 100644 --- a/tree/treeplayer/src/TTreeProcessorMT.cxx +++ b/tree/treeplayer/src/TTreeProcessorMT.cxx @@ -1,5 +1,5 @@ // @(#)root/thread:$Id$ -// Author: Enric Tejedor, CERN 12/09/2016 +// Authors: Enric Tejedor, Enrico Guiraud CERN 05/06/2018 /************************************************************************* * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers. * @@ -30,13 +30,156 @@ objects. using namespace ROOT; +namespace ROOT { +namespace Internal { +//////////////////////////////////////////////////////////////////////// +/// Return a vector of cluster boundaries for the given tree and files. +ClustersAndEntries +MakeClusters(const std::string &treeName, const std::vector &fileNames) +{ + // Note that as a side-effect of opening all files that are going to be used in the + // analysis once, all necessary streamers will be loaded into memory. + TDirectory::TContext c; + std::vector> clustersPerFile; + std::vector entriesPerFile; + const auto nFileNames = fileNames.size(); + Long64_t offset = 0ll; + for (auto i = 0u; i < nFileNames; ++i) { + std::unique_ptr f(TFile::Open(fileNames[i].c_str())); // need TFile::Open to load plugins if need be + TTree *t = nullptr; // not a leak, t will be deleted by f + f->GetObject(treeName.c_str(), t); + auto clusterIter = t->GetClusterIterator(0); + Long64_t start = 0ll, end = 0ll; + const Long64_t entries = t->GetEntries(); + // Iterate over the clusters in the current file + std::vector clusters; + while ((start = clusterIter()) < entries) { + end = clusterIter.GetNextEntry(); + // Add the current file's offset to start and end to make them (chain) global + clusters.emplace_back(EntryCluster{start + offset, end + offset}); + } + offset += entries; + clustersPerFile.emplace_back(std::move(clusters)); + entriesPerFile.emplace_back(entries); + } + + return std::make_pair(std::move(clustersPerFile), std::move(entriesPerFile)); +} + +//////////////////////////////////////////////////////////////////////// +/// Return a vector containing the number of entries of each file of each friend TChain +std::vector> GetFriendEntries(const std::vector> &friendNames, + const std::vector> &friendFileNames) +{ + std::vector> friendEntries; + const auto nFriends = friendNames.size(); + for (auto i = 0u; i < nFriends; ++i) { + std::vector nEntries; + const auto &thisFriendName = friendNames[i].first; + const auto &thisFriendFiles = friendFileNames[i]; + for (const auto &fname : thisFriendFiles) { + std::unique_ptr f(TFile::Open(fname.c_str())); + TTree *t = nullptr; // owned by TFile + f->GetObject(thisFriendName.c_str(), t); + nEntries.emplace_back(t->GetEntries()); + } + friendEntries.emplace_back(std::move(nEntries)); + } + + return friendEntries; +} +} +} + +//////////////////////////////////////////////////////////////////////////////// +/// Get and store the names, aliases and file names of the friends of the tree. +/// \param[in] tree The main tree whose friends to +/// +/// Note that "friends of friends" and circular references in the lists of friends are not supported. +Internal::FriendInfo TTreeProcessorMT::GetFriendInfo(TTree &tree) +{ + std::vector friendNames; + std::vector> friendFileNames; + + const auto friends = tree.GetListOfFriends(); + if (!friends) + return Internal::FriendInfo(); + + for (auto fr : *friends) { + const auto frTree = static_cast(fr)->GetTree(); + + // Check if friend tree has an alias + const auto realName = frTree->GetName(); + const auto alias = tree.GetFriendAlias(frTree); + if (alias) { + friendNames.emplace_back(std::make_pair(realName, std::string(alias))); + } else { + friendNames.emplace_back(std::make_pair(realName, "")); + } + + // Store the file names of the friend tree + friendFileNames.emplace_back(); + auto &fileNames = friendFileNames.back(); + const bool isChain = tree.IsA() == TChain::Class(); + if (isChain) { + const auto frChain = static_cast(frTree); + for (auto f : *(frChain->GetListOfFiles())) { + fileNames.emplace_back(f->GetTitle()); + } + } else { + const auto f = frTree->GetCurrentFile(); + fileNames.emplace_back(f->GetName()); + } + } + + return Internal::FriendInfo{std::move(friendNames), std::move(friendFileNames)}; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Retrieve the name of the first TTree in the first input file, else throw. +std::string TTreeProcessorMT::FindTreeName() +{ + std::string treeName; + + if (fFileNames.empty()) + throw std::runtime_error("Empty list of files and no tree name provided"); + + ::TDirectory::TContext ctxt(gDirectory); + std::unique_ptr f(TFile::Open(fFileNames[0].c_str())); + TIter next(f->GetListOfKeys()); + while (TKey *key = (TKey *)next()) { + const char *className = key->GetClassName(); + if (strcmp(className, "TTree") == 0) { + treeName = key->GetName(); + break; + } + } + if (treeName.empty()) + throw std::runtime_error("Cannot find any tree in file " + fFileNames[0]); + + return treeName; +} + //////////////////////////////////////////////////////////////////////// /// Constructor based on a file name. /// \param[in] filename Name of the file containing the tree to process. /// \param[in] treename Name of the tree to process. If not provided, /// the implementation will automatically search for a /// tree in the file. -TTreeProcessorMT::TTreeProcessorMT(std::string_view filename, std::string_view treename) : treeView(filename, treename) {} +TTreeProcessorMT::TTreeProcessorMT(std::string_view filename, std::string_view treename) + : fFileNames({std::string(filename)}), fTreeName(treename.empty() ? FindTreeName() : treename), fFriendInfo() {} + +std::vector CheckAndConvert(const std::vector & views) +{ + if (views.empty()) + throw std::runtime_error("The provided list of file names is empty"); + + std::vector strings; + strings.reserve(views.size()); + for (const auto &v : views) + strings.emplace_back(v); + return strings; +} //////////////////////////////////////////////////////////////////////// /// Constructor based on a collection of file names. @@ -44,46 +187,47 @@ TTreeProcessorMT::TTreeProcessorMT(std::string_view filename, std::string_view t /// \param[in] treename Name of the tree to process. If not provided, /// the implementation will automatically search for a /// tree in the collection of files. -TTreeProcessorMT::TTreeProcessorMT(const std::vector &filenames, std::string_view treename) : treeView(filenames, treename) {} +TTreeProcessorMT::TTreeProcessorMT(const std::vector &filenames, std::string_view treename) + : fFileNames(CheckAndConvert(filenames)), fTreeName(treename.empty() ? FindTreeName() : treename), fFriendInfo() {} -//////////////////////////////////////////////////////////////////////// -/// Constructor based on a TTree. -/// \param[in] tree Tree or chain of files containing the tree to process. -TTreeProcessorMT::TTreeProcessorMT(TTree &tree) : treeView(tree) {} +std::vector GetFilesFromTree(TTree &tree) +{ + std::vector filenames; + + const bool isChain = tree.IsA() == TChain::Class(); + if (isChain) { + TObjArray *filelist = static_cast(tree).GetListOfFiles(); + const auto nFiles = filelist->GetEntries(); + if (nFiles == 0) + throw std::runtime_error("The provided chain of files is empty"); + filenames.reserve(nFiles); + for (auto f : *filelist) + filenames.emplace_back(f->GetTitle()); + } else { + TFile *f = tree.GetCurrentFile(); + if (!f) { + const auto msg = "The specified TTree is not linked to any file, in-memory-only trees are not supported."; + throw std::runtime_error(msg); + } + + filenames.emplace_back(f->GetName()); + } + + return filenames; +} //////////////////////////////////////////////////////////////////////// /// Constructor based on a TTree and a TEntryList. /// \param[in] tree Tree or chain of files containing the tree to process. /// \param[in] entries List of entry numbers to process. -TTreeProcessorMT::TTreeProcessorMT(TTree &tree, TEntryList &entries) : treeView(tree, entries) {} +TTreeProcessorMT::TTreeProcessorMT(TTree &tree, const TEntryList &entries) + : fFileNames(GetFilesFromTree(tree)), fTreeName(tree.GetName()), fEntryList(entries), + fFriendInfo(GetFriendInfo(tree)) {} //////////////////////////////////////////////////////////////////////// -/// Divide input data in clusters, i.e. the workloads to distribute to tasks -std::vector TTreeProcessorMT::MakeClusters() -{ - TDirectory::TContext c; - std::vector clusters; - const auto &fileNames = treeView->GetFileNames(); - const auto nFileNames = fileNames.size(); - const auto &treeName = treeView->GetTreeName(); - Long64_t offset = 0; - for (auto i = 0u; i < nFileNames; ++i) { // TTreeViewCluster requires the index of the file the cluster belongs to - std::unique_ptr f(TFile::Open(fileNames[i].c_str())); // need TFile::Open to load plugins if need be - TTree *t = nullptr; // not a leak, t will be deleted by f - f->GetObject(treeName.c_str(), t); - auto clusterIter = t->GetClusterIterator(0); - Long64_t start = 0, end = 0; - const Long64_t entries = t->GetEntries(); - // Iterate over the clusters in the current file and generate a task for each of them - while ((start = clusterIter()) < entries) { - end = clusterIter.GetNextEntry(); - // Add the current file's offset to start and end to make them (chain) global - clusters.emplace_back(ROOT::Internal::TreeViewCluster{start + offset, end + offset}); - } - offset += entries; - } - return clusters; -} +/// Constructor based on a TTree. +/// \param[in] tree Tree or chain of files containing the tree to process. +TTreeProcessorMT::TTreeProcessorMT(TTree &tree) : TTreeProcessorMT(tree, TEntryList()) {} ////////////////////////////////////////////////////////////////////////////// /// Process the entries of a TTree in parallel. The user-provided function @@ -104,24 +248,66 @@ std::vector TTreeProcessorMT::MakeClusters() /// \param[in] func User-defined function that processes a subrange of entries void TTreeProcessorMT::Process(std::function func) { - // Enable this IMT use case (activate its locks) - Internal::TParTreeProcessingRAII ptpRAII; + const std::vector &friendNames = fFriendInfo.fFriendNames; + const std::vector> &friendFileNames = fFriendInfo.fFriendFileNames; + + // If an entry list or friend trees are present, we need to generate clusters with global entry numbers, + // so we do it here for all files. + const bool hasFriends = !friendNames.empty(); + const bool hasEntryList = fEntryList.GetN() > 0; + const bool shouldRetrieveAllClusters = hasFriends || hasEntryList; + const auto clustersAndEntries = + shouldRetrieveAllClusters ? Internal::MakeClusters(fTreeName, fFileNames) : Internal::ClustersAndEntries{}; + const auto &clusters = clustersAndEntries.first; + const auto &entries = clustersAndEntries.second; - auto clusters = MakeClusters(); + // Retrieve number of entries for each file for each friend tree + const auto friendEntries = + hasFriends ? Internal::GetFriendEntries(friendNames, friendFileNames) : std::vector>{}; - auto mapFunction = [this, &func](const ROOT::Internal::TreeViewCluster &c) { - // This task will operate with the tree that contains startEntry - treeView->PushLoadedEntry(c.startEntry); + TThreadExecutor pool; + // Parent task, spawns tasks that process each of the entry clusters for each input file + using Internal::EntryCluster; + auto processFile = [&](std::size_t fileIdx) { + + // If cluster information is already present, build TChains with all input files and use global entry numbers + // Otherwise get cluster information only for the file we need to process and use local entry numbers + const bool shouldUseGlobalEntries = hasFriends || hasEntryList; + // theseFiles contains either all files or just the single file to process + const auto &theseFiles = shouldUseGlobalEntries ? fFileNames : std::vector({fFileNames[fileIdx]}); + // Evaluate clusters (with local entry numbers) and number of entries for this file, if needed + const auto theseClustersAndEntries = + shouldUseGlobalEntries ? Internal::ClustersAndEntries{} : Internal::MakeClusters(fTreeName, theseFiles); + + // All clusters for the file to process, either with global or local entry numbers + const auto &thisFileClusters = shouldUseGlobalEntries ? clusters[fileIdx] : theseClustersAndEntries.first[0]; + + // Either all number of entries or just the ones for this file + const auto &theseEntries = + shouldUseGlobalEntries ? entries : std::vector({theseClustersAndEntries.second[0]}); + + auto processCluster = [&](const Internal::EntryCluster &c) { + // This task will operate with the tree that contains start + treeView->PushTaskFirstEntry(c.start); + + std::unique_ptr reader; + std::unique_ptr elist; + std::tie(reader, elist) = treeView->GetTreeReader(c.start, c.end, fTreeName, theseFiles, fFriendInfo, + fEntryList, theseEntries, friendEntries); + func(*reader); - auto readerAndEntryList = treeView->GetTreeReader(c.startEntry, c.endEntry); - auto &reader = std::get<0>(readerAndEntryList); - func(*reader); + // In case of task interleaving, we need to load here the tree of the parent task + treeView->PopTaskFirstEntry(); + }; - // In case of task interleaving, we need to load here the tree of the parent task - treeView->RestoreLoadedEntry(); + pool.Foreach(processCluster, thisFileClusters); }; - // Assume number of threads has been initialized via ROOT::EnableImplicitMT - TThreadExecutor pool; - pool.Foreach(mapFunction, clusters); + std::vector fileIdxs(fFileNames.size()); + std::iota(fileIdxs.begin(), fileIdxs.end(), 0u); + + // Enable this IMT use case (activate its locks) + Internal::TParTreeProcessingRAII ptpRAII; + + pool.Foreach(processFile, fileIdxs); } diff --git a/tree/treeplayer/test/CMakeLists.txt b/tree/treeplayer/test/CMakeLists.txt index 8e03e1350fce1..ad3047941f7b2 100644 --- a/tree/treeplayer/test/CMakeLists.txt +++ b/tree/treeplayer/test/CMakeLists.txt @@ -2,3 +2,6 @@ ROOT_ADD_UNITTEST_DIR(TreePlayer) add_custom_command(TARGET treetreeplayertestUnit POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/data.h data.h) +if(imt) + ROOT_ADD_GTEST(treeprocessormt_manyfiles treeprocmt/treeprocessormt_manyfiles.cxx LIBRARIES TreePlayer) +endif() diff --git a/tree/treeplayer/test/treeprocmt/treeprocessormt_manyfiles.cxx b/tree/treeplayer/test/treeprocmt/treeprocessormt_manyfiles.cxx new file mode 100644 index 0000000000000..bc2ac4d20fd59 --- /dev/null +++ b/tree/treeplayer/test/treeprocmt/treeprocessormt_manyfiles.cxx @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +void WriteFiles(const std::string &treename, const std::vector &filenames) +{ + int v = 0; + for (const auto &f : filenames) { + TFile file(f.c_str(), "recreate"); + TTree t(treename.c_str(), treename.c_str()); + t.Branch("v", &v); + for (auto i = 0; i < 10; ++i) { + ++v; + t.Fill(); + } + t.Write(); + } +} + +void DeleteFiles(const std::vector &filenames) +{ + for (const auto &f : filenames) + gSystem->Unlink(f.c_str()); +} + +TEST(TreeProcessorMT, ManyFiles) +{ + const auto nFiles = 100u; + const std::string treename = "t"; + std::vector filenames; + for (auto i = 0u; i < nFiles; ++i) + filenames.emplace_back("treeprocmt_" + std::to_string(i) + ".root"); + + WriteFiles(treename, filenames); + + std::atomic_int sum(0); + std::atomic_int count(0); + auto sumValues = [&sum, &count](TTreeReader &r) { + TTreeReaderValue v(r, "v"); + std::random_device seed; + std::default_random_engine eng(seed()); + std::uniform_int_distribution<> rand(1, 100); + while (r.Next()) { + std::this_thread::sleep_for(std::chrono::nanoseconds(rand(eng))); + sum += *v; + ++count; + } + }; + + // TTreeProcMT requires a vector + std::vector fnames; + for (const auto &f : filenames) + fnames.emplace_back(f); + + ROOT::TTreeProcessorMT proc(fnames, treename); + proc.Process(sumValues); + + EXPECT_EQ(count.load(), int(nFiles*10)); // 10 entries per file + EXPECT_EQ(sum.load(), 500500); // sum 1..nFiles*10 + + DeleteFiles(filenames); +} diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index fe27066b2bdb6..f1b58da3bb583 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -138,7 +138,7 @@ if(NOT TBB_FOUND AND NOT builtin_tbb) endif() if(NOT ROOT_imt_FOUND) - set(imt_veto multicore/imt*.C multicore/mt*.C dataframe/df018_customActions.C) + set(imt_veto multicore/imt*.C multicore/mt*.C) else() if(MSVC) #---Multiproc is not supported on Windows diff --git a/tutorials/dataframe/df003_profiles.py b/tutorials/dataframe/df003_profiles.py index 75ed348151f1c..2f67121c41cb2 100644 --- a/tutorials/dataframe/df003_profiles.py +++ b/tutorials/dataframe/df003_profiles.py @@ -25,7 +25,7 @@ def fill_tree(treeName, fileName): # We prepare an input tree to run on -fileName = "df003_profiles.root" +fileName = "df003_profiles_py.root" treeName = "myTree" fill_tree(treeName, fileName) diff --git a/tutorials/dataframe/df008_createDataSetFromScratch.py b/tutorials/dataframe/df008_createDataSetFromScratch.py index d2ad24528fa7f..df8bf213ccc8b 100644 --- a/tutorials/dataframe/df008_createDataSetFromScratch.py +++ b/tutorials/dataframe/df008_createDataSetFromScratch.py @@ -17,5 +17,5 @@ tdf_1 = tdf.Define("rnd", "gRandom->Gaus()") # And we write out the dataset on disk -tdf_1.Snapshot("randomNumbers", "df008_createDataSetFromScratch.root") +tdf_1.Snapshot("randomNumbers", "df008_createDataSetFromScratch_py.root") diff --git a/tutorials/dataframe/df013_InspectAnalysis.C b/tutorials/dataframe/df013_InspectAnalysis.C index b00e140f3d6c1..019f1031cd7b6 100644 --- a/tutorials/dataframe/df013_InspectAnalysis.C +++ b/tutorials/dataframe/df013_InspectAnalysis.C @@ -49,8 +49,8 @@ void df013_InspectAnalysis() // - another callback is responsible of updating a simple progress bar from multiple threads // First off we create a TBrowser that contains a "RDFResults" directory - auto *tdfDirectory = new TMemFile("RDFResults", "RECREATE"); - auto *browser = new TBrowser("b", tdfDirectory); + auto tdfDirectory = new TMemFile("RDFResults", "RECREATE"); + auto browser = new TBrowser("b", tdfDirectory); // The global pad should now be set to the TBrowser's canvas, let's store its value in a local variable auto browserPad = gPad; diff --git a/tutorials/dataframe/df018_customActions.C b/tutorials/dataframe/df018_customActions.C index b0069b0be0bc3..0f11fec89828d 100644 --- a/tutorials/dataframe/df018_customActions.C +++ b/tutorials/dataframe/df018_customActions.C @@ -87,7 +87,7 @@ void df018_customActions() {10., 10, 5., 7.}}; // Axes max values // We book the action: it will be treated during the event loop. - auto myTHnT = dd.Book(std::move(helper), {"x0", "x1", "x2", "x3", "x4"}); + auto myTHnT = dd.Book(std::move(helper), {"x0", "x1", "x2", "x3"}); myTHnT->Print(); } diff --git a/tutorials/dataframe/df019_Cache.C b/tutorials/dataframe/df019_Cache.C new file mode 100644 index 0000000000000..342e927d7ddb6 --- /dev/null +++ b/tutorials/dataframe/df019_Cache.C @@ -0,0 +1,47 @@ +/// \file +/// \ingroup tutorial_dataframe +/// \notebook -draw +/// This tutorial shows how the content of a data frame can be cached in memory +/// in form of a data frame. The content of the columns is stored in memory in +/// contiguous slabs of memory and is "ready to use", i.e. no ROOT IO operation +/// is performed. +/// +/// Creating a cached data frame storing all of its content deserialised and uncompressed +/// in memory is particularly useful when dealing with datasets of a moderate size +/// (small enough to fit the RAM) over which several explorative loops need to be +/// performed at as fast as possible. In addition, caching can be useful when no file +/// on disk needs to be created as a side effect of checkpointing part of the analysis. +/// +/// All steps in the caching are lazy, i.e. the cached data frame is actually filled +/// only when the event loop is triggered on it. +/// +/// \macro_code +/// +/// \date June 2018 +/// \author Danilo Piparo + +using ROOT::RDataFrame; + +void df019_Cache() +{ + // We create a data frame on top of the hsimple example + auto hsimplePath = gROOT->GetTutorialDir(); + hsimplePath += "/hsimple.root"; + RDataFrame df("ntuple", hsimplePath.Data()); + + // We apply a simple cut and define a new column + auto df_cut = df.Filter([](float py) { return py > 0.f; }, {"py"}) + .Define("px_plus_py", [](float px, float py) { return px + py; }, {"px", "py"}); + + // We cache the content of the dataset. Nothing has happened yet: the work to accomplish + // has been described. As for `Snapshot`, the types and columns can be written out explicitly + // or left for the jitting to handle (`df_cached` is intentionally unused - it shows how to + // to create a *cached* data frame specifying column types explicitly): + auto df_cached = df_cut.Cache({"px_plus_py", "py"}); + auto df_cached_implicit = df_cut.Cache(); + auto h = df_cached_implicit.Histo1D("px_plus_py"); + + // Now the event loop on the cached dataset is triggered. This event triggers the loop + // on the `df` data frame lazily. + h->DrawCopy(); +} \ No newline at end of file diff --git a/tutorials/dataframe/df019_Cache.py b/tutorials/dataframe/df019_Cache.py new file mode 100644 index 0000000000000..f3bab93386b77 --- /dev/null +++ b/tutorials/dataframe/df019_Cache.py @@ -0,0 +1,43 @@ +## \file +## \ingroup tutorial_dataframe +## \notebook -draw +## This tutorial shows how the content of a data frame can be cached in memory +## in form of a data frame. The content of the columns is stored in memory in +## contiguous slabs of memory and is "ready to use", i.e. no ROOT IO operation +## is performed. +## +## Creating a cached data frame storing all of its content deserialised and uncompressed +## in memory is particularly useful when dealing with datasets of a moderate size +## (small enough to fit the RAM) over which several explorative loops need to be +## performed at as fast as possible. In addition, caching can be useful when no file +## on disk needs to be created as a side effect of checkpointing part of the analysis. +## +## All steps in the caching are lazy, i.e. the cached data frame is actually filled +## only when the event loop is triggered on it. +## +## \macro_code +## +## \date June 2018 +## \author Danilo Piparo + +import ROOT +RDataFrame = ROOT.ROOT.RDataFrame +import os + +# We create a data frame on top of the hsimple example +hsimplePath = os.path.join(str(ROOT.gROOT.GetTutorialDir().Data()), "hsimple.root") +df = RDataFrame("ntuple", hsimplePath) + +#We apply a simple cut and define a new column +df_cut = df.Filter("py > 0.f")\ + .Define("px_plus_py", "px + py") + +# We cache the content of the dataset. Nothing has happened yet: the work to accomplish +# has been described. +df_cached = df_cut.Cache() + +h = df_cached.Histo1D("px_plus_py") + +# Now the event loop on the cached dataset is triggered. This event triggers the loop +# on the `df` data frame lazily. +h.Draw() \ No newline at end of file diff --git a/tutorials/eve/SplitGLView.C b/tutorials/eve/SplitGLView.C index 268ffd16927e2..6d8221eb8edd1 100644 --- a/tutorials/eve/SplitGLView.C +++ b/tutorials/eve/SplitGLView.C @@ -1063,7 +1063,6 @@ void SplitGLView::OnMouseIdle(TGLPhysicalShape *shape, UInt_t posx, UInt_t posy) static TH1F *h1f = 0; TFormula *form1 = new TFormula("form1","abs(sin(x)/x)"); - form1->Update(); // silent warning about unused variable... TF1 *sqroot = new TF1("sqroot","x*gaus(0) + [3]*form1",0,10); sqroot->SetParameters(10,4,1,20); if (h1f == 0) diff --git a/tutorials/eve/alice_vsd.C b/tutorials/eve/alice_vsd.C index 21c4f74f21b03..d4bfd5db442a3 100644 --- a/tutorials/eve/alice_vsd.C +++ b/tutorials/eve/alice_vsd.C @@ -38,7 +38,7 @@ #include -// Include componets -- compile time link :) +// Include components -- compile time link :) #include "MultiView.C" MultiView* gMultiView = 0; @@ -91,8 +91,7 @@ public: fEvDirKeys = new TObjArray; TPMERegexp name_re("Event\\d+"); TObjLink* lnk = fFile->GetListOfKeys()->FirstLink(); - while (lnk) - { + while (lnk) { if (name_re.Match(lnk->GetObject()->GetName())) { fEvDirKeys->Add(lnk->GetObject()); @@ -101,8 +100,7 @@ public: } fMaxEv = fEvDirKeys->GetEntriesFast(); - if (fMaxEv == 0) - { + if (fMaxEv == 0) { Error("VSD_Reader", "No events to show ... terminating."); gSystem->Exit(1); } @@ -190,7 +188,7 @@ public: // Fill projected views. - TEveElement* top = gEve->GetCurrentEvent(); + auto top = gEve->GetCurrentEvent(); gMultiView->DestroyEventRPhi(); gMultiView->ImportEventRPhi(top); @@ -210,16 +208,13 @@ public: void LoadClusters(TEvePointSet*& ps, const TString& det_name, Int_t det_id) { - if (ps == 0) - { + if (ps == 0) { ps = new TEvePointSet(det_name); ps->SetMainColor((Color_t)(det_id + 2)); ps->SetMarkerSize(0.5); ps->SetMarkerStyle(2); ps->IncDenyDestroy(); - } - else - { + } else { ps->Reset(); } @@ -261,8 +256,7 @@ public: { // Read reconstructed tracks from current event. - if (fTrackList == 0) - { + if (fTrackList == 0) { fTrackList = new TEveTrackList("ESD Tracks"); fTrackList->SetMainColor(6); fTrackList->SetMarkerColor(kYellow); @@ -270,21 +264,18 @@ public: fTrackList->SetMarkerSize(0.5); fTrackList->IncDenyDestroy(); - } - else - { + } else { fTrackList->DestroyElements(); } - TEveTrackPropagator* trkProp = fTrackList->GetPropagator(); + auto trkProp = fTrackList->GetPropagator(); // !!!! Need to store field on file !!!! // Can store TEveMagField ? trkProp->SetMagField(0.5); trkProp->SetStepper(TEveTrackPropagator::kRungeKutta); Int_t nTracks = fVSD->fTreeR->GetEntries(); - for (Int_t n = 0; n < nTracks; ++n) - { + for (Int_t n = 0; n < nTracks; ++n) { fVSD->fTreeR->GetEntry(n); TEveTrack* track = new TEveTrack(&fVSD->fR, trkProp); @@ -332,12 +323,12 @@ void alice_vsd(const char* vsd_file_name= TEveGeoShape *gentle_geom = 0; { // Simple geometry - TFile* geom = + auto geom = TFile::Open("http://mtadel.home.cern.ch/mtadel/root/alice_mini_geom.root", "CACHEREAD"); if (!geom) return; - TEveGeoShapeExtract* gse = (TEveGeoShapeExtract*) geom->Get("Gentle"); + auto gse = (TEveGeoShapeExtract*) geom->Get("Gentle"); gentle_geom = TEveGeoShape::ImportShapeExtract(gse, 0); geom->Close(); delete geom; @@ -380,14 +371,14 @@ void make_gui() { // Create minimal GUI for event navigation. - TEveBrowser* browser = gEve->GetBrowser(); + auto browser = gEve->GetBrowser(); browser->StartEmbedding(TRootBrowser::kLeft); - TGMainFrame* frmMain = new TGMainFrame(gClient->GetRoot(), 1000, 600); + auto frmMain = new TGMainFrame(gClient->GetRoot(), 1000, 600); frmMain->SetWindowName("XX GUI"); frmMain->SetCleanup(kDeepCleanup); - TGHorizontalFrame* hf = new TGHorizontalFrame(frmMain); + auto hf = new TGHorizontalFrame(frmMain); { TString icondir(TString::Format("%s/icons/", gSystem->Getenv("ROOTSYS"))); TGPictureButton* b = 0; diff --git a/tutorials/eve/annotation.C b/tutorials/eve/annotation.C index 9c493b66981ec..a398c1c6d6683 100644 --- a/tutorials/eve/annotation.C +++ b/tutorials/eve/annotation.C @@ -48,7 +48,7 @@ void annotation(Float_t a=10, Float_t d=5, Float_t x=0, Float_t y=0, Float_t z=0 TEveManager::Create(); // add a box in scene - TEveBox* b = new TEveBox("Box", "Test Title"); + auto b = new TEveBox("Box", "Test Title"); b->SetMainColor(kCyan); b->SetMainTransparency(0); b->SetVertex(0, x - a, y - a, z - a); @@ -63,13 +63,13 @@ void annotation(Float_t a=10, Float_t d=5, Float_t x=0, Float_t y=0, Float_t z=0 gEve->Redraw3D(kTRUE); // add overlay text - TGLViewer* v = gEve->GetDefaultGLViewer(); + auto v = gEve->GetDefaultGLViewer(); TDatime time; - TGLAnnotation* ann = new TGLAnnotation(v, time.AsString(), 0.1, 0.9); + auto ann = new TGLAnnotation(v, time.AsString(), 0.1, 0.9); ann->SetTextSize(0.1);// % of window diagonal // set timer to update text every second - MyTimer* timer = new MyTimer(ann); + auto timer = new MyTimer(ann); timer->SetTime(1000); timer->Reset(); timer->TurnOn(); diff --git a/tutorials/eve/arrow.C b/tutorials/eve/arrow.C index 91092894ebfd4..a84d3dedc87d4 100644 --- a/tutorials/eve/arrow.C +++ b/tutorials/eve/arrow.C @@ -14,7 +14,7 @@ void arrow() TEveManager::Create(); - TEvePointSet* marker = new TEvePointSet(8); + auto marker = new TEvePointSet(8); marker->SetName("Origin marker"); marker->SetMarkerColor(6); marker->SetMarkerStyle(3); @@ -29,23 +29,23 @@ void arrow() marker->SetPoint(7, -a, -a, -a); gEve->AddElement(marker); - TEveArrow* a1 = new TEveArrow(1., 1., 10., 10., 4., 0.); + auto a1 = new TEveArrow(1., 1., 10., 10., 4., 0.); a1->SetMainColor(kBlue); a1->SetTubeR(0.02); a1->SetPickable(kTRUE); gEve->AddElement(a1); - TEveText* t1 = new TEveText("blue"); + auto t1 = new TEveText("blue"); t1->SetFontSize(20); TEveVector tv = a1->GetVector()*0.5f+a1->GetOrigin(); t1->RefMainTrans().SetPos(tv.Arr()); a1->AddElement(t1); - TEveArrow* a2 = new TEveArrow(20., 1., 10., 3., 0., 4.); + auto a2 = new TEveArrow(20., 1., 10., 3., 0., 4.); a2->SetMainColor(kGreen); a2->SetPickable(kTRUE); gEve->AddElement(a2); - TEveArrow* a3 = new TEveArrow(1., 10., 10., 0., 20., 0.); + auto a3 = new TEveArrow(1., 10., 10., 0., 20., 0.); a3->SetMainColor(kOrange); a3->SetPickable(kTRUE); gEve->AddElement(a3); diff --git a/tutorials/eve/arrow_standalone.C b/tutorials/eve/arrow_standalone.C index 75e5ad68290c3..93735a23d1501 100644 --- a/tutorials/eve/arrow_standalone.C +++ b/tutorials/eve/arrow_standalone.C @@ -16,22 +16,22 @@ void arrow_standalone() // ---------------------------------------------------------------------- - TGMainFrame* mf = new TGMainFrame(gClient->GetRoot(), 800, 400, + auto mf = new TGMainFrame(gClient->GetRoot(), 800, 400, kHorizontalFrame); mf->SetWindowName("Arrow Foo"); // ---------------------------------------------------------------------- - TGCompositeFrame* evf = new TGCompositeFrame(mf, 400, 400); + auto evf = new TGCompositeFrame(mf, 400, 400); mf->AddFrame(evf, new TGLayoutHints(kLHintsNormal | kLHintsExpandX | kLHintsExpandY)); - TGLEmbeddedViewer* ev = new TGLEmbeddedViewer(evf); + auto ev = new TGLEmbeddedViewer(evf); evf->AddFrame(ev->GetFrame(), new TGLayoutHints(kLHintsNormal | kLHintsExpandX | kLHintsExpandY)); - TEveViewer* eve_v = new TEveViewer("YourViewer"); + auto eve_v = new TEveViewer("YourViewer"); eve_v->SetGLViewer(ev, ev->GetFrame()); eve_v->IncDenyDestroy(); eve_v->AddScene(gEve->GetEventScene()); @@ -56,7 +56,7 @@ void arrow_standalone() // To create full canvas with menus. mf->SetEditable(); - TCanvas* c = new TCanvas("Foo", "Bar", 400, 400); + auto c = new TCanvas("Foo", "Bar", 400, 400); mf->SetEditable(kFALSE); // ---------------------------------------------------------------------- diff --git a/tutorials/eve/assembly.C b/tutorials/eve/assembly.C index 776b0de0d1fca..fd728fa171284 100644 --- a/tutorials/eve/assembly.C +++ b/tutorials/eve/assembly.C @@ -2,10 +2,10 @@ /// \ingroup tutorial_eve /// Geometry detector assembly example /// -/// Modified to save the assebly as shape-extract. +/// Modified to save the assembly as shape-extract. /// 1. Run `root assembly.C` /// This will produce assembly.root containing the extract. -/// 2. Display the assebly as: +/// 2. Display the assembly as: /// `root show_extract.C("assembly.root")` /// /// \image html eve_assembly.png @@ -17,22 +17,22 @@ void assembly() { //--- Definition of a simple geometry gSystem->Load("libGeom"); - TGeoManager *geom = new TGeoManager("Assemblies", + auto geom = new TGeoManager("Assemblies", "Geometry using assemblies"); Int_t i; //--- define some materials - TGeoMaterial *matVacuum = new TGeoMaterial("Vacuum", 0,0,0); - TGeoMaterial *matAl = new TGeoMaterial("Al", 26.98,13,2.7); -// //--- define some media - TGeoMedium *Vacuum = new TGeoMedium("Vacuum",1, matVacuum); - TGeoMedium *Al = new TGeoMedium("Aluminium",2, matAl); + auto matVacuum = new TGeoMaterial("Vacuum", 0,0,0); + auto matAl = new TGeoMaterial("Al", 26.98,13,2.7); + //--- define some media + auto Vacuum = new TGeoMedium("Vacuum",1, matVacuum); + auto Al = new TGeoMedium("Aluminium",2, matAl); //--- make the top container volume - TGeoVolume *top = geom->MakeBox("TOP", Vacuum, 1000., 1000., 100.); + auto top = geom->MakeBox("TOP", Vacuum, 1000., 1000., 100.); geom->SetTopVolume(top); // Make the elementary assembly of the whole structure - TGeoVolume *tplate = new TGeoVolumeAssembly("TOOTHPLATE"); + auto tplate = new TGeoVolumeAssembly("TOOTHPLATE"); Int_t ntooth = 5; Double_t xplate = 25; @@ -42,9 +42,9 @@ void assembly() Double_t dshift = 2.*xplate + xtooth; Double_t xt,yt; - TGeoVolume *plate = geom->MakeBox("PLATE", Al, xplate,yplate,1); + auto plate = geom->MakeBox("PLATE", Al, xplate,yplate,1); plate->SetLineColor(kBlue); - TGeoVolume *tooth = geom->MakeBox("TOOTH", Al, xtooth,ytooth,1); + auto tooth = geom->MakeBox("TOOTH", Al, xtooth,ytooth,1); tooth->SetLineColor(kBlue); tplate->AddNode(plate,1); for (i=0; iAddNode(tooth, ntooth+i+1, new TGeoTranslation(xt,yt,0)); } - TGeoRotation *rot1 = new TGeoRotation(); + auto rot1 = new TGeoRotation(); rot1->RotateX(90); TGeoRotation *rot; // Make a hexagone cell out of 6 toothplates. These can zip togeather @@ -75,7 +75,7 @@ void assembly() // Make a row as an assembly of cells, then combine rows in a honeycomb // structure. This again works without any need to define rows as // "overlapping" - TGeoVolume *row = new TGeoVolumeAssembly("ROW"); + auto row = new TGeoVolumeAssembly("ROW"); Int_t ncells = 5; for (i=0; iGetTopNode(); - TEveGeoTopNode* en = new TEveGeoTopNode(gGeoManager, node); + auto node = gGeoManager->GetTopNode(); + auto en = new TEveGeoTopNode(gGeoManager, node); en->SetVisLevel(4); en->GetNode()->GetVolume()->SetVisibility(kFALSE); diff --git a/tutorials/eve/box.C b/tutorials/eve/box.C index 60409ac9d66ad..467c772b2fb81 100644 --- a/tutorials/eve/box.C +++ b/tutorials/eve/box.C @@ -13,7 +13,7 @@ TEveBox* box(Float_t a=10, Float_t d=5, Float_t x=0, Float_t y=0, Float_t z=0) TRandom& r = * gRandom; - TEveBox* b = new TEveBox; + auto b = new TEveBox; b->SetMainColor(kCyan); b->SetMainTransparency(0); diff --git a/tutorials/eve/boxset.C b/tutorials/eve/boxset.C index bd1966ddc93d9..5d372bab03830 100644 --- a/tutorials/eve/boxset.C +++ b/tutorials/eve/boxset.C @@ -14,15 +14,15 @@ TEveBoxSet* boxset(Float_t x=0, Float_t y=0, Float_t z=0, TRandom r(0); - TEveRGBAPalette* pal = new TEveRGBAPalette(0, 130); + auto pal = new TEveRGBAPalette(0, 130); - TEveFrameBox* frm = new TEveFrameBox(); + auto frm = new TEveFrameBox(); frm->SetAABoxCenterHalfSize(0, 0, 0, 12, 12, 12); frm->SetFrameColor(kCyan); frm->SetBackColorRGBA(120,120,120,20); frm->SetDrawBack(kTRUE); - TEveBoxSet* q = new TEveBoxSet("BoxSet"); + auto q = new TEveBoxSet("BoxSet"); q->SetPalette(pal); q->SetFrame(frm); q->Reset(TEveBoxSet::kBT_AABox, kFALSE, 64); @@ -56,7 +56,7 @@ TEveBoxSet* boxset_colisval(Float_t x=0, Float_t y=0, Float_t z=0, TRandom r(0); - TEveBoxSet* q = new TEveBoxSet("BoxSet"); + auto q = new TEveBoxSet("BoxSet"); q->Reset(TEveBoxSet::kBT_AABox, kTRUE, 64); for (Int_t i=0; iAddBox(r.Uniform(-10, 10), r.Uniform(-10, 10), r.Uniform(-10, 10), @@ -85,7 +85,7 @@ TEveBoxSet* boxset_single_color(Float_t x=0, Float_t y=0, Float_t z=0, TRandom r(0); - TEveBoxSet* q = new TEveBoxSet("BoxSet"); + auto q = new TEveBoxSet("BoxSet"); q->UseSingleColor(); q->SetMainColor(kCyan-2); q->SetMainTransparency(50); @@ -99,8 +99,7 @@ TEveBoxSet* boxset_single_color(Float_t x=0, Float_t y=0, Float_t z=0, TEveTrans& t = q->RefMainTrans(); t.SetPos(x, y, z); - if (registerSet) - { + if (registerSet) { gEve->AddElement(q); gEve->Redraw3D(kTRUE); } @@ -114,9 +113,9 @@ TEveBoxSet* boxset_freebox(Int_t num=100, Bool_t registerSet=kTRUE) TRandom r(0); - TEveRGBAPalette* pal = new TEveRGBAPalette(0, 130); + auto pal = new TEveRGBAPalette(0, 130); - TEveBoxSet* q = new TEveBoxSet("BoxSet"); + auto q = new TEveBoxSet("BoxSet"); q->SetPalette(pal); q->Reset(TEveBoxSet::kBT_FreeBox, kFALSE, 64); @@ -149,8 +148,7 @@ TEveBoxSet* boxset_freebox(Int_t num=100, Bool_t registerSet=kTRUE) // q->SetPickable(1); // q->SetAlwaysSecSelect(1); - if (registerSet) - { + if (registerSet) { gEve->AddElement(q); gEve->Redraw3D(kTRUE); } diff --git a/tutorials/eve/boxset_cones.C b/tutorials/eve/boxset_cones.C index 314dedae3acd1..3bdcb80cbd73c 100644 --- a/tutorials/eve/boxset_cones.C +++ b/tutorials/eve/boxset_cones.C @@ -10,110 +10,107 @@ TEveBoxSet* boxset_cones(Float_t x=0, Float_t y=0, Float_t z=0, Int_t num=100, Bool_t register=kTRUE) { - TEveManager::Create(); - - using namespace TMath; - - TEveStraightLineSet* lines = new TEveStraightLineSet("StraightLines"); - lines->SetLineColor(kYellow); - lines->SetLineWidth(2); - - TRandom r(0); - TEveRGBAPalette* pal = new TEveRGBAPalette(0, 500); - TEveBoxSet* cones = new TEveBoxSet("ConeSet"); - cones->SetPalette(pal); - cones->Reset(TEveBoxSet::kBT_Cone, kFALSE, 64); - - Float_t a = 40; // max distance between cones - TEveVector dir, pos; - Float_t theta, phi, height, rad; - for (Int_t i=0; iAddCone(pos, dir, rad); - cones->DigitValue(r.Uniform(0, 500)); - - // draw axis line 30% longer than cone height - TEveVector end = pos + dir*1.3f; - lines->AddLine(pos.fX, pos.fY, pos.fZ, end.fX, end.fY, end.fZ); - } - - // by default cone cap not drawn - if (r.Integer(2)>0) cones->SetDrawConeCap(kTRUE); - - cones->RefitPlex(); - TEveTrans& t = cones->RefMainTrans(); - t.SetPos(x, y, z); - - gEve->AddElement(cones); - gEve->AddElement(lines); - - gEve->Redraw3D(kTRUE); - - return cones; + TEveManager::Create(); + + using namespace TMath; + + auto lines = new TEveStraightLineSet("StraightLines"); + lines->SetLineColor(kYellow); + lines->SetLineWidth(2); + + TRandom r(0); + auto pal = new TEveRGBAPalette(0, 500); + auto cones = new TEveBoxSet("ConeSet"); + cones->SetPalette(pal); + cones->Reset(TEveBoxSet::kBT_Cone, kFALSE, 64); + + Float_t a = 40; // max distance between cones + TEveVector dir, pos; + Float_t theta, phi, height, rad; + for (Int_t i=0; iAddCone(pos, dir, rad); + cones->DigitValue(r.Uniform(0, 500)); + + // draw axis line 30% longer than cone height + TEveVector end = pos + dir*1.3f; + lines->AddLine(pos.fX, pos.fY, pos.fZ, end.fX, end.fY, end.fZ); + } + + // by default cone cap not drawn + if (r.Integer(2)>0) cones->SetDrawConeCap(kTRUE); + + cones->RefitPlex(); + TEveTrans& t = cones->RefMainTrans(); + t.SetPos(x, y, z); + + gEve->AddElement(cones); + gEve->AddElement(lines); + + gEve->Redraw3D(kTRUE); + + return cones; } -TEveBoxSet* -elliptic_boxset_cones(Float_t x=0, Float_t y=0, Float_t z=0, - Int_t num=100, Bool_t register=kTRUE) +TEveBoxSet* elliptic_boxset_cones(Float_t x=0, Float_t y=0, Float_t z=0, + Int_t num=100, Bool_t register=kTRUE) { - TEveManager::Create(); + TEveManager::Create(); - using namespace TMath; + using namespace TMath; - TEveManager::Create(); + TEveManager::Create(); - TEveStraightLineSet* lines = new TEveStraightLineSet("StraightLines"); - lines->SetLineColor(kYellow); - lines->SetLineWidth(2); + auto lines = new TEveStraightLineSet("StraightLines"); + lines->SetLineColor(kYellow); + lines->SetLineWidth(2); - TRandom r(0); + TRandom r(0); - TEveBoxSet* cones = new TEveBoxSet("EllipticConeSet"); - cones->Reset(TEveBoxSet::kBT_EllipticCone, kTRUE, 64); + auto cones = new TEveBoxSet("EllipticConeSet"); + cones->Reset(TEveBoxSet::kBT_EllipticCone, kTRUE, 64); - cones->SetPickable(kTRUE); + cones->SetPickable(kTRUE); - Float_t a = 40; // max distance between cones - TEveVector dir, pos; - Float_t theta, phi, height, rad; - for (Int_t i=0; iAddEllipticCone(pos, dir, rad, 0.5*rad, r.Uniform(0,360)); - cones->DigitColor(r.Uniform(20, 255), r.Uniform(20, 255), + cones->AddEllipticCone(pos, dir, rad, 0.5*rad, r.Uniform(0,360)); + cones->DigitColor(r.Uniform(20, 255), r.Uniform(20, 255), r.Uniform(20, 255), r.Uniform(20, 255)); - // draw axis line 30% longer than cone height - TEveVector end = pos + dir*1.3f; - lines->AddLine(pos.fX, pos.fY, pos.fZ, end.fX, end.fY, end.fZ); - } + // draw axis line 30% longer than cone height + TEveVector end = pos + dir*1.3f; + lines->AddLine(pos.fX, pos.fY, pos.fZ, end.fX, end.fY, end.fZ); + } - // by default cone cap not drawn - if (r.Integer(2)>0) cones->SetDrawConeCap(kTRUE); + // by default cone cap not drawn + if (r.Integer(2)>0) cones->SetDrawConeCap(kTRUE); - cones->RefitPlex(); - TEveTrans& t = cones->RefMainTrans(); - t.SetPos(x, y, z); + cones->RefitPlex(); + TEveTrans& t = cones->RefMainTrans(); + t.SetPos(x, y, z); - gEve->AddElement(cones); - gEve->AddElement(lines); + gEve->AddElement(cones); + gEve->AddElement(lines); - gEve->Redraw3D(kTRUE); + gEve->Redraw3D(kTRUE); - return cones; + return cones; } diff --git a/tutorials/eve/calo_detail.C b/tutorials/eve/calo_detail.C index dce8d7c1d5009..01bb926a5fcd2 100644 --- a/tutorials/eve/calo_detail.C +++ b/tutorials/eve/calo_detail.C @@ -17,28 +17,27 @@ void calo_detail() TEveManager::Create(); // data - TEveCaloDataVec* data = MakeVecData(20); + auto data = MakeVecData(20); data->IncDenyDestroy(); // don't delete if zero parent // frames - TEveWindowSlot* slot = - TEveWindow::CreateWindowInTab(gEve->GetBrowser()->GetTabRight()); - TEveWindowPack* packH = slot->MakePack(); + auto slot = TEveWindow::CreateWindowInTab(gEve->GetBrowser()->GetTabRight()); + auto packH = slot->MakePack(); packH->SetElementName("Projections"); packH->SetHorizontal(); packH->SetShowTitleBar(kFALSE); slot = packH->NewSlot(); - TEveWindowPack* pack0 = slot->MakePack(); + auto pack0 = slot->MakePack(); pack0->SetShowTitleBar(kFALSE); - TEveWindowSlot* slotLeftTop = pack0->NewSlot(); - TEveWindowSlot* slotLeftBottom = pack0->NewSlot(); + auto slotLeftTop = pack0->NewSlot(); + auto slotLeftBottom = pack0->NewSlot(); slot = packH->NewSlot(); - TEveWindowPack* pack1 = slot->MakePack(); + auto pack1 = slot->MakePack(); pack1->SetShowTitleBar(kFALSE); - TEveWindowSlot* slotRightTop = pack1->NewSlot(); - TEveWindowSlot* slotRightBottom = pack1->NewSlot(); + auto slotRightTop = pack1->NewSlot(); + auto slotRightBottom = pack1->NewSlot(); // viewers ans scenes in second tab Float_t maxH = 300; @@ -66,21 +65,21 @@ void calo_detail() //______________________________________________________________________________ TEveCaloDataVec* MakeVecData(Int_t ncells) { - // Example how to fill data when bins can be iregular. + // Example how to fill data when bins can be irregular. // If ncells = 0 (default) whole histogram is taken, // otherwise just ncells cells around the maximum. TFile::SetCacheFileDir("."); - TFile* hf = TFile::Open(histFile, "CACHEREAD"); + auto hf = TFile::Open(histFile, "CACHEREAD"); TH2F* h1 = (TH2F*)hf->Get("ecalLego"); TH2F* h2 = (TH2F*)hf->Get("hcalLego"); - TEveCaloDataVec* data = new TEveCaloDataVec(2); + auto data = new TEveCaloDataVec(2); data->RefSliceInfo(0).Setup("ECAL", 0.3, kRed); data->RefSliceInfo(1).Setup("HCAL", 0.1, kBlue); - TAxis *ax = h1->GetXaxis(); - TAxis *ay = h1->GetYaxis(); + auto ax = h1->GetXaxis(); + auto ay = h1->GetYaxis(); Int_t xm = 1, xM = ax->GetNbins(); Int_t ym = 1, yM = ay->GetNbins(); @@ -95,19 +94,14 @@ TEveCaloDataVec* MakeVecData(Int_t ncells) } // Take every second cell and set a random size. - for(Int_t i=xm; i<=xM; i+=2) - { - for(Int_t j=ym; j<=yM; j+=2) - { - if ( (i+j) % 3) - { + for (Int_t i=xm; i<=xM; i+=2) { + for (Int_t j=ym; j<=yM; j+=2) { + if ( (i+j) % 3) { data->AddTower(ax->GetBinLowEdge(i), ax->GetBinUpEdge(i), ay->GetBinLowEdge(j), ay->GetBinUpEdge(j)); data->FillSlice(0, h1->GetBinContent(i, j)); data->FillSlice(1, h2->GetBinContent(i, j)); - } - else - { + } else { data->AddTower(ax->GetBinLowEdge(i), 2 * ax->GetBinWidth(i) + ax->GetBinLowEdge(i), ay->GetBinLowEdge(j), diff --git a/tutorials/eve/calorimeters.C b/tutorials/eve/calorimeters.C index 8eb66a5cc7571..6c9072fe82c47 100644 --- a/tutorials/eve/calorimeters.C +++ b/tutorials/eve/calorimeters.C @@ -47,10 +47,10 @@ void calorimeters() // event data TFile::SetCacheFileDir("."); - TFile* hf = TFile::Open(histFile, "CACHEREAD"); - TH2F* ecalHist = (TH2F*)hf->Get("ecalLego"); - TH2F* hcalHist = (TH2F*)hf->Get("hcalLego"); - TEveCaloDataHist* data = new TEveCaloDataHist(); + auto hf = TFile::Open(histFile, "CACHEREAD"); + auto ecalHist = (TH2F*)hf->Get("ecalLego"); + auto hcalHist = (TH2F*)hf->Get("hcalLego"); + auto data = new TEveCaloDataHist(); data->AddHistogram(ecalHist); data->RefSliceInfo(0).Setup("ECAL", 0.3, kBlue); data->AddHistogram(hcalHist); @@ -64,34 +64,33 @@ void calorimeters() // first tab - TEveCaloLego* lego = MakeCaloLego(data, 0); + auto lego = MakeCaloLego(data, 0); // // second tab // // frames - TEveWindowSlot* slot = - TEveWindow::CreateWindowInTab(gEve->GetBrowser()->GetTabRight()); - TEveWindowPack* packH = slot->MakePack(); + auto slot = TEveWindow::CreateWindowInTab(gEve->GetBrowser()->GetTabRight()); + auto packH = slot->MakePack(); packH->SetElementName("Projections"); packH->SetHorizontal(); packH->SetShowTitleBar(kFALSE); slot = packH->NewSlot(); - TEveWindowPack* pack0 = slot->MakePack(); + auto pack0 = slot->MakePack(); pack0->SetShowTitleBar(kFALSE); - TEveWindowSlot* slotLeftTop = pack0->NewSlot(); - TEveWindowSlot* slotLeftBottom = pack0->NewSlot(); + auto slotLeftTop = pack0->NewSlot(); + auto slotLeftBottom = pack0->NewSlot(); slot = packH->NewSlot(); - TEveWindowPack* pack1 = slot->MakePack(); + auto pack1 = slot->MakePack(); pack1->SetShowTitleBar(kFALSE); - TEveWindowSlot* slotRightTop = pack1->NewSlot(); - TEveWindowSlot* slotRightBottom = pack1->NewSlot(); + auto slotRightTop = pack1->NewSlot(); + auto slotRightBottom = pack1->NewSlot(); // viewers ans scenes in second tab - TEveCalo3D* calo3d = MakeCalo3D(data, slotRightTop); + auto calo3d = MakeCalo3D(data, slotRightTop); MakeCalo2D(calo3d, slotLeftTop, TEveProjection::kPT_RPhi); MakeCalo2D(calo3d, slotLeftBottom, TEveProjection::kPT_RhoZ); lego = MakeCaloLego(data, slotRightBottom); @@ -108,8 +107,7 @@ TEveCaloLego* MakeCaloLego(TEveCaloData* data, TEveWindowSlot* slot) TEveViewer* v; TEveScene* s; - if (slot) - { + if (slot) { MakeViewerScene(slot, v, s); } else { v = gEve->GetDefaultViewer(); @@ -118,7 +116,7 @@ TEveCaloLego* MakeCaloLego(TEveCaloData* data, TEveWindowSlot* slot) v->SetElementName("Viewer - Lego"); s->SetElementName("Scene - Lego"); - TEveCaloLego* lego = new TEveCaloLego(data); + auto lego = new TEveCaloLego(data); s->AddElement(lego); // By the default lego extends is (1x1x1). Resize it to put in 'natural' @@ -128,7 +126,7 @@ TEveCaloLego* MakeCaloLego(TEveCaloData* data, TEveWindowSlot* slot) lego->RefMainTrans().SetScale(TMath::TwoPi(), TMath::TwoPi(), TMath::Pi()); // draws scales and axis on borders of window - TGLViewer* glv = v->GetGLViewer(); + auto glv = v->GetGLViewer(); TEveCaloLegoOverlay* overlay = new TEveCaloLegoOverlay(); glv->AddOverlayElement(overlay); overlay->SetCaloLego(lego); @@ -145,14 +143,14 @@ TEveCaloLego* MakeCaloLego(TEveCaloData* data, TEveWindowSlot* slot) //______________________________________________________________________________ TEveCalo3D* MakeCalo3D(TEveCaloData* data, TEveWindowSlot* slot) { - // 3D catersian view. + // 3D cartesian view. TEveViewer* v; TEveScene* s; MakeViewerScene(slot, v, s); v->SetElementName("Viewer - 3D"); s->SetElementName("Scene - 3D"); - TEveCalo3D* calo3d = new TEveCalo3D(data); + auto calo3d = new TEveCalo3D(data); calo3d->SetBarrelRadius(129.00); calo3d->SetEndCapPos(268.36); s->AddElement(calo3d); @@ -174,10 +172,10 @@ TEveCalo2D* MakeCalo2D(TEveCalo3D* calo3d, TEveWindowSlot* slot, v->SetElementName("Viewer - 2D"); s->SetElementName("Scene - 2D"); - TEveProjectionManager* mng = new TEveProjectionManager(); + auto mng = new TEveProjectionManager(); mng->SetProjection(t); - TEveProjectionAxes* axes = new TEveProjectionAxes(mng); + auto axes = new TEveProjectionAxes(mng); s->AddElement(axes); TEveCalo2D* calo2d = (TEveCalo2D*) mng->ImportElements(calo3d); s->AddElement(calo2d); @@ -208,7 +206,7 @@ void add_jet(TEveElement* parent, const char* name, Float_t eta, Float_t phi, Float_t deta, Float_t dphi) { - TEveJetCone* jet = new TEveJetCone(name, name); + auto jet = new TEveJetCone(name, name); jet->SetMainTransparency(60); jet->SetLineColor(kRed); jet->SetCylinder(129 - 10, 268.36 - 10); diff --git a/tutorials/eve/compound.C b/tutorials/eve/compound.C index 229f0b069f114..17de97a2abc71 100644 --- a/tutorials/eve/compound.C +++ b/tutorials/eve/compound.C @@ -9,12 +9,11 @@ TEveLine* random_line(TRandom& rnd, Int_t n, Float_t delta) { - TEveLine* line = new TEveLine; + auto line = new TEveLine; line->SetMainColor(kGreen); Float_t x = 0, y = 0, z = 0; - for (Int_t i=0; iSetNextPoint(x, y, z); x += rnd.Uniform(0, delta); y += rnd.Uniform(0, delta); @@ -28,13 +27,13 @@ void compound() { TEveManager::Create(); - TEveLine* ml = new TEveLine; + auto ml = new TEveLine; ml->SetMainColor(kRed); ml->SetLineStyle(2); ml->SetLineWidth(3); gEve->InsertVizDBEntry("BigLine", ml); - TEveCompound* cmp = new TEveCompound; + auto cmp = new TEveCompound; cmp->SetMainColor(kGreen); gEve->AddElement(cmp); @@ -45,25 +44,25 @@ void compound() cmp->AddElement(random_line(rnd, 20, 10)); cmp->AddElement(random_line(rnd, 20, 10)); - TEveLine* line = random_line(rnd, 20, 12); + auto line = random_line(rnd, 20, 12); line->ApplyVizTag("BigLine"); cmp->AddElement(line); cmp->CloseCompound(); // Projected view - TEveViewer *viewer = gEve->SpawnNewViewer("Projected"); - TEveScene *scene = gEve->SpawnNewScene("Projected Event"); + auto viewer = gEve->SpawnNewViewer("Projected"); + auto scene = gEve->SpawnNewScene("Projected Event"); viewer->AddScene(scene); { - TGLViewer* v = viewer->GetGLViewer(); + auto v = viewer->GetGLViewer(); v->SetCurrentCamera(TGLViewer::kCameraOrthoXOY); } // projections - TEveProjectionManager* mng = new TEveProjectionManager(TEveProjection::kPT_RPhi); + auto mng = new TEveProjectionManager(TEveProjection::kPT_RPhi); scene->AddElement(mng); - TEveProjectionAxes* axes = new TEveProjectionAxes(mng); + auto axes = new TEveProjectionAxes(mng); scene->AddElement(axes); gEve->AddToListTree(axes, kTRUE); gEve->AddToListTree(mng, kTRUE); diff --git a/tutorials/eve/csgdemo.C b/tutorials/eve/csgdemo.C index 88941e750c532..7f72aeb768987 100644 --- a/tutorials/eve/csgdemo.C +++ b/tutorials/eve/csgdemo.C @@ -5,7 +5,7 @@ /// Stripped down to demonstrate EVE shape-extracts. /// 1. `Run root csgdemo.C` /// This will produce csg.root containing the extract. -/// 2. Display the assebly as: +/// 2. Display the assembly as: /// `root show_extract.C("csg.root")` /// /// \image html eve_csgdemo.png @@ -20,27 +20,27 @@ void csgdemo () { gSystem->Load("libGeom"); - TCanvas *c = new TCanvas("composite shape", "A * B - C"); + auto c = new TCanvas("composite shape", "A * B - C"); c->Iconify(); if (gGeoManager) delete gGeoManager; new TGeoManager("xtru", "poza12"); - TGeoMaterial *mat = new TGeoMaterial("Al", 26.98,13,2.7); - TGeoMedium *med = new TGeoMedium("MED",1,mat); - TGeoVolume *top = gGeoManager->MakeBox("TOP",med,100,100,100); + auto mat = new TGeoMaterial("Al", 26.98,13,2.7); + auto med = new TGeoMedium("MED",1,mat); + auto top = gGeoManager->MakeBox("TOP",med,100,100,100); gGeoManager->SetTopVolume(top); // define shape components with names - TGeoBBox *box = new TGeoBBox("box", 20., 20., 20.); - TGeoBBox *box1 = new TGeoBBox("box1", 5., 5., 5.); - TGeoSphere *sph = new TGeoSphere("sph", 5., 25.); - TGeoSphere *sph1 = new TGeoSphere("sph1", 1., 15.); + auto box = new TGeoBBox("box", 20., 20., 20.); + auto box1 = new TGeoBBox("box1", 5., 5., 5.); + auto sph = new TGeoSphere("sph", 5., 25.); + auto sph1 = new TGeoSphere("sph1", 1., 15.); // create the composite shape based on a Boolean expression - TGeoTranslation *tr = new TGeoTranslation(0., 30., 0.); - TGeoTranslation *tr1 = new TGeoTranslation(0., 40., 0.); - TGeoTranslation *tr2 = new TGeoTranslation(0., 30., 0.); - TGeoTranslation *tr3 = new TGeoTranslation(0., 30., 0.); + auto tr = new TGeoTranslation(0., 30., 0.); + auto tr1 = new TGeoTranslation(0., 40., 0.); + auto tr2 = new TGeoTranslation(0., 30., 0.); + auto tr3 = new TGeoTranslation(0., 30., 0.); tr->SetName("tr"); tr1->SetName("tr1"); tr2->SetName("tr2"); @@ -54,7 +54,7 @@ void csgdemo () TGeoCompositeShape *cs = new TGeoCompositeShape ("mir", "(sph * box) + (sph1:tr - box1:tr1)"); - TGeoVolume *vol = new TGeoVolume("COMP4", cs); + auto vol = new TGeoVolume("COMP4", cs); vol->SetLineColor(kMagenta); top->AddNode(vol,1); gGeoManager->CloseGeometry(); @@ -66,8 +66,8 @@ void csgdemo () TGLFaceSet::SetEnforceTriangles(kTRUE); TEveManager::Create(); - TGeoNode* node = gGeoManager->GetTopNode(); - TEveGeoTopNode* en = new TEveGeoTopNode(gGeoManager, node); + auto node = gGeoManager->GetTopNode(); + auto en = new TEveGeoTopNode(gGeoManager, node); en->SetVisLevel(4); en->GetNode()->GetVolume()->SetVisibility(kFALSE); diff --git a/tutorials/eve/geom_alias.C b/tutorials/eve/geom_alias.C index 89385980d0f5e..e3cea93237332 100644 --- a/tutorials/eve/geom_alias.C +++ b/tutorials/eve/geom_alias.C @@ -1,6 +1,6 @@ /// \file /// \ingroup tutorial_eve -/// Demonstates usage of geometry aliases - merge ALICE ITS with ATLAS MUON. +/// Demonstrates usage of geometry aliases - merge ALICE ITS with ATLAS MUON. /// /// \image html eve_geom_alias.png /// \macro_code @@ -17,23 +17,21 @@ void geom_alias() gGeoManager = gEve->GetGeometryByAlias("ALICE"); - TGeoNode* node1 = gGeoManager->GetTopVolume()->FindNode("ITSV_1"); - TEveGeoTopNode* its = new TEveGeoTopNode(gGeoManager, node1); + auto node1 = gGeoManager->GetTopVolume()->FindNode("ITSV_1"); + auto its = new TEveGeoTopNode(gGeoManager, node1); gEve->AddGlobalElement(its); - gGeoManager = gEve->GetGeometryByAlias("ATLAS"); - TGeoNode* node2 = gGeoManager->GetTopVolume()->FindNode("OUTE_1"); - TEveGeoTopNode* atlas = new TEveGeoTopNode(gGeoManager, node2); + auto node2 = gGeoManager->GetTopVolume()->FindNode("OUTE_1"); + auto atlas = new TEveGeoTopNode(gGeoManager, node2); gEve->AddGlobalElement(atlas); - gEve->FullRedraw3D(kTRUE); // EClipType not exported to CINT (see TGLUtil.h): // 0 - no clip, 1 - clip plane, 2 - clip box - TGLViewer *v = gEve->GetDefaultGLViewer(); + auto v = gEve->GetDefaultGLViewer(); v->GetClipSet()->SetClipType(TGLClip::EType(2)); v->RefreshPadEditor(v); diff --git a/tutorials/eve/geom_alice_its.C b/tutorials/eve/geom_alice_its.C index 5722744821edf..c980d0ec4d643 100644 --- a/tutorials/eve/geom_alice_its.C +++ b/tutorials/eve/geom_alice_its.C @@ -58,21 +58,18 @@ TEveGeoNode* descend_extract(TGeoNode* node) TEveGeoNode *res = 0; - TGeoMedium *medium = node->GetVolume()->GetMedium(); - if (medium && material == medium->GetName()) - { + auto medium = node->GetVolume()->GetMedium(); + if (medium && material == medium->GetName()) { // Node of interest - instantiate eve representation and return. res = new TEveGeoNode(node); return res; } Int_t nd = node->GetNdaughters(); - for (Int_t i = 0; i < nd; ++i) - { - TEveGeoNode *ed = descend_extract(node->GetDaughter(i)); + for (Int_t i = 0; i < nd; ++i) { + auto ed = descend_extract(node->GetDaughter(i)); - if (ed) - { + if (ed) { if (res == 0) res = new TEveGeoNode(node); res->AddElement(ed); } @@ -95,12 +92,11 @@ void extract_ssd_modules() return; } - TGeoNode *node = gGeoManager->GetCurrentNode(); + auto node = gGeoManager->GetCurrentNode(); TEveGeoNode *egn = descend_extract(node); - if (egn == 0) - { + if (egn == 0) { Warning(kEH, "No matching nodes found."); return; } diff --git a/tutorials/eve/geom_alice_tpc.C b/tutorials/eve/geom_alice_tpc.C index d5da1a6b69fde..d3b9a0848b091 100644 --- a/tutorials/eve/geom_alice_tpc.C +++ b/tutorials/eve/geom_alice_tpc.C @@ -13,8 +13,8 @@ void geom_alice_tpc() gGeoManager = gEve->GetGeometry("http://root.cern.ch/files/alice.root"); - TGeoNode* node = gGeoManager->GetTopVolume()->FindNode("TPC_M_1"); - TEveGeoTopNode* tpc = new TEveGeoTopNode(gGeoManager, node); + auto node = gGeoManager->GetTopVolume()->FindNode("TPC_M_1"); + auto tpc = new TEveGeoTopNode(gGeoManager, node); gEve->AddGlobalElement(tpc); gEve->Redraw3D(kTRUE); diff --git a/tutorials/eve/geom_atlas.C b/tutorials/eve/geom_atlas.C index 2d75f1c9e7a22..fd5343f61d2c5 100644 --- a/tutorials/eve/geom_atlas.C +++ b/tutorials/eve/geom_atlas.C @@ -15,15 +15,15 @@ void geom_atlas() gGeoManager = gEve->GetGeometry("http://root.cern.ch/files/atlas.root"); gGeoManager->DefaultColors(); - TGeoNode* node1 = gGeoManager->GetTopVolume()->FindNode("INNE_1"); + auto node1 = gGeoManager->GetTopVolume()->FindNode("INNE_1"); TEveGeoTopNode* inn = new TEveGeoTopNode(gGeoManager, node1); gEve->AddGlobalElement(inn); - TGeoNode* node2 = gGeoManager->GetTopVolume()->FindNode("CENT_1"); + auto node2 = gGeoManager->GetTopVolume()->FindNode("CENT_1"); TEveGeoTopNode* cnt = new TEveGeoTopNode(gGeoManager, node2); gEve->AddGlobalElement(cnt); - TGeoNode* node3 = gGeoManager->GetTopVolume()->FindNode("OUTE_1"); + auto node3 = gGeoManager->GetTopVolume()->FindNode("OUTE_1"); TEveGeoTopNode* out = new TEveGeoTopNode(gGeoManager, node3); gEve->AddGlobalElement(out); @@ -31,7 +31,7 @@ void geom_atlas() // EClipType not exported to CINT (see TGLUtil.h): // 0 - no clip, 1 - clip plane, 2 - clip box - TGLViewer *v = gEve->GetDefaultGLViewer(); + auto v = gEve->GetDefaultGLViewer(); v->GetClipSet()->SetClipType(TGLClip::EType(1)); v->RefreshPadEditor(v); diff --git a/tutorials/eve/geom_atlas_playback.C b/tutorials/eve/geom_atlas_playback.C index eccfda0d42ac6..c2ac5fd579022 100644 --- a/tutorials/eve/geom_atlas_playback.C +++ b/tutorials/eve/geom_atlas_playback.C @@ -5,7 +5,7 @@ /// /// Script: /// - type: .x geom_atlas.C -/// - demonstratate rotation (left-mouse), zoom (right-mouse left-right) +/// - demonstrate rotation (left-mouse), zoom (right-mouse left-right) /// - show wireframe (w), smooth (r, default) and outline (t) render modes /// - show flip of background color dark-light-dark (e pressed twice) /// - disable clipping plane in GL-viewer panel @@ -20,5 +20,5 @@ void geom_atlas_playback() { - TRecorder* r = new TRecorder("http://mtadel.home.cern.ch/mtadel/geom_atlas_recording.root"); + auto r = new TRecorder("http://mtadel.home.cern.ch/mtadel/geom_atlas_recording.root"); } diff --git a/tutorials/eve/geom_cms.C b/tutorials/eve/geom_cms.C index ff5b07369665c..8eb7eb1ac232e 100644 --- a/tutorials/eve/geom_cms.C +++ b/tutorials/eve/geom_cms.C @@ -15,17 +15,17 @@ void geom_cms() gGeoManager = gEve->GetGeometry("http://root.cern.ch/files/cms.root"); gGeoManager->DefaultColors(); - TGeoVolume* top = gGeoManager->GetTopVolume()->FindNode("CMSE_1")->GetVolume(); + auto top = gGeoManager->GetTopVolume()->FindNode("CMSE_1")->GetVolume(); TEveGeoTopNode* trk = new TEveGeoTopNode(gGeoManager, top->FindNode("TRAK_1")); trk->SetVisLevel(6); gEve->AddGlobalElement(trk); - TEveGeoTopNode* calo = new TEveGeoTopNode(gGeoManager, top->FindNode("CALO_1")); + auto calo = new TEveGeoTopNode(gGeoManager, top->FindNode("CALO_1")); calo->SetVisLevel(3); gEve->AddGlobalElement(calo); - TEveGeoTopNode* muon = new TEveGeoTopNode(gGeoManager, top->FindNode("MUON_1")); + auto muon = new TEveGeoTopNode(gGeoManager, top->FindNode("MUON_1")); muon->SetVisLevel(4); gEve->AddGlobalElement(muon); @@ -33,7 +33,7 @@ void geom_cms() // EClipType not exported to CINT (see TGLUtil.h): // 0 - no clip, 1 - clip plane, 2 - clip box - TGLViewer *v = gEve->GetDefaultGLViewer(); + auto v = gEve->GetDefaultGLViewer(); v->GetClipSet()->SetClipType(TGLClip::EType(1)); v->ColorSet().Background().SetColor(kMagenta+4); v->SetGuideState(TGLUtil::kAxesEdge, kTRUE, kFALSE, 0); diff --git a/tutorials/eve/geom_cms_playback.C b/tutorials/eve/geom_cms_playback.C index bf772af87226b..3a02135bac324 100644 --- a/tutorials/eve/geom_cms_playback.C +++ b/tutorials/eve/geom_cms_playback.C @@ -5,7 +5,7 @@ /// /// Script: /// - type: .x geom_cms.C -/// - demonstratate rotation (left-mouse), zoom (right-mouse left-right) +/// - demonstrate rotation (left-mouse), zoom (right-mouse left-right) /// - show GL window Help Window /// - show wireframe (w), smooth (r, default) and outline (t) render modes /// - show flip of background color dark-light-dark (e pressed twice) @@ -21,5 +21,5 @@ void geom_cms_playback() { - TRecorder* r = new TRecorder("http://root.cern.ch/files/geom_cms_recording.root"); + auto r = new TRecorder("http://root.cern.ch/files/geom_cms_recording.root"); } diff --git a/tutorials/eve/geom_cms_stereo.C b/tutorials/eve/geom_cms_stereo.C index 808a595202248..ab214c04862ad 100644 --- a/tutorials/eve/geom_cms_stereo.C +++ b/tutorials/eve/geom_cms_stereo.C @@ -2,7 +2,7 @@ /// \ingroup tutorial_eve /// Shows CMS geometry in stereo mode. /// This requires quad-buffer support in the OpenGL hardware / driver, -/// otheriwse a fatal error occurs. +/// otherwise a fatal error occurs. /// /// \image html eve_geom_cms_stereo.png /// \macro_code @@ -17,17 +17,17 @@ void geom_cms_stereo(Bool_t quad_buf=kTRUE) gGeoManager = gEve->GetGeometry("http://root.cern.ch/files/cms.root"); gGeoManager->DefaultColors(); - TGeoVolume* top = gGeoManager->GetTopVolume()->FindNode("CMSE_1")->GetVolume(); + auto top = gGeoManager->GetTopVolume()->FindNode("CMSE_1")->GetVolume(); - TEveGeoTopNode* trk = new TEveGeoTopNode(gGeoManager, top->FindNode("TRAK_1")); + auto trk = new TEveGeoTopNode(gGeoManager, top->FindNode("TRAK_1")); trk->SetVisLevel(6); gEve->AddGlobalElement(trk); - TEveGeoTopNode* calo = new TEveGeoTopNode(gGeoManager, top->FindNode("CALO_1")); + auto calo = new TEveGeoTopNode(gGeoManager, top->FindNode("CALO_1")); calo->SetVisLevel(3); gEve->AddGlobalElement(calo); - TEveGeoTopNode* muon = new TEveGeoTopNode(gGeoManager, top->FindNode("MUON_1")); + auto muon = new TEveGeoTopNode(gGeoManager, top->FindNode("MUON_1")); muon->SetVisLevel(4); gEve->AddGlobalElement(muon); @@ -36,7 +36,7 @@ void geom_cms_stereo(Bool_t quad_buf=kTRUE) TEveWindowSlot* slot = 0; slot = TEveWindow::CreateWindowInTab(gEve->GetBrowser()->GetTabRight()); - TEveViewer* sv = new TEveViewer("Stereo GL", "Stereoscopic view"); + auto sv = new TEveViewer("Stereo GL", "Stereoscopic view"); sv->SpawnGLViewer(gEve->GetEditor(), kTRUE, quad_buf); sv->AddScene(gEve->GetGlobalScene()); @@ -55,7 +55,7 @@ void geom_cms_stereo(Bool_t quad_buf=kTRUE) // EClipType not exported to CINT (see TGLUtil.h): // 0 - no clip, 1 - clip plane, 2 - clip box - TGLViewer *v = gEve->GetDefaultGLViewer(); + auto v = gEve->GetDefaultGLViewer(); v->GetClipSet()->SetClipType(TGLClip::EType(1)); v->ColorSet().Background().SetColor(kMagenta+4); v->SetGuideState(TGLUtil::kAxesEdge, kTRUE, kFALSE, 0); diff --git a/tutorials/eve/geom_lhcb.C b/tutorials/eve/geom_lhcb.C index 52235df471c24..ba501e33f8ad9 100644 --- a/tutorials/eve/geom_lhcb.C +++ b/tutorials/eve/geom_lhcb.C @@ -1,6 +1,6 @@ /// \file /// \ingroup tutorial_eve -/// Shows CMS geometry. +/// Shows LHCB geometry. /// /// \image html eve_geom_lhcb.png /// \macro_code @@ -15,7 +15,7 @@ void geom_lhcb() gGeoManager = gEve->GetGeometry("http://root.cern.ch/files/lhcbfull.root"); gGeoManager->DefaultColors(); - TEveGeoTopNode* tn = new TEveGeoTopNode(gGeoManager, gGeoManager->GetTopNode()); + auto tn = new TEveGeoTopNode(gGeoManager, gGeoManager->GetTopNode()); tn->SetVisLevel(4); gEve->AddGlobalElement(tn); @@ -23,7 +23,7 @@ void geom_lhcb() // EClipType not exported to CINT (see TGLUtil.h): // 0 - no clip, 1 - clip plane, 2 - clip box - TGLViewer *v = gEve->GetDefaultGLViewer(); + auto v = gEve->GetDefaultGLViewer(); v->GetClipSet()->SetClipType(TGLClip::EType(1)); v->ColorSet().Background().SetColor(kMagenta+4); v->SetGuideState(TGLUtil::kAxesEdge, kTRUE, kFALSE, 0); diff --git a/tutorials/eve/glplot.C b/tutorials/eve/glplot.C index 751b51ce07f77..6e530714b10ce 100644 --- a/tutorials/eve/glplot.C +++ b/tutorials/eve/glplot.C @@ -12,17 +12,18 @@ void glplot() TEveManager::Create(); gEve->GetDefaultGLViewer()->SetCurrentCamera(TGLViewer::kCameraPerspXOY); - TF2 *f2 = new TF2("f2","x**2 + y**2 - x**3 -8*x*y**4", -1., 1.2, -1.5, 1.5); + auto f2 = new TF2("f2","x**2 + y**2 - x**3 -8*x*y**4", -1., 1.2, -1.5, 1.5); f2->SetFillColor(45); - x = new TEvePlot3D("EvePlot - TF2"); + auto x = new TEvePlot3D("EvePlot - TF2"); x->SetLogZ(kTRUE); x->SetPlot(f2,"glsurf4"); x->RefMainTrans().MoveLF(2, 1); gEve->AddElement(x); - - TH3F *h31 = new TH3F("h31", "h31", 10, -1, 1, 10, -1, 1, 10, -1, 1); - h31->FillRandom("gaus"); + auto h31 = new TH3F("h31", "h31", 10, -1, 1, 10, -1, 1, 10, -1, 1); + auto gxy = new TF3("gaus2","xygaus"); + gxy->SetParameters(1,0,1,0,0.3); + h31->FillRandom("gaus2"); h31->SetFillColor(2); x = new TEvePlot3D("EvePlot - TH3F"); x->SetPlot(h31, "glbox"); diff --git a/tutorials/eve/glplot_geom.C b/tutorials/eve/glplot_geom.C index a799aceaeaf59..a60da6d92bf53 100644 --- a/tutorials/eve/glplot_geom.C +++ b/tutorials/eve/glplot_geom.C @@ -13,10 +13,13 @@ void glplot_geom() TEveUtil::Macro("show_extract.C"); - TH3F *h31 = new TH3F("h31", "h31", 20, -3, 3, 20, -3, 3, 20, -3, 3); - h31->FillRandom("gaus", 20*20*20); + auto h31 = new TH3F("h31", "h31", 20, -3, 3, 20, -3, 3, 20, -3, 3); + auto gxy = new TF3("gaus2","xygaus"); + gxy->SetParameters(1,0,1,0,0.3); + h31->FillRandom("gaus2"); + h31->SetFillColor(2); - x = new TEvePlot3D("EvePlot - TH3F"); + auto x = new TEvePlot3D("EvePlot - TH3F"); x->SetPlot(h31, "glbox"); x->RefMainTrans().Scale(800, 800, 1000); x->RefMainTrans().RotateLF(1, 3, TMath::PiOver2()); diff --git a/tutorials/eve/hierarchical_scene.C b/tutorials/eve/hierarchical_scene.C index ab14d5f088954..7100a1efbe83e 100644 --- a/tutorials/eve/hierarchical_scene.C +++ b/tutorials/eve/hierarchical_scene.C @@ -13,9 +13,8 @@ void add_blobs(TEveElement* p, Float_t rad, Float_t height, Float_t size, { if (level <= 0) return; - for (Int_t i = 0; i < Ns; ++i) - { - TEveGeoShape* x = new TEveGeoShape("SS"); + for (Int_t i = 0; i < Ns; ++i) { + auto x = new TEveGeoShape("SS"); x->SetShape(new TGeoSphere(0, size)); Double_t phi = TMath::TwoPi() * i / Ns; x->RefMainTrans().SetPos(rad*TMath::Cos(phi), @@ -36,7 +35,7 @@ void hierarchical_scene() TColor::SetPalette(1, 0); gRandom = new TRandom3(0); - TEveScene *s = gEve->SpawnNewScene("Hierachical Scene", "OoogaDooga"); + auto s = gEve->SpawnNewScene("Hierarchical Scene", "OoogaDooga"); s->SetHierarchical(kTRUE); gEve->GetDefaultViewer()->AddScene(s); diff --git a/tutorials/eve/jetcone.C b/tutorials/eve/jetcone.C index 04451c1c2e66c..9772e4b712e12 100644 --- a/tutorials/eve/jetcone.C +++ b/tutorials/eve/jetcone.C @@ -29,26 +29,26 @@ void jetcone() Float_t length = 300.; // -- Define palette - TEveRGBAPalette* pal = new TEveRGBAPalette(0, 500); + auto pal = new TEveRGBAPalette(0, 500); // ----------------------------------------------------------------------- // -- Line sets // ----------------------------------------------------------------------- // -- Define cone center - TEveStraightLineSet* axis = new TEveStraightLineSet("Cone Axis"); + auto axis = new TEveStraightLineSet("Cone Axis"); axis->SetLineColor(kGreen); axis->SetLineWidth(2); - TEveStraightLineSet* tracksXYZ = new TEveStraightLineSet("StraightLinesXYZ"); + auto tracksXYZ = new TEveStraightLineSet("StraightLinesXYZ"); tracksXYZ->SetLineColor(kRed); tracksXYZ->SetLineWidth(2); - TEveStraightLineSet* tracksEtaPhi = new TEveStraightLineSet("StraightLinesEtaPhi"); + auto tracksEtaPhi = new TEveStraightLineSet("StraightLinesEtaPhi"); tracksEtaPhi->SetLineColor(kYellow); tracksEtaPhi->SetLineWidth(2); - TEveStraightLineSet* tracksSeedEtaPhi = new TEveStraightLineSet("StraightLinesEtaPhiSeed"); + auto tracksSeedEtaPhi = new TEveStraightLineSet("StraightLinesEtaPhiSeed"); tracksSeedEtaPhi->SetLineColor(kBlue); tracksSeedEtaPhi->SetLineWidth(2); @@ -98,7 +98,7 @@ void jetcone() Float_t coneEta = r.Uniform(-0.9, 0.9); Float_t conePhi = r.Uniform(0.0, TwoPi() ); - // -- Primary vertx as origin + // -- Primary vertex as origin TEveVector coneOrigin(0.0,0.0,0.0); // -- Get Cone Axis - axis line 10% longer than cone height @@ -108,7 +108,7 @@ void jetcone() axis->AddLine( 0., 0., 0., coneAxis.fX, coneAxis.fY, coneAxis.fZ ); // -- Draw jet cone - TEveJetCone* jetCone = new TEveJetCone("JetCone"); + auto jetCone = new TEveJetCone("JetCone"); jetCone->SetPickable(kTRUE); jetCone->SetCylinder( 250., 250. ); if ( (jetCone->AddCone( coneEta, conePhi, coneRadius ) ) != -1) diff --git a/tutorials/eve/lineset.C b/tutorials/eve/lineset.C index 6d71a34faf9af..3c326da520145 100644 --- a/tutorials/eve/lineset.C +++ b/tutorials/eve/lineset.C @@ -14,17 +14,14 @@ TEveStraightLineSet* lineset(Int_t nlines = 40, Int_t nmarkers = 4) TRandom r(0); Float_t s = 100; - TEveStraightLineSet* ls = new TEveStraightLineSet(); + auto ls = new TEveStraightLineSet(); - for(Int_t i = 0; iAddLine( r.Uniform(-s,s), r.Uniform(-s,s), r.Uniform(-s,s), r.Uniform(-s,s), r.Uniform(-s,s), r.Uniform(-s,s)); // add random number of markers Int_t nm = Int_t(nmarkers* r.Rndm()); - for(Int_t m = 0; m < nm; m++) { - ls->AddMarker(i, r.Rndm()); - } + for (Int_t m = 0; m < nm; m++) ls->AddMarker(i, r.Rndm()); } ls->SetMarkerSize(1.5); @@ -43,17 +40,14 @@ TEveStraightLineSet* lineset_2d(Int_t nlines = 40, Int_t nmarkers = 4) TRandom r(0); Float_t s = 100; - TEveStraightLineSet* ls = new TEveStraightLineSet(); + auto ls = new TEveStraightLineSet(); - for(Int_t i = 0; iAddLine( r.Uniform(-s,s), r.Uniform(-s,s), 0, r.Uniform(-s,s), r.Uniform(-s,s), 0); // add random number of markers Int_t nm = Int_t(nmarkers* r.Rndm()); - for(Int_t m = 0; m < nm; m++) { - ls->AddMarker(i, r.Rndm()); - } + for (Int_t m = 0; m < nm; m++) ls->AddMarker(i, r.Rndm()); } ls->SetMarkerSize(1.5); diff --git a/tutorials/eve/overlay_palette.C b/tutorials/eve/overlay_palette.C index 0737a7cb93d4e..572a17fb68728 100644 --- a/tutorials/eve/overlay_palette.C +++ b/tutorials/eve/overlay_palette.C @@ -8,10 +8,8 @@ void overlay_palette() { TEveManager::Create(); - - TEveRGBAPalette *p = new TEveRGBAPalette(0, 100); - TEveRGBAPaletteOverlay *po = new TEveRGBAPaletteOverlay(p, 0.55, 0.1, 0.4, 0.05); - - TGLViewer* v = gEve->GetDefaultGLViewer(); + auto p = new TEveRGBAPalette(0, 100); + auto po = new TEveRGBAPaletteOverlay(p, 0.55, 0.1, 0.4, 0.05); + auto v = gEve->GetDefaultGLViewer(); v->AddOverlayElement(po); } diff --git a/tutorials/eve/pack.C b/tutorials/eve/pack.C index 42af31630a5ef..95194a916c217 100644 --- a/tutorials/eve/pack.C +++ b/tutorials/eve/pack.C @@ -14,7 +14,7 @@ TGTextButton* b = 0; void pack() { - TGMainFrame* mf = new TGMainFrame(0, 400, 300); + auto mf = new TGMainFrame(0, 400, 300); mf->SetWindowName("Foo"); hp = new TGPack(mf, mf->GetWidth(), mf->GetHeight()); diff --git a/tutorials/eve/paramlist.C b/tutorials/eve/paramlist.C index ed4094721ca68..fd30104cab83b 100644 --- a/tutorials/eve/paramlist.C +++ b/tutorials/eve/paramlist.C @@ -26,11 +26,9 @@ public: void OnParamChanged(const char* parameter) { - TEveParamList* pl = dynamic_cast - (reinterpret_cast(gTQSender)); + auto pl = dynamic_cast (reinterpret_cast(gTQSender)); - printf("Change in param-list '%s', parameter '%s'.\n", - pl->GetElementName(), parameter); + printf("Change in param-list '%s', parameter '%s'.\n", pl->GetElementName(), parameter); } ClassDef(TParamFollower, 0); diff --git a/tutorials/eve/pointset.C b/tutorials/eve/pointset.C index 8e01c26e154ee..d602ddcd9158c 100644 --- a/tutorials/eve/pointset.C +++ b/tutorials/eve/pointset.C @@ -19,13 +19,12 @@ TEvePointSet* pointset(Int_t npoints = 512, TEveElement* parent=0) { TEveManager::Create(); - if (!gRandom) - gRandom = new TRandom(0); + if (!gRandom) gRandom = new TRandom(0); TRandom& r= *gRandom; Float_t s = 100; - TEvePointSet* ps = new TEvePointSet(); + auto ps = new TEvePointSet(); ps->SetOwnIds(kTRUE); for(Int_t i = 0; iSetMarkerSize(r.Uniform(1, 2)); ps->SetMarkerStyle(4); - if (parent) - { + if (parent) { parent->AddElement(ps); - } - else - { + } else { gEve->AddElement(ps); gEve->Redraw3D(); } @@ -51,20 +47,17 @@ TEvePointSet* pointset(Int_t npoints = 512, TEveElement* parent=0) return ps; } -TEvePointSet* -pointset_hierarchy(Int_t level=3, Int_t nps=1, Int_t fac=2, - Int_t npoints=512, TEveElement* parent=0) +TEvePointSet* pointset_hierarchy(Int_t level=3, Int_t nps=1, Int_t fac=2, + Int_t npoints=512, TEveElement* parent=0) { // This only works in compiled mode! TEvePointSet* ps = 0; --level; - for (Int_t i=0; iSetSourceCS(TEvePointSelectorConsumer::kTVT_RPhiZ); l->SetMarkerColor(3); l->SetMarkerStyle(4); // antialiased circle @@ -95,13 +88,11 @@ TEvePointSetArray* pointsetarray() l->GetBin(10)->SetMainColor(kWhite); Double_t rad, phi, z; - for (Int_t i = 0; i < 10000; ++i) - { + for (Int_t i = 0; i < 10000; ++i) { rad = r.Uniform(60, 180); phi = r.Uniform(0, TMath::TwoPi()); z = r.Uniform(-250, 250); - l->Fill(rad*TMath::Cos(phi), rad*TMath::Sin(phi), z, - r.Uniform(0, 110)); + l->Fill(rad*TMath::Cos(phi), rad*TMath::Sin(phi), z, r.Uniform(0, 110)); } l->CloseBins(); diff --git a/tutorials/eve/projection.C b/tutorials/eve/projection.C index 3c273c1b9af87..e29f2f21aaf87 100644 --- a/tutorials/eve/projection.C +++ b/tutorials/eve/projection.C @@ -1,6 +1,6 @@ /// \file /// \ingroup tutorial_eve -/// Demonstates usage of automatic 2D projections - class TEveProjectionManager. +/// Demonstrates usage of automatic 2D projections - class TEveProjectionManager. /// /// \image html eve_projection.png /// \macro_code @@ -16,30 +16,29 @@ void projection() TEveManager::Create(); // camera - TEveScene* s = gEve->SpawnNewScene("Projected Event"); + auto s = gEve->SpawnNewScene("Projected Event"); gEve->GetDefaultViewer()->AddScene(s); - TGLViewer* v = gEve->GetDefaultGLViewer(); + auto v = gEve->GetDefaultGLViewer(); v->SetCurrentCamera(TGLViewer::kCameraOrthoXOY); TGLOrthoCamera& cam = (TGLOrthoCamera&) v->CurrentCamera(); cam.SetZoomMinMax(0.2, 20); // projections - TEveProjectionManager* mng = - new TEveProjectionManager(TEveProjection::kPT_RPhi); + auto mng = new TEveProjectionManager(TEveProjection::kPT_RPhi); s->AddElement(mng); - TEveProjectionAxes* axes = new TEveProjectionAxes(mng); + auto axes = new TEveProjectionAxes(mng); axes->SetTitle("TEveProjections demo"); s->AddElement(axes); gEve->AddToListTree(axes, kTRUE); gEve->AddToListTree(mng, kTRUE); // Simple geometry - TFile* geom = TFile::Open(esd_geom_file_name, "CACHEREAD"); + auto geom = TFile::Open(esd_geom_file_name, "CACHEREAD"); if (!geom) return; - TEveGeoShapeExtract* gse = (TEveGeoShapeExtract*) geom->Get("Gentle"); - TEveGeoShape* gsre = TEveGeoShape::ImportShapeExtract(gse, 0); + auto gse = (TEveGeoShapeExtract*) geom->Get("Gentle"); + auto gsre = TEveGeoShape::ImportShapeExtract(gse, 0); geom->Close(); delete geom; gsre->SetPickableRecursively(kTRUE); @@ -47,7 +46,7 @@ void projection() gEve->GetGlobalScene()->SetRnrState(kFALSE); mng->ImportElements(gsre); - TEveLine* line = new TEveLine; + auto line = new TEveLine; line->SetMainColor(kGreen); for (Int_t i=0; i<160; ++i) line->SetNextPoint(120*sin(0.2*i), 120*cos(0.2*i), 80-i); diff --git a/tutorials/eve/projection_prescale.C b/tutorials/eve/projection_prescale.C index 553a322e24a0b..11f04d764858f 100644 --- a/tutorials/eve/projection_prescale.C +++ b/tutorials/eve/projection_prescale.C @@ -1,6 +1,6 @@ /// \file /// \ingroup tutorial_eve -/// Demonstates usage pre-scaling for automatic 2D projections. +/// Demonstrates usage pre-scaling for automatic 2D projections. /// /// \image html eve_projection_prescale.png /// \macro_code @@ -15,22 +15,22 @@ void projection_prescale() TFile::SetCacheFileDir("."); TEveManager::Create(); - TEveViewer *pev = gEve->SpawnNewViewer("Projections"); + auto pev = gEve->SpawnNewViewer("Projections"); // camera - TEveScene* s = gEve->SpawnNewScene("Projected Geom"); + auto s = gEve->SpawnNewScene("Projected Geom"); pev->AddScene(s); - TGLViewer* pgv = pev->GetGLViewer(); + auto pgv = pev->GetGLViewer(); pgv->SetCurrentCamera(TGLViewer::kCameraOrthoXOY); TGLOrthoCamera& cam = (TGLOrthoCamera&) pgv->CurrentCamera(); cam.SetZoomMinMax(0.2, 20); // projections - TEveProjectionManager* mng = new TEveProjectionManager(); + auto mng = new TEveProjectionManager(); { mng->SetProjection(TEveProjection::kPT_RPhi); - TEveProjection* p = mng->GetProjection(); + auto p = mng->GetProjection(); p->AddPreScaleEntry(0, 0, 4); // r scale 4 from 0 p->AddPreScaleEntry(0, 45, 1); // r scale 1 from 45 p->AddPreScaleEntry(0, 310, 0.5); @@ -38,7 +38,7 @@ void projection_prescale() } { mng->SetProjection(TEveProjection::kPT_RhoZ); - TEveProjection* p = mng->GetProjection(); + auto p = mng->GetProjection(); // Increase silicon tracker p->AddPreScaleEntry(0, 0, 4); // rho scale 4 from 0 p->AddPreScaleEntry(1, 0, 4); // z scale 4 from 0 @@ -53,24 +53,24 @@ void projection_prescale() mng->SetProjection(TEveProjection::kPT_RPhi); s->AddElement(mng); - TEveProjectionAxes* axes = new TEveProjectionAxes(mng); + auto axes = new TEveProjectionAxes(mng); s->AddElement(axes); gEve->AddToListTree(axes, kTRUE); gEve->AddToListTree(mng, kTRUE); // Simple geometry - TFile* geom = TFile::Open(esd_geom_file_name, "CACHEREAD"); + auto geom = TFile::Open(esd_geom_file_name, "CACHEREAD"); if (!geom) return; - TEveGeoShapeExtract* gse = (TEveGeoShapeExtract*) geom->Get("Gentle"); - TEveGeoShape* gsre = TEveGeoShape::ImportShapeExtract(gse, 0); + auto gse = (TEveGeoShapeExtract*) geom->Get("Gentle"); + auto gsre = TEveGeoShape::ImportShapeExtract(gse, 0); geom->Close(); delete geom; gEve->AddGlobalElement(gsre); mng->ImportElements(gsre); - TEveLine* line = new TEveLine; + auto line = new TEveLine; line->SetMainColor(kGreen); for (Int_t i=0; i<160; ++i) line->SetNextPoint(120*sin(0.2*i), 120*cos(0.2*i), 80-i); @@ -83,15 +83,14 @@ void projection_prescale() // Scaled 3D "projection" //------------------------------------------------------------------------- - TEveViewer *sev = gEve->SpawnNewViewer("Scaled 3D"); - TEveProjectionManager* smng = - new TEveProjectionManager(TEveProjection::kPT_3D); - TEveProjection* sp = smng->GetProjection(); + auto sev = gEve->SpawnNewViewer("Scaled 3D"); + auto smng = new TEveProjectionManager(TEveProjection::kPT_3D); + auto sp = smng->GetProjection(); sp->SetUsePreScale(kTRUE); sp->AddPreScaleEntry(2, 0, 1); sp->AddPreScaleEntry(2, 100, 0.2); - TEveScene* ss = gEve->SpawnNewScene("Scaled Geom"); + auto ss = gEve->SpawnNewScene("Scaled Geom"); sev->AddScene(ss); ss->AddElement(smng); diff --git a/tutorials/eve/quadset.C b/tutorials/eve/quadset.C index ed7401fd53283..084d68b76b3c5 100644 --- a/tutorials/eve/quadset.C +++ b/tutorials/eve/quadset.C @@ -7,6 +7,12 @@ /// /// \author Matevz Tadel +void quadset_callback(TEveDigitSet* ds, Int_t idx, TObject* obj); +TString quadset_tooltip_callback(TEveDigitSet* ds, Int_t idx); +void quadset_set_callback(TEveDigitSet* ds); + +//------------------------------------------------------------------------------ + TEveQuadSet* quadset(Float_t x=0, Float_t y=0, Float_t z=0, Int_t num=100, Bool_t registerSet=kTRUE) { @@ -234,12 +240,13 @@ TEveQuadSet* quadset_hexid(Float_t x=0, Float_t y=0, Float_t z=0, } } - // This show another way of getting notified about - // secondary selection hit. The callback function and the - // setting of it must be done in compiled code. - gROOT->ProcessLine(".L quadset_callback.cxx+"); quadset_set_callback(q); + // With the following you get per digit highlight with tooltip. + //q->SetPickable(1); + //q->SetAlwaysSecSelect(1); + // Otherwise you need to Alt - left click to get info printout. + return q; } @@ -270,3 +277,27 @@ void quadset_hierarchy(Int_t n=4) gEve->Redraw3D(); } + +//------------------------------------------------------------------------------ + +void quadset_callback(TEveDigitSet* ds, Int_t idx, TObject* obj) +{ + printf("dump_digit_set_hit - 0x%lx, id=%d, obj=0x%lx\n", + (ULong_t) ds, idx, (ULong_t) obj); +} + +TString quadset_tooltip_callback(TEveDigitSet* ds, Int_t idx) +{ + // This gets called for tooltip if the following is set: + // q->SetPickable(1); + // q->SetAlwaysSecSelect(1); + + return TString::Format("callback tooltip for '%s' - 0x%lx, id=%d\n", + ds->GetElementName(), (ULong_t) ds, idx); +} + +void quadset_set_callback(TEveDigitSet* ds) +{ + ds->SetCallbackFoo(quadset_callback); + ds->SetTooltipCBFoo(quadset_tooltip_callback); +} diff --git a/tutorials/eve/quadset_callback.cxx b/tutorials/eve/quadset_callback.cxx deleted file mode 100644 index a833bbc1bd594..0000000000000 --- a/tutorials/eve/quadset_callback.cxx +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -void quadset_callback(TEveDigitSet* ds, Int_t idx, TObject* obj) -{ - printf("dump_digit_set_hit - 0x%lx, id=%d, obj=0x%lx\n", - (ULong_t) ds, idx, (ULong_t) obj); -} - -TString quadset_tooltip_callback(TEveDigitSet* ds, Int_t idx) -{ - // This gets called for tooltip if the following is set: - // q->SetPickable(1); - // q->SetAlwaysSecSelect(1); - - return TString::Format("callback tooltip for '%s' - 0x%lx, id=%d\n", - ds->GetElementName(), (ULong_t) ds, idx); - -} - -void quadset_set_callback(TEveDigitSet* ds) -{ - ds->SetCallbackFoo(quadset_callback); - ds->SetTooltipCBFoo(TEveDigitSet* ds, Int_t idx) -} diff --git a/tutorials/eve/show_extract.C b/tutorials/eve/show_extract.C index a8c4909313271..809686122bb63 100644 --- a/tutorials/eve/show_extract.C +++ b/tutorials/eve/show_extract.C @@ -22,8 +22,8 @@ void show_extract(const char* file="http://root.cern.ch/files/alice_ESDgeometry. { if (xxx == key->GetClassName()) { - TEveGeoShapeExtract* gse = (TEveGeoShapeExtract*) key->ReadObj(); - TEveGeoShape* gs = TEveGeoShape::ImportShapeExtract(gse, 0); + auto gse = (TEveGeoShapeExtract*) key->ReadObj(); + auto gs = TEveGeoShape::ImportShapeExtract(gse, 0); gEve->AddGlobalElement(gs); } } diff --git a/tutorials/eve/text.C b/tutorials/eve/text.C index ea4ecc271ea3d..c7842322503bd 100644 --- a/tutorials/eve/text.C +++ b/tutorials/eve/text.C @@ -13,7 +13,7 @@ TEveText* text() TEveManager::Create(); - TEvePointSet* marker = new TEvePointSet(8); + auto marker = new TEvePointSet(8); marker->SetName("Origin marker"); marker->SetMarkerColor(6); marker->SetMarkerStyle(3); @@ -28,7 +28,7 @@ TEveText* text() marker->SetPoint(7, -a, -a, -a); gEve->AddElement(marker); - TEveText* t = new TEveText("DADA"); + auto t = new TEveText("DADA"); t->PtrMainTrans()->RotateLF(1, 3, TMath::PiOver2()); t->SetMainColor(kOrange-2); t->SetFontSize(64); diff --git a/tutorials/eve/track.C b/tutorials/eve/track.C index 8e87dbc0b7196..4c8e8ca6f75b4 100644 --- a/tutorials/eve/track.C +++ b/tutorials/eve/track.C @@ -10,13 +10,13 @@ /// ~~~ /// void track(Int_t mode = 5, Bool_t isRungeKutta = kTRUE) /// Modes are -/// 0. B = 0, no difference btween signed and charge particles; +/// 0. B = 0, no difference between signed and charge particles; /// 1. constant B field (along z, but could have arbitrary direction); /// 2. variable B field, sign change at R = 200 cm; /// 3. magnetic field with a zero-field region; /// 4. CMS magnetic field - simple track; /// 5. CMS magnetic field - track with different path-marks. -/// 6. Concpetual ILC detector, problematic track +/// 6. Conceptual ILC detector, problematic track /// /// \image html eve_track.png /// \macro_code @@ -100,7 +100,7 @@ public: { //inside solenoid if ( R < 300) return TEveVectorD(0,0,field); - // outside solinoid + // outside solenoid if ( m_simpleModel || ( R>461.0 && R<490.5 ) || ( R>534.5 && R<597.5 ) || @@ -142,19 +142,19 @@ TEveTrack* make_track(TEveTrackPropagator* prop, Int_t sign) // Make track with given propagator. // Add to math-marks to test fit. - TEveRecTrackD *rc = new TEveRecTrackD(); + auto rc = new TEveRecTrackD(); rc->fV.Set(0.028558, -0.000918, 3.691919); rc->fP.Set(0.767095, -2.400006, -0.313103); rc->fSign = sign; - TEveTrack* track = new TEveTrack(rc, prop); + auto track = new TEveTrack(rc, prop); track->SetName(Form("Charge %d", sign)); // daughter 0 - TEvePathMarkD* pm1 = new TEvePathMarkD(TEvePathMarkD::kDaughter); + auto pm1 = new TEvePathMarkD(TEvePathMarkD::kDaughter); pm1->fV.Set(1.479084, -4.370661, 3.119761); track->AddPathMark(*pm1); // daughter 1 - TEvePathMarkD* pm2 = new TEvePathMarkD(TEvePathMarkD::kDaughter); + auto pm2 = new TEvePathMarkD(TEvePathMarkD::kDaughter); pm2->fV.Set(57.72345, -89.77011, -9.783746); track->AddPathMark(*pm2); @@ -168,8 +168,8 @@ void track(Int_t mode = 1, Bool_t isRungeKutta = kTRUE) gSystem->IgnoreSignal(kSigSegmentationViolation, true); TEveManager::Create(); - TEveTrackList *list = new TEveTrackList(); - TEveTrackPropagator* prop = g_prop = list->GetPropagator(); + auto list = new TEveTrackList(); + auto prop = g_prop = list->GetPropagator(); prop->SetFitDaughters(kFALSE); prop->SetMaxZ(1000); @@ -188,7 +188,7 @@ void track(Int_t mode = 1, Bool_t isRungeKutta = kTRUE) { case 0: { - // B = 0 no difference btween signed and charge particles + // B = 0 no difference between signed and charge particles prop->SetMagField(0.); list->SetElementName(Form("%s, zeroB", list->GetElementName())); track = make_track(prop, 1); @@ -220,13 +220,13 @@ void track(Int_t mode = 1, Bool_t isRungeKutta = kTRUE) list->SetElementName(Form("%s, gappedB", list->GetElementName())); - TEveRecTrackD *rc = new TEveRecTrackD(); + auto rc = new TEveRecTrackD(); rc->fV.Set(0.028558, -0.000918, 3.691919); rc->fP.Set(0.767095, -0.400006, 2.313103); rc->fSign = 1; track = new TEveTrack(rc, prop); - TEvePointSet* marker = new TEvePointSet(2); + auto marker = new TEvePointSet(2); marker->SetElementName("B field break points"); marker->SetPoint(0, 0., 0., 300.f); marker->SetPoint(1, 0., 0., 600.f); @@ -238,7 +238,7 @@ void track(Int_t mode = 1, Bool_t isRungeKutta = kTRUE) case 4: { // Magnetic field of CMS I. - CmsMagField* mf = new CmsMagField; + auto mf = new CmsMagField; mf->setReverseState(true); prop->SetMagFieldObj(mf); @@ -250,7 +250,7 @@ void track(Int_t mode = 1, Bool_t isRungeKutta = kTRUE) list->SetElementName(Form("%s, CMS field", list->GetElementName())); - TEveRecTrackD *rc = new TEveRecTrackD(); + auto rc = new TEveRecTrackD(); rc->fV.Set(0.027667, 0.007919, 0.895964); rc->fP.Set(3.903134, 2.252232, -3.731366); rc->fSign = -1; @@ -276,7 +276,7 @@ void track(Int_t mode = 1, Bool_t isRungeKutta = kTRUE) case 5: { // Magnetic field of CMS I. - CmsMagField* mf = new CmsMagField; + auto mf = new CmsMagField; mf->setReverseState(true); mf->setSimpleModel(false); @@ -289,7 +289,7 @@ void track(Int_t mode = 1, Bool_t isRungeKutta = kTRUE) prop->RefPMAtt().SetMarkerStyle(4); list->SetElementName(Form("%s, CMS field", list->GetElementName())); - TEveRecTrackD *rc = new TEveRecTrackD(); + auto rc = new TEveRecTrackD(); rc->fV.Set(-16.426592, 16.403185, -19.782692); rc->fP.Set(3.631100, 3.643450, 0.682254); rc->fSign = -1; @@ -332,7 +332,7 @@ void track(Int_t mode = 1, Bool_t isRungeKutta = kTRUE) list->SetElementName(Form("%s, Some ILC Detector field", list->GetElementName())); - TEveRecTrackD *rc = new TEveRecTrackD(); + auto rc = new TEveRecTrackD(); rc->fV.Set(57.1068, 31.2401, -7.07629); rc->fP.Set(4.82895, 2.35083, -0.611757); rc->fSign = 1; @@ -373,6 +373,4 @@ void track(Int_t mode = 1, Bool_t isRungeKutta = kTRUE) gv->CurrentCamera().RotateRad(-0.5, 1.4); gv->RequestDraw(); -} - -#endif +} \ No newline at end of file diff --git a/tutorials/eve/window_manager.C b/tutorials/eve/window_manager.C index 45b25a84a7d25..9de490fe8ed5b 100644 --- a/tutorials/eve/window_manager.C +++ b/tutorials/eve/window_manager.C @@ -16,6 +16,10 @@ #include "TCanvas.h" #include "TGTab.h" +void PackTest(); +void DetailTest(); +void TabsTest(); + void window_manager() { TEveManager::Create(); @@ -73,9 +77,11 @@ void PackTest() void DetailTest() { + TEveWindowFrame *frame = 0; + TEveWindowSlot* slot = TEveWindow::CreateWindowInTab(gEve->GetBrowser()->GetTabRight()); - pack1 = slot->MakePack(); + TEveWindowPack* pack1 = slot->MakePack(); pack1->SetShowTitleBar(kFALSE); pack1->SetElementName("Detail"); pack1->SetHorizontal(); diff --git a/tutorials/gl/glbox.C b/tutorials/gl/glbox.C index 707c253e1ceb5..b38c2337ff683 100644 --- a/tutorials/gl/glbox.C +++ b/tutorials/gl/glbox.C @@ -10,7 +10,7 @@ void glbox() { gStyle->SetCanvasPreferGL(kTRUE); - TCanvas *c = new TCanvas("glc","TH3 Drawing", 100, 10, 850, 400); + TCanvas *c = new TCanvas("glbox","TH3 Drawing", 100, 10, 850, 400); TPaveLabel *title = new TPaveLabel(0.04, 0.86, 0.96, 0.98, "\"glbox\" and \"glbox1\" options for TH3."); title->SetFillColor(32); diff --git a/tutorials/gl/gltf3.C b/tutorials/gl/gltf3.C index a7dcd10b06da8..3697e69b7a901 100644 --- a/tutorials/gl/gltf3.C +++ b/tutorials/gl/gltf3.C @@ -17,7 +17,7 @@ void gltf3() { gStyle->SetCanvasPreferGL(1); - TCanvas *cnv = new TCanvas("glc", "TF3: Klein bottle", 200, 10, 600, 600); + TCanvas *cnv = new TCanvas("gltf3", "TF3: Klein bottle", 200, 10, 600, 600); TPaveLabel *title = new TPaveLabel(0.04, 0.86, 0.96, 0.98, "\"gl\" option for TF3. Select plot and press 's' to change the color."); diff --git a/tutorials/hist/h2proj.C b/tutorials/hist/h2proj.C index cb26121b7c05a..dabbacefef333 100644 --- a/tutorials/hist/h2proj.C +++ b/tutorials/hist/h2proj.C @@ -17,7 +17,7 @@ TPad *right_pad, *top_pad; void h2proj() { - auto *c1 = new TCanvas("c1", "c1",900,900); + auto c1 = new TCanvas("c1", "c1",900,900); gStyle->SetOptStat(0); TPad *center_pad = new TPad("center_pad", "center_pad",0.0,0.0,0.6,0.6); @@ -57,7 +57,7 @@ void h2proj() t->DrawLatex(0.6,0.88,"This example demonstrates how to display"); t->DrawLatex(0.6,0.85,"a histogram and its two projections."); - auto *ex = new TExec("zoom","ZoomExec()"); + auto ex = new TExec("zoom","ZoomExec()"); h2->GetListOfFunctions()->Add(ex); } diff --git a/tutorials/pyroot/pyroot003_prettyPrinting.py b/tutorials/pyroot/pyroot003_prettyPrinting.py new file mode 100644 index 0000000000000..83bc39d468479 --- /dev/null +++ b/tutorials/pyroot/pyroot003_prettyPrinting.py @@ -0,0 +1,38 @@ +## \file +## \ingroup tutorial_pyroot +## \notebook -nodraw +## This tutorial illustrates the pretty printing feature of PyROOT, which reveals +## the content of the object if a string representation is requested, e.g., by +## Python's print statement. The printing behaves similar to the ROOT prompt +## powered by the C++ interpreter cling. +## +## \macro_code +## +## \date June 2018 +## \author Stefan Wunsch + +import ROOT + +# Create an object with PyROOT +obj = ROOT.std.vector("int")(3) +for i in range(obj.size()): + obj[i] = i + +# Print the object, which reveals the content. Note that `print` calls the special +# method `__str__` of the object internally. +print(obj) + +# The output can be retrieved as string by any function that triggers the `__str__` +# special method of the object, e.g., `str` or `format`. +print(str(obj)) +print("{}".format(obj)) + +# Note that the interactive Python prompt does not call `__str__`, it calls +# `__repr__`, which implements a formal and unique string representation of +# the object. +print(repr(obj)) +obj + +# The print output behaves similar to the ROOT prompt, e.g., here for a ROOT histogram. +hist = ROOT.TH1F("name", "title", 10, 0, 1) +print(hist) diff --git a/tutorials/tree/clonesA_Event.C b/tutorials/tree/clonesA_Event.C index 18d93b5f751c2..53ebf9749c13c 100644 --- a/tutorials/tree/clonesA_Event.C +++ b/tutorials/tree/clonesA_Event.C @@ -17,7 +17,8 @@ #ifndef CLONESA_EVENT_SECOND_RUN void clonesA_Event() { - TString dir = gSystem->UnixPathName(gSystem->DirName(__FILE__)); + std::string s1(__FILE__); + TString dir = gSystem->UnixPathName(s1.substr(0, s1.find_last_of("\\/")).c_str()); gROOT->ProcessLine(TString(".L ")+dir+"/clonesA_Event.cxx+"); #define CLONESA_EVENT_SECOND_RUN yes gROOT->ProcessLine("#include \"" __FILE__ "\""); diff --git a/tutorials/v7/draw.cxx b/tutorials/v7/draw.cxx index d58e6afc5992b..6f22aad107d09 100644 --- a/tutorials/v7/draw.cxx +++ b/tutorials/v7/draw.cxx @@ -21,8 +21,8 @@ R__LOAD_LIBRARY(libROOTHistDraw); #include "ROOT/THist.hxx" -#include "ROOT/TCanvas.hxx" -#include "ROOT/TColor.hxx" +#include "ROOT/RCanvas.hxx" +#include "ROOT/RColor.hxx" #include "ROOT/TDirectory.hxx" void draw() @@ -45,8 +45,8 @@ void draw() Experimental::TDirectory::Heap().Add("hist", pHist); // Create a canvas to be displayed. - auto canvas = Experimental::TCanvas::Create("Canvas Title"); - canvas->Draw(pHist)->SetLineColor(Experimental::TColor::kRed); + auto canvas = Experimental::RCanvas::Create("Canvas Title"); + canvas->Draw(pHist)->SetLineColor(Experimental::RColor::kRed); canvas->Show(); } diff --git a/tutorials/v7/draw_subpads.cxx b/tutorials/v7/draw_subpads.cxx index b42fe1b79d4b8..5a697a5b25516 100644 --- a/tutorials/v7/draw_subpads.cxx +++ b/tutorials/v7/draw_subpads.cxx @@ -16,8 +16,8 @@ *************************************************************************/ #include "ROOT/THist.hxx" -#include "ROOT/TCanvas.hxx" -#include "ROOT/TPad.hxx" +#include "ROOT/RCanvas.hxx" +#include "ROOT/RPad.hxx" void draw_subpads() { using namespace ROOT; @@ -45,22 +45,22 @@ void draw_subpads() { pHist3->Fill(6); // Create a canvas to be displayed. - auto canvas = Experimental::TCanvas::Create("Canvas Title"); + auto canvas = Experimental::RCanvas::Create("Canvas Title"); // Divide canvas on sub-pads auto subpads = canvas->Divide(2,2); - subpads[0][0]->Draw(pHist1)->SetLineColor(Experimental::TColor::kRed); - subpads[1][0]->Draw(pHist2)->SetLineColor(Experimental::TColor::kBlue); - subpads[0][1]->Draw(pHist3)->SetLineColor(Experimental::TColor::kGreen); + subpads[0][0]->Draw(pHist1)->SetLineColor(Experimental::RColor::kRed); + subpads[1][0]->Draw(pHist2)->SetLineColor(Experimental::RColor::kBlue); + subpads[0][1]->Draw(pHist3)->SetLineColor(Experimental::RColor::kGreen); // Divide pad on sub-sub-pads auto subsubpads = subpads[1][1]->Divide(2,2); - subsubpads[0][0]->Draw(pHist1)->SetLineColor(Experimental::TColor::kBlue); - subsubpads[1][0]->Draw(pHist2)->SetLineColor(Experimental::TColor::kGreen); - subsubpads[0][1]->Draw(pHist3)->SetLineColor(Experimental::TColor::kRed); + subsubpads[0][0]->Draw(pHist1)->SetLineColor(Experimental::RColor::kBlue); + subsubpads[1][0]->Draw(pHist2)->SetLineColor(Experimental::RColor::kGreen); + subsubpads[0][1]->Draw(pHist3)->SetLineColor(Experimental::RColor::kRed); canvas->Show(); } diff --git a/tutorials/v7/draw_th1.cxx b/tutorials/v7/draw_th1.cxx index b5c94091a3c27..bf0b58fb0d89c 100644 --- a/tutorials/v7/draw_th1.cxx +++ b/tutorials/v7/draw_th1.cxx @@ -22,7 +22,7 @@ R__LOAD_LIBRARY(libROOTGpadv7); #include "ROOT/THist.hxx" -#include "ROOT/TCanvas.hxx" +#include "ROOT/RCanvas.hxx" void draw_th1() { using namespace ROOT; @@ -44,9 +44,9 @@ void draw_th1() { pHist2->Fill(7); // Create a canvas to be displayed. - auto canvas = Experimental::TCanvas::Create("Canvas Title"); - canvas->Draw(pHist)->SetLineColor(Experimental::TColor::kRed); - canvas->Draw(pHist2)->SetLineColor(Experimental::TColor::kBlue); + auto canvas = Experimental::RCanvas::Create("Canvas Title"); + canvas->Draw(pHist)->SetLineColor(Experimental::RColor::kRed); + canvas->Draw(pHist2)->SetLineColor(Experimental::RColor::kBlue); canvas->Show(); canvas->SaveAs("th1.png"); diff --git a/tutorials/v7/draw_v6.cxx b/tutorials/v7/draw_v6.cxx index ae3e15948c400..3d0e8e4745e96 100644 --- a/tutorials/v7/draw_v6.cxx +++ b/tutorials/v7/draw_v6.cxx @@ -18,13 +18,13 @@ R__LOAD_LIBRARY(libGpad); -#include -#include +#include +#include #include #include -// Show how to display v6 objects in a v7 TCanvas. +// Show how to display v6 objects in a v7 RCanvas. void draw_v6() { @@ -34,7 +34,7 @@ void draw_v6() double x[npoints] = {0., 1., 2., 3.}; double y[npoints] = {.1, .2, .3, .4}; auto gr = std::make_shared(npoints, x, y); - auto canvas = Experimental::TCanvas::Create("v7 TCanvas showing a v6 TGraph"); + auto canvas = Experimental::RCanvas::Create("v7 RCanvas showing a v6 TGraph"); canvas->Draw(gr, "AL"); canvas->Show(); // new window should popup and async update will be triggered diff --git a/tutorials/v7/fitpanel.cxx b/tutorials/v7/fitpanel.cxx index 9096aee059334..cafcbaef7b521 100644 --- a/tutorials/v7/fitpanel.cxx +++ b/tutorials/v7/fitpanel.cxx @@ -18,7 +18,7 @@ R__LOAD_LIBRARY(libGpad); #include "ROOT/THist.hxx" -#include "ROOT/TCanvas.hxx" +#include "ROOT/RCanvas.hxx" #include "ROOT/TFitPanel.hxx" #include "ROOT/TDirectory.hxx" @@ -45,7 +45,7 @@ void fitpanel0() { // Create a canvas to be displayed. - // auto canvas = Experimental::TCanvas::Create("Canvas Title"); + // auto canvas = Experimental::RCanvas::Create("Canvas Title"); // canvas->Draw(pHist)->SetLineColor(Experimental::TColor::kRed); // canvas->Draw(pHist2)->SetLineColor(Experimental::TColor::kBlue); @@ -67,7 +67,7 @@ void fitpanel() { pHist->Fill(2); pHist->Fill(3); - auto canvas = Experimental::TCanvas::Create("Canvas Title"); + auto canvas = Experimental::RCanvas::Create("Canvas Title"); canvas->Draw(pHist)->SetLineColor(Experimental::TColor::kRed); canvas->Show(); diff --git a/tutorials/v7/line.cxx b/tutorials/v7/line.cxx index de57d3a1612f0..f25022889af9c 100644 --- a/tutorials/v7/line.cxx +++ b/tutorials/v7/line.cxx @@ -8,10 +8,10 @@ /// is welcome! /// \authors Olivier couet, Iliana Betsou -#include "ROOT/TCanvas.hxx" -#include "ROOT/TColor.hxx" -#include "ROOT/TLine.hxx" -#include +#include "ROOT/RCanvas.hxx" +#include "ROOT/RColor.hxx" +#include "ROOT/RLine.hxx" +#include void line() { @@ -19,24 +19,24 @@ void line() using namespace ROOT::Experimental; // Create a canvas to be displayed. - auto canvas = Experimental::TCanvas::Create("Canvas Title"); + auto canvas = Experimental::RCanvas::Create("Canvas Title"); for (double i = 0; i < 360; i+=1) { double angle = i * TMath::Pi() / 180; - TPadPos p(0.3_normal*TMath::Cos(angle) + 0.5_normal, + RPadPos p(0.3_normal*TMath::Cos(angle) + 0.5_normal, 0.3_normal*TMath::Sin(angle) + 0.5_normal); - auto opts = canvas->Draw(Experimental::TLine({0.5_normal, 0.5_normal} , p)); - Experimental::TColor col(0.0025*i, 0, 0); + auto opts = canvas->Draw(Experimental::RLine({0.5_normal, 0.5_normal} , p)); + Experimental::RColor col(0.0025*i, 0, 0); opts->SetLineColor(col); opts->SetLineWidth(1); } - canvas->Draw(Experimental::TLine({0.0_normal, 0.0_normal}, {1.0_normal,1.0_normal})); - canvas->Draw(Experimental::TLine({0.1_normal, 0.1_normal}, {0.9_normal,0.1_normal})); - canvas->Draw(Experimental::TLine({0.9_normal, 0.1_normal}, {0.9_normal,0.9_normal})); - canvas->Draw(Experimental::TLine({0.9_normal, 0.9_normal}, {0.1_normal,0.9_normal})); - canvas->Draw(Experimental::TLine({0.1_normal, 0.1_normal}, {0.1_normal,0.9_normal})); - canvas->Draw(Experimental::TLine({0.0_normal, 1.0_normal}, {1.0_normal,0.0_normal})); + canvas->Draw(Experimental::RLine({0.0_normal, 0.0_normal}, {1.0_normal,1.0_normal})); + canvas->Draw(Experimental::RLine({0.1_normal, 0.1_normal}, {0.9_normal,0.1_normal})); + canvas->Draw(Experimental::RLine({0.9_normal, 0.1_normal}, {0.9_normal,0.9_normal})); + canvas->Draw(Experimental::RLine({0.9_normal, 0.9_normal}, {0.1_normal,0.9_normal})); + canvas->Draw(Experimental::RLine({0.1_normal, 0.1_normal}, {0.1_normal,0.9_normal})); + canvas->Draw(Experimental::RLine({0.0_normal, 1.0_normal}, {1.0_normal,0.0_normal})); canvas->Show(); } diff --git a/tutorials/v7/lineStyle.cxx b/tutorials/v7/lineStyle.cxx index c65d58958cdc5..93d6d191d5798 100644 --- a/tutorials/v7/lineStyle.cxx +++ b/tutorials/v7/lineStyle.cxx @@ -8,31 +8,31 @@ /// is welcome! /// \author Iliana Betsou -#include "ROOT/TCanvas.hxx" -#include "ROOT/TColor.hxx" -#include "ROOT/TText.hxx" -#include "ROOT/TLine.hxx" -#include "ROOT/TPadPos.hxx" +#include "ROOT/RCanvas.hxx" +#include "ROOT/RColor.hxx" +#include "ROOT/RText.hxx" +#include "ROOT/RLine.hxx" +#include "ROOT/RPadPos.hxx" void lineStyle() { using namespace ROOT; using namespace ROOT::Experimental; - auto canvas = Experimental::TCanvas::Create("Canvas Title"); + auto canvas = Experimental::RCanvas::Create("Canvas Title"); double num = 0.3; for (int i=10; i>0; i--){ - num = num + 0.02; + num = num + 0.05; - TPadPos pt(.3_normal, TPadLength::Normal(num)); - auto optts = canvas->Draw(Experimental::TText(pt, Form("%d", i))); + RPadPos pt(.3_normal, RPadLength::Normal(num)); + auto optts = canvas->Draw(Experimental::RText(pt, Form("%d", i))); optts->SetTextSize(13); optts->SetTextAlign(32); optts->SetTextFont(52); - TPadPos pl1(.32_normal, TPadLength::Normal(num)); - TPadPos pl2(.8_normal , TPadLength::Normal(num)); - auto optls = canvas->Draw(Experimental::TLine(pl1, pl2)); + RPadPos pl1(.32_normal, RPadLength::Normal(num)); + RPadPos pl2(.8_normal , RPadLength::Normal(num)); + auto optls = canvas->Draw(Experimental::RLine(pl1, pl2)); optls->SetLineStyle(i); } diff --git a/tutorials/v7/lineWidth.cxx b/tutorials/v7/lineWidth.cxx index 9a75748c94519..8ecb7fa0dc8e4 100644 --- a/tutorials/v7/lineWidth.cxx +++ b/tutorials/v7/lineWidth.cxx @@ -8,32 +8,32 @@ /// is welcome! /// \author Iliana Betsou -#include "ROOT/TCanvas.hxx" -#include "ROOT/TColor.hxx" -#include "ROOT/TText.hxx" -#include "ROOT/TLine.hxx" -#include "ROOT/TPadPos.hxx" +#include "ROOT/RCanvas.hxx" +#include "ROOT/RColor.hxx" +#include "ROOT/RText.hxx" +#include "ROOT/RLine.hxx" +#include "ROOT/RPadPos.hxx" void lineWidth() { using namespace ROOT; using namespace ROOT::Experimental; - auto canvas = Experimental::TCanvas::Create("Canvas Title"); + auto canvas = Experimental::RCanvas::Create("Canvas Title"); double num = 0.3; for (int i=10; i>0; i--){ - num = num + 0.02; + num = num + 0.05; - TPadPos pt(.3_normal, TPadLength::Normal(num)); - auto optts = canvas->Draw(Experimental::TText(pt, Form("%d", i))); + RPadPos pt(.3_normal, RPadLength::Normal(num)); + auto optts = canvas->Draw(Experimental::RText(pt, Form("%d", i))); optts->SetTextSize(13); optts->SetTextAlign(32); optts->SetTextFont(52); - TPadPos pl1(.32_normal, TPadLength::Normal(num)); - TPadPos pl2(.8_normal , TPadLength::Normal(num)); - auto optls = canvas->Draw(Experimental::TLine(pl1, pl2)); + RPadPos pl1(.32_normal, RPadLength::Normal(num)); + RPadPos pl2(.8_normal , RPadLength::Normal(num)); + auto optls = canvas->Draw(Experimental::RLine(pl1, pl2)); optls->SetLineWidth(i); } diff --git a/tutorials/v7/markerStyle.cxx b/tutorials/v7/markerStyle.cxx index f623eb0e62419..104398d059cf7 100644 --- a/tutorials/v7/markerStyle.cxx +++ b/tutorials/v7/markerStyle.cxx @@ -8,17 +8,16 @@ /// is welcome! /// \author Iliana Betsou -#include "ROOT/TCanvas.hxx" -#include "ROOT/TColor.hxx" -#include "ROOT/TText.hxx" -#include "ROOT/TMarker.hxx" -#include "ROOT/TPadPos.hxx" +#include "ROOT/RCanvas.hxx" +#include "ROOT/RText.hxx" +#include "ROOT/RMarker.hxx" +#include "ROOT/RPadPos.hxx" void markerStyle() { using namespace ROOT; using namespace ROOT::Experimental; - auto canvas = Experimental::TCanvas::Create("Canvas Title"); + auto canvas = Experimental::RCanvas::Create("Canvas Title"); double num = 0.3; double x = 0; @@ -26,24 +25,24 @@ void markerStyle() { for (Int_t i=1;i<16;i++) { x += dx; - TPadPos pt1(TPadLength::Normal(x), .12_normal); - auto ot1 = canvas->Draw(Experimental::TText(pt1, Form("%d", i))); - TPadPos pm1(TPadLength::Normal(x), .25_normal); - auto om1 = canvas->Draw(Experimental::TMarker(pm1)); + RPadPos pt1(RPadLength::Normal(x), .12_normal); + auto ot1 = canvas->Draw(Experimental::RText(pt1, Form("%d", i))); + RPadPos pm1(RPadLength::Normal(x), .25_normal); + auto om1 = canvas->Draw(Experimental::RMarker(pm1)); om1->SetMarkerStyle(i); om1->SetMarkerSize(2.5); - TPadPos pt2(TPadLength::Normal(x), .42_normal); - auto ot2 = canvas->Draw(Experimental::TText(pt2, Form("%d", i+19))); - TPadPos pm2(TPadLength::Normal(x), .55_normal); - auto om2 = canvas->Draw(Experimental::TMarker(pm2)); + RPadPos pt2(RPadLength::Normal(x), .42_normal); + auto ot2 = canvas->Draw(Experimental::RText(pt2, Form("%d", i+19))); + RPadPos pm2(RPadLength::Normal(x), .55_normal); + auto om2 = canvas->Draw(Experimental::RMarker(pm2)); om2->SetMarkerStyle(i+19); om2->SetMarkerSize(2.5); - TPadPos pt3(TPadLength::Normal(x), .72_normal); - auto ot3 = canvas->Draw(Experimental::TText(pt3, Form("%d", i+34))); - TPadPos pm3(TPadLength::Normal(x), .85_normal); - auto om3 = canvas->Draw(Experimental::TMarker(pm3)); + RPadPos pt3(RPadLength::Normal(x), .72_normal); + auto ot3 = canvas->Draw(Experimental::RText(pt3, Form("%d", i+34))); + RPadPos pm3(RPadLength::Normal(x), .85_normal); + auto om3 = canvas->Draw(Experimental::RMarker(pm3)); om3->SetMarkerStyle(i+34); om3->SetMarkerSize(2.5); } diff --git a/tutorials/v7/pad.cxx b/tutorials/v7/pad.cxx index 747ce5d613438..444b45b3eb570 100644 --- a/tutorials/v7/pad.cxx +++ b/tutorials/v7/pad.cxx @@ -20,21 +20,21 @@ R__LOAD_LIBRARY(libROOTGpadv7); -#include "ROOT/TCanvas.hxx" -#include "ROOT/TFrame.hxx" -#include "ROOT/TLine.hxx" +#include "ROOT/RCanvas.hxx" +#include "ROOT/RFrame.hxx" +#include "ROOT/Rline.hxx" void pad() { using namespace ROOT; using namespace ROOT::Experimental; - auto canvas = Experimental::TCanvas::Create("what to do with a pad!"); - auto pads = canvas->Divide(3, 3); + auto canvas = Experimental::RCanvas::Create("what to do with a pad!"); + auto pads = canvas->Divide(3, 3); auto &pad12 = pads[1][2]; pad12->SetAllAxisBounds({{50., 250.}, {-1., 1.}}); - // Please fix TLine such that {x,y} are TPadPos! - //pad12->Draw(Experimental::TLine({100._user, 0.5_normal}, {200._user, 0.5_normal})); + // Please fix Rline such that {x,y} are TPadPos! + //pad12->Draw(Experimental::Rline({100._user, 0.5_normal}, {200._user, 0.5_normal})); canvas->Show(); } diff --git a/tutorials/v7/text.cxx b/tutorials/v7/text.cxx index d4fd40ef09051..a53edb7b069e0 100644 --- a/tutorials/v7/text.cxx +++ b/tutorials/v7/text.cxx @@ -16,10 +16,10 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "ROOT/TCanvas.hxx" -#include "ROOT/TColor.hxx" -#include "ROOT/TText.hxx" -#include +#include "ROOT/RCanvas.hxx" +#include "ROOT/RColor.hxx" +#include "ROOT/RText.hxx" +#include "ROOT/RPadPos.hxx" #include "ROOT/TDirectory.hxx" void text() @@ -28,12 +28,12 @@ void text() using namespace ROOT::Experimental; // Create a canvas to be displayed. - auto canvas = Experimental::TCanvas::Create("Canvas Title"); + auto canvas = Experimental::RCanvas::Create("Canvas Title"); for (int i=0; i<=360; i+=10) { - auto opts = canvas->Draw(Experimental::TText({0.5_normal, 0.6_normal}, "____ Hello World")); + auto opts = canvas->Draw(Experimental::RText({0.5_normal, 0.6_normal}, "____ Hello World")); - Experimental::TColor col(0.0015*i, 0.0025*i ,0.003*i); + Experimental::RColor col(0.0015*i, 0.0025*i ,0.003*i); opts->SetTextColor(col); opts->SetTextSize(10+i/10); opts->SetTextAngle(i);