diff --git a/CMakeLists.txt b/CMakeLists.txt index 21bf11b0..e3626289 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,9 +21,7 @@ # SOFTWARE. cmake_minimum_required(VERSION 3.15) -project(mp-units-dev - LANGUAGES CXX -) +project(mp-units-dev LANGUAGES CXX) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") @@ -50,8 +48,7 @@ if(${projectPrefix}IWYU) include(include-what-you-use) enable_iwyu( MAPPING_FILE "${PROJECT_SOURCE_DIR}/.mp-units.imp" - NO_FORWARD_DECLARATIONS - QUOTED_INCLUDES_FIRST + NO_FORWARD_DECLARATIONS QUOTED_INCLUDES_FIRST MAX_LINE_LENGTH 120 NO_COMMENTS ) diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake index 7b1504ab..a7d4382d 100644 --- a/cmake/FindSphinx.cmake +++ b/cmake/FindSphinx.cmake @@ -1,11 +1,7 @@ # Look for an executable called sphinx-build -find_program(SPHINX_EXECUTABLE - NAMES sphinx-build - DOC "Path to sphinx-build executable") +find_program(SPHINX_EXECUTABLE NAMES sphinx-build DOC "Path to sphinx-build executable") include(FindPackageHandleStandardArgs) # Handle standard arguments to find_package like REQUIRED and QUIET -find_package_handle_standard_args(Sphinx - "Failed to find sphinx-build executable" - SPHINX_EXECUTABLE) +find_package_handle_standard_args(Sphinx "Failed to find sphinx-build executable" SPHINX_EXECUTABLE) diff --git a/cmake/ccache.cmake b/cmake/ccache.cmake index 396b52df..f14ec3c0 100644 --- a/cmake/ccache.cmake +++ b/cmake/ccache.cmake @@ -134,7 +134,7 @@ function(enable_ccache) endif() if("${_ccache_version}" VERSION_LESS 3.3.0) - list(APPEND _ccacheEnv CCACHE_CPP2=1) # avoids spurious warnings with some compilers for ccache older than 3.3 + list(APPEND _ccacheEnv CCACHE_CPP2=1) # avoids spurious warnings with some compilers for ccache older than 3.3 endif() if(_enable_ccache_MODE STREQUAL DIRECT_DEPEND) @@ -188,25 +188,18 @@ function(enable_ccache) if(CMAKE_GENERATOR MATCHES "Ninja|Makefiles") foreach(_lang IN ITEMS C CXX OBJC OBJCXX CUDA) - set(CMAKE_${_lang}_COMPILER_LAUNCHER - ${CMAKE_COMMAND} -E env - ${_ccacheEnv} ${CCACHE_PATH} - PARENT_SCOPE - ) + set(CMAKE_${_lang}_COMPILER_LAUNCHER ${CMAKE_COMMAND} -E env ${_ccacheEnv} ${CCACHE_PATH} PARENT_SCOPE) endforeach() elseif(CMAKE_GENERATOR STREQUAL Xcode) # Each of the Xcode project variables allow specifying only a single value, but the ccache command line needs to have multiple options. # A separate launch script needs to be written out and the project variables pointed at them. foreach(_lang IN ITEMS C CXX) - set(launch${_lang} ${CMAKE_BINARY_DIR}/launch-${_lang}) - file(WRITE ${launch${_lang}} "#!/bin/bash\n\n") - foreach(keyVal IN LISTS _ccacheEnv) - file(APPEND ${launch${_lang}} "export ${keyVal}\n") - endforeach() - file(APPEND ${launch${_lang}} - "exec \"${CCACHE_PROGRAM}\" " - "\"${CMAKE_${_lang}_COMPILER}\" \"$@\"\n" - ) + set(launch${_lang} ${CMAKE_BINARY_DIR}/launch-${_lang}) + file(WRITE ${launch${_lang}} "#!/bin/bash\n\n") + foreach(keyVal IN LISTS _ccacheEnv) + file(APPEND ${launch${_lang}} "export ${keyVal}\n") + endforeach() + file(APPEND ${launch${_lang}} "exec \"${CCACHE_PROGRAM}\" " "\"${CMAKE_${_lang}_COMPILER}\" \"$@\"\n") execute_process(COMMAND chmod a+rx ${launch${_lang}}) endforeach() set(CMAKE_XCODE_ATTRIBUTE_CC ${launchC} PARENT_SCOPE) diff --git a/cmake/documentation.cmake b/cmake/documentation.cmake index d3cbf585..3e6b239d 100644 --- a/cmake/documentation.cmake +++ b/cmake/documentation.cmake @@ -22,7 +22,8 @@ cmake_minimum_required(VERSION 3.5) -find_package(Doxygen MODULE REQUIRED) # TODO Switch to CONFIG when Conan will start supporting imported executables in CMakeDeps +find_package(Doxygen MODULE REQUIRED +)# TODO Switch to CONFIG when Conan will start supporting imported executables in CMakeDeps find_package(Sphinx REQUIRED) # @@ -80,16 +81,14 @@ function(add_documentation targetName) set(_doxygenIndexFile "${DOXYGEN_OUTPUT_DIR}/xml/index.xml") # Only regenerate Doxygen when the Doxyfile or given dependencies change - add_custom_command(OUTPUT "${_doxygenIndexFile}" + add_custom_command( + OUTPUT "${_doxygenIndexFile}" COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIR} COMMAND Doxygen::doxygen ARGS "${_doxyfile}" MAIN_DEPENDENCY "${_doxyfileIn}" - DEPENDS - "${_doxyfile}" - "${_args_CODE_DEPENDS}" + DEPENDS "${_doxyfile}" "${_args_CODE_DEPENDS}" COMMENT "Generating doxygen XML metadata" - USES_TERMINAL - VERBATIM + USES_TERMINAL VERBATIM ) set(_sphinx_docs_dir "${CMAKE_CURRENT_BINARY_DIR}/sphinx") @@ -99,16 +98,16 @@ function(add_documentation targetName) # - Doxygen has rerun # - Our doc files have been updated # - The Sphinx config has been updated - add_custom_command(OUTPUT "${_sphinx_index_file}" - COMMAND "${SPHINX_EXECUTABLE}" ARGS -b html -j auto "-Dbreathe_projects.${_args_BREATHE_PROJECT}=${DOXYGEN_OUTPUT_DIR}/xml" "${_args_DOCS_SOURCE_DIR}" "${_sphinx_docs_dir}" + add_custom_command( + OUTPUT "${_sphinx_index_file}" + COMMAND "${SPHINX_EXECUTABLE}" ARGS -b html -j auto + "-Dbreathe_projects.${_args_BREATHE_PROJECT}=${DOXYGEN_OUTPUT_DIR}/xml" "${_args_DOCS_SOURCE_DIR}" + "${_sphinx_docs_dir}" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" MAIN_DEPENDENCY "${_args_DOCS_SOURCE_DIR}/conf.py" - DEPENDS - "${_doxygenIndexFile}" - "${_args_DOCS_DEPENDS}" + DEPENDS "${_doxygenIndexFile}" "${_args_DOCS_DEPENDS}" COMMENT "Generating documentation with Sphinx" - USES_TERMINAL - VERBATIM + USES_TERMINAL VERBATIM ) # Custom target @@ -118,7 +117,7 @@ function(add_documentation targetName) add_custom_target(${targetName} ${_all} DEPENDS "${_sphinx_index_file}") if(_args_INSTALL_DIR) - # Add an install step to install the docs - install(DIRECTORY ${_sphinx_docs_dir} TYPE DOC) + # Add an install step to install the docs + install(DIRECTORY ${_sphinx_docs_dir} TYPE DOC) endif() endfunction() diff --git a/cmake/include-what-you-use.cmake b/cmake/include-what-you-use.cmake index 41853ae6..53556e7a 100644 --- a/cmake/include-what-you-use.cmake +++ b/cmake/include-what-you-use.cmake @@ -48,7 +48,17 @@ macro(_enable_iwyu_failed log_postfix) endmacro() macro(_process_iwyu_arguments offset log_postfix) - set(_options QUIET REQUIRED NO_DEFAULT_MAPPINGS PCH_IN_CODE TRANSITIVE_INCLUDES_ONLY NO_COMMENTS NO_FORWARD_DECLARATIONS CXX17_NAMESPACES QUOTED_INCLUDES_FIRST) + set(_options + QUIET + REQUIRED + NO_DEFAULT_MAPPINGS + PCH_IN_CODE + TRANSITIVE_INCLUDES_ONLY + NO_COMMENTS + NO_FORWARD_DECLARATIONS + CXX17_NAMESPACES + QUOTED_INCLUDES_FIRST + ) set(_one_value_args PROGRAM MAPPING_FILE MAX_LINE_LENGTH) set(_multi_value_args KEEP) cmake_parse_arguments(PARSE_ARGV ${offset} _enable_iwyu "${_options}" "${_one_value_args}" "${_multi_value_args}") @@ -160,7 +170,5 @@ endfunction() # function(enable_target_iwyu target) _process_iwyu_arguments(1 " for '${target}'") - set_target_properties(${target} PROPERTIES - CXX_INCLUDE_WHAT_YOU_USE "${_iwyu_path};${_iwyu_args}" - ) + set_target_properties(${target} PROPERTIES CXX_INCLUDE_WHAT_YOU_USE "${_iwyu_path};${_iwyu_args}") endfunction() diff --git a/cmake/metabench.cmake b/cmake/metabench.cmake index 4f183ff3..0b4002d9 100644 --- a/cmake/metabench.cmake +++ b/cmake/metabench.cmake @@ -20,7 +20,6 @@ endif() # avoid polluting the build tree. set(METABENCH_DIR "${CMAKE_CURRENT_BINARY_DIR}/_metabench") - # metabench_add_dataset(target path_to_template range # [NAME name] # [ENV env] @@ -124,41 +123,40 @@ function(metabench_add_dataset target path_to_template range) set(multi_value_args) cmake_parse_arguments(ARGS "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN}) - if (NOT IS_ABSOLUTE "${path_to_template}") + if(NOT IS_ABSOLUTE "${path_to_template}") set(path_to_template "${CMAKE_CURRENT_SOURCE_DIR}/${path_to_template}") endif() - if (NOT EXISTS ${path_to_template}) + if(NOT EXISTS ${path_to_template}) message(FATAL_ERROR "The file specified to metabench_add_dataset (${path_to_template}) does not exist.") endif() - if (NOT ARGS_NAME) + if(NOT ARGS_NAME) set(ARGS_NAME ${target}) endif() - if (NOT ARGS_ENV) + if(NOT ARGS_ENV) set(ARGS_ENV "{}") endif() - if (NOT ARGS_COLOR) + if(NOT ARGS_COLOR) set(ARGS_COLOR "") endif() - if (NOT ARGS_SCALE) + if(NOT ARGS_SCALE) set(ARGS_SCALE 1.0) endif() - if (NOT ARGS_MEDIAN_OF) + if(NOT ARGS_MEDIAN_OF) set(ARGS_MEDIAN_OF 1) endif() - if (NOT ARGS_OUTPUT) + if(NOT ARGS_OUTPUT) set(ARGS_OUTPUT "${target}.json") endif() if(NOT IS_ABSOLUTE "${ARGS_OUTPUT}") set(ARGS_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_OUTPUT}") endif() - # Add a dummy executable that will be used to collect the dataset. # We'll build this executable multiple times for different values # of `n`, and collect compilation statistics each time. Compiling @@ -169,46 +167,42 @@ function(metabench_add_dataset target path_to_template range) # so we store it in a custom property. file(WRITE "${METABENCH_DIR}/${target}.cpp" "") add_executable(${target} EXCLUDE_FROM_ALL "${METABENCH_DIR}/${target}.cpp") - set_target_properties(${target} PROPERTIES - RULE_LAUNCH_COMPILE "${RUBY_EXECUTABLE} -- \"${COMPILE_RB_PATH}\"" - RULE_LAUNCH_LINK "${RUBY_EXECUTABLE} -- \"${LINK_RB_PATH}\"" - RUNTIME_OUTPUT_DIRECTORY "${METABENCH_DIR}" - RUNTIME_OUTPUT_DIRECTORY_RELEASE "${METABENCH_DIR}" - RUNTIME_OUTPUT_DIRECTORY_DEBUG "${METABENCH_DIR}" - RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${METABENCH_DIR}" - RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${METABENCH_DIR}" - METABENCH_DATASET_PATH "${ARGS_OUTPUT}" + set_target_properties( + ${target} + PROPERTIES + RULE_LAUNCH_COMPILE "${RUBY_EXECUTABLE} -- \"${COMPILE_RB_PATH}\"" + RULE_LAUNCH_LINK "${RUBY_EXECUTABLE} -- \"${LINK_RB_PATH}\"" + RUNTIME_OUTPUT_DIRECTORY "${METABENCH_DIR}" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${METABENCH_DIR}" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${METABENCH_DIR}" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${METABENCH_DIR}" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${METABENCH_DIR}" + METABENCH_DATASET_PATH "${ARGS_OUTPUT}" ) get_filename_component(template_dir "${path_to_template}" DIRECTORY) target_include_directories(${target} PUBLIC "${template_dir}") # Add a command to generate the JSON file that will contain the measurements # we collect for this dataset when we build the executable above. - add_custom_command(OUTPUT "${ARGS_OUTPUT}" - COMMAND "${RUBY_EXECUTABLE}" -r json -r fileutils -r "${METABENCH_RB_PATH}" - -e "range = (${range}).to_a" - -e "env = (${ARGS_ENV})" - -e "data = {}" - -e "data['key'] = '${ARGS_NAME}'" - -e "data['scale'] = (${ARGS_SCALE})" - -e "data['color'] = '${ARGS_COLOR}'" - -e "data['values'] = measure('${target}', '${path_to_template}', range, env, ${ARGS_MEDIAN_OF})" - -e "FileUtils.mkdir_p(File.dirname('${ARGS_OUTPUT}'))" - -e "IO.write('${ARGS_OUTPUT}', JSON.generate(data))" + add_custom_command( + OUTPUT "${ARGS_OUTPUT}" + COMMAND "${RUBY_EXECUTABLE}" -r json -r fileutils -r "${METABENCH_RB_PATH}" -e "range = (${range}).to_a" -e + "env = (${ARGS_ENV})" -e "data = {}" -e "data['key'] = '${ARGS_NAME}'" -e + "data['scale'] = (${ARGS_SCALE})" -e "data['color'] = '${ARGS_COLOR}'" -e + "data['values'] = measure('${target}', '${path_to_template}', range, env, ${ARGS_MEDIAN_OF})" -e + "FileUtils.mkdir_p(File.dirname('${ARGS_OUTPUT}'))" -e "IO.write('${ARGS_OUTPUT}', JSON.generate(data))" DEPENDS "${path_to_template}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" VERBATIM USES_TERMINAL ) - # We also setup a CTest target to test the generation of the dataset. # We do not actually collect any data here. - add_test(NAME ${target} - COMMAND "${RUBY_EXECUTABLE}" -r "${METABENCH_RB_PATH}" - -e "range = (${range}).to_a" - -e "range = [range[0], range[-1]] if range.length >= 2" - -e "env = (${ARGS_ENV})" - -e "data = measure('${target}', '${path_to_template}', range, env, 1)" + add_test( + NAME ${target} + COMMAND "${RUBY_EXECUTABLE}" -r "${METABENCH_RB_PATH}" -e "range = (${range}).to_a" -e + "range = [range[0], range[-1]] if range.length >= 2" -e "env = (${ARGS_ENV})" -e + "data = measure('${target}', '${path_to_template}', range, env, 1)" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) endfunction() @@ -276,7 +270,7 @@ function(metabench_add_chart target) set(multi_value_args DATASETS) cmake_parse_arguments(ARGS "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN}) - if (NOT ARGS_ASPECT) + if(NOT ARGS_ASPECT) set(ARGS_ASPECT "COMPILATION_TIME") endif() @@ -284,7 +278,7 @@ function(metabench_add_chart target) message(FATAL_ERROR "metabench_add_chart requires at least one dataset.") endif() - if (NOT ARGS_OUTPUT) + if(NOT ARGS_OUTPUT) set(ARGS_OUTPUT "${target}.html") endif() @@ -300,22 +294,17 @@ function(metabench_add_chart target) add_custom_command( OUTPUT "${ARGS_OUTPUT}" - COMMAND "${RUBY_EXECUTABLE}" -r erb -r json -r fileutils - -e "options = {}" - -e "options['TITLE'] = '${ARGS_TITLE}'" - -e "options['SUBTITLE'] = '${ARGS_SUBTITLE}'" - -e "options['XLABEL'] = '${ARGS_XLABEL}'" - -e "options['YLABEL'] = '${ARGS_YLABEL}'" - -e "aspect = '${ARGS_ASPECT}'" - -e "data = '${data}'.split(';').map { |datum| JSON.parse(IO.read(datum)) }" - -e "html = ERB.new(File.read('${CHART_HTML_ERB_PATH}')).result(binding)" - -e "FileUtils.mkdir_p(File.dirname('${ARGS_OUTPUT}'))" - -e "IO.write('${ARGS_OUTPUT}', html)" + COMMAND "${RUBY_EXECUTABLE}" -r erb -r json -r fileutils -e "options = {}" -e + "options['TITLE'] = '${ARGS_TITLE}'" -e "options['SUBTITLE'] = '${ARGS_SUBTITLE}'" -e + "options['XLABEL'] = '${ARGS_XLABEL}'" -e "options['YLABEL'] = '${ARGS_YLABEL}'" -e + "aspect = '${ARGS_ASPECT}'" -e "data = '${data}'.split(';').map { |datum| JSON.parse(IO.read(datum)) }" + -e "html = ERB.new(File.read('${CHART_HTML_ERB_PATH}')).result(binding)" -e + "FileUtils.mkdir_p(File.dirname('${ARGS_OUTPUT}'))" -e "IO.write('${ARGS_OUTPUT}', html)" DEPENDS ${data} "${ARGS_CHART}" VERBATIM ) - if (${ARGS_ALL}) + if(${ARGS_ALL}) add_custom_target(${target} ALL DEPENDS "${ARGS_OUTPUT}") else() add_custom_target(${target} DEPENDS "${ARGS_OUTPUT}") @@ -338,109 +327,109 @@ endfunction() ################################################################################ set(METABENCH_RB_PATH "${METABENCH_DIR}/metabench.rb") file(WRITE "${METABENCH_RB_PATH}" -"require 'benchmark' \n" -"require 'erb' \n" -"require 'fileutils' \n" -"require 'open3' \n" -"require 'pathname' \n" -"require 'time' \n" -" \n" -" \n" -"def report_error(command_line, stdout, stderr, code) \n" -" raise [%{\\ncommand line: #{command_line}}, \n" -" %{stdout\\n#{'-'*80}\\n#{stdout}}, \n" -" %{stderr\\n#{'-'*80}\\n#{stderr}}, \n" -" %{code\\n#{'-'*80}\\n#{code}}].join(%{\\n\\n}) \n" -"end \n" -" \n" -"# Build the specified CMake target and return the measurements that were taken. \n" -"# The exact format of a measurement returned by this function is explained \n" -"# in the JavaScript code that loads it, in the chart template file below. \n" -"def build(target) \n" -" command = ['${CMAKE_COMMAND}', '--build', '${CMAKE_BINARY_DIR}', '--target', target] \n" -" exe_file = %{${METABENCH_DIR}/#{target}${CMAKE_EXECUTABLE_SUFFIX}} \n" -" cpp_file = %{${METABENCH_DIR}/#{target}.cpp} \n" -" \n" -" # We change the timestamp of the source file and remove the executable \n" -" # to make sure CMake considers the target as outdated; otherwise, we \n" -" # might skip the compilation and/or link steps. This is because CMake's \n" -" # timestamps are not precise enough. \n" -" FileUtils.touch(cpp_file, mtime: Time.now+1) \n" -" File.delete(exe_file) if File.exist?(exe_file) \n" -" \n" -" stdout, stderr, status = Open3.capture3(*command) \n" -" compile_cli = stdout.match(/\\[compilation command: (.+)\\]/i) \n" -" compile_cli = compile_cli ? compile_cli.captures[0] : '(unavailable)' \n" -" link_cli = stdout.match(/\\[link command: (.+)\\]/i) \n" -" link_cli = link_cli ? link_cli.captures[0] : '(unavailable)' \n" -" \n" -" if not status.success? \n" -" cli = %{compile: #{compile_cli}\\nlink: #{link_cli}} \n" -" report_error(cli, stdout, stderr, IO.read(cpp_file)) \n" -" end \n" -" \n" -" result = {} \n" -" \n" -" # Compilation and link times in seconds. They are output to stdout because \n" -" # we use the `compile.rb` and `link.rb` scripts below to launch the compiler \n" -" # and linker with CMake. \n" -" result['COMPILATION_TIME'] = stdout.match(/\\[COMPILATION_TIME: (.+)\\]/i).captures[0].to_f \n" -" result['LINK_TIME'] = stdout.match(/\\[LINK_TIME: (.+)\\]/i).captures[0].to_f \n" -" \n" -" # Peak memory usage \n" -" result['PEAK_MEMORY'] = stdout.match(/\\[PEAK_MEMORY: (.+)\\]/i).captures[0].to_f \n" -" \n" -" # Size of the generated executable in KB \n" -" result['EXECUTABLE_SIZE'] = File.size(exe_file).to_f / 1000 \n" -" \n" -" return result \n" -"end \n" -" \n" -"# Render the ERB template and return the generated code. \n" -"def render(erb_template, n, env) \n" -" begin \n" -" ERB.new(File.read(erb_template)).result(binding) \n" -" rescue Exception => e \n" -" $stderr.puts(%{\\nError while generating a C++ file from the ERB template #{erb_template}:\\n}) \n" -" raise e \n" -" end \n" -"end \n" -" \n" -"# Formats the progress bar that we print while we run the benchmark \n" -"def progress_bar(range, index, start_time, filename) \n" -" n = range[index] \n" -" percentage = (index+1) * 100 / range.size \n" -" relative = filename.relative_path_from(Pathname.getwd) \n" -" elapsed = Time.now - start_time \n" -" return %{==> #{percentage}% (#{elapsed.round(2)}s) #{relative} (n = #{n})} \n" -"end \n" -" \n" -"# Returns an array of measurements representing the compilation of an ERB \n" -"# template for the values of `n` in the specified `range`. \n" -"def measure(target, erb_template, range, env, repetitions) \n" -" erb_template = Pathname.new(erb_template) \n" -" cpp_file = %{${METABENCH_DIR}/#{target}.cpp} \n" -" data = [] \n" -" range = range.to_a \n" -" start = Time.now \n" -" $stderr.write(progress_bar(range, 0, start, erb_template)) # Setup the initial progress bar \n" -" range.each_with_index do |n, index| \n" -" compile = -> (code) { \n" -" IO.write(cpp_file, code) \n" -" return repetitions.times.map { build(target) } \n" -" } \n" -" code = render(erb_template, n, env) \n" -" compile[code] if index == 0 # Fill the cache on the first iteration \n" -" base = compile[code] \n" -" total = compile[%{#define METABENCH\\n} + code] \n" -" data << {'n' => n, 'base' => base, 'total' => total} \n" -" $stderr.write(%{\\r} + progress_bar(range, index, start, erb_template)) # Update the progress bar \n" -" end \n" -" return data \n" -"ensure \n" -" $stderr.puts # Otherwise the output of the next CMake command appears on the same line \n" -" IO.write(cpp_file, '') \n" -"end \n" + "require 'benchmark' \n" + "require 'erb' \n" + "require 'fileutils' \n" + "require 'open3' \n" + "require 'pathname' \n" + "require 'time' \n" + " \n" + " \n" + "def report_error(command_line, stdout, stderr, code) \n" + " raise [%{\\ncommand line: #{command_line}}, \n" + " %{stdout\\n#{'-'*80}\\n#{stdout}}, \n" + " %{stderr\\n#{'-'*80}\\n#{stderr}}, \n" + " %{code\\n#{'-'*80}\\n#{code}}].join(%{\\n\\n}) \n" + "end \n" + " \n" + "# Build the specified CMake target and return the measurements that were taken. \n" + "# The exact format of a measurement returned by this function is explained \n" + "# in the JavaScript code that loads it, in the chart template file below. \n" + "def build(target) \n" + " command = ['${CMAKE_COMMAND}', '--build', '${CMAKE_BINARY_DIR}', '--target', target] \n" + " exe_file = %{${METABENCH_DIR}/#{target}${CMAKE_EXECUTABLE_SUFFIX}} \n" + " cpp_file = %{${METABENCH_DIR}/#{target}.cpp} \n" + " \n" + " # We change the timestamp of the source file and remove the executable \n" + " # to make sure CMake considers the target as outdated; otherwise, we \n" + " # might skip the compilation and/or link steps. This is because CMake's \n" + " # timestamps are not precise enough. \n" + " FileUtils.touch(cpp_file, mtime: Time.now+1) \n" + " File.delete(exe_file) if File.exist?(exe_file) \n" + " \n" + " stdout, stderr, status = Open3.capture3(*command) \n" + " compile_cli = stdout.match(/\\[compilation command: (.+)\\]/i) \n" + " compile_cli = compile_cli ? compile_cli.captures[0] : '(unavailable)' \n" + " link_cli = stdout.match(/\\[link command: (.+)\\]/i) \n" + " link_cli = link_cli ? link_cli.captures[0] : '(unavailable)' \n" + " \n" + " if not status.success? \n" + " cli = %{compile: #{compile_cli}\\nlink: #{link_cli}} \n" + " report_error(cli, stdout, stderr, IO.read(cpp_file)) \n" + " end \n" + " \n" + " result = {} \n" + " \n" + " # Compilation and link times in seconds. They are output to stdout because \n" + " # we use the `compile.rb` and `link.rb` scripts below to launch the compiler \n" + " # and linker with CMake. \n" + " result['COMPILATION_TIME'] = stdout.match(/\\[COMPILATION_TIME: (.+)\\]/i).captures[0].to_f \n" + " result['LINK_TIME'] = stdout.match(/\\[LINK_TIME: (.+)\\]/i).captures[0].to_f \n" + " \n" + " # Peak memory usage \n" + " result['PEAK_MEMORY'] = stdout.match(/\\[PEAK_MEMORY: (.+)\\]/i).captures[0].to_f \n" + " \n" + " # Size of the generated executable in KB \n" + " result['EXECUTABLE_SIZE'] = File.size(exe_file).to_f / 1000 \n" + " \n" + " return result \n" + "end \n" + " \n" + "# Render the ERB template and return the generated code. \n" + "def render(erb_template, n, env) \n" + " begin \n" + " ERB.new(File.read(erb_template)).result(binding) \n" + " rescue Exception => e \n" + " $stderr.puts(%{\\nError while generating a C++ file from the ERB template #{erb_template}:\\n}) \n" + " raise e \n" + " end \n" + "end \n" + " \n" + "# Formats the progress bar that we print while we run the benchmark \n" + "def progress_bar(range, index, start_time, filename) \n" + " n = range[index] \n" + " percentage = (index+1) * 100 / range.size \n" + " relative = filename.relative_path_from(Pathname.getwd) \n" + " elapsed = Time.now - start_time \n" + " return %{==> #{percentage}% (#{elapsed.round(2)}s) #{relative} (n = #{n})} \n" + "end \n" + " \n" + "# Returns an array of measurements representing the compilation of an ERB \n" + "# template for the values of `n` in the specified `range`. \n" + "def measure(target, erb_template, range, env, repetitions) \n" + " erb_template = Pathname.new(erb_template) \n" + " cpp_file = %{${METABENCH_DIR}/#{target}.cpp} \n" + " data = [] \n" + " range = range.to_a \n" + " start = Time.now \n" + " $stderr.write(progress_bar(range, 0, start, erb_template)) # Setup the initial progress bar \n" + " range.each_with_index do |n, index| \n" + " compile = -> (code) { \n" + " IO.write(cpp_file, code) \n" + " return repetitions.times.map { build(target) } \n" + " } \n" + " code = render(erb_template, n, env) \n" + " compile[code] if index == 0 # Fill the cache on the first iteration \n" + " base = compile[code] \n" + " total = compile[%{#define METABENCH\\n} + code] \n" + " data << {'n' => n, 'base' => base, 'total' => total} \n" + " $stderr.write(%{\\r} + progress_bar(range, index, start, erb_template)) # Update the progress bar \n" + " end \n" + " return data \n" + "ensure \n" + " $stderr.puts # Otherwise the output of the next CMake command appears on the same line \n" + " IO.write(cpp_file, '') \n" + "end \n" ) ################################################################################ # end metabench.rb @@ -454,47 +443,47 @@ file(WRITE "${METABENCH_RB_PATH}" ################################################################################ set(MEMUSG_RB_PATH "${METABENCH_DIR}/memusg.rb") file(WRITE "${MEMUSG_RB_PATH}" -"module OS \n" -" def OS.windows? \n" -" (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil \n" -" end \n" -" def OS.mac? \n" -" (/darwin/ =~ RUBY_PLATFORM) != nil \n" -" end \n" -" def OS.unix? \n" -" !OS.windows? \n" -" end \n" -" def OS.linux? \n" -" OS.unix? and not OS.mac? \n" -" end \n" -"end \n" -" \n" -"if OS.mac? \n" -" def memusg(pgid) \n" -" `/bin/ps -o rss= -g #{pgid}`.to_i \n" -" end \n" -"elsif OS.linux? \n" -" def memusg(pgid) \n" -" `/bin/ps -o rss= -#{pgid}`.to_i \n" -" end \n" -"else \n" -" throw %{Unsupported platform #{RUBY_PLATFORM}} \n" -"end \n" -" \n" -"pid = Process.spawn(*ARGV) \n" -"Process.detach(pid) # Make sure the child process does not become a zombie \n" -"peak = 0 \n" -"# Loop until getpgid throws ESRCH, which means the process is not alive anymore \n" -"begin \n" -" while true \n" -" pgid = Process.getpgid(pid) \n" -" peak = [peak, memusg(pgid)].max \n" -" sleep 0.01 \n" -" end \n" -"rescue Errno::ESRCH \n" -"end \n" -" \n" -"puts %{[PEAK_MEMORY: #{peak}]} \n" + "module OS \n" + " def OS.windows? \n" + " (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil \n" + " end \n" + " def OS.mac? \n" + " (/darwin/ =~ RUBY_PLATFORM) != nil \n" + " end \n" + " def OS.unix? \n" + " !OS.windows? \n" + " end \n" + " def OS.linux? \n" + " OS.unix? and not OS.mac? \n" + " end \n" + "end \n" + " \n" + "if OS.mac? \n" + " def memusg(pgid) \n" + " `/bin/ps -o rss= -g #{pgid}`.to_i \n" + " end \n" + "elsif OS.linux? \n" + " def memusg(pgid) \n" + " `/bin/ps -o rss= -#{pgid}`.to_i \n" + " end \n" + "else \n" + " throw %{Unsupported platform #{RUBY_PLATFORM}} \n" + "end \n" + " \n" + "pid = Process.spawn(*ARGV) \n" + "Process.detach(pid) # Make sure the child process does not become a zombie \n" + "peak = 0 \n" + "# Loop until getpgid throws ESRCH, which means the process is not alive anymore \n" + "begin \n" + " while true \n" + " pgid = Process.getpgid(pid) \n" + " peak = [peak, memusg(pgid)].max \n" + " sleep 0.01 \n" + " end \n" + "rescue Errno::ESRCH \n" + "end \n" + " \n" + "puts %{[PEAK_MEMORY: #{peak}]} \n" ) ################################################################################ # end memusg.rb @@ -508,18 +497,18 @@ file(WRITE "${MEMUSG_RB_PATH}" ################################################################################ set(COMPILE_RB_PATH "${METABENCH_DIR}/compile.rb") file(WRITE "${COMPILE_RB_PATH}" -"require 'benchmark' \n" -"require 'open3' \n" -"stdout = stderr = status = nil \n" -"command_line = ['${RUBY_EXECUTABLE}', '--', '${MEMUSG_RB_PATH}'] + ARGV \n" -"time = Benchmark.measure { \n" -" stdout, stderr, status = Open3.capture3(*command_line) \n" -"}.total \n" -"$stdout.puts(stdout) \n" -"$stdout.puts(%{[compilation command: #{command_line.join(' ')}]}) \n" -"$stdout.puts(%{[COMPILATION_TIME: #{time}]}) \n" -"$stderr.puts(stderr) \n" -"exit(status.success?) \n" + "require 'benchmark' \n" + "require 'open3' \n" + "stdout = stderr = status = nil \n" + "command_line = ['${RUBY_EXECUTABLE}', '--', '${MEMUSG_RB_PATH}'] + ARGV \n" + "time = Benchmark.measure { \n" + " stdout, stderr, status = Open3.capture3(*command_line) \n" + "}.total \n" + "$stdout.puts(stdout) \n" + "$stdout.puts(%{[compilation command: #{command_line.join(' ')}]}) \n" + "$stdout.puts(%{[COMPILATION_TIME: #{time}]}) \n" + "$stderr.puts(stderr) \n" + "exit(status.success?) \n" ) ################################################################################ # end compile.rb @@ -532,15 +521,15 @@ file(WRITE "${COMPILE_RB_PATH}" ################################################################################ set(LINK_RB_PATH "${METABENCH_DIR}/link.rb") file(WRITE "${LINK_RB_PATH}" -"require 'benchmark' \n" -"require 'open3' \n" -"stdout = stderr = status = nil \n" -"time = Benchmark.measure { stdout, stderr, status = Open3.capture3(*ARGV) }.total\n" -"$stdout.puts(stdout) \n" -"$stdout.puts(%{[link command: #{ARGV.join(' ')}]}) \n" -"$stdout.puts(%{[LINK_TIME: #{time}]}) \n" -"$stderr.puts(stderr) \n" -"exit(status.success?) \n" + "require 'benchmark' \n" + "require 'open3' \n" + "stdout = stderr = status = nil \n" + "time = Benchmark.measure { stdout, stderr, status = Open3.capture3(*ARGV) }.total\n" + "$stdout.puts(stdout) \n" + "$stdout.puts(%{[link command: #{ARGV.join(' ')}]}) \n" + "$stdout.puts(%{[LINK_TIME: #{time}]}) \n" + "$stderr.puts(stderr) \n" + "exit(status.success?) \n" ) ################################################################################ # end link.rb @@ -555,191 +544,191 @@ file(WRITE "${LINK_RB_PATH}" ################################################################################ set(CHART_HTML_ERB_PATH "${METABENCH_DIR}/chart.html.erb") file(WRITE "${CHART_HTML_ERB_PATH}" -" \n" -" \n" -"
\n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" ) ################################################################################ # end chart.html.erb @@ -751,13 +740,15 @@ file(WRITE "${CHART_HTML_ERB_PATH}" # The following is a copy of the nvd3 1.8.5 css file. # https://github.com/novus/nvd3 ################################################################################ -file(WRITE "${METABENCH_DIR}/nvd3.css" "\ +file(WRITE "${METABENCH_DIR}/nvd3.css" + "\ .nvd3 .nv-axis line,.nvd3 .nv-axis path{fill:none;shape-rendering:crispEdges}.nv-brush .extent,.nvd3 .background path,.nvd3 .nv-axis line,.nvd3 .nv-axis path{shape-rendering:crispEdges}.nv-distx,.nv-disty,.nv-noninteractive,.nvd3 .nv-axis,.nvd3.nv-pie .nv-label,.nvd3.nv-sparklineplus g.nv-hoverValue{pointer-events:none}.nvd3 .nv-axis{opacity:1}.nvd3 .nv-axis.nv-disabled,.nvd3 .nv-controlsWrap .nv-legend .nv-check-box .nv-check{opacity:0}.nvd3 .nv-axis path{stroke:#000;stroke-opacity:.75}.nvd3 .nv-axis path.domain{stroke-opacity:.75}.nvd3 .nv-axis.nv-x path.domain{stroke-opacity:0}.nvd3 .nv-axis line{stroke:#e5e5e5}.nvd3 .nv-axis .zero line, .nvd3 .nv-axis line.zero{stroke-opacity:.75}.nvd3 .nv-axis .nv-axisMaxMin text{font-weight:700}.nvd3 .x .nv-axis .nv-axisMaxMin text,.nvd3 .x2 .nv-axis .nv-axisMaxMin text,.nvd3 .x3 .nv-axis .nv-axisMaxMin text{text-anchor:middle}.nvd3 .nv-bars rect{fill-opacity:.75;transition:fill-opacity 250ms linear}.nvd3 .nv-bars rect.hover{fill-opacity:1}.nvd3 .nv-bars .hover rect{fill:#add8e6}.nvd3 .nv-bars text{fill:transparent}.nvd3 .nv-bars .hover text{fill:rgba(0,0,0,1)}.nvd3 .nv-discretebar .nv-groups rect,.nvd3 .nv-multibar .nv-groups rect,.nvd3 .nv-multibarHorizontal .nv-groups rect{stroke-opacity:0;transition:fill-opacity 250ms linear}.with-transitions .nv-candlestickBar .nv-ticks .nv-tick,.with-transitions .nvd3 .nv-groups .nv-point{transition:stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3 .nv-candlestickBar .nv-ticks rect:hover,.nvd3 .nv-discretebar .nv-groups rect:hover,.nvd3 .nv-multibar .nv-groups rect:hover,.nvd3 .nv-multibarHorizontal .nv-groups rect:hover{fill-opacity:1}.nvd3 .nv-discretebar .nv-groups text,.nvd3 .nv-multibarHorizontal .nv-groups text{font-weight:700;fill:rgba(0,0,0,1);stroke:transparent}.nvd3 .nv-boxplot circle{fill-opacity:.5}.nvd3 .nv-boxplot circle:hover,.nvd3 .nv-boxplot rect:hover{fill-opacity:1}.nvd3 line.nv-boxplot-median{stroke:#000}.nv-boxplot-tick:hover{stroke-width:2.5px}.nvd3.nv-bullet{font:10px sans-serif}.nvd3.nv-bullet .nv-measure{fill-opacity:.8}.nvd3.nv-bullet \ .nv-measure:hover{fill-opacity:1}.nvd3.nv-bullet .nv-marker{stroke:#000;stroke-width:2px}.nvd3.nv-bullet .nv-markerTriangle{stroke:#000;fill:#fff;stroke-width:1.5px}.nvd3.nv-bullet .nv-markerLine{stroke:#000;stroke-width:1.5px}.nvd3.nv-bullet .nv-tick line{stroke:#666;stroke-width:.5px}.nvd3.nv-bullet .nv-range.nv-s0{fill:#eee}.nvd3.nv-bullet .nv-range.nv-s1{fill:#ddd}.nvd3.nv-bullet .nv-range.nv-s2{fill:#ccc}.nvd3.nv-bullet .nv-title{font-size:14px;font-weight:700}.nvd3.nv-bullet .nv-subtitle{fill:#999}.nvd3.nv-bullet .nv-range{fill:#bababa;fill-opacity:.4}.nvd3.nv-bullet .nv-range:hover{fill-opacity:.7}.nvd3.nv-candlestickBar .nv-ticks .nv-tick{stroke-width:1px}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.hover{stroke-width:2px}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.positive rect{stroke:#2ca02c;fill:#2ca02c}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.negative rect{stroke:#d62728;fill:#d62728}.nvd3.nv-candlestickBar .nv-ticks line{stroke:#333}.nv-force-node{stroke:#fff;stroke-width:1.5px}.nv-force-link{stroke:#999;stroke-opacity:.6}.nv-force-node text{stroke-width:0}.nvd3 .nv-check-box .nv-box{fill-opacity:0;stroke-width:2}.nvd3 .nv-check-box .nv-check{fill-opacity:0;stroke-width:4}.nvd3 .nv-series.nv-disabled .nv-check-box .nv-check{fill-opacity:0;stroke-opacity:0}.nvd3.nv-linePlusBar .nv-bar rect{fill-opacity:.75}.nvd3.nv-linePlusBar .nv-bar rect:hover{fill-opacity:1}.nvd3 .nv-groups path.nv-line{fill:none}.nvd3 .nv-groups path.nv-area{stroke:none}.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point{fill-opacity:0;stroke-opacity:0}.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point{fill-opacity:.5!important;stroke-opacity:.5!important}.nvd3 .nv-groups .nv-point.hover,.nvd3.nv-scatter .nv-groups .nv-point.hover{stroke-width:7px;fill-opacity:.95!important;stroke-opacity:.95!important}.nvd3 .nv-point-paths path{stroke:#aaa;stroke-opacity:0;fill:#eee;fill-opacity:0}.nvd3 .nv-indexLine{cursor:ew-resize}svg.nvd3-svg{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:block;width:100%;\ height:100%}.nvtooltip.with-3d-shadow,.with-3d-shadow .nvtooltip{box-shadow:0 5px 10px rgba(0,0,0,.2);border-radius:5px}.nvd3 text{font:400 12px Arial,sans-serif}.nvd3 .title{font:700 14px Arial,sans-serif}.nvd3 .nv-background{fill:#fff;fill-opacity:0}.nvd3.nv-noData{font-size:18px;font-weight:700}.nv-brush .extent{fill-opacity:.125}.nv-brush .resize path{fill:#eee;stroke:#666}.nvd3 .nv-legend .nv-series{cursor:pointer}.nvd3 .nv-legend .nv-disabled circle{fill-opacity:0}.nvd3 .nv-brush .extent{fill-opacity:0!important}.nvd3 .nv-brushBackground rect{stroke:#000;stroke-width:.4;fill:#fff;fill-opacity:.7}\@media print{.nvd3 text{stroke-width:0;fill-opacity:1}}.nvd3.nv-ohlcBar .nv-ticks .nv-tick{stroke-width:1px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover{stroke-width:2px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive{stroke:#2ca02c}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative{stroke:#d62728}.nvd3 .background path{fill:none;stroke:#EEE;stroke-opacity:.4}.nvd3 .foreground path{fill:none;stroke-opacity:.7}.nvd3 .nv-parallelCoordinates-brush .extent{fill:#fff;fill-opacity:.6;stroke:gray;shape-rendering:crispEdges}.nvd3 .nv-parallelCoordinates .hover{fill-opacity:1;stroke-width:3px}.nvd3 .missingValuesline line{fill:none;stroke:#000;stroke-width:1;stroke-opacity:1;stroke-dasharray:5,5}.nvd3.nv-pie .nv-pie-title{font-size:24px;fill:rgba(19,196,249,.59)}.nvd3.nv-pie .nv-slice text{stroke:#000;stroke-width:0}.nvd3.nv-pie path{transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;stroke:#fff;stroke-width:1px;stroke-opacity:1;fill-opacity:.7}.nvd3.nv-pie .hover path{fill-opacity:1}.nvd3.nv-pie .nv-label rect{fill-opacity:0;stroke-opacity:0}.nvd3 .nv-groups .nv-point.hover{stroke-width:20px;stroke-opacity:.5}.nvd3 .nv-scatter .nv-point.hover{fill-opacity:1}.nvd3.nv-sparkline path{fill:none}.nvd3.nv-sparklineplus .nv-hoverValue line{stroke:#333;stroke-width:1.5px}.nvd3.nv-sparklineplus,.nvd3.nv-sparklineplus g{pointer-events:all}.nvd3 .nv-interactiveGuideLine,.nvtooltip{pointer-events:none}.nvd3 .nv-hoverArea{fill-opacity:0;\ stroke-opacity:0}.nvd3.nv-sparklineplus .nv-xValue,.nvd3.nv-sparklineplus .nv-yValue{stroke-width:0;font-size:.9em;font-weight:400}.nvd3.nv-sparklineplus .nv-yValue{stroke:#f66}.nvd3.nv-sparklineplus .nv-maxValue{stroke:#2ca02c;fill:#2ca02c}.nvd3.nv-sparklineplus .nv-minValue{stroke:#d62728;fill:#d62728}.nvd3.nv-sparklineplus .nv-currentValue{font-weight:700;font-size:1.1em}.nvtooltip h3,.nvtooltip table td.key{font-weight:400}.nvd3.nv-stackedarea path.nv-area{fill-opacity:.7;stroke-opacity:0;transition:fill-opacity 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-stackedarea path.nv-area.hover{fill-opacity:.9}.nvd3.nv-stackedarea .nv-groups .nv-point{stroke-opacity:0;fill-opacity:0}.nvtooltip{position:absolute;color:rgba(0,0,0,1);padding:1px;z-index:10000;display:block;font-family:Arial,sans-serif;font-size:13px;text-align:left;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background:rgba(255,255,255,.8);border:1px solid rgba(0,0,0,.5);border-radius:4px}.nvtooltip h3,.nvtooltip p{margin:0;text-align:center}.nvtooltip.with-transitions,.with-transitions .nvtooltip{transition:opacity 50ms linear;transition-delay:200ms}.nvtooltip.x-nvtooltip,.nvtooltip.y-nvtooltip{padding:8px}.nvtooltip h3{padding:4px 14px;line-height:18px;background-color:rgba(247,247,247,.75);color:rgba(0,0,0,1);border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.nvtooltip p{padding:5px 14px}.nvtooltip span{display:inline-block;margin:2px 0}.nvtooltip table{margin:6px;border-spacing:0}.nvtooltip table td{padding:2px 9px 2px 0;vertical-align:middle}.nvtooltip table td.key.total{font-weight:700}.nvtooltip table td.value{text-align:right;font-weight:700}.nvtooltip table td.percent{color:#a9a9a9}.nvtooltip table tr.highlight td{padding:1px 9px 1px 0;border-bottom-style:solid;border-bottom-width:1px;border-top-style:solid;border-top-width:1px}.nvtooltip table td.legend-color-guide div{vertical-align:middle;width:12px;height:12px;border:1px solid #999}.nvtooltip .footer{padding:3px;text-align:center}.nvtooltip-pending-removal{pointer-events:none;\ display:none}.nvd3 line.nv-guideline{stroke:#ccc}\ -") +" +) ################################################################################ # end nvd3.css ################################################################################ @@ -770,7 +761,8 @@ display:none}.nvd3 line.nv-guideline{stroke:#ccc}\ # parsing too long strings. # https://github.com/novus/nvd3 ################################################################################ -file(WRITE "${METABENCH_DIR}/nvd3.js" "\ +file(WRITE "${METABENCH_DIR}/nvd3.js" + "\ /* nvd3 version 1.8.5 (https://github.com/novus/nvd3) 2016-12-01 */\ !function(){var a={};a.dev=!1,a.tooltip=a.tooltip||{},a.utils=a.utils||{},a.models=a.models||{},a.charts={},a.logs={},a.dom={},\"undefined\"!=typeof module&&\"undefined\"!=typeof exports&&\"undefined\"==typeof d3&&(d3=require(\"d3\")),a.dispatch=d3.dispatch(\"render_start\",\"render_end\"),Function.prototype.bind||(Function.prototype.bind=function(a){if(\"function\"!=typeof this)throw new TypeError(\"Function.prototype.bind - what is trying to be bound is not callable\");var b=Array.prototype.slice.call(arguments,1),c=this,d=function(){},e=function(){return c.apply(this instanceof d&&a?this:a,b.concat(Array.prototype.slice.call(arguments)))};return d.prototype=this.prototype,e.prototype=new d,e}),a.dev&&(a.dispatch.on(\"render_start\",function(b){a.logs.startTime=+new Date}),a.dispatch.on(\"render_end\",function(b){a.logs.endTime=+new Date,a.logs.totalTime=a.logs.endTime-a.logs.startTime,a.log(\"total\",a.logs.totalTime)})),a.log=function(){if(a.dev&&window.console&&console.log&&console.log.apply)console.log.apply(console,arguments);else if(a.dev&&window.console&&\"function\"==typeof console.log&&Function.prototype.bind){var b=Function.prototype.bind.call(console.log,console);b.apply(console,arguments)}return arguments[arguments.length-1]},a.deprecated=function(a,b){console&&console.warn&&console.warn(\"nvd3 warning: `\"+a+\"` has been deprecated. \",b||\"\")},a.render=function(b){b=b||1,a.render.active=!0,a.dispatch.render_start();var c=function(){for(var d,e,f=0;b>f&&(e=a.render.queue[f]);f++)d=e.generate(),typeof e.callback==typeof Function&&e.callback(d);a.render.queue.splice(0,f),a.render.queue.length?setTimeout(c):(a.dispatch.render_end(),a.render.active=!1)};setTimeout(c)},a.render.active=!1,a.render.queue=[],a.addGraph=function(b){typeof arguments[0]==typeof Function&&(b={generate:arguments[0],callback:arguments[1]}),a.render.queue.push(b),a.render.active||a.render()},\"undefined\"!=typeof module&&\"undefined\"!=typeof exports&&(module.exports=a),\"undefined\"!=typeof window&&(window.nv=a),a.dom.write=function(a){return void 0!==window.fastdom?fastdom.mutate(a):a()},\ a.dom.read=function(a){return void 0!==window.fastdom?fastdom.measure(a):a()},a.interactiveGuideline=function(){\"use strict\";function b(l){l.each(function(l){function m(){var a=d3.mouse(this),d=a[0],e=a[1],h=!0,i=!1;if(k&&(d=d3.event.offsetX,e=d3.event.offsetY,\"svg\"!==d3.event.target.tagName&&(h=!1),d3.event.target.className.baseVal.match(\"nv-legend\")&&(i=!0)),h&&(d-=c.left,e-=c.top),\"mouseout\"===d3.event.type||0>d||0>e||d>o||e>p||d3.event.relatedTarget&&void 0===d3.event.relatedTarget.ownerSVGElement||i){if(k&&d3.event.relatedTarget&&void 0===d3.event.relatedTarget.ownerSVGElement&&(void 0===d3.event.relatedTarget.className||d3.event.relatedTarget.className.match(j.nvPointerEventsClass)))return;return g.elementMouseout({mouseX:d,mouseY:e}),b.renderGuideLine(null),void j.hidden(!0)}j.hidden(!1);var l=\"function\"==typeof f.rangeBands,m=void 0;if(l){var n=d3.bisect(f.range(),d)-1;if(!(f.range()[n]+f.rangeBand()>=d))return g.elementMouseout({mouseX:d,mouseY:e}),b.renderGuideLine(null),void j.hidden(!0);m=f.domain()[d3.bisect(f.range(),d)-1]}else m=f.invert(d);g.elementMousemove({mouseX:d,mouseY:e,pointXValue:m}),\"dblclick\"===d3.event.type&&g.elementDblclick({mouseX:d,mouseY:e,pointXValue:m}),\"click\"===d3.event.type&&g.elementClick({mouseX:d,mouseY:e,pointXValue:m}),\"mousedown\"===d3.event.type&&g.elementMouseDown({mouseX:d,mouseY:e,pointXValue:m}),\"mouseup\"===d3.event.type&&g.elementMouseUp({mouseX:d,mouseY:e,pointXValue:m})}var n=d3.select(this),o=d||960,p=e||400,q=n.selectAll(\"g.nv-wrap.nv-interactiveLineLayer\").data([l]),r=q.enter().append(\"g\").attr(\"class\",\" nv-wrap nv-interactiveLineLayer\");r.append(\"g\").attr(\"class\",\"nv-interactiveGuideLine\"),i&&(i.on(\"touchmove\",m).on(\"mousemove\",m,!0).on(\"mouseout\",m,!0).on(\"mousedown\",m,!0).on(\"mouseup\",m,!0).on(\"dblclick\",m).on(\"click\",m),b.guideLine=null,b.renderGuideLine=function(c){h&&(b.guideLine&&b.guideLine.attr(\"x1\")===c||a.dom.write(function(){var b=q.select(\".nv-interactiveGuideLine\").selectAll(\"line\").data(null!=c?[a.utils.NaNtoZero(c)]:[],String);b.enter().append(\"line\").attr(\"class\",\ @@ -800,9 +792,11 @@ c>d?m(d)-m(c):m(c)-m(d)})}),b}var c,d,e,f,g,h={top:0,right:0,bottom:0,left:0},i= h.bottom=void 0!=a.bottom?a.bottom:h.bottom,h.left=void 0!=a.left?a.left:h.left}},color:{get:function(){return x},set:function(b){x=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.cumulativeLineChart=function(){\"use strict\";function b(l){return I.reset(),I.models(f),s&&I.models(g),t&&I.models(h),l.each(function(l){function B(a,c){d3.select(b.container).style(\"cursor\",\"ew-resize\")}function F(a,b){H.x=d3.event.x,H.i=Math.round(G.invert(H.x)),L()}function I(a,c){d3.select(b.container).style(\"cursor\",\"auto\"),z.index=H.i,D.stateChange(z)}function L(){ba.data([H]);var a=b.duration();b.duration(0),b.update(),b.duration(a)}var M=d3.select(this);a.utils.initSVG(M),M.classed(\"nv-chart-\"+y,!0);var N=a.utils.availableWidth(p,M,m),O=a.utils.availableHeight(q,M,m);if(b.update=function(){0===E?M.call(b):M.transition().duration(E).call(b)},b.container=this,z.setter(K(l),b.update).getter(J(l)).update(),z.disabled=l.map(function(a){return!!a.disabled}),!A){var P;A={};for(P in z)z[P]instanceof Array?A[P]=z[P].slice(0):A[P]=z[P]}var Q=d3.behavior.drag().on(\"dragstart\",B).on(\"drag\",F).on(\"dragend\",I);if(!(l&&l.length&&l.filter(function(a){return a.values.length}).length))return a.utils.noData(b,M),b;if(M.selectAll(\".nv-noData\").remove(),d=f.xScale(),e=f.yScale(),x)f.yDomain(null);else{var R=l.filter(function(a){return!a.disabled}).map(function(a,b){var c=d3.extent(a.values,f.y());return c[0]<-.95&&(c[0]=-.95),[(c[0]-c[1])/(1+c[1]),(c[1]-c[0])/(1+c[0])]}),S=[d3.min(R,function(a){return a[0]}),d3.max(R,function(a){return a[1]})];f.yDomain(S)}G.domain([0,l[0].values.length-1]).range([0,N]).clamp(!0);var l=c(H.i,l),T=w?\"none\":\"all\",U=M.selectAll(\"g.nv-wrap.nv-cumulativeLine\").data([l]),V=U.enter().append(\"g\").attr(\"class\",\"nvd3 nv-wrap nv-cumulativeLine\").append(\"g\"),W=U.select(\"g\");if(V.append(\"g\").attr(\"class\",\"nv-interactive\"),V.append(\"g\").attr(\"class\",\"nv-x nv-axis\").style(\"pointer-events\",\"none\"),V.append(\"g\").attr(\"class\",\"nv-y nv-axis\"),V.append(\"g\").attr(\"class\",\"nv-background\"),V.append(\"g\").attr(\"class\",\"nv-linesWrap\").style(\"pointer-events\",\ T),V.append(\"g\").attr(\"class\",\"nv-avgLinesWrap\").style(\"pointer-events\",\"none\"),V.append(\"g\").attr(\"class\",\"nv-legendWrap\"),V.append(\"g\").attr(\"class\",\"nv-controlsWrap\"),r?(i.width(N),W.select(\".nv-legendWrap\").datum(l).call(i),n||i.height()===m.top||(m.top=i.height(),O=a.utils.availableHeight(q,M,m)),W.select(\".nv-legendWrap\").attr(\"transform\",\"translate(0,\"+-m.top+\")\")):W.select(\".nv-legendWrap\").selectAll(\"*\").remove(),v){var X=[{key:\"Re-scale y-axis\",disabled:!x}];j.width(140).color([\"#444\",\"#444\",\"#444\"]).rightAlign(!1).margin({top:5,right:0,bottom:5,left:20}),W.select(\".nv-controlsWrap\").datum(X).attr(\"transform\",\"translate(0,\"+-m.top+\")\").call(j)}else W.select(\".nv-controlsWrap\").selectAll(\"*\").remove();U.attr(\"transform\",\"translate(\"+m.left+\",\"+m.top+\")\"),u&&W.select(\".nv-y.nv-axis\").attr(\"transform\",\"translate(\"+N+\",0)\");var Y=l.filter(function(a){return a.tempDisabled});U.select(\".tempDisabled\").remove(),Y.length&&U.append(\"text\").attr(\"class\",\"tempDisabled\").attr(\"x\",N/2).attr(\"y\",\"-.71em\").style(\"text-anchor\",\"end\").text(Y.map(function(a){return a.key}).join(\", \")+\" values cannot be calculated for this time period.\"),w&&(k.width(N).height(O).margin({left:m.left,top:m.top}).svgContainer(M).xScale(d),U.select(\".nv-interactive\").call(k)),V.select(\".nv-background\").append(\"rect\"),W.select(\".nv-background rect\").attr(\"width\",N).attr(\"height\",O),f.y(function(a){return a.display.y}).width(N).height(O).color(l.map(function(a,b){return a.color||o(a,b)}).filter(function(a,b){return!l[b].disabled&&!l[b].tempDisabled}));var Z=W.select(\".nv-linesWrap\").datum(l.filter(function(a){return!a.disabled&&!a.tempDisabled}));Z.call(f),l.forEach(function(a,b){a.seriesIndex=b});var $=l.filter(function(a){return!a.disabled&&!!C(a)}),_=W.select(\".nv-avgLinesWrap\").selectAll(\"line\").data($,function(a){return a.key}),aa=function(a){var b=e(C(a));return 0>b?0:b>O?O:b};_.enter().append(\"line\").style(\"stroke-width\",2).style(\"stroke-dasharray\",\"10,10\").style(\"stroke\",function(a,b){return f.color()(a,a.seriesIndex)}).attr(\"x1\",0).attr(\"x2\",\ N).attr(\"y1\",aa).attr(\"y2\",aa),_.style(\"stroke-opacity\",function(a){var b=e(C(a));return 0>b||b>O?0:1}).attr(\"x1\",0).attr(\"x2\",N).attr(\"y1\",aa).attr(\"y2\",aa),_.exit().remove();var ba=Z.selectAll(\".nv-indexLine\").data([H]);ba.enter().append(\"rect\").attr(\"class\",\"nv-indexLine\").attr(\"width\",3).attr(\"x\",-2).attr(\"fill\",\"red\").attr(\"fill-opacity\",.5).style(\"pointer-events\",\"all\").call(Q),ba.attr(\"transform\",function(a){return\"translate(\"+G(a.i)+\",0)\"}).attr(\"height\",O),s&&(g.scale(d)._ticks(a.utils.calcTicksX(N/70,l)).tickSize(-O,0),W.select(\".nv-x.nv-axis\").attr(\"transform\",\"translate(0,\"+e.range()[0]+\")\"),W.select(\".nv-x.nv-axis\").call(g)),t&&(h.scale(e)._ticks(a.utils.calcTicksY(O/36,l)).tickSize(-N,0),W.select(\".nv-y.nv-axis\").call(h)),W.select(\".nv-background rect\").on(\"click\",function(){H.x=d3.mouse(this)[0],H.i=Math.round(G.invert(H.x)),z.index=H.i,D.stateChange(z),L()}),f.dispatch.on(\"elementClick\",function(a){H.i=a.pointIndex,H.x=G(H.i),z.index=H.i,D.stateChange(z),L()}),j.dispatch.on(\"legendClick\",function(a,c){a.disabled=!a.disabled,x=!a.disabled,z.rescaleY=x,D.stateChange(z),b.update()}),i.dispatch.on(\"stateChange\",function(a){for(var c in a)z[c]=a[c];D.stateChange(z),b.update()}),k.dispatch.on(\"elementMousemove\",function(c){f.clearHighlights();var d,e,i,j=[];if(l.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(g,h){e=a.interactiveBisect(g.values,c.pointXValue,b.x()),f.highlightPoint(h,e,!0);var k=g.values[e];\"undefined\"!=typeof k&&(\"undefined\"==typeof d&&(d=k),\"undefined\"==typeof i&&(i=b.xScale()(b.x()(k,e))),j.push({key:g.key,value:b.y()(k,e),color:o(g,g.seriesIndex)}))}),j.length>2){var m=b.yScale().invert(c.mouseY),n=Math.abs(b.yScale().domain()[0]-b.yScale().domain()[1]),p=.03*n,q=a.nearestValueIndex(j.map(function(a){return a.value}),m,p);null!==q&&(j[q].highlight=!0)}var r=g.tickFormat()(b.x()(d,e),e);k.tooltip.valueFormatter(function(a,b){return h.tickFormat()(a)}).data({value:r,series:j})(),k.renderGuideLine(i)}),k.dispatch.on(\"elementMouseout\",function(a){f.clearHighlights()}),\ -") +" +) -file(APPEND "${METABENCH_DIR}/nvd3.js" "\ +file(APPEND "${METABENCH_DIR}/nvd3.js" + "\ D.on(\"changeState\",function(a){\"undefined\"!=typeof a.disabled&&(l.forEach(function(b,c){b.disabled=a.disabled[c]}),z.disabled=a.disabled),\"undefined\"!=typeof a.index&&(H.i=a.index,H.x=G(H.i),z.index=a.index,ba.data([H])),\"undefined\"!=typeof a.rescaleY&&(x=a.rescaleY),b.update()})}),I.renderEnd(\"cumulativeLineChart immediate\"),b}function c(a,b){return L||(L=f.y()),b.map(function(b,c){if(!b.values)return b;var d=b.values[a];if(null==d)return b;var e=L(d,a);return-.95>e&&!F?(b.tempDisabled=!0,b):(b.tempDisabled=!1,b.values=b.values.map(function(a,b){return a.display={y:(L(a,b)-e)/(1+e)},a}),b)})}var d,e,f=a.models.line(),g=a.models.axis(),h=a.models.axis(),i=a.models.legend(),j=a.models.legend(),k=a.interactiveGuideline(),l=a.models.tooltip(),m={top:30,right:30,bottom:50,left:60},n=null,o=a.utils.defaultColor(),p=null,q=null,r=!0,s=!0,t=!0,u=!1,v=!0,w=!1,x=!0,y=f.id(),z=a.utils.state(),A=null,B=null,C=function(a){return a.average},D=d3.dispatch(\"stateChange\",\"changeState\",\"renderEnd\"),E=250,F=!1;z.index=0,z.rescaleY=x,g.orient(\"bottom\").tickPadding(7),h.orient(u?\"right\":\"left\"),l.valueFormatter(function(a,b){return h.tickFormat()(a,b)}).headerFormatter(function(a,b){return g.tickFormat()(a,b)}),j.updateState(!1);var G=d3.scale.linear(),H={i:0,x:0},I=a.utils.renderWatch(D,E),J=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),index:H.i,rescaleY:x}}},K=function(a){return function(b){void 0!==b.index&&(H.i=b.index),void 0!==b.rescaleY&&(x=b.rescaleY),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};f.dispatch.on(\"elementMouseover.tooltip\",function(a){var c={x:b.x()(a.point),y:b.y()(a.point),color:a.point.color};a.point=c,l.data(a).hidden(!1)}),f.dispatch.on(\"elementMouseout.tooltip\",function(a){l.hidden(!0)});var L=null;return b.dispatch=D,b.lines=f,b.legend=i,b.controls=j,b.xAxis=g,b.yAxis=h,b.interactiveLayer=k,b.state=z,b.tooltip=l,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return p},set:function(a){p=a}},height:{get:function(){return \ q},set:function(a){q=a}},rescaleY:{get:function(){return x},set:function(a){x=a}},showControls:{get:function(){return v},set:function(a){v=a}},showLegend:{get:function(){return r},set:function(a){r=a}},average:{get:function(){return C},set:function(a){C=a}},defaultState:{get:function(){return A},set:function(a){A=a}},noData:{get:function(){return B},set:function(a){B=a}},showXAxis:{get:function(){return s},set:function(a){s=a}},showYAxis:{get:function(){return t},set:function(a){t=a}},noErrorCheck:{get:function(){return F},set:function(a){F=a}},margin:{get:function(){return m},set:function(a){void 0!==a.top&&(m.top=a.top,n=a.top),m.right=void 0!==a.right?a.right:m.right,m.bottom=void 0!==a.bottom?a.bottom:m.bottom,m.left=void 0!==a.left?a.left:m.left}},color:{get:function(){return o},set:function(b){o=a.utils.getColor(b),i.color(o)}},useInteractiveGuideline:{get:function(){return w},set:function(a){w=a,a===!0&&(b.interactive(!1),b.useVoronoi(!1))}},rightAlignYAxis:{get:function(){return u},set:function(a){u=a,h.orient(a?\"right\":\"left\")}},duration:{get:function(){return E},set:function(a){E=a,f.duration(E),g.duration(E),h.duration(E),I.reset(E)}}}),a.utils.inheritOptions(b,f),a.utils.initOptions(b),b},a.models.discreteBar=function(){\"use strict\";function b(m){return y.reset(),m.each(function(b){var m=k-j.left-j.right,x=l-j.top-j.bottom;c=d3.select(this),a.utils.initSVG(c),b.forEach(function(a,b){a.values.forEach(function(a){a.series=b})});var z=d&&e?[]:b.map(function(a){return a.values.map(function(a,b){return{x:p(a,b),y:q(a,b),y0:a.y0}})});n.domain(d||d3.merge(z).map(function(a){return a.x})).rangeBands(f||[0,m],.1),o.domain(e||d3.extent(d3.merge(z).map(function(a){return a.y}).concat(r))),t?o.range(g||[x-(o.domain()[0]<0?12:0),o.domain()[1]>0?12:0]):o.range(g||[x,0]),h=h||n,i=i||o.copy().range([o(0),o(0)]);var A=c.selectAll(\"g.nv-wrap.nv-discretebar\").data([b]),B=A.enter().append(\"g\").attr(\"class\",\"nvd3 nv-wrap nv-discretebar\"),C=B.append(\"g\");A.select(\"g\");C.append(\"g\").attr(\"class\",\"nv-groups\"),A.attr(\"transform\",\ \"translate(\"+j.left+\",\"+j.top+\")\");var D=A.select(\".nv-groups\").selectAll(\".nv-group\").data(function(a){return a},function(a){return a.key});D.enter().append(\"g\").style(\"stroke-opacity\",1e-6).style(\"fill-opacity\",1e-6),D.exit().watchTransition(y,\"discreteBar: exit groups\").style(\"stroke-opacity\",1e-6).style(\"fill-opacity\",1e-6).remove(),D.attr(\"class\",function(a,b){return\"nv-group nv-series-\"+b}).classed(\"hover\",function(a){return a.hover}),D.watchTransition(y,\"discreteBar: groups\").style(\"stroke-opacity\",1).style(\"fill-opacity\",.75);var E=D.selectAll(\"g.nv-bar\").data(function(a){return a.values});E.exit().remove();var F=E.enter().append(\"g\").attr(\"transform\",function(a,b,c){return\"translate(\"+(n(p(a,b))+.05*n.rangeBand())+\", \"+o(0)+\")\"}).on(\"mouseover\",function(a,b){d3.select(this).classed(\"hover\",!0),v.elementMouseover({data:a,index:b,color:d3.select(this).style(\"fill\")})}).on(\"mouseout\",function(a,b){d3.select(this).classed(\"hover\",!1),v.elementMouseout({data:a,index:b,color:d3.select(this).style(\"fill\")})}).on(\"mousemove\",function(a,b){v.elementMousemove({data:a,index:b,color:d3.select(this).style(\"fill\")})}).on(\"click\",function(a,b){var c=this;v.elementClick({data:a,index:b,color:d3.select(this).style(\"fill\"),event:d3.event,element:c}),d3.event.stopPropagation()}).on(\"dblclick\",function(a,b){v.elementDblClick({data:a,index:b,color:d3.select(this).style(\"fill\")}),d3.event.stopPropagation()});F.append(\"rect\").attr(\"height\",0).attr(\"width\",.9*n.rangeBand()/b.length),t?(F.append(\"text\").attr(\"text-anchor\",\"middle\"),E.select(\"text\").text(function(a,b){return u(q(a,b))}).watchTransition(y,\"discreteBar: bars text\").attr(\"x\",.9*n.rangeBand()/2).attr(\"y\",function(a,b){return q(a,b)<0?o(q(a,b))-o(0)+12:-4})):E.selectAll(\"text\").remove(),E.attr(\"class\",function(a,b){return q(a,b)<0?\"nv-bar negative\":\"nv-bar positive\"}).style(\"fill\",function(a,b){return a.color||s(a,b)}).style(\"stroke\",function(a,b){return a.color||s(a,b)}).select(\"rect\").attr(\"class\",w).watchTransition(y,\"discreteBar: bars rect\").attr(\"width\",.9*n.rangeBand()/b.length),\ @@ -833,9 +827,11 @@ K.select(\".nv-legendWrap\").attr(\"transform\",\"translate(0,\"+-l.top+\")\"))) i.tooltip.valueFormatter(i.tooltip.valueFormatter()||s).data({value:b.x()(f,h),index:h,series:m})(),i.renderGuideLine(l)}),i.dispatch.on(\"elementClick\",function(c){var d,f=[];j.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(e){var g=a.interactiveBisect(e.values,c.pointXValue,b.x()),h=e.values[g];if(\"undefined\"!=typeof h){\"undefined\"==typeof d&&(d=b.xScale()(b.x()(h,g)));var i=b.yScale()(b.y()(h,g));f.push({point:h,pointIndex:g,pos:[d,i],seriesIndex:e.seriesIndex,series:e})}}),e.dispatch.elementClick(f)}),i.dispatch.on(\"elementMouseout\",function(a){e.clearHighlights()}),A.on(\"changeState\",function(a){\"undefined\"!=typeof a.disabled&&j.length===a.disabled.length&&(j.forEach(function(b,c){b.disabled=a.disabled[c]}),x.disabled=a.disabled),b.update()})}),C.renderEnd(\"lineChart immediate\"),b}var c,d,e=a.models.line(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend(),i=a.interactiveGuideline(),j=a.models.tooltip(),k=a.models.focus(a.models.line()),l={top:30,right:20,bottom:50,left:60},m=null,n=a.utils.defaultColor(),o=null,p=null,q=!0,r=\"top\",s=!0,t=!0,u=!1,v=!1,w=!1,x=a.utils.state(),y=null,z=null,A=d3.dispatch(\"tooltipShow\",\"tooltipHide\",\"stateChange\",\"changeState\",\"renderEnd\"),B=250;f.orient(\"bottom\").tickPadding(7),g.orient(u?\"right\":\"left\"),e.clipEdge(!0).duration(0),j.valueFormatter(function(a,b){return g.tickFormat()(a,b)}).headerFormatter(function(a,b){return f.tickFormat()(a,b)}),i.tooltip.valueFormatter(function(a,b){return g.tickFormat()(a,b)}).headerFormatter(function(a,b){return f.tickFormat()(a,b)});var C=a.utils.renderWatch(A,B),D=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},E=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return e.dispatch.on(\"elementMouseover.tooltip\",function(a){a.series.disableTooltip||j.data(a).hidden(!1)}),e.dispatch.on(\"elementMouseout.tooltip\",function(a){j.hidden(!0)}),b.dispatch=A,b.lines=e,b.legend=h,b.focus=k,b.xAxis=f,b.x2Axis=k.xAxis,b.yAxis=g,b.y2Axis=k.yAxis,\ b.interactiveLayer=i,b.tooltip=j,b.state=x,b.dispatch=A,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return o},set:function(a){o=a}},height:{get:function(){return p},set:function(a){p=a}},showLegend:{get:function(){return q},set:function(a){q=a}},legendPosition:{get:function(){return r},set:function(a){r=a}},showXAxis:{get:function(){return s},set:function(a){s=a}},showYAxis:{get:function(){return t},set:function(a){t=a}},defaultState:{get:function(){return y},set:function(a){y=a}},noData:{get:function(){return z},set:function(a){z=a}},focusEnable:{get:function(){return w},set:function(a){w=a}},focusHeight:{get:function(){return k.height()},set:function(a){k.height(a)}},focusShowAxisX:{get:function(){return k.showXAxis()},set:function(a){k.showXAxis(a)}},focusShowAxisY:{get:function(){return k.showYAxis()},set:function(a){k.showYAxis(a)}},brushExtent:{get:function(){return k.brushExtent()},set:function(a){k.brushExtent(a)}},focusMargin:{get:function(){return k.margin},set:function(a){void 0!==a.top&&(l.top=a.top,m=a.top),k.margin.right=void 0!==a.right?a.right:k.margin.right,k.margin.bottom=void 0!==a.bottom?a.bottom:k.margin.bottom,k.margin.left=void 0!==a.left?a.left:k.margin.left}},margin:{get:function(){return l},set:function(a){l.top=void 0!==a.top?a.top:l.top,l.right=void 0!==a.right?a.right:l.right,l.bottom=void 0!==a.bottom?a.bottom:l.bottom,l.left=void 0!==a.left?a.left:l.left}},duration:{get:function(){return B},set:function(a){B=a,C.reset(B),e.duration(B),k.duration(B),f.duration(B),g.duration(B)}},color:{get:function(){return n},set:function(b){n=a.utils.getColor(b),h.color(n),e.color(n),k.color(n)}},interpolate:{get:function(){return e.interpolate()},set:function(a){e.interpolate(a),k.interpolate(a)}},xTickFormat:{get:function(){return f.tickFormat()},set:function(a){f.tickFormat(a),k.xTickFormat(a)}},yTickFormat:{get:function(){return g.tickFormat()},set:function(a){g.tickFormat(a),k.yTickFormat(a)}},x:{get:function(){return e.x()},set:function(a){e.x(a),k.x(a)}},\ y:{get:function(){return e.y()},set:function(a){e.y(a),k.y(a)}},rightAlignYAxis:{get:function(){return u},set:function(a){u=a,g.orient(u?\"right\":\"left\")}},useInteractiveGuideline:{get:function(){return v},set:function(a){v=a,v&&(e.interactive(!1),e.useVoronoi(!1))}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.lineWithFocusChart=function(){return a.models.lineChart().margin({bottom:30}).focusEnable(!0)},a.models.linePlusBarChart=function(){\"use strict\";function b(v){return v.each(function(v){function K(a){var b=+(\"e\"==a),c=b?1:-1,d=$/3;return\"M\"+.5*c+\",\"+d+\"A6,6 0 0 \"+b+\" \"+6.5*c+\",\"+(d+6)+\"V\"+(2*d-6)+\"A6,6 0 0 \"+b+\" \"+.5*c+\",\"+2*d+\"ZM\"+2.5*c+\",\"+(d+8)+\"V\"+(2*d-8)+\"M\"+4.5*c+\",\"+(d+8)+\"V\"+(2*d-8)}function S(){u.empty()||u.extent(J),na.data([u.empty()?e.domain():J]).each(function(a,b){var c=e(a[0])-e.range()[0],d=e.range()[1]-e(a[1]);d3.select(this).select(\".left\").attr(\"width\",0>c?0:c),d3.select(this).select(\".right\").attr(\"x\",e(a[1])).attr(\"width\",0>d?0:d)})}function T(){J=u.empty()?null:u.extent(),c=u.empty()?e.domain():u.extent(),L.brush({extent:c,brush:u}),S(),l.width(Y).height(Z).color(v.map(function(a,b){return a.color||D(a,b)}).filter(function(a,b){return!v[b].disabled&&v[b].bar})),j.width(Y).height(Z).color(v.map(function(a,b){return a.color||D(a,b)}).filter(function(a,b){return!v[b].disabled&&!v[b].bar}));var b=ga.select(\".nv-focus .nv-barsWrap\").datum(aa.length?aa.map(function(a,b){return{key:a.key,values:a.values.filter(function(a,b){return l.x()(a,b)>=c[0]&&l.x()(a,b)<=c[1]})}}):[{values:[]}]),h=ga.select(\".nv-focus .nv-linesWrap\").datum(W(ba)?[{values:[]}]:ba.filter(function(a){return!a.disabled}).map(function(a,b){return{area:a.area,fillOpacity:a.fillOpacity,strokeWidth:a.strokeWidth,key:a.key,values:a.values.filter(function(a,b){return j.x()(a,b)>=c[0]&&j.x()(a,b)<=c[1]})}}));d=aa.length&&!R?l.xScale():j.xScale(),n.scale(d)._ticks(a.utils.calcTicksX(Y/100,v)).tickSize(-Z,0),n.domain([Math.ceil(c[0]),Math.floor(c[1])]),ga.select(\".nv-x.nv-axis\").transition().duration(M).call(n),b.transition().duration(M).call(l),\ -") +" +) -file(APPEND "${METABENCH_DIR}/nvd3.js" "\ +file(APPEND "${METABENCH_DIR}/nvd3.js" + "\ h.transition().duration(M).call(j),ga.select(\".nv-focus .nv-x.nv-axis\").attr(\"transform\",\"translate(0,\"+f.range()[0]+\")\"),p.scale(f)._ticks(a.utils.calcTicksY(Z/36,v)).tickSize(-Y,0),q.scale(g)._ticks(a.utils.calcTicksY(Z/36,v)),R?q.tickSize(ba.length?0:-Y,0):q.tickSize(aa.length?0:-Y,0);var i=aa.length?1:0,k=ba.length&&!W(ba)?1:0,m=R?k:i,o=R?i:k;ga.select(\".nv-focus .nv-y1.nv-axis\").style(\"opacity\",m),ga.select(\".nv-focus .nv-y2.nv-axis\").style(\"opacity\",o).attr(\"transform\",\"translate(\"+d.range()[1]+\",0)\"),ga.select(\".nv-focus .nv-y1.nv-axis\").transition().duration(M).call(p),ga.select(\".nv-focus .nv-y2.nv-axis\").transition().duration(M).call(q)}var X=d3.select(this);a.utils.initSVG(X);var Y=a.utils.availableWidth(z,X,w),Z=a.utils.availableHeight(A,X,w)-(F?I:0),$=I-y.top-y.bottom;if(b.update=function(){X.transition().duration(M).call(b)},b.container=this,N.setter(V(v),b.update).getter(U(v)).update(),N.disabled=v.map(function(a){return!!a.disabled}),!O){var _;O={};for(_ in N)N[_]instanceof Array?O[_]=N[_].slice(0):O[_]=N[_]}if(!(v&&v.length&&v.filter(function(a){return a.values.length}).length))return a.utils.noData(b,X),b;X.selectAll(\".nv-noData\").remove();var aa=v.filter(function(a){return!a.disabled&&a.bar}),ba=v.filter(function(a){return!a.bar});d=aa.length&&!R?l.xScale():j.xScale(),e=o.scale(),f=R?j.yScale():l.yScale(),g=R?l.yScale():j.yScale(),h=R?k.yScale():m.yScale(),i=R?m.yScale():k.yScale();var ca=v.filter(function(a){return!a.disabled&&(R?!a.bar:a.bar)}).map(function(a){return a.values.map(function(a,b){return{x:B(a,b),y:C(a,b)}})}),da=v.filter(function(a){return!a.disabled&&(R?a.bar:!a.bar)}).map(function(a){return a.values.map(function(a,b){return{x:B(a,b),y:C(a,b)}})});d.range([0,Y]),e.domain(d3.extent(d3.merge(ca.concat(da)),function(a){return a.x})).range([0,Y]);var ea=X.selectAll(\"g.nv-wrap.nv-linePlusBar\").data([v]),fa=ea.enter().append(\"g\").attr(\"class\",\"nvd3 nv-wrap nv-linePlusBar\").append(\"g\"),ga=ea.select(\"g\");fa.append(\"g\").attr(\"class\",\"nv-legendWrap\");var ha=fa.append(\"g\").attr(\"class\",\"nv-focus\");\ ha.append(\"g\").attr(\"class\",\"nv-x nv-axis\"),ha.append(\"g\").attr(\"class\",\"nv-y1 nv-axis\"),ha.append(\"g\").attr(\"class\",\"nv-y2 nv-axis\"),ha.append(\"g\").attr(\"class\",\"nv-barsWrap\"),ha.append(\"g\").attr(\"class\",\"nv-linesWrap\");var ia=fa.append(\"g\").attr(\"class\",\"nv-context\");if(ia.append(\"g\").attr(\"class\",\"nv-x nv-axis\"),ia.append(\"g\").attr(\"class\",\"nv-y1 nv-axis\"),ia.append(\"g\").attr(\"class\",\"nv-y2 nv-axis\"),ia.append(\"g\").attr(\"class\",\"nv-barsWrap\"),ia.append(\"g\").attr(\"class\",\"nv-linesWrap\"),ia.append(\"g\").attr(\"class\",\"nv-brushBackground\"),ia.append(\"g\").attr(\"class\",\"nv-x nv-brush\"),E){var ja=t.align()?Y/2:Y,ka=t.align()?ja:0;t.width(ja),ga.select(\".nv-legendWrap\").datum(v.map(function(a){return a.originalKey=void 0===a.originalKey?a.key:a.originalKey,R?a.key=a.originalKey+(a.bar?Q:P):a.key=a.originalKey+(a.bar?P:Q),a})).call(t),x||t.height()===w.top||(w.top=t.height(),Z=a.utils.availableHeight(A,X,w)-I),ga.select(\".nv-legendWrap\").attr(\"transform\",\"translate(\"+ka+\",\"+-w.top+\")\")}else ga.select(\".nv-legendWrap\").selectAll(\"*\").remove();ea.attr(\"transform\",\"translate(\"+w.left+\",\"+w.top+\")\"),ga.select(\".nv-context\").style(\"display\",F?\"initial\":\"none\"),m.width(Y).height($).color(v.map(function(a,b){return a.color||D(a,b)}).filter(function(a,b){return!v[b].disabled&&v[b].bar})),k.width(Y).height($).color(v.map(function(a,b){return a.color||D(a,b)}).filter(function(a,b){return!v[b].disabled&&!v[b].bar}));var la=ga.select(\".nv-context .nv-barsWrap\").datum(aa.length?aa:[{values:[]}]),ma=ga.select(\".nv-context .nv-linesWrap\").datum(W(ba)?[{values:[]}]:ba.filter(function(a){return!a.disabled}));ga.select(\".nv-context\").attr(\"transform\",\"translate(0,\"+(Z+w.bottom+y.top)+\")\"),la.transition().call(m),ma.transition().call(k),H&&(o._ticks(a.utils.calcTicksX(Y/100,v)).tickSize(-$,0),ga.select(\".nv-context .nv-x.nv-axis\").attr(\"transform\",\"translate(0,\"+h.range()[0]+\")\"),ga.select(\".nv-context .nv-x.nv-axis\").transition().call(o)),G&&(r.scale(h)._ticks($/36).tickSize(-Y,0),s.scale(i)._ticks($/36).tickSize(aa.length?0:-Y,0),ga.select(\".nv-context \ .nv-y3.nv-axis\").style(\"opacity\",aa.length?1:0).attr(\"transform\",\"translate(0,\"+e.range()[0]+\")\"),ga.select(\".nv-context .nv-y2.nv-axis\").style(\"opacity\",ba.length?1:0).attr(\"transform\",\"translate(\"+e.range()[1]+\",0)\"),ga.select(\".nv-context .nv-y1.nv-axis\").transition().call(r),ga.select(\".nv-context .nv-y2.nv-axis\").transition().call(s)),u.x(e).on(\"brush\",T),J&&u.extent(J);var na=ga.select(\".nv-brushBackground\").selectAll(\"g\").data([J||u.extent()]),oa=na.enter().append(\"g\");oa.append(\"rect\").attr(\"class\",\"left\").attr(\"x\",0).attr(\"y\",0).attr(\"height\",$),oa.append(\"rect\").attr(\"class\",\"right\").attr(\"x\",0).attr(\"y\",0).attr(\"height\",$);var pa=ga.select(\".nv-x.nv-brush\").call(u);pa.selectAll(\"rect\").attr(\"height\",$),pa.selectAll(\".resize\").append(\"path\").attr(\"d\",K),t.dispatch.on(\"stateChange\",function(a){for(var c in a)N[c]=a[c];L.stateChange(N),b.update()}),L.on(\"changeState\",function(a){\"undefined\"!=typeof a.disabled&&(v.forEach(function(b,c){b.disabled=a.disabled[c]}),N.disabled=a.disabled),b.update()}),T()}),b}var c,d,e,f,g,h,i,j=a.models.line(),k=a.models.line(),l=a.models.historicalBar(),m=a.models.historicalBar(),n=a.models.axis(),o=a.models.axis(),p=a.models.axis(),q=a.models.axis(),r=a.models.axis(),s=a.models.axis(),t=a.models.legend(),u=d3.svg.brush(),v=a.models.tooltip(),w={top:30,right:30,bottom:30,left:60},x=null,y={top:0,right:30,bottom:20,left:60},z=null,A=null,B=function(a){return a.x},C=function(a){return a.y},D=a.utils.defaultColor(),E=!0,F=!0,G=!1,H=!0,I=50,J=null,K=null,L=d3.dispatch(\"brush\",\"stateChange\",\"changeState\"),M=0,N=a.utils.state(),O=null,P=\" (left axis)\",Q=\" (right axis)\",R=!1;j.clipEdge(!0),k.interactive(!1),k.pointActive(function(a){return!1}),n.orient(\"bottom\").tickPadding(5),p.orient(\"left\"),q.orient(\"right\"),o.orient(\"bottom\").tickPadding(5),r.orient(\"left\"),s.orient(\"right\"),v.headerEnabled(!0).headerFormatter(function(a,b){return n.tickFormat()(a,b)});var S=function(){return R?{main:q,focus:s}:{main:p,focus:r}},T=function(){return R?{main:p,focus:r}:{main:q,focus:s}},U=function(a){return \ @@ -866,9 +862,11 @@ D=C.enter().append(\"g\").attr(\"class\",\"nvd3 nv-wrap nv-ohlcBar\"),E=D.append d[1]]);l[b.key].brush.y(f),v.push(b.key)}if(isNaN(a.values[b.key])||isNaN(parseFloat(a.values[b.key])))return[k(b.key),l[b.key](e)]}return void 0!==U&&(v.length>0||O?(U.style(\"display\",\"inline\"),V.style(\"display\",\"inline\")):(U.style(\"display\",\"none\"),V.style(\"display\",\"none\"))),[k(b.key),l[b.key](a.values[b.key])]}))}function B(a){s.forEach(function(b){var c=l[b.dimension].brush.y().domain();b.hasOnlyNaN&&(b.extent[1]=(l[b.dimension].domain()[1]-c[0])*(b.extent[1]-b.extent[0])/(N[b.dimension]-b.extent[0])+c[0]),b.hasNaN&&(b.extent[0]=c[0]),a&&l[b.dimension].brush.extent(b.extent)}),e.select(\".nv-brushBackground\").each(function(a){d3.select(this).call(l[a.key].brush)}).selectAll(\"rect\").attr(\"x\",-8).attr(\"width\",16),F()}function C(){q===!1&&(q=!0,B(!0))}function D(){$=p.filter(function(a){return!l[a].brush.empty()}),_=$.map(function(a){return l[a].brush.extent()}),s=[],$.forEach(function(a,b){s[b]={dimension:a,extent:_[b],hasNaN:!1,hasOnlyNaN:!1}}),t=[],c.style(\"display\",function(a){var b=$.every(function(b,c){return(isNaN(a.values[b])||isNaN(parseFloat(a.values[b])))&&_[c][0]==l[b].brush.y().domain()[0]?!0:_[c][0]<=a.values[b]&&a.values[b]<=_[c][1]&&!isNaN(parseFloat(a.values[b]))});return b&&t.push(a),b?null:\"none\"}),F(),z.brush({filters:s,active:t})}function E(){var a=$.length>0?!0:!1;s.forEach(function(a){a.extent[0]===l[a.dimension].brush.y().domain()[0]&&v.indexOf(a.dimension)>=0&&(a.hasNaN=!0),a.extent[1]'+a.key+\" | ||
'+a.key+' | '+a.value+\" |