more info on index site and css added
This commit is contained in:
parent
69d6b27f31
commit
9b30acc5e2
|
@ -1,8 +1,14 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
#list(INSERT
|
||||
# CMAKE_MODULE_PATH 0 ${PROJECT_SOURCE_DIR}/cmake)
|
||||
set(CMAKE_MODULE_PATH
|
||||
${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
set(PROJECT_NAME
|
||||
crowxmr)
|
||||
|
||||
|
||||
project(${PROJECT_NAME})
|
||||
|
||||
set(CMAKE_CXX_FLAGS
|
||||
|
@ -82,24 +88,70 @@ add_subdirectory(src/)
|
|||
set(SOURCE_FILES
|
||||
main.cpp)
|
||||
|
||||
ADD_CUSTOM_TARGET(driver DEPENDS src/templates/index.html)
|
||||
#ADD_CUSTOM_TARGET(driver DEPENDS src/templates/index.html)
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
${SOURCE_FILES})
|
||||
|
||||
#add_custom_command(OUTPUT template_folder
|
||||
# COMMAND ${CMAKE_COMMAND} -E
|
||||
# copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/src/templates" "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
# DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/templates")
|
||||
#add_custom_command(TARGET template_folder POST_BUILD
|
||||
# COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
# "${CMAKE_CURRENT_SOURCE_DIR}/src/templates" "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
#
|
||||
#add_custom_target(index_html
|
||||
#add_custom_target(template_folder
|
||||
# ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/templates")
|
||||
#
|
||||
#ADD_DEPENDENCIES(${PROJECT_NAME}
|
||||
# index_html)
|
||||
# template_folder)
|
||||
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/src/templates"
|
||||
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
#file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/src/templates"
|
||||
# DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
#
|
||||
#include(copy_files)
|
||||
#copy_files(${CMAKE_CURRENT_SOURCE_DIR}/src/templates/ *.html ${CMAKE_CURRENT_BINARY_DIR})
|
||||
#
|
||||
|
||||
macro(configure_files srcDir destDir)
|
||||
message(STATUS "Configuring directory ${destDir}")
|
||||
make_directory(${destDir})
|
||||
|
||||
file(GLOB templateFiles RELATIVE ${srcDir} ${srcDir}/*)
|
||||
foreach(templateFile ${templateFiles})
|
||||
set(srcTemplatePath ${srcDir}/${templateFile})
|
||||
if(NOT IS_DIRECTORY ${srcTemplatePath})
|
||||
message(STATUS "Configuring file ${templateFile}")
|
||||
configure_file(
|
||||
${srcTemplatePath}
|
||||
${destDir}/${templateFile}
|
||||
@ONLY)
|
||||
endif(NOT IS_DIRECTORY ${srcTemplatePath})
|
||||
endforeach(templateFile)
|
||||
endmacro(configure_files)
|
||||
|
||||
configure_files(${CMAKE_CURRENT_SOURCE_DIR}/src/templates ${CMAKE_CURRENT_BINARY_DIR}/templates)
|
||||
configure_files(${CMAKE_CURRENT_SOURCE_DIR}/src/templates/css ${CMAKE_CURRENT_BINARY_DIR}/templates/css)
|
||||
|
||||
#macro(copy_files GLOBPAT DESTINATION)
|
||||
#
|
||||
# message(STATUS "Configuring directory ${DESTINATION}")
|
||||
#
|
||||
# file(GLOB COPY_FILES
|
||||
# RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
# ${GLOBPAT})
|
||||
# add_custom_target(copy ALL
|
||||
# COMMENT "Copying files: ${GLOBPAT}")
|
||||
#
|
||||
# foreach(FILENAME ${COPY_FILES})
|
||||
# set(SRC "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}")
|
||||
# set(DST "${DESTINATION}/${FILENAME}")
|
||||
#
|
||||
# add_custom_command(
|
||||
# TARGET copy
|
||||
# COMMAND ${CMAKE_COMMAND} -E copy ${SRC} ${DST}
|
||||
# )
|
||||
# endforeach(FILENAME)
|
||||
#endmacro(copy_files)
|
||||
#
|
||||
#copy_files(${CMAKE_CURRENT_SOURCE_DIR}/src/templates ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
myxrm
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
#
|
||||
# Utility macros for copying files
|
||||
#
|
||||
# Last update: 9th January 2013
|
||||
#
|
||||
|
||||
#
|
||||
# Create a target for copying files.
|
||||
#
|
||||
if (NOT TARGET copy_files)
|
||||
add_custom_target(copy_files ALL)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Create a variable to keep track of the number of copy files targets created.
|
||||
#
|
||||
if (NOT copy_target_count)
|
||||
set(copy_target_count 0)
|
||||
endif (NOT copy_target_count)
|
||||
set(copy_target_count ${copy_target_count} CACHE INTERNAL "" FORCE)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Macro: COPY_FILES
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Description:
|
||||
# Adds a command to the build target 'copy_files' which copies files matching
|
||||
# the specifeid globbing expression from the specified source directory to
|
||||
# the specified destination directory.
|
||||
#
|
||||
# Usage:
|
||||
# COPY_FILES(SRC_DIR GLOB_PAT DST_DIR)
|
||||
#
|
||||
# Arguments:
|
||||
# - SRC_DIR : The source directory containging files to be copied.
|
||||
# - GLOB_PAT : globbing expression used to match files for copying.
|
||||
# - DST_DIR : The destination directory where files are to be copied to.
|
||||
#
|
||||
# Example:
|
||||
# copy_files(${CMAKE_CURRENT_SOURCE_DIR} *.dat ${CMAKE_CURRENT_BINARY_DIR})
|
||||
# Will copy all files in the current source directory with the extension
|
||||
# '.dat' into the current binary directory.
|
||||
#
|
||||
macro(COPY_FILES SRC_DIR GLOB_PAT DST_DIR)
|
||||
file(GLOB file_list
|
||||
RELATIVE ${SRC_DIR}
|
||||
${SRC_DIR}/${GLOB_PAT})
|
||||
math(EXPR copy_target_count '${copy_target_count}+1')
|
||||
set(copy_target_count ${copy_target_count} CACHE INTERNAL "" FORCE)
|
||||
set(target "copy_files_${copy_target_count}")
|
||||
add_custom_target(${target})
|
||||
foreach(filename ${file_list})
|
||||
set(src "${SRC_DIR}/${filename}")
|
||||
set(dst "${DST_DIR}/${filename}")
|
||||
add_custom_command(TARGET ${target} PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${src} ${dst}
|
||||
COMMENT "copying: ${src} to ${dst} " VERBATIM
|
||||
)
|
||||
endforeach(filename)
|
||||
#add_dependencies(copy_files ${target})
|
||||
add_dependencies(copy_files crowxmr)
|
||||
endmacro(COPY_FILES)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Macro: COPY_FILE
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Description:
|
||||
# Adds a command to the build target 'copy_files' which copies the specified
|
||||
# file to the specified destination.
|
||||
#
|
||||
# Usage:
|
||||
# COPY_FILE(SRC DST)
|
||||
#
|
||||
# Arguments:
|
||||
# - SRC : The source filename path (the file to be copied).
|
||||
# - DST : The destiation filename path.
|
||||
#
|
||||
# Example:
|
||||
# copy_file(
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/myfile.txt
|
||||
# ${CMAKE_CURRENT_BINARY_DIR}/myfile.txt
|
||||
# )
|
||||
#
|
||||
macro(COPY_FILE SRC DST)
|
||||
math(EXPR copy_target_count '${copy_target_count}+1')
|
||||
set(copy_target_count ${copy_target_count} CACHE INTERNAL "" FORCE)
|
||||
set(target "copy_files_${copy_target_count}")
|
||||
add_custom_target(${target})
|
||||
add_custom_command(TARGET ${target} PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${SRC} ${DST}
|
||||
COMMENT "copying: ${SRC} to ${DST}" VERBATIM
|
||||
)
|
||||
add_dependencies(copy_files ${target})
|
||||
endmacro(COPY_FILE)
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// Created by mwo on 24/05/15.
|
||||
//
|
||||
// source: http://codereview.stackexchange.com/questions/13176/infix-iterator-code
|
||||
|
||||
// infix_iterator.h
|
||||
#if !defined(INFIX_ITERATOR_H_)
|
||||
#define INFIX_ITERATOR_H_
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
template <class T, class charT=char, class traits=std::char_traits<charT> >
|
||||
class infix_ostream_iterator :
|
||||
public std::iterator<std::output_iterator_tag, void, void, void, void>
|
||||
{
|
||||
std::basic_ostream<charT,traits> *os;
|
||||
std::basic_string<charT> delimiter;
|
||||
std::basic_string<charT> real_delim;
|
||||
|
||||
public:
|
||||
|
||||
typedef charT char_type;
|
||||
typedef traits traits_type;
|
||||
typedef std::basic_ostream<charT, traits> ostream_type;
|
||||
|
||||
infix_ostream_iterator(ostream_type &s)
|
||||
: os(&s)
|
||||
{}
|
||||
|
||||
infix_ostream_iterator(ostream_type &s, charT const *d)
|
||||
: os(&s),
|
||||
real_delim(d)
|
||||
{}
|
||||
|
||||
infix_ostream_iterator<T, charT, traits> &operator=(T const &item)
|
||||
{
|
||||
*os << delimiter << item;
|
||||
delimiter = real_delim;
|
||||
return *this;
|
||||
}
|
||||
|
||||
infix_ostream_iterator<T, charT, traits> &operator*() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
infix_ostream_iterator<T, charT, traits> &operator++() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
infix_ostream_iterator<T, charT, traits> &operator++(int) {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
13
main.cpp
13
main.cpp
|
@ -43,9 +43,16 @@ int main() {
|
|||
crow::SimpleApp app;
|
||||
|
||||
CROW_ROUTE(app, "/")
|
||||
([&]() {
|
||||
return xmrblocks.index();
|
||||
});
|
||||
([&]() {
|
||||
return xmrblocks.index();
|
||||
});
|
||||
|
||||
|
||||
CROW_ROUTE(app, "/css/style.css")
|
||||
([&]() {
|
||||
return xmreg::read("./templates/css/style.css");
|
||||
});
|
||||
|
||||
|
||||
app.port(8080).multithreaded().run();
|
||||
|
||||
|
|
90
src/page.h
90
src/page.h
|
@ -19,12 +19,16 @@
|
|||
#include "tools.h"
|
||||
|
||||
|
||||
#define TMPL_DIR "./templates"
|
||||
#define TMPL_INDEX TMPL_DIR "/index.html"
|
||||
#define TMPL_HEADER TMPL_DIR "/header.html"
|
||||
#define TMPL_FOOTER TMPL_DIR "/footer.html"
|
||||
#include <algorithm>
|
||||
|
||||
#include<ctime>
|
||||
|
||||
#define TMPL_DIR "./templates"
|
||||
#define TMPL_INDEX TMPL_DIR "/index.html"
|
||||
#define TMPL_HEADER TMPL_DIR "/header.html"
|
||||
#define TMPL_FOOTER TMPL_DIR "/footer.html"
|
||||
|
||||
|
||||
#define READ_TMPL(tmpl_path) xmreg::read(tmpl_path)
|
||||
|
||||
namespace xmreg {
|
||||
|
||||
|
@ -49,50 +53,102 @@ namespace xmreg {
|
|||
string
|
||||
index()
|
||||
{
|
||||
//get current server timestamp
|
||||
time_t server_timestamp = std::time(nullptr);
|
||||
|
||||
// get the current blockchain height. Just to check if it reads ok.
|
||||
uint64_t height = core_storage->get_current_blockchain_height() - 1;
|
||||
|
||||
// initalise page tempate map with basic info about blockchain
|
||||
mstch::map context {
|
||||
{"height", fmt::format("{:d}", height)},
|
||||
{"height", fmt::format("{:d}", height)},
|
||||
{"server_timestamp", xmreg::timestamp_to_str(server_timestamp)},
|
||||
{"blocks", mstch::array()}
|
||||
};
|
||||
|
||||
size_t no_of_last_blocks {50};
|
||||
// number of last blocks to show
|
||||
size_t no_of_last_blocks {100};
|
||||
|
||||
// get reference to blocks template map to be field below
|
||||
mstch::array& blocks = boost::get<mstch::array>(context["blocks"]);
|
||||
|
||||
// iterate over last no_of_last_blocks of blocks
|
||||
for (size_t i = height; i > height - no_of_last_blocks; --i)
|
||||
{
|
||||
// get block at the given height i
|
||||
block blk;
|
||||
|
||||
mcore->get_block_by_height(i, blk);
|
||||
|
||||
// get block's hash
|
||||
crypto::hash blk_hash = core_storage->get_block_id_by_height(i);
|
||||
|
||||
// get xmr in the block reward
|
||||
array<uint64_t, 2> coinbase_tx = sum_money_in_tx(blk.miner_tx);
|
||||
|
||||
// get transactions in the block
|
||||
const vector<cryptonote::transaction>& txs_in_blk =
|
||||
core_storage->get_db().get_tx_list(blk.tx_hashes);
|
||||
|
||||
// sum xmr in the inputs and ouputs of all transactions
|
||||
array<uint64_t, 2> sum_xmr_in_out = sum_money_in_txs(txs_in_blk);
|
||||
|
||||
// get mixin number in each transaction
|
||||
vector<uint64_t> mixin_numbers = get_mixin_no_in_txs(txs_in_blk);
|
||||
|
||||
// find minimum and maxium mixin numbers
|
||||
int mixin_min {-1};
|
||||
int mixin_max {-1};
|
||||
|
||||
if (!mixin_numbers.empty())
|
||||
{
|
||||
mixin_min = static_cast<int>(
|
||||
*std::min_element(mixin_numbers.begin(), mixin_numbers.end()));
|
||||
mixin_max = static_cast<int>(
|
||||
*max_element(mixin_numbers.begin(), mixin_numbers.end()));
|
||||
}
|
||||
|
||||
auto mixin_format = [=]() -> mstch::node
|
||||
{
|
||||
if (mixin_min < 0)
|
||||
{
|
||||
return string("N/A");
|
||||
}
|
||||
return fmt::format("{:d} - {:d}", mixin_min, mixin_max);
|
||||
};
|
||||
|
||||
// set output page template map
|
||||
blocks.push_back(mstch::map {
|
||||
{"height" , to_string(i)},
|
||||
{"timestamp" , xmreg::timestamp_to_str(blk.timestamp)},
|
||||
{"hash" , fmt::format("{:s}", blk_hash)},
|
||||
{"notx" , fmt::format("{:d}", blk.tx_hashes.size())}
|
||||
{"height" , to_string(i)},
|
||||
{"timestamp" , xmreg::timestamp_to_str(blk.timestamp)},
|
||||
{"hash" , fmt::format("{:s}", blk_hash)},
|
||||
{"block_reward", fmt::format("{:0.4f}", XMR_AMOUNT(coinbase_tx[1]))},
|
||||
{"notx" , fmt::format("{:d}", blk.tx_hashes.size())},
|
||||
{"xmr_inputs" , fmt::format("{:0.4f}", XMR_AMOUNT(sum_xmr_in_out[0]))},
|
||||
{"xmr_outputs" , fmt::format("{:0.4f}", XMR_AMOUNT(sum_xmr_in_out[1]))},
|
||||
{"mixin_range" , mstch::lambda {mixin_format}}
|
||||
});
|
||||
}
|
||||
|
||||
// read index.html
|
||||
std::string index_html = xmreg::read(TMPL_INDEX);
|
||||
|
||||
std::string view = READ_TMPL(TMPL_INDEX);
|
||||
// add header and footer
|
||||
string full_page = get_full_page(index_html);
|
||||
|
||||
string full_page = get_full_page(view);
|
||||
|
||||
return mstch::render(view, context);
|
||||
// render the page
|
||||
return mstch::render(full_page, context);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
string
|
||||
get_full_page(string& middle)
|
||||
{
|
||||
return READ_TMPL(TMPL_HEADER)
|
||||
return xmreg::read(TMPL_HEADER)
|
||||
+ middle
|
||||
+ READ_TMPL(TMPL_FOOTER);
|
||||
+ xmreg::read(TMPL_FOOTER);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
tr {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size : 14px;
|
||||
height: 22px;
|
||||
}
|
|
@ -2,7 +2,8 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Monero blocks</title>
|
||||
<title>Hidden Monero Explorer</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
|
@ -1,15 +1,28 @@
|
|||
|
||||
<h1>Hidden Monero blockchain explorer</h1>
|
||||
<h2>Current height: {{height}}</h2>
|
||||
<h2>Current height: {{height}} | Server time {{server_timestamp}}</h2>
|
||||
<div>
|
||||
<ul>
|
||||
<table>
|
||||
<tr>
|
||||
<td>height</td>
|
||||
<td>timestamp</td>
|
||||
<td>block_hash</td>
|
||||
<td>block_reward</td>
|
||||
<td>no_of_txs</td>
|
||||
<td>xmr_inputs</td>
|
||||
<td>xmr_outputs</td>
|
||||
<td>mixin_range</td>
|
||||
</tr>
|
||||
{{#blocks}}
|
||||
<tr>
|
||||
<td>{{height}}</td>
|
||||
<td>{{timestamp}}</td>
|
||||
<td>{{hash}}</td>
|
||||
<td>{{block_reward}}</td>
|
||||
<td>{{notx}}</td>
|
||||
<td>{{xmr_outputs}}</td>
|
||||
<td>{{mixin_range}}</td>
|
||||
</tr>
|
||||
{{/blocks}}
|
||||
</table>
|
||||
|
|
|
@ -307,6 +307,36 @@ namespace xmreg
|
|||
return sum_xmr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
array<uint64_t, 2>
|
||||
sum_money_in_tx(const transaction& tx)
|
||||
{
|
||||
array<uint64_t, 2> sum_xmr;
|
||||
|
||||
sum_xmr[0] = sum_money_in_inputs(tx);
|
||||
sum_xmr[1] = sum_money_in_outputs(tx);
|
||||
|
||||
return sum_xmr;
|
||||
};
|
||||
|
||||
|
||||
array<uint64_t, 2>
|
||||
sum_money_in_txs(const vector<transaction>& txs)
|
||||
{
|
||||
array<uint64_t, 2> sum_xmr {0,0};
|
||||
|
||||
for (const transaction& tx: txs)
|
||||
{
|
||||
sum_xmr[0] += sum_money_in_inputs(tx);
|
||||
sum_xmr[1] += sum_money_in_outputs(tx);
|
||||
}
|
||||
|
||||
return sum_xmr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
vector<pair<txout_to_key, uint64_t>>
|
||||
get_ouputs(const transaction& tx)
|
||||
{
|
||||
|
@ -363,6 +393,19 @@ namespace xmreg
|
|||
return mixin_no;
|
||||
}
|
||||
|
||||
vector<uint64_t>
|
||||
get_mixin_no_in_txs(const vector<transaction>& txs)
|
||||
{
|
||||
vector<uint64_t> mixin_no;
|
||||
|
||||
for (const transaction& tx: txs)
|
||||
{
|
||||
mixin_no.push_back(get_mixin_no(tx));
|
||||
}
|
||||
|
||||
return mixin_no;
|
||||
}
|
||||
|
||||
|
||||
vector<txin_to_key>
|
||||
get_key_images(const transaction& tx)
|
||||
|
@ -461,10 +504,11 @@ namespace xmreg
|
|||
{
|
||||
if (!bf::exists(bf::path(filename)))
|
||||
{
|
||||
cerr << "File does not exist: " << filename << endl;
|
||||
return string();
|
||||
}
|
||||
|
||||
std::ifstream t("./templates/index.html");
|
||||
std::ifstream t(filename);
|
||||
return string(std::istreambuf_iterator<char>(t),
|
||||
std::istreambuf_iterator<char>());
|
||||
}
|
||||
|
|
31
src/tools.h
31
src/tools.h
|
@ -7,10 +7,14 @@
|
|||
|
||||
#define PATH_SEPARARTOR '/'
|
||||
|
||||
#define XMR_AMOUNT(value) \
|
||||
static_cast<double>(value) / 1e12
|
||||
|
||||
#include "monero_headers.h"
|
||||
#include "tx_details.h"
|
||||
|
||||
#include "../ext/dateparser.h"
|
||||
#include "../ext/infix_iterator.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
@ -128,14 +132,23 @@ namespace xmreg
|
|||
uint64_t
|
||||
sum_money_in_inputs(const transaction& tx);
|
||||
|
||||
array<uint64_t, 2>
|
||||
sum_money_in_tx(const transaction& tx);
|
||||
|
||||
array<uint64_t, 2>
|
||||
sum_money_in_txs(const vector<transaction>& txs);
|
||||
|
||||
uint64_t
|
||||
get_mixin_no(const transaction& tx);
|
||||
|
||||
vector<uint64_t>
|
||||
get_mixin_no_in_txs(const vector<transaction>& txs);
|
||||
|
||||
vector<pair<txout_to_key, uint64_t>>
|
||||
get_ouputs(const transaction& tx);
|
||||
|
||||
vector<txin_to_key>
|
||||
get_key_images(const transaction& tx);
|
||||
get_key_images(const transaction& tx);
|
||||
|
||||
|
||||
inline void
|
||||
|
@ -162,6 +175,22 @@ namespace xmreg
|
|||
string
|
||||
read(string filename);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* prints an iterable such as vector
|
||||
*/
|
||||
template<typename T>
|
||||
void print_iterable(const T & elems) {
|
||||
|
||||
infix_ostream_iterator<typename T::value_type>
|
||||
oiter(std::cout, ",");
|
||||
|
||||
std::cout << "[";
|
||||
std::copy(elems.begin(), elems.end(),oiter);
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //XMREG01_TOOLS_H
|
||||
|
|
Loading…
Reference in New Issue