diff --git a/.gitignore b/.gitignore index 259148f..d726022 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Things +.vscode + # Prerequisites *.d diff --git a/README.md b/README.md index 88d257f..160139f 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Credits - The code was later improved and maintained by Christopher Snowhill (a.k.a. [kode54](https://kode54.net/)) - I could trace further contributions (e.g., new mappers) by retrowertz, CaH4e3, some adaptations from the [FCEUX emulator](https://github.com/TASEmulators/fceux) (see mapper021) - The latest version of the code is maintained by Libretro's community [here](https://github.com/libretro/QuickNES_Core) +- For the interactive player, this project uses a modified version of [HeadlessQuickNES (HQN)](https://github.com/Bindernews/HeadlessQuickNes). -All base code for this project was found under the GNU GPLv2 license, which I am preserving. Any non-credited work is unintentional and shall be immediately rectfied. +All base code for this project was found under open source licenses, which I preserved in their corresponding files/folders. Any non-credited work is unintentional and shall be immediately rectfied. diff --git a/core/utils.hpp b/core/utils.hpp new file mode 100644 index 0000000..fcb0fdf --- /dev/null +++ b/core/utils.hpp @@ -0,0 +1,204 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +// If we use NCurses, we need to use the appropriate printing function +#ifdef NCURSES + #include + #define LOG printw +#else + #define LOG printf +#endif + +// If we use NCurses, define the following useful functions +#ifdef NCURSES + +// Function to check for keypress taken from https://github.com/ajpaulson/learning-ncurses/blob/master/kbhit.c +inline int kbhit() +{ + int ch, r; + + // turn off getch() blocking and echo + nodelay(stdscr, TRUE); + noecho(); + + // check for input + ch = getch(); + if (ch == ERR) // no input + r = FALSE; + else // input + { + r = TRUE; + ungetch(ch); + } + + // restore block and echo + echo(); + nodelay(stdscr, FALSE); + + return (r); +} + +inline int getKeyPress() +{ + while (!kbhit()) + { + usleep(100000ul); + refresh(); + } + return getch(); +} + +#endif + +// Function to split a string into a sub-strings delimited by a character +// Taken from stack overflow answer to https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string +// By Evan Teran + +template inline void split(const std::string &s, char delim, Out result) +{ + std::istringstream iss(s); + std::string item; + while (std::getline(iss, item, delim)) + { + *result++ = item; + } +} + +inline std::vector split(const std::string &s, char delim) +{ + std::string newString = s; + std::replace(newString.begin(), newString.end(), '\n', ' '); + std::vector elems; + split(newString, delim, std::back_inserter(elems)); + return elems; +} + +// Taken from https://stackoverflow.com/questions/116038/how-do-i-read-an-entire-file-into-a-stdstring-in-c/116220#116220 +inline std::string slurp(std::ifstream &in) +{ + std::ostringstream sstr; + sstr << in.rdbuf(); + return sstr.str(); +} + +#define EXIT_WITH_ERROR(...) exitWithError(__FILE__, __LINE__, __VA_ARGS__) +inline void exitWithError [[noreturn]] (const char *fileName, const int lineNumber, const char *format, ...) +{ + char *outstr = 0; + va_list ap; + va_start(ap, format); + int ret = vasprintf(&outstr, format, ap); + if (ret < 0) exit(-1); + + std::string outString = outstr; + free(outstr); + + char info[1024]; + + snprintf(info, sizeof(info) - 1, " + From %s:%d\n", fileName, lineNumber); + outString += info; + + throw std::runtime_error(outString.c_str()); +} + +// Loads a string from a given file +inline bool loadStringFromFile(std::string &dst, const char *fileName) +{ + std::ifstream fi(fileName); + + // If file not found or open, return false + if (fi.good() == false) return false; + + // Reading entire file + dst = slurp(fi); + + // Closing file + fi.close(); + + return true; +} + +// Save string to a file +inline bool saveStringToFile(const std::string &src, const char *fileName) +{ + FILE *fid = fopen(fileName, "w"); + if (fid != NULL) + { + fwrite(src.c_str(), 1, src.size(), fid); + fclose(fid); + return true; + } + return false; +} + +// Function to split a vector into n mostly fair chunks +template inline std::vector splitVector(const T size, const T n) +{ + std::vector subSizes(n); + + T length = size / n; + T remain = size % n; + + for (T i = 0; i < n; i++) + subSizes[i] = i < remain ? length + 1 : length; + + return subSizes; +} + +inline std::string simplifyMove(const std::string& move) +{ + std::string simpleMove; + + bool isEmptyMove = true; + for (size_t i = 0; i < move.size(); i++) if (move[i] != '.' && move[i] != '|') { simpleMove += move[i]; isEmptyMove = false; } + if (isEmptyMove) return "."; + return simpleMove; +} + +inline bool getBitFlag(const uint8_t value, const uint8_t idx) +{ + if (((idx == 7) && (value & 0b10000000)) || + ((idx == 6) && (value & 0b01000000)) || + ((idx == 5) && (value & 0b00100000)) || + ((idx == 4) && (value & 0b00010000)) || + ((idx == 3) && (value & 0b00001000)) || + ((idx == 2) && (value & 0b00000100)) || + ((idx == 1) && (value & 0b00000010)) || + ((idx == 0) && (value & 0b00000001))) return true; + return false; +} + + +inline size_t countButtonsPressedString(const std::string& input) { size_t count = 0; for (size_t i = 0; i < input.size(); i++) if (input[i] != '.') count++; return count; }; + +template inline uint16_t countButtonsPressedNumber(const T& input) { + uint16_t count = 0; + if (input & 0b0000000000000001) count++; + if (input & 0b0000000000000010) count++; + if (input & 0b0000000000000100) count++; + if (input & 0b0000000000001000) count++; + if (input & 0b0000000000010000) count++; + if (input & 0b0000000000100000) count++; + if (input & 0b0000000001000000) count++; + if (input & 0b0000000010000000) count++; + if (input & 0b0000000100000000) count++; + if (input & 0b0000001000000000) count++; + if (input & 0b0000010000000000) count++; + if (input & 0b0000100000000000) count++; + if (input & 0b0001000000000000) count++; + if (input & 0b0010000000000000) count++; + if (input & 0b0100000000000000) count++; + if (input & 0b1000000000000000) count++; + return count; +}; + +static auto moveCountComparerString = [](const std::string& a, const std::string& b) { return countButtonsPressedString(a) < countButtonsPressedString(b); }; +static auto moveCountComparerNumber = [](const uint8_t a, const uint8_t b) { return countButtonsPressedNumber(a) < countButtonsPressedNumber(b); }; diff --git a/extern/argparse/argparse.hpp b/extern/argparse/argparse.hpp new file mode 100644 index 0000000..04f04b9 --- /dev/null +++ b/extern/argparse/argparse.hpp @@ -0,0 +1,1089 @@ +/* + __ _ _ __ __ _ _ __ __ _ _ __ ___ ___ + / _` | '__/ _` | '_ \ / _` | '__/ __|/ _ \ Argument Parser for Modern C++ +| (_| | | | (_| | |_) | (_| | | \__ \ __/ http://github.com/p-ranav/argparse + \__,_|_| \__, | .__/ \__,_|_| |___/\___| + |___/|_| + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2019 Pranav Srinivas Kumar . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace argparse { + +namespace details { // namespace for helper methods + +template +struct is_container : std::false_type {}; + +template <> struct is_container : std::false_type {}; + +template +struct is_container().begin()), + decltype(std::declval().end()), + decltype(std::declval().size())>> + : std::true_type {}; + +template +static constexpr bool is_container_v = is_container::value; + +template +struct is_streamable : std::false_type {}; + +template +struct is_streamable< + T, std::void_t() << std::declval())>> + : std::true_type {}; + +template +static constexpr bool is_streamable_v = is_streamable::value; + +template +static constexpr bool is_representable_v = + is_streamable_v || is_container_v; + +constexpr size_t repr_max_container_size = 5; + +template std::string repr(T const &val) { + if constexpr (std::is_same_v) { + return val ? "true" : "false"; + } else if constexpr (std::is_convertible_v) { + return '"' + std::string{std::string_view{val}} + '"'; + } else if constexpr (is_container_v) { + std::stringstream out; + out << "{"; + const auto size = val.size(); + if (size > 1) { + out << repr(*val.begin()); + std::for_each( + std::next(val.begin()), + std::next(val.begin(), std::min(size, repr_max_container_size) - 1), + [&out](const auto &v) { out << " " << repr(v); }); + if (size <= repr_max_container_size) + out << " "; + else + out << "..."; + } + if (size > 0) + out << repr(*std::prev(val.end())); + out << "}"; + return out.str(); + } else if constexpr (is_streamable_v) { + std::stringstream out; + out << val; + return out.str(); + } else { + return ""; + } +} + +namespace { + +template constexpr bool standard_signed_integer = false; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; + +template constexpr bool standard_unsigned_integer = false; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> +constexpr bool standard_unsigned_integer = true; + +} // namespace + +template +constexpr bool standard_integer = + standard_signed_integer || standard_unsigned_integer; + +template +constexpr decltype(auto) apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x, + std::index_sequence) { + return std::invoke(std::forward(f), std::get(std::forward(t))..., + std::forward(x)); +} + +template +constexpr decltype(auto) apply_plus_one(F &&f, Tuple &&t, Extra &&x) { + return details::apply_plus_one_impl( + std::forward(f), std::forward(t), std::forward(x), + std::make_index_sequence< + std::tuple_size_v>>{}); +} + +constexpr auto pointer_range(std::string_view s) noexcept { + return std::tuple(s.data(), s.data() + s.size()); +} + +template +constexpr bool starts_with(std::basic_string_view prefix, + std::basic_string_view s) noexcept { + return s.substr(0, prefix.size()) == prefix; +} + +enum class chars_format { + scientific = 0x1, + fixed = 0x2, + hex = 0x4, + general = fixed | scientific +}; + +struct consume_hex_prefix_result { + bool is_hexadecimal; + std::string_view rest; +}; + +using namespace std::literals; + +constexpr auto consume_hex_prefix(std::string_view s) + -> consume_hex_prefix_result { + if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { + s.remove_prefix(2); + return {true, s}; + } else { + return {false, s}; + } +} + +template +inline auto do_from_chars(std::string_view s) -> T { + T x; + auto [first, last] = pointer_range(s); + auto [ptr, ec] = std::from_chars(first, last, x, Param); + if (ec == std::errc()) { + if (ptr == last) + return x; + else + throw std::invalid_argument{"pattern does not match to the end"}; + } else if (ec == std::errc::invalid_argument) { + throw std::invalid_argument{"pattern not found"}; + } else if (ec == std::errc::result_out_of_range) { + throw std::range_error{"not representable"}; + } else { + return x; // unreachable + } +} + +template struct parse_number { + auto operator()(std::string_view s) -> T { + return do_from_chars(s); + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + if (auto [ok, rest] = consume_hex_prefix(s); ok) + return do_from_chars(rest); + else + throw std::invalid_argument{"pattern not found"}; + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + if (auto [ok, rest] = consume_hex_prefix(s); ok) + return do_from_chars(rest); + else if (starts_with("0"sv, s)) + return do_from_chars(rest); + else + return do_from_chars(rest); + } +}; + +namespace { + +template constexpr auto generic_strtod = nullptr; +template <> constexpr auto generic_strtod = strtof; +template <> constexpr auto generic_strtod = strtod; +template <> constexpr auto generic_strtod = strtold; + +} // namespace + +template inline auto do_strtod(std::string const &s) -> T { + if (isspace(static_cast(s[0])) || s[0] == '+') + throw std::invalid_argument{"pattern not found"}; + + auto [first, last] = pointer_range(s); + char *ptr; + + errno = 0; + if (auto x = generic_strtod(first, &ptr); errno == 0) { + if (ptr == last) + return x; + else + throw std::invalid_argument{"pattern does not match to the end"}; + } else if (errno == ERANGE) { + throw std::range_error{"not representable"}; + } else { + return x; // unreachable + } +} + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) + throw std::invalid_argument{ + "chars_format::general does not parse hexfloat"}; + + return do_strtod(s); + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); !r.is_hexadecimal) + throw std::invalid_argument{"chars_format::hex parses hexfloat"}; + + return do_strtod(s); + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) + throw std::invalid_argument{ + "chars_format::scientific does not parse hexfloat"}; + if (s.find_first_of("eE") == s.npos) + throw std::invalid_argument{ + "chars_format::scientific requires exponent part"}; + + return do_strtod(s); + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) + throw std::invalid_argument{ + "chars_format::fixed does not parse hexfloat"}; + if (s.find_first_of("eE") != s.npos) + throw std::invalid_argument{ + "chars_format::fixed does not parse exponent part"}; + + return do_strtod(s); + } +}; + +} // namespace details + +class ArgumentParser; + +class Argument { + friend class ArgumentParser; + friend auto operator<<(std::ostream &, ArgumentParser const &) + -> std::ostream &; + + template + explicit Argument(std::string_view(&&a)[N], std::index_sequence) + : mIsOptional((is_optional(a[I]) || ...)), mIsRequired(false), + mIsUsed(false) { + ((void)mNames.emplace_back(a[I]), ...); + std::sort( + mNames.begin(), mNames.end(), [](const auto &lhs, const auto &rhs) { + return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); + }); + } + +public: + template + explicit Argument(std::string_view(&&a)[N]) + : Argument(std::move(a), std::make_index_sequence{}) {} + + Argument &help(std::string aHelp) { + mHelp = std::move(aHelp); + return *this; + } + + template Argument &default_value(T &&aDefaultValue) { + mDefaultValueRepr = details::repr(aDefaultValue); + mDefaultValue = std::forward(aDefaultValue); + return *this; + } + + Argument &required() { + mIsRequired = true; + return *this; + } + + Argument &implicit_value(std::any aImplicitValue) { + mImplicitValue = std::move(aImplicitValue); + mNumArgs = 0; + return *this; + } + + template + auto action(F &&aAction, Args &&... aBound) + -> std::enable_if_t, + Argument &> { + using action_type = std::conditional_t< + std::is_void_v>, + void_action, valued_action>; + if constexpr (sizeof...(Args) == 0) + mAction.emplace(std::forward(aAction)); + else + mAction.emplace( + [f = std::forward(aAction), + tup = std::make_tuple(std::forward(aBound)...)]( + std::string const &opt) mutable { + return details::apply_plus_one(f, tup, opt); + }); + return *this; + } + + template + auto scan() -> std::enable_if_t, Argument &> { + static_assert(!(std::is_const_v || std::is_volatile_v), + "T should not be cv-qualified"); + auto is_one_of = [](char c, auto... x) constexpr { + return ((c == x) || ...); + }; + + if constexpr (is_one_of(Shape, 'd') && details::standard_integer) + action(details::parse_number()); + else if constexpr (is_one_of(Shape, 'i') && details::standard_integer) + action(details::parse_number()); + else if constexpr (is_one_of(Shape, 'u') && + details::standard_unsigned_integer) + action(details::parse_number()); + else if constexpr (is_one_of(Shape, 'o') && + details::standard_unsigned_integer) + action(details::parse_number()); + else if constexpr (is_one_of(Shape, 'x', 'X') && + details::standard_unsigned_integer) + action(details::parse_number()); + else if constexpr (is_one_of(Shape, 'a', 'A') && + std::is_floating_point_v) + action(details::parse_number()); + else if constexpr (is_one_of(Shape, 'e', 'E') && + std::is_floating_point_v) + action(details::parse_number()); + else if constexpr (is_one_of(Shape, 'f', 'F') && + std::is_floating_point_v) + action(details::parse_number()); + else if constexpr (is_one_of(Shape, 'g', 'G') && + std::is_floating_point_v) + action(details::parse_number()); + else + static_assert(alignof(T) == 0, "No scan specification for T"); + + return *this; + } + + Argument &nargs(int aNumArgs) { + if (aNumArgs < 0) + throw std::logic_error("Number of arguments must be non-negative"); + mNumArgs = aNumArgs; + return *this; + } + + Argument &remaining() { + mNumArgs = -1; + return *this; + } + + template + Iterator consume(Iterator start, Iterator end, + std::string_view usedName = {}) { + if (mIsUsed) { + throw std::runtime_error("Duplicate argument"); + } + mIsUsed = true; + mUsedName = usedName; + if (mNumArgs == 0) { + mValues.emplace_back(mImplicitValue); + return start; + } else if (mNumArgs <= std::distance(start, end)) { + if (auto expected = maybe_nargs()) { + end = std::next(start, *expected); + if (std::any_of(start, end, Argument::is_optional)) { + throw std::runtime_error("optional argument in parameter sequence"); + } + } + + struct action_apply { + void operator()(valued_action &f) { + std::transform(start, end, std::back_inserter(self.mValues), f); + } + + void operator()(void_action &f) { + std::for_each(start, end, f); + if (!self.mDefaultValue.has_value()) { + if (auto expected = self.maybe_nargs()) + self.mValues.resize(*expected); + } + } + + Iterator start, end; + Argument &self; + }; + std::visit(action_apply{start, end, *this}, mAction); + return end; + } else if (mDefaultValue.has_value()) { + return start; + } else { + throw std::runtime_error("Too few arguments"); + } + } + + /* + * @throws std::runtime_error if argument values are not valid + */ + void validate() const { + if (auto expected = maybe_nargs()) { + if (mIsOptional) { + if (mIsUsed && mValues.size() != *expected && + !mDefaultValue.has_value()) { + std::stringstream stream; + stream << mUsedName << ": expected " << *expected << " argument(s). " + << mValues.size() << " provided."; + throw std::runtime_error(stream.str()); + } else { + // TODO: check if an implicit value was programmed for this argument + if (!mIsUsed && !mDefaultValue.has_value() && mIsRequired) { + std::stringstream stream; + stream << mNames[0] << ": required."; + throw std::runtime_error(stream.str()); + } + if (mIsUsed && mIsRequired && mValues.size() == 0) { + std::stringstream stream; + stream << mUsedName << ": no value provided."; + throw std::runtime_error(stream.str()); + } + } + } else { + if (mValues.size() != expected && !mDefaultValue.has_value()) { + std::stringstream stream; + if (!mUsedName.empty()) + stream << mUsedName << ": "; + stream << *expected << " argument(s) expected. " << mValues.size() + << " provided."; + throw std::runtime_error(stream.str()); + } + } + } + } + + auto maybe_nargs() const -> std::optional { + if (mNumArgs < 0) + return std::nullopt; + else + return static_cast(mNumArgs); + } + + size_t get_arguments_length() const { + return std::accumulate(std::begin(mNames), std::end(mNames), size_t(0), + [](const auto &sum, const auto &s) { + return sum + s.size() + + 1; // +1 for space between names + }); + } + + friend std::ostream &operator<<(std::ostream &stream, + const Argument &argument) { + std::stringstream nameStream; + std::copy(std::begin(argument.mNames), std::end(argument.mNames), + std::ostream_iterator(nameStream, " ")); + stream << nameStream.str() << "\t" << argument.mHelp; + if (argument.mDefaultValue.has_value()) { + if (!argument.mHelp.empty()) + stream << " "; + stream << "[default: " << argument.mDefaultValueRepr << "]"; + } else if (argument.mIsRequired) { + if (!argument.mHelp.empty()) + stream << " "; + stream << "[required]"; + } + stream << "\n"; + return stream; + } + + template bool operator!=(const T &aRhs) const { + return !(*this == aRhs); + } + + /* + * Compare to an argument value of known type + * @throws std::logic_error in case of incompatible types + */ + template bool operator==(const T &aRhs) const { + if constexpr (!details::is_container_v) { + return get() == aRhs; + } else { + using ValueType = typename T::value_type; + auto tLhs = get(); + return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs), + std::end(aRhs), [](const auto &lhs, const auto &rhs) { + return std::any_cast(lhs) == rhs; + }); + } + } + +private: + static constexpr int eof = std::char_traits::eof(); + + static auto lookahead(std::string_view s) -> int { + if (s.empty()) + return eof; + else + return static_cast(static_cast(s[0])); + } + + /* + * decimal-literal: + * '0' + * nonzero-digit digit-sequence_opt + * integer-part fractional-part + * fractional-part + * integer-part '.' exponent-part_opt + * integer-part exponent-part + * + * integer-part: + * digit-sequence + * + * fractional-part: + * '.' post-decimal-point + * + * post-decimal-point: + * digit-sequence exponent-part_opt + * + * exponent-part: + * 'e' post-e + * 'E' post-e + * + * post-e: + * sign_opt digit-sequence + * + * sign: one of + * '+' '-' + */ + static bool is_decimal_literal(std::string_view s) { + auto is_digit = [](auto c) constexpr { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return true; + default: + return false; + } + }; + + // precondition: we have consumed or will consume at least one digit + auto consume_digits = [=](std::string_view s) { + auto it = std::find_if_not(std::begin(s), std::end(s), is_digit); + return s.substr(it - std::begin(s)); + }; + + switch (lookahead(s)) { + case '0': { + s.remove_prefix(1); + if (s.empty()) + return true; + else + goto integer_part; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + s = consume_digits(s); + if (s.empty()) + return true; + else + goto integer_part_consumed; + } + case '.': { + s.remove_prefix(1); + goto post_decimal_point; + } + default: + return false; + } + + integer_part: + s = consume_digits(s); + integer_part_consumed: + switch (lookahead(s)) { + case '.': { + s.remove_prefix(1); + if (is_digit(lookahead(s))) + goto post_decimal_point; + else + goto exponent_part_opt; + } + case 'e': + case 'E': { + s.remove_prefix(1); + goto post_e; + } + default: + return false; + } + + post_decimal_point: + if (is_digit(lookahead(s))) { + s = consume_digits(s); + goto exponent_part_opt; + } else { + return false; + } + + exponent_part_opt: + switch (lookahead(s)) { + case eof: + return true; + case 'e': + case 'E': { + s.remove_prefix(1); + goto post_e; + } + default: + return false; + } + + post_e: + switch (lookahead(s)) { + case '-': + case '+': + s.remove_prefix(1); + } + if (is_digit(lookahead(s))) { + s = consume_digits(s); + return s.empty(); + } else { + return false; + } + } + + static bool is_optional(std::string_view aName) { + return !is_positional(aName); + } + + /* + * positional: + * _empty_ + * '-' + * '-' decimal-literal + * !'-' anything + */ + static bool is_positional(std::string_view aName) { + switch (lookahead(aName)) { + case eof: + return true; + case '-': { + aName.remove_prefix(1); + if (aName.empty()) + return true; + else + return is_decimal_literal(aName); + } + default: + return true; + } + } + + /* + * Get argument value given a type + * @throws std::logic_error in case of incompatible types + */ + template T get() const { + if (!mValues.empty()) { + if constexpr (details::is_container_v) + return any_cast_container(mValues); + else + return std::any_cast(mValues.front()); + } + if (mDefaultValue.has_value()) { + return std::any_cast(mDefaultValue); + } + throw std::logic_error("No value provided"); + } + + /* + * Get argument value given a type. + * @pre The object has no default value. + * @returns The stored value if any, std::nullopt otherwise. + */ + template auto present() const -> std::optional { + if (mDefaultValue.has_value()) + throw std::logic_error("Argument with default value always presents"); + + if (mValues.empty()) + return std::nullopt; + else if constexpr (details::is_container_v) + return any_cast_container(mValues); + else + return std::any_cast(mValues.front()); + } + + template + static auto any_cast_container(const std::vector &aOperand) -> T { + using ValueType = typename T::value_type; + + T tResult; + std::transform( + std::begin(aOperand), std::end(aOperand), std::back_inserter(tResult), + [](const auto &value) { return std::any_cast(value); }); + return tResult; + } + + std::vector mNames; + std::string_view mUsedName; + std::string mHelp; + std::any mDefaultValue; + std::string mDefaultValueRepr; + std::any mImplicitValue; + using valued_action = std::function; + using void_action = std::function; + std::variant mAction{ + std::in_place_type, + [](const std::string &aValue) { return aValue; }}; + std::vector mValues; + int mNumArgs = 1; + bool mIsOptional : 1; + bool mIsRequired : 1; + bool mIsUsed : 1; // True if the optional argument is used by user +}; + +class ArgumentParser { +public: + explicit ArgumentParser(std::string aProgramName = {}, + std::string aVersion = "1.0") + : mProgramName(std::move(aProgramName)), mVersion(std::move(aVersion)) { + add_argument("-h", "--help").help("shows help message and exits").nargs(0); + add_argument("-v", "--version") + .help("prints version information and exits") + .nargs(0); + } + + ArgumentParser(ArgumentParser &&) noexcept = default; + ArgumentParser &operator=(ArgumentParser &&) = default; + + ArgumentParser(const ArgumentParser &other) + : mProgramName(other.mProgramName), + mPositionalArguments(other.mPositionalArguments), + mOptionalArguments(other.mOptionalArguments) { + for (auto it = std::begin(mPositionalArguments); it != std::end(mPositionalArguments); + ++it) + index_argument(it); + for (auto it = std::begin(mOptionalArguments); it != std::end(mOptionalArguments); + ++it) + index_argument(it); + } + + ArgumentParser &operator=(const ArgumentParser &other) { + auto tmp = other; + std::swap(*this, tmp); + return *this; + } + + // Parameter packing + // Call add_argument with variadic number of string arguments + template Argument &add_argument(Targs... Fargs) { + using array_of_sv = std::string_view[sizeof...(Targs)]; + auto tArgument = mOptionalArguments.emplace(cend(mOptionalArguments), + array_of_sv{Fargs...}); + + if (!tArgument->mIsOptional) + mPositionalArguments.splice(cend(mPositionalArguments), + mOptionalArguments, tArgument); + + index_argument(tArgument); + return *tArgument; + } + + // Parameter packed add_parents method + // Accepts a variadic number of ArgumentParser objects + template + ArgumentParser &add_parents(const Targs &... Fargs) { + for (const ArgumentParser &tParentParser : {std::ref(Fargs)...}) { + for (auto &tArgument : tParentParser.mPositionalArguments) { + auto it = + mPositionalArguments.insert(cend(mPositionalArguments), tArgument); + index_argument(it); + } + for (auto &tArgument : tParentParser.mOptionalArguments) { + auto it = + mOptionalArguments.insert(cend(mOptionalArguments), tArgument); + index_argument(it); + } + } + return *this; + } + + ArgumentParser &add_description(std::string aDescription) { + mDescription = std::move(aDescription); + return *this; + } + + ArgumentParser &add_epilog(std::string aEpilog) { + mEpilog = std::move(aEpilog); + return *this; + } + + /* Call parse_args_internal - which does all the work + * Then, validate the parsed arguments + * This variant is used mainly for testing + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args(const std::vector &aArguments) { + parse_args_internal(aArguments); + parse_args_validate(); + } + + /* Main entry point for parsing command-line arguments using this + * ArgumentParser + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args(int argc, const char *const argv[]) { + std::vector arguments; + std::copy(argv, argv + argc, std::back_inserter(arguments)); + parse_args(arguments); + } + + /* Getter for options with default values. + * @throws std::logic_error if there is no such option + * @throws std::logic_error if the option has no value + * @throws std::bad_any_cast if the option is not of type T + */ + template + T get(std::string_view aArgumentName) const { + return (*this)[aArgumentName].get(); + } + + /* Getter for options without default values. + * @pre The option has no default value. + * @throws std::logic_error if there is no such option + * @throws std::bad_any_cast if the option is not of type T + */ + template + auto present(std::string_view aArgumentName) -> std::optional { + return (*this)[aArgumentName].present(); + } + + /* Indexing operator. Return a reference to an Argument object + * Used in conjuction with Argument.operator== e.g., parser["foo"] == true + * @throws std::logic_error in case of an invalid argument name + */ + Argument &operator[](std::string_view aArgumentName) const { + auto tIterator = mArgumentMap.find(aArgumentName); + if (tIterator != mArgumentMap.end()) { + return *(tIterator->second); + } + throw std::logic_error("No such argument"); + } + + // Print help message + friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) + -> std::ostream & { + if (auto sen = std::ostream::sentry(stream)) { + stream.setf(std::ios_base::left); + stream << "Usage: " << parser.mProgramName << " [options] "; + size_t tLongestArgumentLength = parser.get_length_of_longest_argument(); + + for (const auto &argument : parser.mPositionalArguments) { + stream << argument.mNames.front() << " "; + } + stream << "\n\n"; + + if (!parser.mDescription.empty()) + stream << parser.mDescription << "\n\n"; + + if (!parser.mPositionalArguments.empty()) + stream << "Positional arguments:\n"; + + for (const auto &mPositionalArgument : parser.mPositionalArguments) { + stream.width(tLongestArgumentLength); + stream << mPositionalArgument; + } + + if (!parser.mOptionalArguments.empty()) + stream << (parser.mPositionalArguments.empty() ? "" : "\n") + << "Optional arguments:\n"; + + for (const auto &mOptionalArgument : parser.mOptionalArguments) { + stream.width(tLongestArgumentLength); + stream << mOptionalArgument; + } + + if (!parser.mEpilog.empty()) + stream << parser.mEpilog << "\n\n"; + } + + return stream; + } + + // Format help message + auto help() const -> std::stringstream { + std::stringstream out; + out << *this; + return out; + } + + // Printing the one and only help message + // I've stuck with a simple message format, nothing fancy. + [[deprecated("Use cout << program; instead. See also help().")]] std::string + print_help() { + auto out = help(); + std::cout << out.rdbuf(); + return out.str(); + } + +private: + /* + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args_internal(const std::vector &aArguments) { + if (mProgramName.empty() && !aArguments.empty()) { + mProgramName = aArguments.front(); + } + auto end = std::end(aArguments); + auto positionalArgumentIt = std::begin(mPositionalArguments); + for (auto it = std::next(std::begin(aArguments)); it != end;) { + const auto &tCurrentArgument = *it; + if (Argument::is_positional(tCurrentArgument)) { + if (positionalArgumentIt == std::end(mPositionalArguments)) { + throw std::runtime_error( + "Maximum number of positional arguments exceeded"); + } + auto tArgument = positionalArgumentIt++; + it = tArgument->consume(it, end); + continue; + } + + auto tIterator = mArgumentMap.find(tCurrentArgument); + if (tIterator != mArgumentMap.end()) { + auto tArgument = tIterator->second; + + // the first optional argument is --help + if (tArgument == mOptionalArguments.begin()) { + std::cout << *this; + std::exit(0); + } + // the second optional argument is --version + else if (tArgument == std::next(mOptionalArguments.begin(), 1)) { + std::cout << mVersion << "\n"; + std::exit(0); + } + + it = tArgument->consume(std::next(it), end, tIterator->first); + } else if (const auto &tCompoundArgument = tCurrentArgument; + tCompoundArgument.size() > 1 && tCompoundArgument[0] == '-' && + tCompoundArgument[1] != '-') { + ++it; + for (size_t j = 1; j < tCompoundArgument.size(); j++) { + auto tHypotheticalArgument = std::string{'-', tCompoundArgument[j]}; + auto tIterator2 = mArgumentMap.find(tHypotheticalArgument); + if (tIterator2 != mArgumentMap.end()) { + auto tArgument = tIterator2->second; + it = tArgument->consume(it, end, tIterator2->first); + } else { + throw std::runtime_error("Unknown argument"); + } + } + } else { + throw std::runtime_error("Unknown argument"); + } + } + } + + /* + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args_validate() { + // Check if all arguments are parsed + std::for_each(std::begin(mArgumentMap), std::end(mArgumentMap), + [](const auto &argPair) { + const auto &tArgument = argPair.second; + tArgument->validate(); + }); + } + + // Used by print_help. + size_t get_length_of_longest_argument() const { + if (mArgumentMap.empty()) + return 0; + std::vector argumentLengths(mArgumentMap.size()); + std::transform(std::begin(mArgumentMap), std::end(mArgumentMap), + std::begin(argumentLengths), [](const auto &argPair) { + const auto &tArgument = argPair.second; + return tArgument->get_arguments_length(); + }); + return *std::max_element(std::begin(argumentLengths), + std::end(argumentLengths)); + } + + using list_iterator = std::list::iterator; + + void index_argument(list_iterator argIt) { + for (auto &mName : argIt->mNames) + mArgumentMap.insert_or_assign(mName, argIt); + } + + std::string mProgramName; + std::string mVersion; + std::string mDescription; + std::string mEpilog; + std::list mPositionalArguments; + std::list mOptionalArguments; + std::map> mArgumentMap; +}; + +} // namespace argparse diff --git a/extern/metrohash128/metrohash128.cpp b/extern/metrohash128/metrohash128.cpp new file mode 100644 index 0000000..5c143db --- /dev/null +++ b/extern/metrohash128/metrohash128.cpp @@ -0,0 +1,413 @@ +// metrohash128.cpp +// +// Copyright 2015-2018 J. Andrew Rogers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "platform.h" +#include "metrohash128.h" + +const char * MetroHash128::test_string = "012345678901234567890123456789012345678901234567890123456789012"; + +const uint8_t MetroHash128::test_seed_0[16] = { + 0xC7, 0x7C, 0xE2, 0xBF, 0xA4, 0xED, 0x9F, 0x9B, + 0x05, 0x48, 0xB2, 0xAC, 0x50, 0x74, 0xA2, 0x97 + }; + +const uint8_t MetroHash128::test_seed_1[16] = { + 0x45, 0xA3, 0xCD, 0xB8, 0x38, 0x19, 0x9D, 0x7F, + 0xBD, 0xD6, 0x8D, 0x86, 0x7A, 0x14, 0xEC, 0xEF + }; + + + +MetroHash128::MetroHash128(const uint64_t seed) +{ + Initialize(seed); +} + + +void MetroHash128::Initialize(const uint64_t seed) +{ + // initialize internal hash registers + state.v[0] = (static_cast(seed) - k0) * k3; + state.v[1] = (static_cast(seed) + k1) * k2; + state.v[2] = (static_cast(seed) + k0) * k2; + state.v[3] = (static_cast(seed) - k1) * k3; + + // initialize total length of input + bytes = 0; +} + + +void MetroHash128::Update(const uint8_t * const buffer, const uint64_t length) +{ + const uint8_t * ptr = reinterpret_cast(buffer); + const uint8_t * const end = ptr + length; + + // input buffer may be partially filled + if (bytes % 32) + { + uint64_t fill = 32 - (bytes % 32); + if (fill > length) + fill = length; + + memcpy(input.b + (bytes % 32), ptr, static_cast(fill)); + ptr += fill; + bytes += fill; + + // input buffer is still partially filled + if ((bytes % 32) != 0) return; + + // process full input buffer + state.v[0] += read_u64(&input.b[ 0]) * k0; state.v[0] = rotate_right(state.v[0],29) + state.v[2]; + state.v[1] += read_u64(&input.b[ 8]) * k1; state.v[1] = rotate_right(state.v[1],29) + state.v[3]; + state.v[2] += read_u64(&input.b[16]) * k2; state.v[2] = rotate_right(state.v[2],29) + state.v[0]; + state.v[3] += read_u64(&input.b[24]) * k3; state.v[3] = rotate_right(state.v[3],29) + state.v[1]; + } + + // bulk update + bytes += (end - ptr); + while (ptr <= (end - 32)) + { + // process directly from the source, bypassing the input buffer + state.v[0] += read_u64(ptr) * k0; ptr += 8; state.v[0] = rotate_right(state.v[0],29) + state.v[2]; + state.v[1] += read_u64(ptr) * k1; ptr += 8; state.v[1] = rotate_right(state.v[1],29) + state.v[3]; + state.v[2] += read_u64(ptr) * k2; ptr += 8; state.v[2] = rotate_right(state.v[2],29) + state.v[0]; + state.v[3] += read_u64(ptr) * k3; ptr += 8; state.v[3] = rotate_right(state.v[3],29) + state.v[1]; + } + + // store remaining bytes in input buffer + if (ptr < end) + memcpy(input.b, ptr, end - ptr); +} + + +void MetroHash128::Finalize(uint8_t * const hash) +{ + // finalize bulk loop, if used + if (bytes >= 32) + { + state.v[2] ^= rotate_right(((state.v[0] + state.v[3]) * k0) + state.v[1], 21) * k1; + state.v[3] ^= rotate_right(((state.v[1] + state.v[2]) * k1) + state.v[0], 21) * k0; + state.v[0] ^= rotate_right(((state.v[0] + state.v[2]) * k0) + state.v[3], 21) * k1; + state.v[1] ^= rotate_right(((state.v[1] + state.v[3]) * k1) + state.v[2], 21) * k0; + } + + // process any bytes remaining in the input buffer + const uint8_t * ptr = reinterpret_cast(input.b); + const uint8_t * const end = ptr + (bytes % 32); + + if ((end - ptr) >= 16) + { + state.v[0] += read_u64(ptr) * k2; ptr += 8; state.v[0] = rotate_right(state.v[0],33) * k3; + state.v[1] += read_u64(ptr) * k2; ptr += 8; state.v[1] = rotate_right(state.v[1],33) * k3; + state.v[0] ^= rotate_right((state.v[0] * k2) + state.v[1], 45) * k1; + state.v[1] ^= rotate_right((state.v[1] * k3) + state.v[0], 45) * k0; + } + + if ((end - ptr) >= 8) + { + state.v[0] += read_u64(ptr) * k2; ptr += 8; state.v[0] = rotate_right(state.v[0],33) * k3; + state.v[0] ^= rotate_right((state.v[0] * k2) + state.v[1], 27) * k1; + } + + if ((end - ptr) >= 4) + { + state.v[1] += read_u32(ptr) * k2; ptr += 4; state.v[1] = rotate_right(state.v[1],33) * k3; + state.v[1] ^= rotate_right((state.v[1] * k3) + state.v[0], 46) * k0; + } + + if ((end - ptr) >= 2) + { + state.v[0] += read_u16(ptr) * k2; ptr += 2; state.v[0] = rotate_right(state.v[0],33) * k3; + state.v[0] ^= rotate_right((state.v[0] * k2) + state.v[1], 22) * k1; + } + + if ((end - ptr) >= 1) + { + state.v[1] += read_u8 (ptr) * k2; state.v[1] = rotate_right(state.v[1],33) * k3; + state.v[1] ^= rotate_right((state.v[1] * k3) + state.v[0], 58) * k0; + } + + state.v[0] += rotate_right((state.v[0] * k0) + state.v[1], 13); + state.v[1] += rotate_right((state.v[1] * k1) + state.v[0], 37); + state.v[0] += rotate_right((state.v[0] * k2) + state.v[1], 13); + state.v[1] += rotate_right((state.v[1] * k3) + state.v[0], 37); + + bytes = 0; + + // do any endian conversion here + + memcpy(hash, state.v, 16); +} + + +void MetroHash128::Hash(const uint8_t * buffer, const uint64_t length, uint8_t * const hash, const uint64_t seed) +{ + const uint8_t * ptr = reinterpret_cast(buffer); + const uint8_t * const end = ptr + length; + + uint64_t v[4]; + + v[0] = (static_cast(seed) - k0) * k3; + v[1] = (static_cast(seed) + k1) * k2; + + if (length >= 32) + { + v[2] = (static_cast(seed) + k0) * k2; + v[3] = (static_cast(seed) - k1) * k3; + + do + { + v[0] += read_u64(ptr) * k0; ptr += 8; v[0] = rotate_right(v[0],29) + v[2]; + v[1] += read_u64(ptr) * k1; ptr += 8; v[1] = rotate_right(v[1],29) + v[3]; + v[2] += read_u64(ptr) * k2; ptr += 8; v[2] = rotate_right(v[2],29) + v[0]; + v[3] += read_u64(ptr) * k3; ptr += 8; v[3] = rotate_right(v[3],29) + v[1]; + } + while (ptr <= (end - 32)); + + v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 21) * k1; + v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 21) * k0; + v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 21) * k1; + v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 21) * k0; + } + + if ((end - ptr) >= 16) + { + v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],33) * k3; + v[1] += read_u64(ptr) * k2; ptr += 8; v[1] = rotate_right(v[1],33) * k3; + v[0] ^= rotate_right((v[0] * k2) + v[1], 45) * k1; + v[1] ^= rotate_right((v[1] * k3) + v[0], 45) * k0; + } + + if ((end - ptr) >= 8) + { + v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],33) * k3; + v[0] ^= rotate_right((v[0] * k2) + v[1], 27) * k1; + } + + if ((end - ptr) >= 4) + { + v[1] += read_u32(ptr) * k2; ptr += 4; v[1] = rotate_right(v[1],33) * k3; + v[1] ^= rotate_right((v[1] * k3) + v[0], 46) * k0; + } + + if ((end - ptr) >= 2) + { + v[0] += read_u16(ptr) * k2; ptr += 2; v[0] = rotate_right(v[0],33) * k3; + v[0] ^= rotate_right((v[0] * k2) + v[1], 22) * k1; + } + + if ((end - ptr) >= 1) + { + v[1] += read_u8 (ptr) * k2; v[1] = rotate_right(v[1],33) * k3; + v[1] ^= rotate_right((v[1] * k3) + v[0], 58) * k0; + } + + v[0] += rotate_right((v[0] * k0) + v[1], 13); + v[1] += rotate_right((v[1] * k1) + v[0], 37); + v[0] += rotate_right((v[0] * k2) + v[1], 13); + v[1] += rotate_right((v[1] * k3) + v[0], 37); + + // do any endian conversion here + + memcpy(hash, v, 16); +} + + +bool MetroHash128::ImplementationVerified() +{ + uint8_t hash[16]; + const uint8_t * key = reinterpret_cast(MetroHash128::test_string); + + // verify one-shot implementation + MetroHash128::Hash(key, strlen(MetroHash128::test_string), hash, 0); + if (memcmp(hash, MetroHash128::test_seed_0, 16) != 0) return false; + + MetroHash128::Hash(key, strlen(MetroHash128::test_string), hash, 1); + if (memcmp(hash, MetroHash128::test_seed_1, 16) != 0) return false; + + // verify incremental implementation + MetroHash128 metro; + + metro.Initialize(0); + metro.Update(reinterpret_cast(MetroHash128::test_string), strlen(MetroHash128::test_string)); + metro.Finalize(hash); + if (memcmp(hash, MetroHash128::test_seed_0, 16) != 0) return false; + + metro.Initialize(1); + metro.Update(reinterpret_cast(MetroHash128::test_string), strlen(MetroHash128::test_string)); + metro.Finalize(hash); + if (memcmp(hash, MetroHash128::test_seed_1, 16) != 0) return false; + + return true; +} + + +void metrohash128_1(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out) +{ + static const uint64_t k0 = 0xC83A91E1; + static const uint64_t k1 = 0x8648DBDB; + static const uint64_t k2 = 0x7BDEC03B; + static const uint64_t k3 = 0x2F5870A5; + + const uint8_t * ptr = reinterpret_cast(key); + const uint8_t * const end = ptr + len; + + uint64_t v[4]; + + v[0] = ((static_cast(seed) - k0) * k3) + len; + v[1] = ((static_cast(seed) + k1) * k2) + len; + + if (len >= 32) + { + v[2] = ((static_cast(seed) + k0) * k2) + len; + v[3] = ((static_cast(seed) - k1) * k3) + len; + + do + { + v[0] += read_u64(ptr) * k0; ptr += 8; v[0] = rotate_right(v[0],29) + v[2]; + v[1] += read_u64(ptr) * k1; ptr += 8; v[1] = rotate_right(v[1],29) + v[3]; + v[2] += read_u64(ptr) * k2; ptr += 8; v[2] = rotate_right(v[2],29) + v[0]; + v[3] += read_u64(ptr) * k3; ptr += 8; v[3] = rotate_right(v[3],29) + v[1]; + } + while (ptr <= (end - 32)); + + v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 26) * k1; + v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 26) * k0; + v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 26) * k1; + v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 30) * k0; + } + + if ((end - ptr) >= 16) + { + v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],33) * k3; + v[1] += read_u64(ptr) * k2; ptr += 8; v[1] = rotate_right(v[1],33) * k3; + v[0] ^= rotate_right((v[0] * k2) + v[1], 17) * k1; + v[1] ^= rotate_right((v[1] * k3) + v[0], 17) * k0; + } + + if ((end - ptr) >= 8) + { + v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],33) * k3; + v[0] ^= rotate_right((v[0] * k2) + v[1], 20) * k1; + } + + if ((end - ptr) >= 4) + { + v[1] += read_u32(ptr) * k2; ptr += 4; v[1] = rotate_right(v[1],33) * k3; + v[1] ^= rotate_right((v[1] * k3) + v[0], 18) * k0; + } + + if ((end - ptr) >= 2) + { + v[0] += read_u16(ptr) * k2; ptr += 2; v[0] = rotate_right(v[0],33) * k3; + v[0] ^= rotate_right((v[0] * k2) + v[1], 24) * k1; + } + + if ((end - ptr) >= 1) + { + v[1] += read_u8 (ptr) * k2; v[1] = rotate_right(v[1],33) * k3; + v[1] ^= rotate_right((v[1] * k3) + v[0], 24) * k0; + } + + v[0] += rotate_right((v[0] * k0) + v[1], 13); + v[1] += rotate_right((v[1] * k1) + v[0], 37); + v[0] += rotate_right((v[0] * k2) + v[1], 13); + v[1] += rotate_right((v[1] * k3) + v[0], 37); + + // do any endian conversion here + + memcpy(out, v, 16); +} + + +void metrohash128_2(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out) +{ + static const uint64_t k0 = 0xD6D018F5; + static const uint64_t k1 = 0xA2AA033B; + static const uint64_t k2 = 0x62992FC1; + static const uint64_t k3 = 0x30BC5B29; + + const uint8_t * ptr = reinterpret_cast(key); + const uint8_t * const end = ptr + len; + + uint64_t v[4]; + + v[0] = ((static_cast(seed) - k0) * k3) + len; + v[1] = ((static_cast(seed) + k1) * k2) + len; + + if (len >= 32) + { + v[2] = ((static_cast(seed) + k0) * k2) + len; + v[3] = ((static_cast(seed) - k1) * k3) + len; + + do + { + v[0] += read_u64(ptr) * k0; ptr += 8; v[0] = rotate_right(v[0],29) + v[2]; + v[1] += read_u64(ptr) * k1; ptr += 8; v[1] = rotate_right(v[1],29) + v[3]; + v[2] += read_u64(ptr) * k2; ptr += 8; v[2] = rotate_right(v[2],29) + v[0]; + v[3] += read_u64(ptr) * k3; ptr += 8; v[3] = rotate_right(v[3],29) + v[1]; + } + while (ptr <= (end - 32)); + + v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 33) * k1; + v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 33) * k0; + v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 33) * k1; + v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 33) * k0; + } + + if ((end - ptr) >= 16) + { + v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],29) * k3; + v[1] += read_u64(ptr) * k2; ptr += 8; v[1] = rotate_right(v[1],29) * k3; + v[0] ^= rotate_right((v[0] * k2) + v[1], 29) * k1; + v[1] ^= rotate_right((v[1] * k3) + v[0], 29) * k0; + } + + if ((end - ptr) >= 8) + { + v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],29) * k3; + v[0] ^= rotate_right((v[0] * k2) + v[1], 29) * k1; + } + + if ((end - ptr) >= 4) + { + v[1] += read_u32(ptr) * k2; ptr += 4; v[1] = rotate_right(v[1],29) * k3; + v[1] ^= rotate_right((v[1] * k3) + v[0], 25) * k0; + } + + if ((end - ptr) >= 2) + { + v[0] += read_u16(ptr) * k2; ptr += 2; v[0] = rotate_right(v[0],29) * k3; + v[0] ^= rotate_right((v[0] * k2) + v[1], 30) * k1; + } + + if ((end - ptr) >= 1) + { + v[1] += read_u8 (ptr) * k2; v[1] = rotate_right(v[1],29) * k3; + v[1] ^= rotate_right((v[1] * k3) + v[0], 18) * k0; + } + + v[0] += rotate_right((v[0] * k0) + v[1], 33); + v[1] += rotate_right((v[1] * k1) + v[0], 33); + v[0] += rotate_right((v[0] * k2) + v[1], 33); + v[1] += rotate_right((v[1] * k3) + v[0], 33); + + // do any endian conversion here + + memcpy(out, v, 16); +} + diff --git a/extern/metrohash128/metrohash128.h b/extern/metrohash128/metrohash128.h new file mode 100644 index 0000000..bda65ae --- /dev/null +++ b/extern/metrohash128/metrohash128.h @@ -0,0 +1,82 @@ +// metrohash128.h +// +// Copyright 2015-2018 J. Andrew Rogers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef METROHASH_METROHASH_128_H +#define METROHASH_METROHASH_128_H + +#include +#include + +typedef std::pair _uint128_t; + +class MetroHash128 +{ +public: + static const uint32_t bits = 128; + + // Constructor initializes the same as Initialize() + MetroHash128(const uint64_t seed=0); + + // Initializes internal state for new hash with optional seed + void Initialize(const uint64_t seed=0); + + // Update the hash state with a string of bytes. If the length + // is sufficiently long, the implementation switches to a bulk + // hashing algorithm directly on the argument buffer for speed. + void Update(const void* buffer, const uint64_t length) { + Update(reinterpret_cast(buffer), length); + } + void Update(const uint8_t* buffer, const uint64_t length); + template + void Update(const T& x) { + Update(&x, sizeof(x)); + } + + // Constructs the final hash and writes it to the argument buffer. + // After a hash is finalized, this instance must be Initialized()-ed + // again or the behavior of Update() and Finalize() is undefined. + void Finalize(uint8_t * const hash); + + // A non-incremental function implementation. This can be significantly + // faster than the incremental implementation for some usage patterns. + static void Hash(const uint8_t * buffer, const uint64_t length, uint8_t * const hash, const uint64_t seed=0); + + // Does implementation correctly execute test vectors? + static bool ImplementationVerified(); + + // test vectors -- Hash(test_string, seed=0) => test_seed_0 + static const char * test_string; + static const uint8_t test_seed_0[16]; + static const uint8_t test_seed_1[16]; + +private: + static const uint64_t k0 = 0xC83A91E1; + static const uint64_t k1 = 0x8648DBDB; + static const uint64_t k2 = 0x7BDEC03B; + static const uint64_t k3 = 0x2F5870A5; + + struct { uint64_t v[4]; } state; + struct { uint8_t b[32]; } input; + uint64_t bytes; +}; + + +// Legacy 128-bit hash functions -- do not use +void metrohash128_1(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out); +void metrohash128_2(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out); + + +#endif // #ifndef METROHASH_METROHASH_128_H diff --git a/extern/metrohash128/platform.h b/extern/metrohash128/platform.h new file mode 100644 index 0000000..31291b9 --- /dev/null +++ b/extern/metrohash128/platform.h @@ -0,0 +1,50 @@ +// platform.h +// +// Copyright 2015-2018 J. Andrew Rogers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef METROHASH_PLATFORM_H +#define METROHASH_PLATFORM_H + +#include + +// rotate right idiom recognized by most compilers +inline static uint64_t rotate_right(uint64_t v, unsigned k) +{ + return (v >> k) | (v << (64 - k)); +} + +// unaligned reads, fast and safe on Nehalem and later microarchitectures +inline static uint64_t read_u64(const void * const ptr) +{ + return static_cast(*reinterpret_cast(ptr)); +} + +inline static uint64_t read_u32(const void * const ptr) +{ + return static_cast(*reinterpret_cast(ptr)); +} + +inline static uint64_t read_u16(const void * const ptr) +{ + return static_cast(*reinterpret_cast(ptr)); +} + +inline static uint64_t read_u8 (const void * const ptr) +{ + return static_cast(*reinterpret_cast(ptr)); +} + + +#endif // #ifndef METROHASH_PLATFORM_H diff --git a/extern/phmap/.appveyor_old.yml b/extern/phmap/.appveyor_old.yml new file mode 100644 index 0000000..c9b9286 --- /dev/null +++ b/extern/phmap/.appveyor_old.yml @@ -0,0 +1,57 @@ +# Use the Appveyor build number for naming the build. +# src: https://www.appveyor.com/docs/build-configuration/#build-versioning +version: '{Windows}' +# see https://www.appveyor.com/docs/how-to/repository-shallow-clone/ +shallow_clone: true + +platform: x64 + +environment: + matrix: +# CMake + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + VS: 2017 + CONFIG: Release + TEST: OFF + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + VS: 2017 + CONFIG: Release + TEST: ON + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + VS: 2017 + CONFIG: Debug + TEST: ON + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + VS: 2015 + CONFIG: Release + TEST: OFF + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + VS: 2015 + CONFIG: Release + TEST: ON + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + VS: 2015 + CONFIG: Debug + TEST: ON + +matrix: + fast_finish: false + +before_build: + # see https://www.appveyor.com/docs/lang/cpp/#visual-studio-2017 + - if "%VS%"=="2017" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" + - if "%VS%"=="2017" set CMAKE_GENERATOR="Visual Studio 15 2017 Win64" + # see https://www.appveyor.com/docs/lang/cpp/#visual-studio-2015 + - if "%VS%"=="2015" call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 + - if "%VS%"=="2015" call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 + - if "%VS%"=="2015" set CMAKE_GENERATOR="Visual Studio 14 2015 Win64" + +build_script: + - cmake --version + - cmake -H. -Bbuild -DPHMAP_BUILD_TESTS=%TEST% -DPHMAP_BUILD_EXAMPLES=%TEST% -G %CMAKE_GENERATOR% + - cmake --build build --config %CONFIG% --target ALL_BUILD -- /maxcpucount + +test_script: + - if "%TEST%"=="ON" set CTEST_OUTPUT_ON_FAILURE=1 + - if "%TEST%"=="ON" cmake --build build --config %CONFIG% --target RUN_TESTS diff --git a/extern/phmap/.gitattributes b/extern/phmap/.gitattributes new file mode 100644 index 0000000..3f8c819 --- /dev/null +++ b/extern/phmap/.gitattributes @@ -0,0 +1,2 @@ +* linguist-vendored +*.cc linguist-vendored=false diff --git a/extern/phmap/.github/FUNDING.yml b/extern/phmap/.github/FUNDING.yml new file mode 100644 index 0000000..24008d5 --- /dev/null +++ b/extern/phmap/.github/FUNDING.yml @@ -0,0 +1 @@ +github: greg7mdp diff --git a/extern/phmap/.github/workflows/linux.yml b/extern/phmap/.github/workflows/linux.yml new file mode 100644 index 0000000..86a472a --- /dev/null +++ b/extern/phmap/.github/workflows/linux.yml @@ -0,0 +1,25 @@ +name: Linux + +on: + push: + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + compiler: [g++, clang++] + flags: [-std=c++11, -std=c++17] + optimize: [-O2] + steps: + - name: Checkout + uses: actions/checkout@v2.0.0 + - name: Build and test + env: + CXX: ${{ matrix.compiler }} + CXXFLAGS: ${{ matrix.flags }} ${{ matrix.optimize }} + run: | + mkdir build && cd build && cmake -DPHMAP_BUILD_TESTS=ON -DPHMAP_BUILD_EXAMPLES=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_BUILD_TYPE=Release .. && cmake --build . && make test diff --git a/extern/phmap/.github/workflows/macos.yml b/extern/phmap/.github/workflows/macos.yml new file mode 100644 index 0000000..c20934b --- /dev/null +++ b/extern/phmap/.github/workflows/macos.yml @@ -0,0 +1,25 @@ +name: MacOS + +on: + push: + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + compiler: [g++, clang++] + flags: [-std=c++11, -std=c++17] + optimize: [-O2] + steps: + - name: Checkout + uses: actions/checkout@v2.0.0 + - name: Build and test + env: + CXX: ${{ matrix.compiler }} + CXXFLAGS: ${{ matrix.flags }} ${{ matrix.optimize }} + run: | + mkdir build && cd build && cmake -DPHMAP_BUILD_TESTS=ON -DPHMAP_BUILD_EXAMPLES=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_BUILD_TYPE=Release .. && cmake --build . && make test diff --git a/extern/phmap/.github/workflows/windows.yml b/extern/phmap/.github/workflows/windows.yml new file mode 100644 index 0000000..0fb07f7 --- /dev/null +++ b/extern/phmap/.github/workflows/windows.yml @@ -0,0 +1,25 @@ +name: Windows + +on: + push: + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest] + flags: ["/std:c++11", "/std:c++latest"] + optimize: [/O2] + steps: + - name: Checkout + uses: actions/checkout@v2.0.0 + - name: Build and test + env: + CXX: ${{ matrix.compiler }} + CXXFLAGS: ${{ matrix.flags }} ${{ matrix.optimize }} + CTEST_OUTPUT_ON_FAILURE: 1 + run: | + cmake -Bbuild -DPHMAP_BUILD_TESTS=ON -DPHMAP_BUILD_EXAMPLES=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_BUILD_TYPE=Release && cmake --build build --target ALL_BUILD && cmake --build build --target RUN_TESTS diff --git a/extern/phmap/.gitignore b/extern/phmap/.gitignore new file mode 100644 index 0000000..b208e24 --- /dev/null +++ b/extern/phmap/.gitignore @@ -0,0 +1,8 @@ +VagrantFile +benchmark/build +benchmark/output +benchmark/charts.html +build* +.vagrant +**/.vscode +TAGS diff --git a/extern/phmap/CMakeLists.txt b/extern/phmap/CMakeLists.txt new file mode 100644 index 0000000..3fd9d58 --- /dev/null +++ b/extern/phmap/CMakeLists.txt @@ -0,0 +1,150 @@ +cmake_minimum_required(VERSION 3.8) + +list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include(DetectVersion) + +cmake_policy(SET CMP0048 NEW) ## set VERSION as documented by the project() command. +set(CMAKE_CXX_STANDARD 11) ## compile with C++11 support +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +project(phmap VERSION ${DETECTED_PHMAP_VERSION} LANGUAGES CXX) + +set(PHMAP_DIR parallel_hashmap) +set(PHMAP_HEADERS ${PHMAP_DIR}/phmap.h + ${PHMAP_DIR}/phmap_base.h + ${PHMAP_DIR}/phmap_bits.h + ${PHMAP_DIR}/phmap_utils.h + ${PHMAP_DIR}/phmap_config.h) +set(CMAKE_SUPPRESS_REGENERATION true) ## suppress ZERO_CHECK project + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) +include(helpers) +include_directories("${CMAKE_CURRENT_SOURCE_DIR}") + +add_library(${PROJECT_NAME} INTERFACE) + +target_sources(${PROJECT_NAME} INTERFACE ${PHMAP_HEADERS}) + +target_include_directories( + ${PROJECT_NAME} INTERFACE + $ + $) + +install( + DIRECTORY ${PROJECT_SOURCE_DIR}/${PHMAP_DIR}/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PHMAP_DIR}) + +install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets) + +export(EXPORT ${PROJECT_NAME}-targets + FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") + +## ------------------------- building tests and examples ------------- +option(PHMAP_BUILD_TESTS "Whether or not to build the tests" OFF) +option(PHMAP_BUILD_EXAMPLES "Whether or not to build the examples" OFF) + +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") +endif() + +if (PHMAP_BUILD_TESTS) + + include(cmake/DownloadGTest.cmake) + include_directories(${PROJECT_SOURCE_DIR}) + + check_target(gtest) + check_target(gtest_main) + check_target(gmock) + + enable_testing() + + ## ---------------- regular hash maps ---------------------------- + phmap_cc_test(NAME compressed_tuple SRCS "tests/compressed_tuple_test.cc" + DEPS gmock_main) + + phmap_cc_test(NAME container_memory SRCS "tests/container_memory_test.cc" + DEPS gmock_main) + + phmap_cc_test(NAME hash_policy_testing SRCS "tests/hash_policy_testing_test.cc" + DEPS gmock_main) + + phmap_cc_test(NAME node_hash_policy SRCS "tests/node_hash_policy_test.cc" + DEPS gmock_main) + + phmap_cc_test(NAME raw_hash_set SRCS "tests/raw_hash_set_test.cc" + DEPS gmock_main) + + phmap_cc_test(NAME raw_hash_set_allocator SRCS "tests/raw_hash_set_allocator_test.cc" + DEPS gmock_main) + + ## ---------------- regular hash maps ---------------------------- + phmap_cc_test(NAME flat_hash_set SRCS "tests/flat_hash_set_test.cc" + COPTS "-DUNORDERED_SET_CXX17" DEPS gmock_main) + + phmap_cc_test(NAME flat_hash_map SRCS "tests/flat_hash_map_test.cc" + DEPS gmock_main) + + phmap_cc_test(NAME node_hash_map SRCS "tests/node_hash_map_test.cc" + DEPS gmock_main) + + phmap_cc_test(NAME node_hash_set SRCS "tests/node_hash_set_test.cc" + COPTS "-DUNORDERED_SET_CXX17" DEPS gmock_main) + + ## --------------- parallel hash maps ----------------------------------------------- + phmap_cc_test(NAME parallel_flat_hash_map SRCS "tests/parallel_flat_hash_map_test.cc" + COPTS "-DUNORDERED_MAP_CXX17" DEPS gmock_main) + + phmap_cc_test(NAME parallel_flat_hash_set SRCS "tests/parallel_flat_hash_set_test.cc" + COPTS "-DUNORDERED_SET_CXX17" DEPS gmock_main) + + phmap_cc_test(NAME parallel_node_hash_map SRCS "tests/parallel_node_hash_map_test.cc" + DEPS gmock_main) + + phmap_cc_test(NAME parallel_node_hash_set SRCS "tests/parallel_node_hash_set_test.cc" + COPTS "-DUNORDERED_SET_CXX17" DEPS gmock_main) + + phmap_cc_test(NAME parallel_flat_hash_map_mutex SRCS "tests/parallel_flat_hash_map_mutex_test.cc" + COPTS "-DUNORDERED_MAP_CXX17" DEPS gmock_main) + + phmap_cc_test(NAME dump_load SRCS "tests/dump_load_test.cc" + COPTS "-DUNORDERED_MAP_CXX17" DEPS gmock_main) + + ## --------------- btree ----------------------------------------------- + phmap_cc_test(NAME btree SRCS "tests/btree_test.cc" + CLOPTS "-w" DEPS gmock_main) + + +endif() + +if (PHMAP_BUILD_EXAMPLES) + if(NOT MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wdisabled-optimization -Winit-self -Wlogical-op -Wmissing-include-dirs -Woverloaded-virtual -Wredundant-decls -Wshadow -Wstrict-null-sentinel -Wswitch-default -Wno-unused -Wno-unknown-warning-option -Wno-gnu-zero-variadic-macro-arguments") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /Zc:__cplusplus") + endif() + + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + + add_executable(ex_allmaps examples/allmaps.cc phmap.natvis) + add_executable(ex_basic examples/basic.cc phmap.natvis) + add_executable(ex_bench examples/bench.cc phmap.natvis) + add_executable(ex_emplace examples/emplace.cc phmap.natvis) + add_executable(ex_serialize examples/serialize.cc phmap.natvis) + target_include_directories(ex_serialize PUBLIC $) + add_executable(ex_hash_std examples/hash_std.cc phmap.natvis) + add_executable(ex_hash_value examples/hash_value.cc phmap.natvis) + add_executable(ex_two_files examples/f1.cc examples/f2.cc phmap.natvis) + add_executable(ex_insert_bench examples/insert_bench.cc phmap.natvis) + add_executable(ex_knucleotide examples/knucleotide.cc phmap.natvis) + add_executable(ex_dump_load examples/dump_load.cc phmap.natvis) + add_executable(ex_btree examples/btree.cc phmap.natvis) + add_executable(ex_matt examples/matt.cc phmap.natvis) + + target_link_libraries(ex_knucleotide Threads::Threads) + target_link_libraries(ex_bench Threads::Threads) +endif() + diff --git a/extern/phmap/LICENSE b/extern/phmap/LICENSE new file mode 100644 index 0000000..62589ed --- /dev/null +++ b/extern/phmap/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/extern/phmap/README.md b/extern/phmap/README.md new file mode 100644 index 0000000..4ffa40a --- /dev/null +++ b/extern/phmap/README.md @@ -0,0 +1,305 @@ + + + +# The Parallel Hashmap [![Linux](https://github.com/greg7mdp/parallel-hashmap/actions/workflows/linux.yml/badge.svg)](https://github.com/greg7mdp/parallel-hashmap/actions/workflows/linux.yml) [![MacOS](https://github.com/greg7mdp/parallel-hashmap/actions/workflows/macos.yml/badge.svg)](https://github.com/greg7mdp/parallel-hashmap/actions/workflows/macos.yml) [![Windows](https://github.com/greg7mdp/parallel-hashmap/actions/workflows/windows.yml/badge.svg)](https://github.com/greg7mdp/parallel-hashmap/actions/workflows/windows.yml) + +## Overview + +This repository aims to provide a set of excellent **hash map** implementations, as well as a **btree** alternative to std::map and std::set, with the following characteristics: + +- **Header only**: nothing to build, just copy the `parallel_hashmap` directory to your project and you are good to go. + +- **drop-in replacement** for `std::unordered_map`, `std::unordered_set`, `std::map` and `std::set` + +- Compiler with **C++11 support** required, **C++14 and C++17 APIs are provided (such as `try_emplace`)** + +- **Very efficient**, significantly faster than your compiler's unordered map/set or Boost's, or than [sparsepp](https://github.com/greg7mdp/sparsepp) + +- **Memory friendly**: low memory usage, although a little higher than [sparsepp](https://github.com/greg7mdp/sparsepp) + +- Supports **heterogeneous lookup** + +- Easy to **forward declare**: just include `phmap_fwd_decl.h` in your header files to forward declare Parallel Hashmap containers [note: this does not work currently for hash maps with pointer keys] + +- **Dump/load** feature: when a `flat` hash map stores data that is `std::trivially_copyable`, the table can be dumped to disk and restored as a single array, very efficiently, and without requiring any hash computation. This is typically about 10 times faster than doing element-wise serialization to disk, but it will use 10% to 60% extra disk space. See `examples/serialize.cc`. _(flat hash map/set only)_ + +- **Tested** on Windows (vs2015 & vs2017, vs2019, Intel compiler 18 and 19), linux (g++ 4.8.4, 5, 6, 7, 8, clang++ 3.9, 4.0, 5.0) and MacOS (g++ and clang++) - click on travis and appveyor icons above for detailed test status. + +- Automatic support for **boost's hash_value()** method for providing the hash function (see `examples/hash_value.h`). Also default hash support for `std::pair` and `std::tuple`. + +- **natvis** visualization support in Visual Studio _(hash map/set only)_ + +@byronhe kindly provided this [Chinese translation](https://byronhe.com/post/2020/11/10/parallel-hashmap-btree-fast-multi-thread-intro/) of the README.md. + + +## Fast *and* memory friendly + +Click here [For a full writeup explaining the design and benefits of the Parallel Hashmap](https://greg7mdp.github.io/parallel-hashmap/). + +The hashmaps and btree provided here are built upon those open sourced by Google in the Abseil library. The hashmaps use closed hashing, where values are stored directly into a memory array, avoiding memory indirections. By using parallel SSE2 instructions, these hashmaps are able to look up items by checking 16 slots in parallel, allowing the implementation to remain fast even when the table is filled up to 87.5% capacity. + +> **IMPORTANT:** This repository borrows code from the [abseil-cpp](https://github.com/abseil/abseil-cpp) repository, with modifications, and may behave differently from the original. This repository is an independent work, with no guarantees implied or provided by the authors. Please visit [abseil-cpp](https://github.com/abseil/abseil-cpp) for the official Abseil libraries. + +## Installation + +Copy the parallel_hashmap directory to your project. Update your include path. That's all. + +If you are using Visual Studio, you probably want to add `phmap.natvis` to your projects. This will allow for a clear display of the hash table contents in the debugger. + +> A cmake configuration files (CMakeLists.txt) is provided for building the tests and examples. Command for building and running the tests is: `mkdir build && cd build && cmake -DPHMAP_BUILD_TESTS=ON -DPHMAP_BUILD_EXAMPLES=ON .. && cmake --build . && make test` + +## Example + +```c++ +#include +#include +#include + +using phmap::flat_hash_map; + +int main() +{ + // Create an unordered_map of three strings (that map to strings) + flat_hash_map email = + { + { "tom", "tom@gmail.com"}, + { "jeff", "jk@gmail.com"}, + { "jim", "jimg@microsoft.com"} + }; + + // Iterate and print keys and values + for (const auto& n : email) + std::cout << n.first << "'s email is: " << n.second << "\n"; + + // Add a new entry + email["bill"] = "bg@whatever.com"; + + // and print it + std::cout << "bill's email is: " << email["bill"] << "\n"; + + return 0; +} +``` + +## Various hash maps and their pros and cons + +The header `parallel_hashmap/phmap.h` provides the implementation for the following eight hash tables: +- phmap::flat_hash_set +- phmap::flat_hash_map +- phmap::node_hash_set +- phmap::node_hash_map +- phmap::parallel_flat_hash_set +- phmap::parallel_flat_hash_map +- phmap::parallel_node_hash_set +- phmap::parallel_node_hash_map + +The header `parallel_hashmap/btree.h` provides the implementation for the following btree-based ordered containers: +- phmap::btree_set +- phmap::btree_map +- phmap::btree_multiset +- phmap::btree_multimap + +The btree containers are direct ports from Abseil, and should behave exactly the same as the Abseil ones, modulo small differences (such as supporting std::string_view instead of absl::string_view, and being forward declarable). + +When btrees are mutated, values stored within can be moved in memory. This means that pointers or iterators to values stored in btree containers can be invalidated when that btree is modified. This is a significant difference with `std::map` and `std::set`, as the std containers do offer a guarantee of pointer stability. The same is true for the 'flat' hash maps and sets. + +The full types with template parameters can be found in the [parallel_hashmap/phmap_fwd_decl.h](https://raw.githubusercontent.com/greg7mdp/parallel-hashmap/master/parallel_hashmap/phmap_fwd_decl.h) header, which is useful for forward declaring the Parallel Hashmaps when necessary. + +**Key decision points for hash containers:** + +- The `flat` hash maps will move the keys and values in memory. So if you keep a pointer to something inside a `flat` hash map, this pointer may become invalid when the map is mutated. The `node` hash maps don't, and should be used instead if this is a problem. + +- The `flat` hash maps will use less memory, and usually be faster than the `node` hash maps, so use them if you can. the exception is when the values inserted in the hash map are large (say more than 100 bytes [*needs testing*]) and costly to move. + +- The `parallel` hash maps are preferred when you have a few hash maps that will store a very large number of values. The `non-parallel` hash maps are preferred if you have a large number of hash maps, each storing a relatively small number of values. + +- The benefits of the `parallel` hash maps are: + a. reduced peak memory usage (when resizing), and + b. multithreading support (and inherent internal parallelism) + +**Key decision points for btree containers:** + +Btree containers are ordered containers, which can be used as alternatives to `std::map` and `std::set`. They store multiple values in each tree node, and are therefore more cache friendly and use significantly less memory. + +Btree containers will usually be preferable to the default red-black trees of the STL, except when: +- pointer stability or iterator stability is required +- the value_type is large and expensive to move + +When an ordering is not needed, a hash container is typically a better choice than a btree one. + +## Changes to Abseil's hashmaps + +- The default hash framework is std::hash, not absl::Hash. However, if you prefer the default to be the Abseil hash framework, include the Abseil headers before `phmap.h` and define the preprocessor macro `PHMAP_USE_ABSL_HASH`. + +- The `erase(iterator)` and `erase(const_iterator)` both return an iterator to the element following the removed element, as does the std::unordered_map. A non-standard `void _erase(iterator)` is provided in case the return value is not needed. + +- No new types, such as `absl::string_view`, are provided. All types with a `std::hash<>` implementation are supported by phmap tables (including `std::string_view` of course if your compiler provides it). + +- The Abseil hash tables internally randomize a hash seed, so that the table iteration order is non-deterministic. This can be useful to prevent *Denial Of Service* attacks when a hash table is used for a customer facing web service, but it can make debugging more difficult. The *phmap* hashmaps by default do **not** implement this randomization, but it can be enabled by adding `#define PHMAP_NON_DETERMINISTIC 1` before including the header `phmap.h` (as is done in raw_hash_set_test.cc). + +- Unlike the Abseil hash maps, we do an internal mixing of the hash value provided. This prevents serious degradation of the hash table performance when the hash function provided by the user has poor entropy distribution. The cost in performance is very minimal, and this helps provide reliable performance even with *imperfect* hash functions. + + +## Memory usage + +| type | memory usage | additional *peak* memory usage when resizing | +|-----------------------|-------------------|-----------------------------------------------| +| flat tables | ![flat_mem_usage](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/flat_mem_usage.png?raw=true) | ![flat_peak_usage](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/flat_peak.png?raw=true) | +| node tables | ![node_mem_usage](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/node_mem_usage.png?raw=true) | ![node_peak_usage](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/node_peak.png?raw=true) | +| parallel flat tables | ![flat_mem_usage](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/flat_mem_usage.png?raw=true) | ![parallel_flat_peak](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/parallel_flat_peak.png?raw=true) | +| parallel node tables | ![node_mem_usage](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/node_mem_usage.png?raw=true) | ![parallel_node_peak](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/parallel_node_peak.png?raw=true) | + + +- *size()* is the number of values in the container, as returned by the size() method +- *load_factor()* is the ratio: `size() / bucket_count()`. It varies between 0.4375 (just after the resize) to 0.875 (just before the resize). The size of the bucket array doubles at each resize. +- the value 9 comes from `sizeof(void *) + 1`, as the *node* hash maps store one pointer plus one byte of metadata for each entry in the bucket array. +- flat tables store the values, plus one byte of metadata per value), directly into the bucket array, hence the `sizeof(C::value_type) + 1`. +- the additional peak memory usage (when resizing) corresponds the the old bucket array (half the size of the new one, hence the 0.5), which contains the values to be copied to the new bucket array, and which is freed when the values have been copied. +- the *parallel* hashmaps, when created with a template parameter N=4, create 16 submaps. When the hash values are well distributed, and in single threaded mode, only one of these 16 submaps resizes at any given time, hence the factor `0.03` roughly equal to `0.5 / 16` + +## Iterator invalidation for hash containers + +The rules are the same as for `std::unordered_map`, and are valid for all the phmap hash containers: + + +| Operations | Invalidated | +|-------------------------------------------|----------------------------| +| All read only operations, swap, std::swap | Never | +| clear, rehash, reserve, operator= | Always | +| insert, emplace, emplace_hint, operator[] | Only if rehash triggered | +| erase | Only to the element erased | + +## Iterator invalidation for btree containers + +Unlike for `std::map` and `std::set`, any mutating operation may invalidate existing iterators to btree containers. + + +| Operations | Invalidated | +|-------------------------------------------|----------------------------| +| All read only operations, swap, std::swap | Never | +| clear, operator= | Always | +| insert, emplace, emplace_hint, operator[] | Yes | +| erase | Yes | + +## Example 2 - providing a hash function for a user-defined class + +In order to use a flat_hash_set or flat_hash_map, a hash function should be provided. This can be done with one of the following methods: + +- Provide a hash functor via the HashFcn template parameter + +- As with boost, you may add a `hash_value()` friend function in your class. + +For example: + +```c++ +#include // minimal header providing phmap::HashState() +#include +using std::string; + +struct Person +{ + bool operator==(const Person &o) const + { + return _first == o._first && _last == o._last && _age == o._age; + } + + friend size_t hash_value(const Person &p) + { + return phmap::HashState().combine(0, p._first, p._last, p._age); + } + + string _first; + string _last; + int _age; +}; +``` + +- Inject a specialization of `std::hash` for the class into the "std" namespace. We provide a convenient and small header `phmap_utils.h` which allows to easily add such specializations. + +For example: + +### file "Person.h" + +```c++ +#include // minimal header providing phmap::HashState() +#include +using std::string; + +struct Person +{ + bool operator==(const Person &o) const + { + return _first == o._first && _last == o._last && _age == o._age; + } + + string _first; + string _last; + int _age; +}; + +namespace std +{ + // inject specialization of std::hash for Person into namespace std + // ---------------------------------------------------------------- + template<> struct hash + { + std::size_t operator()(Person const &p) const + { + return phmap::HashState().combine(0, p._first, p._last, p._age); + } + }; +} +``` + +The `std::hash` specialization for `Person` combines the hash values for both first and last name and age, using the convenient phmap::HashState() function, and returns the combined hash value. + +### file "main.cpp" + +```c++ +#include "Person.h" // defines Person with std::hash specialization + +#include +#include + +int main() +{ + // As we have defined a specialization of std::hash() for Person, + // we can now create sparse_hash_set or sparse_hash_map of Persons + // ---------------------------------------------------------------- + phmap::flat_hash_set persons = + { { "John", "Mitchell", 35 }, + { "Jane", "Smith", 32 }, + { "Jane", "Smith", 30 }, + }; + + for (auto& p: persons) + std::cout << p._first << ' ' << p._last << " (" << p._age << ")" << '\n'; + +} +``` + + +## Thread safety + +Parallel Hashmap containers follow the thread safety rules of the Standard C++ library. In Particular: + +- A single phmap hash table is thread safe for reading from multiple threads. For example, given a hash table A, it is safe to read A from thread 1 and from thread 2 simultaneously. + +- If a single hash table is being written to by one thread, then all reads and writes to that hash table on the same or other threads must be protected. For example, given a hash table A, if thread 1 is writing to A, then thread 2 must be prevented from reading from or writing to A. + +- It is safe to read and write to one instance of a type even if another thread is reading or writing to a different instance of the same type. For example, given hash tables A and B of the same type, it is safe if A is being written in thread 1 and B is being read in thread 2. + +- The *parallel* tables can be made internally thread-safe for concurrent read and write access, by providing a synchronization type (for example [std::mutex](https://en.cppreference.com/w/cpp/thread/mutex)) as the last template argument. Because locking is performed at the *submap* level, a high level of concurrency can still be achieved. Read access can be done safely using `if_contains()`, which passes a reference value to the callback while holding the *submap* lock. Similarly, write access can be done safely using `modify_if`, `try_emplace_l` or `lazy_emplace_l`. However, please be aware that iterators or references returned by standard APIs are not protected by the mutex, so they cannot be used reliably on a hash map which can be changed by another thread. + +- Examples on how to use various mutex types, including boost::mutex, boost::shared_mutex and absl::Mutex can be found in `examples/bench.cc` + + +## Using the Parallel Hashmap from languages other than C++ + +While C++ is the native language of the Parallel Hashmap, we welcome bindings making it available for other languages. One such implementation has been created for Python and is described below: + +- [GetPy - A Simple, Fast, and Small Hash Map for Python](https://github.com/atom-moyer/getpy): GetPy is a thin and robust binding to The Parallel Hashmap (https://github.com/greg7mdp/parallel-hashmap.git) which is the current state of the art for minimal memory overhead and fast runtime speed. The binding layer is supported by PyBind11 (https://github.com/pybind/pybind11.git) which is fast to compile and simple to extend. Serialization is handled by Cereal (https://github.com/USCiLab/cereal.git) which supports streaming binary serialization, a critical feature for the large hash maps this package is designed to support. + +## Acknowledgements + +Many thanks to the Abseil developers for implementing the swiss table and btree data structures (see [abseil-cpp](https://github.com/abseil/abseil-cpp)) upon which this work is based, and to Google for releasing it as open-source. diff --git a/extern/phmap/benchmark/BENCHMARK.md b/extern/phmap/benchmark/BENCHMARK.md new file mode 100644 index 0000000..eb3fecf --- /dev/null +++ b/extern/phmap/benchmark/BENCHMARK.md @@ -0,0 +1,16 @@ +# parallel-hashmap + +How to run these benchmarks +=========================== + +These bencharks were run on windows using Visual Studio 2017, in a cygwin window with the VC++ 2017 compiler env vars (add something like this in your Cygwin.bat: + +CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" + +Running them on linux would require Makefile changes. + +To build and run the tests, just update the path to the abseil libraries in the makefile, and run make. + +Your charts are now in charts.html. + + diff --git a/extern/phmap/benchmark/Makefile b/extern/phmap/benchmark/Makefile new file mode 100644 index 0000000..8ac6b5a --- /dev/null +++ b/extern/phmap/benchmark/Makefile @@ -0,0 +1,63 @@ +CXX=CL -EHsc -DNDEBUG -Fo$@ -O2 +#CXX=CL -EHsc -g -debug -Zi -Fo$@ +#CXX=g++ -ggdb -O2 -lm -std=c++11 -DNDEBUG + +ABSEIL_LIBS=absl_bad_optional_access.lib absl_bad_variant_access.lib absl_base.lib absl_demangle_internal.lib absl_hash.lib absl_int128.lib absl_internal_bad_any_cast_impl.lib absl_internal_city.lib absl_internal_civil_time.lib absl_internal_debugging_internal.lib absl_internal_graphcycles_internal.lib absl_internal_hashtablez_sampler.lib absl_internal_malloc_internal.lib absl_internal_spinlock_wait.lib absl_internal_strings_internal.lib absl_internal_throw_delegate.lib absl_internal_time_zone.lib absl_optional.lib absl_raw_hash_set.lib absl_stacktrace.lib absl_strings.lib absl_symbolize.lib absl_synchronization.lib absl_time.lib + +PROGS = stl_unordered_map sparsepp phmap abseil_flat abseil_parallel_flat phmap_flat +BUILD_PROGS = $(addprefix build/,$(PROGS)) +SIZE = 100000000 +ABSEIL = ../../abseil-cpp +PHMAP_SRC = ../parallel_hashmap + +all: test + +builddir: + @if [ ! -d build ]; then mkdir build; fi + +build/stl_unordered_map: bench.cc Makefile + $(CXX) -DSTL_UNORDERED -I.. bench.cc -o $@ + +build/sparsepp: bench.cc Makefile + $(CXX) -DSPARSEPP -I.. -I../../sparsepp bench.cc -o $@ + +build/phmap: bench.cc Makefile $(PHMAP_SRC)/phmap.h + $(CXX) -DPHMAP -I.. -I$(ABSEIL) bench.cc /MD -o $@ /link /LIBPATH:$(ABSEIL)/build/lib ${ABSEIL_LIBS} + +build/phmap_flat: bench.cc Makefile $(PHMAP_SRC)/phmap.h + $(CXX) -DPHMAP_FLAT -I.. bench.cc /MD -o $@ + +build/abseil_flat: bench.cc Makefile + $(CXX) -DABSEIL_FLAT -I.. -I$(ABSEIL) bench.cc /MD -o $@ /link /LIBPATH:$(ABSEIL)/build/lib ${ABSEIL_LIBS} + +build/abseil_parallel_flat: bench.cc Makefile + $(CXX) -DABSEIL_PARALLEL_FLAT -I.. -I $(ABSEIL) bench.cc /MD -o $@ /link /LIBPATH:$(ABSEIL)/build/lib ${ABSEIL_LIBS} + +build/emplace: emplace.cc Makefile $(PHMAP_SRC)/phmap.h + $(CXX) -DABSEIL_FLAT -I.. -I$(ABSEIL) emplace.cc /MD -o $@ /link /LIBPATH:$(ABSEIL)/build/lib ${ABSEIL_LIBS} + +progs: $(BUILD_PROGS) + +test: builddir progs + -rm -f output + #./build/stl_unordered_map $(SIZE) random >> output + #./build/sparsepp $(SIZE) random >> output + ./build/abseil_flat $(SIZE) random >> output + #./build/phmap_flat $(SIZE) random >> output + ./build/phmap $(SIZE) random >> output + ./build/abseil_parallel_flat $(SIZE) random >> output + python make_chart_data.py < output + +test_cust: + -rm -f output + #./build/abseil_flat $(SIZE) random >> output + #./build/sparsepp $(SIZE) random >> output + ./build/abseil_parallel_flat_5 $(SIZE) random >> output + ./build/abseil_parallel_flat $(SIZE) random >> output + python make_chart_data.py < output + +chart: + python make_chart_data.py < output + +clean: + -rm -fr output build diff --git a/extern/phmap/benchmark/bench.cc b/extern/phmap/benchmark/bench.cc new file mode 100644 index 0000000..479a9e3 --- /dev/null +++ b/extern/phmap/benchmark/bench.cc @@ -0,0 +1,451 @@ +#include + +#ifdef STL_UNORDERED + #include + #define MAPNAME std::unordered_map + #define EXTRAARGS +#elif defined(SPARSEPP) + #define SPP_USE_SPP_ALLOC 1 + #include + #define MAPNAME spp::sparse_hash_map + #define EXTRAARGS +#elif defined(ABSEIL_FLAT) + #include "absl/container/flat_hash_map.h" + #define MAPNAME absl::flat_hash_map + #define EXTRAARGS +#elif defined(PHMAP_FLAT) + #include "parallel_hashmap/phmap.h" + #define MAPNAME phmap::flat_hash_map + #define NMSP phmap + #define EXTRAARGS +#elif defined(ABSEIL_PARALLEL_FLAT) || defined(PHMAP) + #if defined(ABSEIL_PARALLEL_FLAT) + #include "absl/container/parallel_flat_hash_map.h" + #define MAPNAME absl::parallel_flat_hash_map + #define NMSP absl + #define MTX absl::Mutex + #else + #if 1 + // use Abseil's mutex... faster + #include "absl/synchronization/mutex.h" + #define MTX absl::Mutex + #else + #include + #define MTX std::mutex + #endif + + #include "parallel_hashmap/phmap.h" + #define MAPNAME phmap::parallel_flat_hash_map + #define NMSP phmap + #endif + + #define MT_SUPPORT 2 + #if MT_SUPPORT == 1 + // create the parallel_flat_hash_map without internal mutexes, for when + // we programatically ensure that each thread uses different internal submaps + // -------------------------------------------------------------------------- + #define EXTRAARGS , NMSP::priv::hash_default_hash, \ + NMSP::priv::hash_default_eq, \ + std::allocator>, 4, NMSP::NullMutex + #elif MT_SUPPORT == 2 + // create the parallel_flat_hash_map with internal mutexes, for when + // we read/write the same parallel_flat_hash_map from multiple threads, + // without any special precautions. + // -------------------------------------------------------------------------- + #define EXTRAARGS , NMSP::priv::hash_default_hash, \ + NMSP::priv::hash_default_eq, \ + std::allocator>, 4, MTX + #else + #define EXTRAARGS + #endif + +#endif + +#define xstr(s) str(s) +#define str(s) #s + +template +using HashT = MAPNAME; + +using hash_t = HashT; +using str_hash_t = HashT; + +const char *program_slug = xstr(MAPNAME); // "_4"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "parallel_hashmap/meminfo.h" +#include +using std::vector; + +int64_t _abs(int64_t x) { return (x < 0) ? -x : x; } + + +// -------------------------------------------------------------------------- +class Timer +{ + typedef std::chrono::high_resolution_clock high_resolution_clock; + typedef std::chrono::milliseconds milliseconds; + +public: + explicit Timer(bool run = false) { if (run) reset(); } + void reset() { _start = high_resolution_clock::now(); } + + milliseconds elapsed() const + { + return std::chrono::duration_cast(high_resolution_clock::now() - _start); + } + +private: + high_resolution_clock::time_point _start; +}; + + +// -------------------------------------------------------------------------- +// from: https://github.com/preshing/RandomSequence +// -------------------------------------------------------------------------- +class RSU +{ +private: + unsigned int m_index; + unsigned int m_intermediateOffset; + + static unsigned int permuteQPR(unsigned int x) + { + static const unsigned int prime = 4294967291u; + if (x >= prime) + return x; // The 5 integers out of range are mapped to themselves. + unsigned int residue = ((unsigned long long) x * x) % prime; + return (x <= prime / 2) ? residue : prime - residue; + } + +public: + RSU(unsigned int seedBase, unsigned int seedOffset) + { + m_index = permuteQPR(permuteQPR(seedBase) + 0x682f0161); + m_intermediateOffset = permuteQPR(permuteQPR(seedOffset) + 0x46790905); + } + + unsigned int next() + { + return permuteQPR((permuteQPR(m_index++) + m_intermediateOffset) ^ 0x5bf03635); + } +}; + +// -------------------------------------------------------------------------- +char * new_string_from_integer(int num) +{ + int ndigits = num == 0 ? 1 : (int)log10(num) + 1; + char * str = (char *)malloc(ndigits + 1); + sprintf(str, "%d", num); + return str; +} + +// -------------------------------------------------------------------------- +template +void _fill(vector &v) +{ + srand(1); // for a fair/deterministic comparison + for (size_t i = 0, sz = v.size(); i < sz; ++i) + v[i] = (T)(i * 10 + rand() % 10); +} + +// -------------------------------------------------------------------------- +template +void _shuffle(vector &v) +{ + for (size_t n = v.size(); n >= 2; --n) + std::swap(v[n - 1], v[static_cast(rand()) % n]); +} + +// -------------------------------------------------------------------------- +template +Timer _fill_random(vector &v, HT &hash) +{ + _fill(v); + _shuffle(v); + + Timer timer(true); + + for (size_t i = 0, sz = v.size(); i < sz; ++i) + hash.insert(typename HT::value_type(v[i], 0)); + return timer; +} + +// -------------------------------------------------------------------------- +void out(const char* test, int64_t cnt, const Timer &t) +{ + printf("%s,time,%lld,%s,%f\n", test, cnt, program_slug, (float)((double)t.elapsed().count() / 1000)); +} + +// -------------------------------------------------------------------------- +void outmem(const char* test, int64_t cnt, uint64_t mem) +{ + printf("%s,memory,%lld,%s,%lld\n", test, cnt, program_slug, mem); +} + +static bool all_done = false; +static int64_t num_keys[16] = { 0 }; +static int64_t loop_idx = 0; +static int64_t inner_cnt = 0; +static const char *test = "random"; + +// -------------------------------------------------------------------------- +template +void _fill_random_inner(int64_t cnt, HT &hash, RSU &rsu) +{ + for (int64_t i=0; i +void _fill_random_inner_mt(int64_t cnt, HT &hash, RSU &rsu) +{ + constexpr int64_t num_threads = 8; // has to be a power of two + std::unique_ptr threads[num_threads]; + + auto thread_fn = [&hash, cnt, num_threads](int64_t thread_idx, RSU rsu) { +#if MT_SUPPORT + size_t modulo = hash.subcnt() / num_threads; // subcnt() returns the number of submaps + + for (int64_t i=0; ijoin(); +} + +// -------------------------------------------------------------------------- +size_t total_num_keys() +{ + size_t n = 0; + for (int i=0; i<16; ++i) + n += num_keys[i]; + return n; +} + +// -------------------------------------------------------------------------- +template +Timer _fill_random2(int64_t cnt, HT &hash) +{ + test = "random"; + unsigned int seed = 76687; + RSU rsu(seed, seed + 1); + + Timer timer(true); + const int64_t num_loops = 10; + inner_cnt = cnt / num_loops; + + for (int i=0; i<16; ++i) + num_keys[i] = 0; + + for (loop_idx=0; loop_idx +Timer _lookup(vector &v, HT &hash, size_t &num_present) +{ + _fill_random(v, hash); + + num_present = 0; + size_t max_val = v.size() * 10; + Timer timer(true); + + for (size_t i = 0, sz = v.size(); i < sz; ++i) + { + num_present += (size_t)(hash.find(v[i]) != hash.end()); + num_present += (size_t)(hash.find((T)(rand() % max_val)) != hash.end()); + } + return timer; +} + +// -------------------------------------------------------------------------- +template +Timer _delete(vector &v, HT &hash) +{ + _fill_random(v, hash); + _shuffle(v); // don't delete in insertion order + + Timer timer(true); + + for(size_t i = 0, sz = v.size(); i < sz; ++i) + hash.erase(v[i]); + return timer; +} + +// -------------------------------------------------------------------------- +void memlog() +{ + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + uint64_t nbytes_old_out = spp::GetProcessMemoryUsed(); + uint64_t nbytes_old = spp::GetProcessMemoryUsed(); // last non outputted mem measurement + outmem(test, 0, nbytes_old); + int64_t last_loop = 0; + + while (!all_done) + { + uint64_t nbytes = spp::GetProcessMemoryUsed(); + + if ((double)_abs(nbytes - nbytes_old_out) / nbytes_old_out > 0.03 || + (double)_abs(nbytes - nbytes_old) / nbytes_old > 0.01) + { + if ((double)(nbytes - nbytes_old) / nbytes_old > 0.03) + outmem(test, total_num_keys() - 1, nbytes_old); + outmem(test, total_num_keys(), nbytes); + nbytes_old_out = nbytes; + last_loop = loop_idx; + } + else if (loop_idx > last_loop) + { + outmem(test, total_num_keys(), nbytes); + nbytes_old_out = nbytes; + last_loop = loop_idx; + } + nbytes_old = nbytes; + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } +} + + +// -------------------------------------------------------------------------- +int main(int argc, char ** argv) +{ + int64_t i, value = 0; + + if(argc <= 2) + return 1; + + int64_t num_keys = atoi(argv[1]); + + hash_t hash; + str_hash_t str_hash; + + srand(1); // for a fair/deterministic comparison + Timer timer(true); + +#if MT_SUPPORT + if (!strcmp(program_slug,"absl::parallel_flat_hash_map") || + !strcmp(program_slug,"phmap::parallel_flat_hash_map")) + program_slug = xstr(MAPNAME) "_mt"; +#endif + + std::thread t1(memlog); + + try + { + if(!strcmp(argv[2], "sequential")) + { + for(i = 0; i < num_keys; i++) + hash.insert(hash_t::value_type(i, value)); + } +#if 0 + else if(!strcmp(argv[2], "random")) + { + vector v(num_keys); + timer = _fill_random(v, hash); + out("random", num_keys, timer); + } +#endif + else if(!strcmp(argv[2], "random")) + { + fprintf(stderr, "size = %d\n", sizeof(hash)); + timer = _fill_random2(num_keys, hash); + //out("random", num_keys, timer); + //fprintf(stderr, "inserted %llu\n", hash.size()); + } + else if(!strcmp(argv[2], "lookup")) + { + vector v(num_keys); + size_t num_present; + + timer = _lookup(v, hash, num_present); + //fprintf(stderr, "found %llu\n", num_present); + } + else if(!strcmp(argv[2], "delete")) + { + vector v(num_keys); + timer = _delete(v, hash); + } + else if(!strcmp(argv[2], "sequentialstring")) + { + for(i = 0; i < num_keys; i++) + str_hash.insert(str_hash_t::value_type(new_string_from_integer(i), value)); + } + else if(!strcmp(argv[2], "randomstring")) + { + for(i = 0; i < num_keys; i++) + str_hash.insert(str_hash_t::value_type(new_string_from_integer((int)rand()), value)); + } + else if(!strcmp(argv[2], "deletestring")) + { + for(i = 0; i < num_keys; i++) + str_hash.insert(str_hash_t::value_type(new_string_from_integer(i), value)); + timer.reset(); + for(i = 0; i < num_keys; i++) + str_hash.erase(new_string_from_integer(i)); + } + + + //printf("%f\n", (float)((double)timer.elapsed().count() / 1000)); + fflush(stdout); + //std::this_thread::sleep_for(std::chrono::seconds(1000)); + } + catch (...) + { + } + + all_done = true; + t1.join(); + return 0; +} diff --git a/extern/phmap/benchmark/bench.py b/extern/phmap/benchmark/bench.py new file mode 100644 index 0000000..142e571 --- /dev/null +++ b/extern/phmap/benchmark/bench.py @@ -0,0 +1,73 @@ +import sys, os, subprocess, signal + +programs = [ + 'stl_unordered_map', + 'abseil_flat', + 'abseil_parallel_flat' +] + +test_size = 1 +minkeys = 0 +maxkeys = 1000 +interval = 100 +best_out_of = 1 + +if test_size == 2: + multiplier = 1000 * 1000 + maxkeys = 500 + best_out_of = 3 + +elif test_size == 1: + multiplier = 100 * 1000 + interval = 200 +else: + multiplier = 10 * 1000 + +# and use nice/ionice +# and shut down to the console +# and swapoff any swap files/partitions + +outfile = open('output', 'w') + +if len(sys.argv) > 1: + benchtypes = sys.argv[1:] +else: + benchtypes = ( 'random', 'lookup', 'delete',) + #benchtypes = ( 'lookup', ) + +for benchtype in benchtypes: + nkeys = minkeys * multiplier + while nkeys <= (maxkeys * multiplier): + for program in programs: + fastest_attempt = 1000000 + fastest_attempt_data = '' + + for attempt in range(best_out_of): + proc = subprocess.Popen(['./build/'+program, str(nkeys), benchtype], stdout=subprocess.PIPE) + + # wait for the program to fill up memory and spit out its "ready" message + try: + runtime = float(proc.stdout.readline().strip()) + except: + runtime = 0 + + ps_proc = subprocess.Popen(['ps up %d | tail -n1' % proc.pid], shell=True, stdout=subprocess.PIPE) + #nbytes = int(ps_proc.stdout.read().split()[4]) * 1024 + #ps_proc.wait() + nbytes = 1000000 + + os.kill(proc.pid, signal.SIGKILL) + proc.wait() + + if nbytes and runtime: # otherwise it crashed + line = ','.join(map(str, [benchtype, nkeys, program, nbytes, "%0.6f" % runtime])) + + if runtime < fastest_attempt: + fastest_attempt = runtime + fastest_attempt_data = line + + if fastest_attempt != 1000000: + print >> outfile, fastest_attempt_data + print fastest_attempt_data + + nkeys += interval * multiplier diff --git a/extern/phmap/benchmark/charts-template.html b/extern/phmap/benchmark/charts-template.html new file mode 100644 index 0000000..9d5ca53 --- /dev/null +++ b/extern/phmap/benchmark/charts-template.html @@ -0,0 +1,135 @@ + + + + + Hash Table Benchmarks + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +__PLOT_DIV_SPEC_GOES_HERE__ + + + diff --git a/extern/phmap/benchmark/js/examples.css b/extern/phmap/benchmark/js/examples.css new file mode 100644 index 0000000..d63816a --- /dev/null +++ b/extern/phmap/benchmark/js/examples.css @@ -0,0 +1,146 @@ +* { padding: 0; margin: 0; vertical-align: top; } + +body { + background: url(background.png) repeat-x; + font: 18px "proxima-nova", Helvetica, Arial, sans-serif; + line-height: 1.5; +} + +a { color: #069; } +a:hover { color: #28b; } + +h2 { + margin-top: 15px; + font: normal 32px "omnes-pro", Helvetica, Arial, sans-serif; +} + +h3 { + margin-left: 30px; + font: normal 26px "omnes-pro", Helvetica, Arial, sans-serif; + color: #666; +} + +p { + margin-top: 10px; +} + +button { + font-size: 18px; + padding: 1px 7px; +} + +input { + font-size: 18px; +} + +input[type=checkbox] { + margin: 7px; +} + +#header { + position: relative; + width: 900px; + margin: auto; +} + +#header h2 { + margin-left: 10px; + vertical-align: middle; + font-size: 42px; + font-weight: bold; + text-decoration: none; + color: #000; +} + +#content { + width: 880px; + margin: 0 auto; + padding: 10px; +} + +#footer { + margin-top: 25px; + margin-bottom: 10px; + text-align: center; + font-size: 12px; + color: #999; +} + +.demo-container { + box-sizing: border-box; + width: 850px; + height: 450px; + padding: 20px 15px 15px 15px; + margin: 15px auto 30px auto; + border: 1px solid #ddd; + background: #fff; + background: linear-gradient(#f6f6f6 0, #fff 50px); + background: -o-linear-gradient(#f6f6f6 0, #fff 50px); + background: -ms-linear-gradient(#f6f6f6 0, #fff 50px); + background: -moz-linear-gradient(#f6f6f6 0, #fff 50px); + background: -webkit-linear-gradient(#f6f6f6 0, #fff 50px); + box-shadow: 0 3px 10px rgba(0,0,0,0.15); + -o-box-shadow: 0 3px 10px rgba(0,0,0,0.1); + -ms-box-shadow: 0 3px 10px rgba(0,0,0,0.1); + -moz-box-shadow: 0 3px 10px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 3px 10px rgba(0,0,0,0.1); + -webkit-tap-highlight-color: rgba(0,0,0,0); + -webkit-tap-highlight-color: transparent; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.demo-placeholder { + width: 100%; + height: 100%; + font-size: 14px; +} + +fieldset { + display: block; + -webkit-margin-start: 2px; + -webkit-margin-end: 2px; + -webkit-padding-before: 0.35em; + -webkit-padding-start: 0.75em; + -webkit-padding-end: 0.75em; + -webkit-padding-after: 0.625em; + min-width: -webkit-min-content; + border-width: 2px; + border-style: groove; + border-color: threedface; + border-image: initial; + padding: 10px; +} + +.legend { + display: block; + -webkit-padding-start: 2px; + -webkit-padding-end: 2px; + border-width: initial; + border-style: none; + border-color: initial; + border-image: initial; + padding-left: 10px; + padding-right: 10px; + padding-top: 10px; + padding-bottom: 10px; +} + +.legendLayer .background { + fill: rgba(255, 255, 255, 0.85); + stroke: rgba(0, 0, 0, 0.85); + stroke-width: 1; +} + +input[type="radio"] { + margin-top: -1px; + vertical-align: middle; +} + +.tickLabel { + line-height: 1.1; +} diff --git a/extern/phmap/benchmark/js/jquery.canvaswrapper.js b/extern/phmap/benchmark/js/jquery.canvaswrapper.js new file mode 100644 index 0000000..69eb0f3 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.canvaswrapper.js @@ -0,0 +1,538 @@ +/** ## jquery.flot.canvaswrapper + +This plugin contains the function for creating and manipulating both the canvas +layers and svg layers. + +The Canvas object is a wrapper around an HTML5 canvas tag. +The constructor Canvas(cls, container) takes as parameters cls, +the list of classes to apply to the canvas adnd the containter, +element onto which to append the canvas. The canvas operations +don't work unless the canvas is attached to the DOM. + +### jquery.canvaswrapper.js API functions +*/ + +(function($) { + var Canvas = function(cls, container) { + var element = container.getElementsByClassName(cls)[0]; + + if (!element) { + element = document.createElement('canvas'); + element.className = cls; + element.style.direction = 'ltr'; + element.style.position = 'absolute'; + element.style.left = '0px'; + element.style.top = '0px'; + + container.appendChild(element); + + // If HTML5 Canvas isn't available, throw + + if (!element.getContext) { + throw new Error('Canvas is not available.'); + } + } + + this.element = element; + + var context = this.context = element.getContext('2d'); + this.pixelRatio = $.plot.browser.getPixelRatio(context); + + // Size the canvas to match the internal dimensions of its container + + var box = container.getBoundingClientRect(); + this.resize(box.width, box.height); + + // Collection of HTML div layers for text overlaid onto the canvas + + this.SVGContainer = null; + this.SVG = {}; + + // Cache of text fragments and metrics, so we can avoid expensively + // re-calculating them when the plot is re-rendered in a loop. + + this._textCache = {}; + } + + /** + - resize(width, height) + + Resizes the canvas to the given dimensions. + The width represents the new width of the canvas, meanwhile the height + is the new height of the canvas, both of them in pixels. + */ + + Canvas.prototype.resize = function(width, height) { + var minSize = 10; + width = width < minSize ? minSize : width; + height = height < minSize ? minSize : height; + + var element = this.element, + context = this.context, + pixelRatio = this.pixelRatio; + + // Resize the canvas, increasing its density based on the display's + // pixel ratio; basically giving it more pixels without increasing the + // size of its element, to take advantage of the fact that retina + // displays have that many more pixels in the same advertised space. + + // Resizing should reset the state (excanvas seems to be buggy though) + + if (this.width !== width) { + element.width = width * pixelRatio; + element.style.width = width + 'px'; + this.width = width; + } + + if (this.height !== height) { + element.height = height * pixelRatio; + element.style.height = height + 'px'; + this.height = height; + } + + // Save the context, so we can reset in case we get replotted. The + // restore ensure that we're really back at the initial state, and + // should be safe even if we haven't saved the initial state yet. + + context.restore(); + context.save(); + + // Scale the coordinate space to match the display density; so even though we + // may have twice as many pixels, we still want lines and other drawing to + // appear at the same size; the extra pixels will just make them crisper. + + context.scale(pixelRatio, pixelRatio); + }; + + /** + - clear() + + Clears the entire canvas area, not including any overlaid HTML text + */ + Canvas.prototype.clear = function() { + this.context.clearRect(0, 0, this.width, this.height); + }; + + /** + - render() + + Finishes rendering the canvas, including managing the text overlay. + */ + Canvas.prototype.render = function() { + var cache = this._textCache; + + // For each text layer, add elements marked as active that haven't + // already been rendered, and remove those that are no longer active. + + for (var layerKey in cache) { + if (hasOwnProperty.call(cache, layerKey)) { + var layer = this.getSVGLayer(layerKey), + layerCache = cache[layerKey]; + + var display = layer.style.display; + layer.style.display = 'none'; + + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + var val = styleCache[key], + positions = val.positions; + + for (var i = 0, position; positions[i]; i++) { + position = positions[i]; + if (position.active) { + if (!position.rendered) { + layer.appendChild(position.element); + position.rendered = true; + } + } else { + positions.splice(i--, 1); + if (position.rendered) { + while (position.element.firstChild) { + position.element.removeChild(position.element.firstChild); + } + position.element.parentNode.removeChild(position.element); + } + } + } + + if (positions.length === 0) { + if (val.measured) { + val.measured = false; + } else { + delete styleCache[key]; + } + } + } + } + } + } + + layer.style.display = display; + } + } + }; + + /** + - getSVGLayer(classes) + + Creates (if necessary) and returns the SVG overlay container. + The classes string represents the string of space-separated CSS classes + used to uniquely identify the text layer. It return the svg-layer div. + */ + Canvas.prototype.getSVGLayer = function(classes) { + var layer = this.SVG[classes]; + + // Create the SVG layer if it doesn't exist + + if (!layer) { + // Create the svg layer container, if it doesn't exist + + var svgElement; + + if (!this.SVGContainer) { + this.SVGContainer = document.createElement('div'); + this.SVGContainer.className = 'flot-svg'; + this.SVGContainer.style.position = 'absolute'; + this.SVGContainer.style.top = '0px'; + this.SVGContainer.style.left = '0px'; + this.SVGContainer.style.bottom = '0px'; + this.SVGContainer.style.right = '0px'; + this.SVGContainer.style.pointerEvents = 'none'; + this.element.parentNode.appendChild(this.SVGContainer); + + svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + svgElement.style.width = '100%'; + svgElement.style.height = '100%'; + + this.SVGContainer.appendChild(svgElement); + } else { + svgElement = this.SVGContainer.firstChild; + } + + layer = document.createElementNS('http://www.w3.org/2000/svg', 'g'); + layer.setAttribute('class', classes); + layer.style.position = 'absolute'; + layer.style.top = '0px'; + layer.style.left = '0px'; + layer.style.bottom = '0px'; + layer.style.right = '0px'; + svgElement.appendChild(layer); + this.SVG[classes] = layer; + } + + return layer; + }; + + /** + - getTextInfo(layer, text, font, angle, width) + + Creates (if necessary) and returns a text info object. + The object looks like this: + ```js + { + width //Width of the text's wrapper div. + height //Height of the text's wrapper div. + element //The HTML div containing the text. + positions //Array of positions at which this text is drawn. + } + ``` + The positions array contains objects that look like this: + ```js + { + active //Flag indicating whether the text should be visible. + rendered //Flag indicating whether the text is currently visible. + element //The HTML div containing the text. + text //The actual text and is identical with element[0].textContent. + x //X coordinate at which to draw the text. + y //Y coordinate at which to draw the text. + } + ``` + Each position after the first receives a clone of the original element. + The idea is that that the width, height, and general 'identity' of the + text is constant no matter where it is placed; the placements are a + secondary property. + + Canvas maintains a cache of recently-used text info objects; getTextInfo + either returns the cached element or creates a new entry. + + The layer parameter is string of space-separated CSS classes uniquely + identifying the layer containing this text. + Text is the text string to retrieve info for. + Font is either a string of space-separated CSS classes or a font-spec object, + defining the text's font and style. + Angle is the angle at which to rotate the text, in degrees. Angle is currently unused, + it will be implemented in the future. + The last parameter is the Maximum width of the text before it wraps. + The method returns a text info object. + */ + Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) { + var textStyle, layerCache, styleCache, info; + + // Cast the value to a string, in case we were given a number or such + + text = '' + text; + + // If the font is a font-spec object, generate a CSS font definition + + if (typeof font === 'object') { + textStyle = font.style + ' ' + font.variant + ' ' + font.weight + ' ' + font.size + 'px/' + font.lineHeight + 'px ' + font.family; + } else { + textStyle = font; + } + + // Retrieve (or create) the cache for the text's layer and styles + + layerCache = this._textCache[layer]; + + if (layerCache == null) { + layerCache = this._textCache[layer] = {}; + } + + styleCache = layerCache[textStyle]; + + if (styleCache == null) { + styleCache = layerCache[textStyle] = {}; + } + + var key = generateKey(text); + info = styleCache[key]; + + // If we can't find a matching element in our cache, create a new one + + if (!info) { + var element = document.createElementNS('http://www.w3.org/2000/svg', 'text'); + if (text.indexOf('
') !== -1) { + addTspanElements(text, element, -9999); + } else { + var textNode = document.createTextNode(text); + element.appendChild(textNode); + } + + element.style.position = 'absolute'; + element.style.maxWidth = width; + element.setAttributeNS(null, 'x', -9999); + element.setAttributeNS(null, 'y', -9999); + + if (typeof font === 'object') { + element.style.font = textStyle; + element.style.fill = font.fill; + } else if (typeof font === 'string') { + element.setAttribute('class', font); + } + + this.getSVGLayer(layer).appendChild(element); + var elementRect = element.getBBox(); + + info = styleCache[key] = { + width: elementRect.width, + height: elementRect.height, + measured: true, + element: element, + positions: [] + }; + + //remove elements from dom + while (element.firstChild) { + element.removeChild(element.firstChild); + } + element.parentNode.removeChild(element); + } + + info.measured = true; + return info; + }; + + /** + - addText (layer, x, y, text, font, angle, width, halign, valign, transforms) + + Adds a text string to the canvas text overlay. + The text isn't drawn immediately; it is marked as rendering, which will + result in its addition to the canvas on the next render pass. + + The layer is string of space-separated CSS classes uniquely + identifying the layer containing this text. + X and Y represents the X and Y coordinate at which to draw the text. + and text is the string to draw + */ + Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign, transforms) { + var info = this.getTextInfo(layer, text, font, angle, width), + positions = info.positions; + + // Tweak the div's position to match the text's alignment + + if (halign === 'center') { + x -= info.width / 2; + } else if (halign === 'right') { + x -= info.width; + } + + if (valign === 'middle') { + y -= info.height / 2; + } else if (valign === 'bottom') { + y -= info.height; + } + + y += 0.75 * info.height; + + // Determine whether this text already exists at this position. + // If so, mark it for inclusion in the next render pass. + + for (var i = 0, position; positions[i]; i++) { + position = positions[i]; + if (position.x === x && position.y === y && position.text === text) { + position.active = true; + return; + } else if (position.active === false) { + position.active = true; + position.text = text; + if (text.indexOf('
') !== -1) { + y -= 0.25 * info.height; + addTspanElements(text, position.element, x); + } else { + position.element.textContent = text; + } + position.element.setAttributeNS(null, 'x', x); + position.element.setAttributeNS(null, 'y', y); + position.x = x; + position.y = y; + return; + } + } + + // If the text doesn't exist at this position, create a new entry + + // For the very first position we'll re-use the original element, + // while for subsequent ones we'll clone it. + + position = { + active: true, + rendered: false, + element: positions.length ? info.element.cloneNode() : info.element, + text: text, + x: x, + y: y + }; + + positions.push(position); + + if (text.indexOf('
') !== -1) { + y -= 0.25 * info.height; + addTspanElements(text, position.element, x); + } else { + position.element.textContent = text; + } + + // Move the element to its final position within the container + position.element.setAttributeNS(null, 'x', x); + position.element.setAttributeNS(null, 'y', y); + position.element.style.textAlign = halign; + + if (transforms) { + transforms.forEach(function(t) { + info.element.transform.baseVal.appendItem(t); + }); + } + }; + + var addTspanElements = function(text, element, x) { + var lines = text.split('
'), + tspan, i, offset; + + for (i = 0; i < lines.length; i++) { + if (!element.childNodes[i]) { + tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan'); + element.appendChild(tspan); + } else { + tspan = element.childNodes[i]; + } + tspan.textContent = lines[i]; + offset = i * 1 + 'em'; + tspan.setAttributeNS(null, 'dy', offset); + tspan.setAttributeNS(null, 'x', x); + } + } + + /** + - removeText (layer, x, y, text, font, angle) + + The function removes one or more text strings from the canvas text overlay. + If no parameters are given, all text within the layer is removed. + + Note that the text is not immediately removed; it is simply marked as + inactive, which will result in its removal on the next render pass. + This avoids the performance penalty for 'clear and redraw' behavior, + where we potentially get rid of all text on a layer, but will likely + add back most or all of it later, as when redrawing axes, for example. + + The layer is a string of space-separated CSS classes uniquely + identifying the layer containing this text. The following parameter are + X and Y coordinate of the text. + Text is the string to remove, while the font is either a string of space-separated CSS + classes or a font-spec object, defining the text's font and style. + */ + Canvas.prototype.removeText = function(layer, x, y, text, font, angle) { + var info, htmlYCoord; + if (text == null) { + var layerCache = this._textCache[layer]; + if (layerCache != null) { + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + var positions = styleCache[key].positions; + positions.forEach(function(position) { + position.active = false; + }); + } + } + } + } + } + } else { + info = this.getTextInfo(layer, text, font, angle); + positions = info.positions; + positions.forEach(function(position) { + htmlYCoord = y + 0.75 * info.height; + if (position.x === x && position.y === htmlYCoord && position.text === text) { + position.active = false; + } + }); + } + }; + + /** + - clearCache() + + Clears the cache used to speed up the text size measurements. + As an (unfortunate) side effect all text within the text Layer is removed. + Use this function before plot.setupGrid() and plot.draw() if the plot just + became visible or the styles changed. + */ + Canvas.prototype.clearCache = function() { + var cache = this._textCache; + for (var layerKey in cache) { + if (hasOwnProperty.call(cache, layerKey)) { + var layer = this.getSVGLayer(layerKey); + while (layer.firstChild) { + layer.removeChild(layer.firstChild); + } + } + }; + + this._textCache = {}; + }; + + function generateKey(text) { + return text.replace(/0|1|2|3|4|5|6|7|8|9/g, '0'); + } + + if (!window.Flot) { + window.Flot = {}; + } + + window.Flot.Canvas = Canvas; +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.colorhelpers.js b/extern/phmap/benchmark/js/jquery.colorhelpers.js new file mode 100644 index 0000000..c59cf2f --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.colorhelpers.js @@ -0,0 +1,199 @@ +/* Plugin for jQuery for working with colors. + * + * Version 1.1. + * + * Inspiration from jQuery color animation plugin by John Resig. + * + * Released under the MIT license by Ole Laursen, October 2009. + * + * Examples: + * + * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString() + * var c = $.color.extract($("#mydiv"), 'background-color'); + * console.log(c.r, c.g, c.b, c.a); + * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)" + * + * Note that .scale() and .add() return the same modified object + * instead of making a new one. + * + * V. 1.1: Fix error handling so e.g. parsing an empty string does + * produce a color rather than just crashing. + */ + +(function($) { + $.color = {}; + + // construct color object with some convenient chainable helpers + $.color.make = function (r, g, b, a) { + var o = {}; + o.r = r || 0; + o.g = g || 0; + o.b = b || 0; + o.a = a != null ? a : 1; + + o.add = function (c, d) { + for (var i = 0; i < c.length; ++i) { + o[c.charAt(i)] += d; + } + + return o.normalize(); + }; + + o.scale = function (c, f) { + for (var i = 0; i < c.length; ++i) { + o[c.charAt(i)] *= f; + } + + return o.normalize(); + }; + + o.toString = function () { + if (o.a >= 1.0) { + return "rgb(" + [o.r, o.g, o.b].join(",") + ")"; + } else { + return "rgba(" + [o.r, o.g, o.b, o.a].join(",") + ")"; + } + }; + + o.normalize = function () { + function clamp(min, value, max) { + return value < min ? min : (value > max ? max : value); + } + + o.r = clamp(0, parseInt(o.r), 255); + o.g = clamp(0, parseInt(o.g), 255); + o.b = clamp(0, parseInt(o.b), 255); + o.a = clamp(0, o.a, 1); + return o; + }; + + o.clone = function () { + return $.color.make(o.r, o.b, o.g, o.a); + }; + + return o.normalize(); + } + + // extract CSS color property from element, going up in the DOM + // if it's "transparent" + $.color.extract = function (elem, css) { + var c; + + do { + c = elem.css(css).toLowerCase(); + // keep going until we find an element that has color, or + // we hit the body or root (have no parent) + if (c !== '' && c !== 'transparent') { + break; + } + + elem = elem.parent(); + } while (elem.length && !$.nodeName(elem.get(0), "body")); + + // catch Safari's way of signalling transparent + if (c === "rgba(0, 0, 0, 0)") { + c = "transparent"; + } + + return $.color.parse(c); + } + + // parse CSS color string (like "rgb(10, 32, 43)" or "#fff"), + // returns color object, if parsing failed, you get black (0, 0, + // 0) out + $.color.parse = function (str) { + var res, m = $.color.make; + + // Look for rgb(num,num,num) + res = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str); + if (res) { + return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10)); + } + + // Look for rgba(num,num,num,num) + res = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str) + if (res) { + return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10), parseFloat(res[4])); + } + + // Look for rgb(num%,num%,num%) + res = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*\)/.exec(str); + if (res) { + return m(parseFloat(res[1]) * 2.55, parseFloat(res[2]) * 2.55, parseFloat(res[3]) * 2.55); + } + + // Look for rgba(num%,num%,num%,num) + res = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str); + if (res) { + return m(parseFloat(res[1]) * 2.55, parseFloat(res[2]) * 2.55, parseFloat(res[3]) * 2.55, parseFloat(res[4])); + } + + // Look for #a0b1c2 + res = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str); + if (res) { + return m(parseInt(res[1], 16), parseInt(res[2], 16), parseInt(res[3], 16)); + } + + // Look for #fff + res = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str); + if (res) { + return m(parseInt(res[1] + res[1], 16), parseInt(res[2] + res[2], 16), parseInt(res[3] + res[3], 16)); + } + + // Otherwise, we're most likely dealing with a named color + var name = $.trim(str).toLowerCase(); + if (name === "transparent") { + return m(255, 255, 255, 0); + } else { + // default to black + res = lookupColors[name] || [0, 0, 0]; + return m(res[0], res[1], res[2]); + } + } + + var lookupColors = { + aqua: [0, 255, 255], + azure: [240, 255, 255], + beige: [245, 245, 220], + black: [0, 0, 0], + blue: [0, 0, 255], + brown: [165, 42, 42], + cyan: [0, 255, 255], + darkblue: [0, 0, 139], + darkcyan: [0, 139, 139], + darkgrey: [169, 169, 169], + darkgreen: [0, 100, 0], + darkkhaki: [189, 183, 107], + darkmagenta: [139, 0, 139], + darkolivegreen: [85, 107, 47], + darkorange: [255, 140, 0], + darkorchid: [153, 50, 204], + darkred: [139, 0, 0], + darksalmon: [233, 150, 122], + darkviolet: [148, 0, 211], + fuchsia: [255, 0, 255], + gold: [255, 215, 0], + green: [0, 128, 0], + indigo: [75, 0, 130], + khaki: [240, 230, 140], + lightblue: [173, 216, 230], + lightcyan: [224, 255, 255], + lightgreen: [144, 238, 144], + lightgrey: [211, 211, 211], + lightpink: [255, 182, 193], + lightyellow: [255, 255, 224], + lime: [0, 255, 0], + magenta: [255, 0, 255], + maroon: [128, 0, 0], + navy: [0, 0, 128], + olive: [128, 128, 0], + orange: [255, 165, 0], + pink: [255, 192, 203], + purple: [128, 0, 128], + violet: [128, 0, 128], + red: [255, 0, 0], + silver: [192, 192, 192], + white: [255, 255, 255], + yellow: [255, 255, 0] + }; +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.axislabels.js b/extern/phmap/benchmark/js/jquery.flot.axislabels.js new file mode 100644 index 0000000..8c80828 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.axislabels.js @@ -0,0 +1,212 @@ +/* +Axis label plugin for flot + +Derived from: +Axis Labels Plugin for flot. +http://github.com/markrcote/flot-axislabels + +Original code is Copyright (c) 2010 Xuan Luo. +Original code was released under the GPLv3 license by Xuan Luo, September 2010. +Original code was rereleased under the MIT license by Xuan Luo, April 2012. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +(function($) { + "use strict"; + + var options = { + axisLabels: { + show: true + } + }; + + function AxisLabel(axisName, position, padding, placeholder, axisLabel, surface) { + this.axisName = axisName; + this.position = position; + this.padding = padding; + this.placeholder = placeholder; + this.axisLabel = axisLabel; + this.surface = surface; + this.width = 0; + this.height = 0; + this.elem = null; + } + + AxisLabel.prototype.calculateSize = function() { + var axisId = this.axisName + 'Label', + layerId = axisId + 'Layer', + className = axisId + ' axisLabels'; + + var info = this.surface.getTextInfo(layerId, this.axisLabel, className); + this.labelWidth = info.width; + this.labelHeight = info.height; + + if (this.position === 'left' || this.position === 'right') { + this.width = this.labelHeight + this.padding; + this.height = 0; + } else { + this.width = 0; + this.height = this.labelHeight + this.padding; + } + }; + + AxisLabel.prototype.transforms = function(degrees, x, y, svgLayer) { + var transforms = [], translate, rotate; + if (x !== 0 || y !== 0) { + translate = svgLayer.createSVGTransform(); + translate.setTranslate(x, y); + transforms.push(translate); + } + if (degrees !== 0) { + rotate = svgLayer.createSVGTransform(); + var centerX = Math.round(this.labelWidth / 2), + centerY = 0; + rotate.setRotate(degrees, centerX, centerY); + transforms.push(rotate); + } + + return transforms; + }; + + AxisLabel.prototype.calculateOffsets = function(box) { + var offsets = { + x: 0, + y: 0, + degrees: 0 + }; + if (this.position === 'bottom') { + offsets.x = box.left + box.width / 2 - this.labelWidth / 2; + offsets.y = box.top + box.height - this.labelHeight; + } else if (this.position === 'top') { + offsets.x = box.left + box.width / 2 - this.labelWidth / 2; + offsets.y = box.top; + } else if (this.position === 'left') { + offsets.degrees = -90; + offsets.x = box.left - this.labelWidth / 2; + offsets.y = box.height / 2 + box.top; + } else if (this.position === 'right') { + offsets.degrees = 90; + offsets.x = box.left + box.width - this.labelWidth / 2; + offsets.y = box.height / 2 + box.top; + } + offsets.x = Math.round(offsets.x); + offsets.y = Math.round(offsets.y); + + return offsets; + }; + + AxisLabel.prototype.cleanup = function() { + var axisId = this.axisName + 'Label', + layerId = axisId + 'Layer', + className = axisId + ' axisLabels'; + this.surface.removeText(layerId, 0, 0, this.axisLabel, className); + }; + + AxisLabel.prototype.draw = function(box) { + var axisId = this.axisName + 'Label', + layerId = axisId + 'Layer', + className = axisId + ' axisLabels', + offsets = this.calculateOffsets(box), + style = { + position: 'absolute', + bottom: '', + right: '', + display: 'inline-block', + 'white-space': 'nowrap' + }; + + var layer = this.surface.getSVGLayer(layerId); + var transforms = this.transforms(offsets.degrees, offsets.x, offsets.y, layer.parentNode); + + this.surface.addText(layerId, 0, 0, this.axisLabel, className, undefined, undefined, undefined, undefined, transforms); + this.surface.render(); + Object.keys(style).forEach(function(key) { + layer.style[key] = style[key]; + }); + }; + + function init(plot) { + plot.hooks.processOptions.push(function(plot, options) { + if (!options.axisLabels.show) { + return; + } + + var axisLabels = {}; + var defaultPadding = 2; // padding between axis and tick labels + + plot.hooks.axisReserveSpace.push(function(plot, axis) { + var opts = axis.options; + var axisName = axis.direction + axis.n; + + axis.labelHeight += axis.boxPosition.centerY; + axis.labelWidth += axis.boxPosition.centerX; + + if (!opts || !opts.axisLabel || !axis.show) { + return; + } + + var padding = opts.axisLabelPadding === undefined + ? defaultPadding + : opts.axisLabelPadding; + + var axisLabel = axisLabels[axisName]; + if (!axisLabel) { + axisLabel = new AxisLabel(axisName, + opts.position, padding, + plot.getPlaceholder()[0], opts.axisLabel, plot.getSurface()); + axisLabels[axisName] = axisLabel; + } + + axisLabel.calculateSize(); + + // Incrementing the sizes of the tick labels. + axis.labelHeight += axisLabel.height; + axis.labelWidth += axisLabel.width; + }); + + // TODO - use the drawAxis hook + plot.hooks.draw.push(function(plot, ctx) { + $.each(plot.getAxes(), function(flotAxisName, axis) { + var opts = axis.options; + if (!opts || !opts.axisLabel || !axis.show) { + return; + } + + var axisName = axis.direction + axis.n; + axisLabels[axisName].draw(axis.box); + }); + }); + + plot.hooks.shutdown.push(function(plot, eventHolder) { + for (var axisName in axisLabels) { + axisLabels[axisName].cleanup(); + } + }); + }); + }; + + $.plot.plugins.push({ + init: init, + options: options, + name: 'axisLabels', + version: '3.0' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.browser.js b/extern/phmap/benchmark/js/jquery.flot.browser.js new file mode 100644 index 0000000..e50a629 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.browser.js @@ -0,0 +1,98 @@ +/** ## jquery.flot.browser.js + +This plugin is used to make available some browser-related utility functions. + +### Methods +*/ + +(function ($) { + 'use strict'; + + var browser = { + /** + - getPageXY(e) + + Calculates the pageX and pageY using the screenX, screenY properties of the event + and the scrolling of the page. This is needed because the pageX and pageY + properties of the event are not correct while running tests in Edge. */ + getPageXY: function (e) { + // This code is inspired from https://stackoverflow.com/a/3464890 + var doc = document.documentElement, + pageX = e.clientX + (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0), + pageY = e.clientY + (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0); + return { X: pageX, Y: pageY }; + }, + + /** + - getPixelRatio(context) + + This function returns the current pixel ratio defined by the product of desktop + zoom and page zoom. + Additional info: https://www.html5rocks.com/en/tutorials/canvas/hidpi/ + */ + getPixelRatio: function(context) { + var devicePixelRatio = window.devicePixelRatio || 1, + backingStoreRatio = + context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || 1; + return devicePixelRatio / backingStoreRatio; + }, + + /** + - isSafari, isMobileSafari, isOpera, isFirefox, isIE, isEdge, isChrome, isBlink + + This is a collection of functions, used to check if the code is running in a + particular browser or Javascript engine. + */ + isSafari: function() { + // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser + // Safari 3.0+ "[object HTMLElementConstructor]" + return /constructor/i.test(window.top.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window.top['safari'] || (typeof window.top.safari !== 'undefined' && window.top.safari.pushNotification)); + }, + + isMobileSafari: function() { + //isMobileSafari adapted from https://stackoverflow.com/questions/3007480/determine-if-user-navigated-from-mobile-safari + return navigator.userAgent.match(/(iPod|iPhone|iPad)/) && navigator.userAgent.match(/AppleWebKit/); + }, + + isOpera: function() { + // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser + //Opera 8.0+ + return (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0; + }, + + isFirefox: function() { + // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser + // Firefox 1.0+ + return typeof InstallTrigger !== 'undefined'; + }, + + isIE: function() { + // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser + // Internet Explorer 6-11 + return /*@cc_on!@*/false || !!document.documentMode; + }, + + isEdge: function() { + // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser + // Edge 20+ + return !browser.isIE() && !!window.StyleMedia; + }, + + isChrome: function() { + // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser + // Chrome 1+ + return !!window.chrome && !!window.chrome.webstore; + }, + + isBlink: function() { + // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser + return (browser.isChrome() || browser.isOpera()) && !!window.CSS; + } + }; + + $.plot.browser = browser; +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.categories.js b/extern/phmap/benchmark/js/jquery.flot.categories.js new file mode 100644 index 0000000..af16f78 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.categories.js @@ -0,0 +1,202 @@ +/* Flot plugin for plotting textual data or categories. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +Consider a dataset like [["February", 34], ["March", 20], ...]. This plugin +allows you to plot such a dataset directly. + +To enable it, you must specify mode: "categories" on the axis with the textual +labels, e.g. + + $.plot("#placeholder", data, { xaxis: { mode: "categories" } }); + +By default, the labels are ordered as they are met in the data series. If you +need a different ordering, you can specify "categories" on the axis options +and list the categories there: + + xaxis: { + mode: "categories", + categories: ["February", "March", "April"] + } + +If you need to customize the distances between the categories, you can specify +"categories" as an object mapping labels to values + + xaxis: { + mode: "categories", + categories: { "February": 1, "March": 3, "April": 4 } + } + +If you don't specify all categories, the remaining categories will be numbered +from the max value plus 1 (with a spacing of 1 between each). + +Internally, the plugin works by transforming the input data through an auto- +generated mapping where the first category becomes 0, the second 1, etc. +Hence, a point like ["February", 34] becomes [0, 34] internally in Flot (this +is visible in hover and click events that return numbers rather than the +category labels). The plugin also overrides the tick generator to spit out the +categories as ticks instead of the values. + +If you need to map a value back to its label, the mapping is always accessible +as "categories" on the axis object, e.g. plot.getAxes().xaxis.categories. + +*/ + +(function ($) { + var options = { + xaxis: { + categories: null + }, + yaxis: { + categories: null + } + }; + + function processRawData(plot, series, data, datapoints) { + // if categories are enabled, we need to disable + // auto-transformation to numbers so the strings are intact + // for later processing + + var xCategories = series.xaxis.options.mode === "categories", + yCategories = series.yaxis.options.mode === "categories"; + + if (!(xCategories || yCategories)) { + return; + } + + var format = datapoints.format; + + if (!format) { + // FIXME: auto-detection should really not be defined here + var s = series; + format = []; + format.push({ x: true, number: true, required: true, computeRange: true}); + format.push({ y: true, number: true, required: true, computeRange: true }); + + if (s.bars.show || (s.lines.show && s.lines.fill)) { + var autoScale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero)); + format.push({ y: true, number: true, required: false, defaultValue: 0, computeRange: autoScale }); + if (s.bars.horizontal) { + delete format[format.length - 1].y; + format[format.length - 1].x = true; + } + } + + datapoints.format = format; + } + + for (var m = 0; m < format.length; ++m) { + if (format[m].x && xCategories) { + format[m].number = false; + } + + if (format[m].y && yCategories) { + format[m].number = false; + format[m].computeRange = false; + } + } + } + + function getNextIndex(categories) { + var index = -1; + + for (var v in categories) { + if (categories[v] > index) { + index = categories[v]; + } + } + + return index + 1; + } + + function categoriesTickGenerator(axis) { + var res = []; + for (var label in axis.categories) { + var v = axis.categories[label]; + if (v >= axis.min && v <= axis.max) { + res.push([v, label]); + } + } + + res.sort(function (a, b) { return a[0] - b[0]; }); + + return res; + } + + function setupCategoriesForAxis(series, axis, datapoints) { + if (series[axis].options.mode !== "categories") { + return; + } + + if (!series[axis].categories) { + // parse options + var c = {}, o = series[axis].options.categories || {}; + if ($.isArray(o)) { + for (var i = 0; i < o.length; ++i) { + c[o[i]] = i; + } + } else { + for (var v in o) { + c[v] = o[v]; + } + } + + series[axis].categories = c; + } + + // fix ticks + if (!series[axis].options.ticks) { + series[axis].options.ticks = categoriesTickGenerator; + } + + transformPointsOnAxis(datapoints, axis, series[axis].categories); + } + + function transformPointsOnAxis(datapoints, axis, categories) { + // go through the points, transforming them + var points = datapoints.points, + ps = datapoints.pointsize, + format = datapoints.format, + formatColumn = axis.charAt(0), + index = getNextIndex(categories); + + for (var i = 0; i < points.length; i += ps) { + if (points[i] == null) { + continue; + } + + for (var m = 0; m < ps; ++m) { + var val = points[i + m]; + + if (val == null || !format[m][formatColumn]) { + continue; + } + + if (!(val in categories)) { + categories[val] = index; + ++index; + } + + points[i + m] = categories[val]; + } + } + } + + function processDatapoints(plot, series, datapoints) { + setupCategoriesForAxis(series, "xaxis", datapoints); + setupCategoriesForAxis(series, "yaxis", datapoints); + } + + function init(plot) { + plot.hooks.processRawData.push(processRawData); + plot.hooks.processDatapoints.push(processDatapoints); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'categories', + version: '1.0' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.composeImages.js b/extern/phmap/benchmark/js/jquery.flot.composeImages.js new file mode 100644 index 0000000..a3d6fe6 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.composeImages.js @@ -0,0 +1,325 @@ +/** ## jquery.flot.composeImages.js + +This plugin is used to expose a function used to overlap several canvases and +SVGs, for the purpose of creating a snaphot out of them. + +### When composeImages is used: +When multiple canvases and SVGs have to be overlapped into a single image +and their offset on the page, must be preserved. + +### Where can be used: +In creating a downloadable snapshot of the plots, axes, cursors etc of a graph. + +### How it works: +The entry point is composeImages function. It expects an array of objects, +which should be either canvases or SVGs (or a mix). It does a prevalidation +of them, by verifying if they will be usable or not, later in the flow. +After selecting only usable sources, it passes them to getGenerateTempImg +function, which generates temporary images out of them. This function +expects that some of the passed sources (canvas or SVG) may still have +problems being converted to an image and makes sure the promises system, +used by composeImages function, moves forward. As an example, SVGs with +missing information from header or with unsupported content, may lead to +failure in generating the temporary image. Temporary images are required +mostly on extracting content from SVGs, but this is also where the x/y +offsets are extracted for each image which will be added. For SVGs in +particular, their CSS rules have to be applied. +After all temporary images are generated, they are overlapped using +getExecuteImgComposition function. This is where the destination canvas +is set to the proper dimensions. It is then output by composeImages. +This function returns a promise, which can be used to wait for the whole +composition process. It requires to be asynchronous, because this is how +temporary images load their data. +*/ + +(function($) { + "use strict"; + const GENERALFAILURECALLBACKERROR = -100; //simply a negative number + const SUCCESSFULIMAGEPREPARATION = 0; + const EMPTYARRAYOFIMAGESOURCES = -1; + const NEGATIVEIMAGESIZE = -2; + var pixelRatio = 1; + var browser = $.plot.browser; + var getPixelRatio = browser.getPixelRatio; + + function composeImages(canvasOrSvgSources, destinationCanvas) { + var validCanvasOrSvgSources = canvasOrSvgSources.filter(isValidSource); + pixelRatio = getPixelRatio(destinationCanvas.getContext('2d')); + + var allImgCompositionPromises = validCanvasOrSvgSources.map(function(validCanvasOrSvgSource) { + var tempImg = new Image(); + var currentPromise = new Promise(getGenerateTempImg(tempImg, validCanvasOrSvgSource)); + return currentPromise; + }); + + var lastPromise = Promise.all(allImgCompositionPromises).then(getExecuteImgComposition(destinationCanvas), failureCallback); + return lastPromise; + } + + function isValidSource(canvasOrSvgSource) { + var isValidFromCanvas = true; + var isValidFromContent = true; + if ((canvasOrSvgSource === null) || (canvasOrSvgSource === undefined)) { + isValidFromContent = false; + } else { + if (canvasOrSvgSource.tagName === 'CANVAS') { + if ((canvasOrSvgSource.getBoundingClientRect().right === canvasOrSvgSource.getBoundingClientRect().left) || + (canvasOrSvgSource.getBoundingClientRect().bottom === canvasOrSvgSource.getBoundingClientRect().top)) { + isValidFromCanvas = false; + } + } + } + return isValidFromContent && isValidFromCanvas && (window.getComputedStyle(canvasOrSvgSource).visibility === 'visible'); + } + + function getGenerateTempImg(tempImg, canvasOrSvgSource) { + tempImg.sourceDescription = ''; + tempImg.sourceComponent = canvasOrSvgSource; + + return function doGenerateTempImg(successCallbackFunc, failureCallbackFunc) { + tempImg.onload = function(evt) { + tempImg.successfullyLoaded = true; + successCallbackFunc(tempImg); + }; + + tempImg.onabort = function(evt) { + tempImg.successfullyLoaded = false; + console.log('Can\'t generate temp image from ' + tempImg.sourceDescription + '. It is possible that it is missing some properties or its content is not supported by this browser. Source component:', tempImg.sourceComponent); + successCallbackFunc(tempImg); //call successCallback, to allow snapshot of all working images + }; + + tempImg.onerror = function(evt) { + tempImg.successfullyLoaded = false; + console.log('Can\'t generate temp image from ' + tempImg.sourceDescription + '. It is possible that it is missing some properties or its content is not supported by this browser. Source component:', tempImg.sourceComponent); + successCallbackFunc(tempImg); //call successCallback, to allow snapshot of all working images + }; + + generateTempImageFromCanvasOrSvg(canvasOrSvgSource, tempImg); + }; + } + + function getExecuteImgComposition(destinationCanvas) { + return function executeImgComposition(tempImgs) { + var compositionResult = copyImgsToCanvas(tempImgs, destinationCanvas); + return compositionResult; + }; + } + + function copyCanvasToImg(canvas, img) { + img.src = canvas.toDataURL('image/png'); + } + + function getCSSRules(document) { + var styleSheets = document.styleSheets, + rulesList = []; + for (var i = 0; i < styleSheets.length; i++) { + // in Chrome, the external CSS files are empty when the page is directly loaded from disk + var rules = styleSheets[i].cssRules || []; + for (var j = 0; j < rules.length; j++) { + var rule = rules[j]; + rulesList.push(rule.cssText); + } + } + return rulesList; + } + + function embedCSSRulesInSVG(rules, svg) { + var text = [ + '', + '', + svg.innerHTML, + '' + ].join('\n'); + return text; + } + + function copySVGToImgMostBrowsers(svg, img) { + var rules = getCSSRules(document), + source = embedCSSRulesInSVG(rules, svg); + + source = patchSVGSource(source); + + var blob = new Blob([source], {type: "image/svg+xml;charset=utf-8"}), + domURL = self.URL || self.webkitURL || self, + url = domURL.createObjectURL(blob); + img.src = url; + } + + function copySVGToImgSafari(svg, img) { + // Use this method to convert a string buffer array to a binary string. + // Do so by breaking up large strings into smaller substrings; this is necessary to avoid the + // "maximum call stack size exceeded" exception that can happen when calling 'String.fromCharCode.apply' + // with a very long array. + function buildBinaryString (arrayBuffer) { + var binaryString = ""; + const utf8Array = new Uint8Array(arrayBuffer); + const blockSize = 16384; + for (var i = 0; i < utf8Array.length; i = i + blockSize) { + const binarySubString = String.fromCharCode.apply(null, utf8Array.subarray(i, i + blockSize)); + binaryString = binaryString + binarySubString; + } + return binaryString; + }; + + var rules = getCSSRules(document), + source = embedCSSRulesInSVG(rules, svg), + data, + utf8BinaryString; + + source = patchSVGSource(source); + + // Encode the string as UTF-8 and convert it to a binary string. The UTF-8 encoding is required to + // capture unicode characters correctly. + utf8BinaryString = buildBinaryString(new (TextEncoder || TextEncoderLite)('utf-8').encode(source)); + + data = "data:image/svg+xml;base64," + btoa(utf8BinaryString); + img.src = data; + } + + function patchSVGSource(svgSource) { + var source = ''; + //add name spaces. + if (!svgSource.match(/^]+xmlns="http:\/\/www\.w3\.org\/2000\/svg"/)) { + source = svgSource.replace(/^]+"http:\/\/www\.w3\.org\/1999\/xlink"/)) { + source = svgSource.replace(/^\r\n' + source; + } + + function copySVGToImg(svg, img) { + if (browser.isSafari() || browser.isMobileSafari()) { + copySVGToImgSafari(svg, img); + } else { + copySVGToImgMostBrowsers(svg, img); + } + } + + function adaptDestSizeToZoom(destinationCanvas, sources) { + function containsSVGs(source) { + return source.srcImgTagName === 'svg'; + } + + if (sources.find(containsSVGs) !== undefined) { + if (pixelRatio < 1) { + destinationCanvas.width = destinationCanvas.width * pixelRatio; + destinationCanvas.height = destinationCanvas.height * pixelRatio; + } + } + } + + function prepareImagesToBeComposed(sources, destination) { + var result = SUCCESSFULIMAGEPREPARATION; + if (sources.length === 0) { + result = EMPTYARRAYOFIMAGESOURCES; //nothing to do if called without sources + } else { + var minX = sources[0].genLeft; + var minY = sources[0].genTop; + var maxX = sources[0].genRight; + var maxY = sources[0].genBottom; + var i = 0; + + for (i = 1; i < sources.length; i++) { + if (minX > sources[i].genLeft) { + minX = sources[i].genLeft; + } + + if (minY > sources[i].genTop) { + minY = sources[i].genTop; + } + } + + for (i = 1; i < sources.length; i++) { + if (maxX < sources[i].genRight) { + maxX = sources[i].genRight; + } + + if (maxY < sources[i].genBottom) { + maxY = sources[i].genBottom; + } + } + + if ((maxX - minX <= 0) || (maxY - minY <= 0)) { + result = NEGATIVEIMAGESIZE; //this might occur on hidden images + } else { + destination.width = Math.round(maxX - minX); + destination.height = Math.round(maxY - minY); + + for (i = 0; i < sources.length; i++) { + sources[i].xCompOffset = sources[i].genLeft - minX; + sources[i].yCompOffset = sources[i].genTop - minY; + } + + adaptDestSizeToZoom(destination, sources); + } + } + return result; + } + + function copyImgsToCanvas(sources, destination) { + var prepareImagesResult = prepareImagesToBeComposed(sources, destination); + if (prepareImagesResult === SUCCESSFULIMAGEPREPARATION) { + var destinationCtx = destination.getContext('2d'); + + for (var i = 0; i < sources.length; i++) { + if (sources[i].successfullyLoaded === true) { + destinationCtx.drawImage(sources[i], sources[i].xCompOffset * pixelRatio, sources[i].yCompOffset * pixelRatio); + } + } + } + return prepareImagesResult; + } + + function adnotateDestImgWithBoundingClientRect(srcCanvasOrSvg, destImg) { + destImg.genLeft = srcCanvasOrSvg.getBoundingClientRect().left; + destImg.genTop = srcCanvasOrSvg.getBoundingClientRect().top; + + if (srcCanvasOrSvg.tagName === 'CANVAS') { + destImg.genRight = destImg.genLeft + srcCanvasOrSvg.width; + destImg.genBottom = destImg.genTop + srcCanvasOrSvg.height; + } + + if (srcCanvasOrSvg.tagName === 'svg') { + destImg.genRight = srcCanvasOrSvg.getBoundingClientRect().right; + destImg.genBottom = srcCanvasOrSvg.getBoundingClientRect().bottom; + } + } + + function generateTempImageFromCanvasOrSvg(srcCanvasOrSvg, destImg) { + if (srcCanvasOrSvg.tagName === 'CANVAS') { + copyCanvasToImg(srcCanvasOrSvg, destImg); + } + + if (srcCanvasOrSvg.tagName === 'svg') { + copySVGToImg(srcCanvasOrSvg, destImg); + } + + destImg.srcImgTagName = srcCanvasOrSvg.tagName; + adnotateDestImgWithBoundingClientRect(srcCanvasOrSvg, destImg); + } + + function failureCallback() { + return GENERALFAILURECALLBACKERROR; + } + + // used for testing + $.plot.composeImages = composeImages; + + function init(plot) { + // used to extend the public API of the plot + plot.composeImages = composeImages; + } + + $.plot.plugins.push({ + init: init, + name: 'composeImages', + version: '1.0' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.crosshair.js b/extern/phmap/benchmark/js/jquery.flot.crosshair.js new file mode 100644 index 0000000..385c705 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.crosshair.js @@ -0,0 +1,202 @@ +/* Flot plugin for showing crosshairs when the mouse hovers over the plot. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + + crosshair: { + mode: null or "x" or "y" or "xy" + color: color + lineWidth: number + } + +Set the mode to one of "x", "y" or "xy". The "x" mode enables a vertical +crosshair that lets you trace the values on the x axis, "y" enables a +horizontal crosshair and "xy" enables them both. "color" is the color of the +crosshair (default is "rgba(170, 0, 0, 0.80)"), "lineWidth" is the width of +the drawn lines (default is 1). + +The plugin also adds four public methods: + + - setCrosshair( pos ) + + Set the position of the crosshair. Note that this is cleared if the user + moves the mouse. "pos" is in coordinates of the plot and should be on the + form { x: xpos, y: ypos } (you can use x2/x3/... if you're using multiple + axes), which is coincidentally the same format as what you get from a + "plothover" event. If "pos" is null, the crosshair is cleared. + + - clearCrosshair() + + Clear the crosshair. + + - lockCrosshair(pos) + + Cause the crosshair to lock to the current location, no longer updating if + the user moves the mouse. Optionally supply a position (passed on to + setCrosshair()) to move it to. + + Example usage: + + var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } }; + $("#graph").bind( "plothover", function ( evt, position, item ) { + if ( item ) { + // Lock the crosshair to the data point being hovered + myFlot.lockCrosshair({ + x: item.datapoint[ 0 ], + y: item.datapoint[ 1 ] + }); + } else { + // Return normal crosshair operation + myFlot.unlockCrosshair(); + } + }); + + - unlockCrosshair() + + Free the crosshair to move again after locking it. +*/ + +(function ($) { + var options = { + crosshair: { + mode: null, // one of null, "x", "y" or "xy", + color: "rgba(170, 0, 0, 0.80)", + lineWidth: 1 + } + }; + + function init(plot) { + // position of crosshair in pixels + var crosshair = {x: -1, y: -1, locked: false, highlighted: false}; + + plot.setCrosshair = function setCrosshair(pos) { + if (!pos) { + crosshair.x = -1; + } else { + var o = plot.p2c(pos); + crosshair.x = Math.max(0, Math.min(o.left, plot.width())); + crosshair.y = Math.max(0, Math.min(o.top, plot.height())); + } + + plot.triggerRedrawOverlay(); + }; + + plot.clearCrosshair = plot.setCrosshair; // passes null for pos + + plot.lockCrosshair = function lockCrosshair(pos) { + if (pos) { + plot.setCrosshair(pos); + } + + crosshair.locked = true; + }; + + plot.unlockCrosshair = function unlockCrosshair() { + crosshair.locked = false; + crosshair.rect = null; + }; + + function onMouseOut(e) { + if (crosshair.locked) { + return; + } + + if (crosshair.x !== -1) { + crosshair.x = -1; + plot.triggerRedrawOverlay(); + } + } + + function onMouseMove(e) { + var offset = plot.offset(); + if (crosshair.locked) { + var mouseX = Math.max(0, Math.min(e.pageX - offset.left, plot.width())); + var mouseY = Math.max(0, Math.min(e.pageY - offset.top, plot.height())); + + if ((mouseX > crosshair.x - 4) && (mouseX < crosshair.x + 4) && (mouseY > crosshair.y - 4) && (mouseY < crosshair.y + 4)) { + if (!crosshair.highlighted) { + crosshair.highlighted = true; + plot.triggerRedrawOverlay(); + } + } else { + if (crosshair.highlighted) { + crosshair.highlighted = false; + plot.triggerRedrawOverlay(); + } + } + return; + } + + if (plot.getSelection && plot.getSelection()) { + crosshair.x = -1; // hide the crosshair while selecting + return; + } + + crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width())); + crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height())); + plot.triggerRedrawOverlay(); + } + + plot.hooks.bindEvents.push(function (plot, eventHolder) { + if (!plot.getOptions().crosshair.mode) { + return; + } + + eventHolder.mouseout(onMouseOut); + eventHolder.mousemove(onMouseMove); + }); + + plot.hooks.drawOverlay.push(function (plot, ctx) { + var c = plot.getOptions().crosshair; + if (!c.mode) { + return; + } + + var plotOffset = plot.getPlotOffset(); + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + if (crosshair.x !== -1) { + var adj = plot.getOptions().crosshair.lineWidth % 2 ? 0.5 : 0; + + ctx.strokeStyle = c.color; + ctx.lineWidth = c.lineWidth; + ctx.lineJoin = "round"; + + ctx.beginPath(); + if (c.mode.indexOf("x") !== -1) { + var drawX = Math.floor(crosshair.x) + adj; + ctx.moveTo(drawX, 0); + ctx.lineTo(drawX, plot.height()); + } + if (c.mode.indexOf("y") !== -1) { + var drawY = Math.floor(crosshair.y) + adj; + ctx.moveTo(0, drawY); + ctx.lineTo(plot.width(), drawY); + } + if (crosshair.locked) { + if (crosshair.highlighted) ctx.fillStyle = 'orange'; + else ctx.fillStyle = c.color; + ctx.fillRect(Math.floor(crosshair.x) + adj - 4, Math.floor(crosshair.y) + adj - 4, 8, 8); + } + ctx.stroke(); + } + ctx.restore(); + }); + + plot.hooks.shutdown.push(function (plot, eventHolder) { + eventHolder.unbind("mouseout", onMouseOut); + eventHolder.unbind("mousemove", onMouseMove); + }); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'crosshair', + version: '1.0' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.drawSeries.js b/extern/phmap/benchmark/js/jquery.flot.drawSeries.js new file mode 100644 index 0000000..472ad30 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.drawSeries.js @@ -0,0 +1,604 @@ +/** +## jquery.flot.drawSeries.js + +This plugin is used by flot for drawing lines, plots, bars or area. + +### Public methods +*/ + +(function($) { + "use strict"; + + function DrawSeries() { + function plotLine(datapoints, xoffset, yoffset, axisx, axisy, ctx) { + var points = datapoints.points, + ps = datapoints.pointsize, + prevx = null, + prevy = null; + var x1 = 0.0, + y1 = 0.0, + x2 = 0.0, + y2 = 0.0, + i = 0; + + ctx.beginPath(); + for (i = ps; i < points.length; i += ps) { + x1 = points[i - ps]; + y1 = points[i - ps + 1]; + x2 = points[i]; + y2 = points[i + 1]; + + if (x1 === null || x2 === null) { + continue; + } + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min) { + if (y2 < axisy.min) { + // line segment is outside + continue; + } + // compute new intersection point + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } else if (y2 <= y1 && y2 < axisy.min) { + if (y1 < axisy.min) { + continue; + } + + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max) { + if (y2 > axisy.max) { + continue; + } + + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } else if (y2 >= y1 && y2 > axisy.max) { + if (y1 > axisy.max) { + continue; + } + + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) { + continue; + } + + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) { + continue; + } + + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) { + continue; + } + + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) { + continue; + } + + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (x1 !== prevx || y1 !== prevy) { + ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset); + } + + prevx = x2; + prevy = y2; + ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset); + } + ctx.stroke(); + } + + function plotLineArea(datapoints, axisx, axisy, fillTowards, ctx) { + var points = datapoints.points, + ps = datapoints.pointsize, + bottom = fillTowards > axisy.min ? Math.min(axisy.max, fillTowards) : axisy.min, + i = 0, + ypos = 1, + areaOpen = false, + segmentStart = 0, + segmentEnd = 0; + + // we process each segment in two turns, first forward + // direction to sketch out top, then once we hit the + // end we go backwards to sketch the bottom + while (true) { + if (ps > 0 && i > points.length + ps) { + break; + } + + i += ps; // ps is negative if going backwards + + var x1 = points[i - ps], + y1 = points[i - ps + ypos], + x2 = points[i], + y2 = points[i + ypos]; + + if (ps === -2) { + /* going backwards and no value for the bottom provided in the series*/ + y1 = y2 = bottom; + } + + if (areaOpen) { + if (ps > 0 && x1 != null && x2 == null) { + // at turning point + segmentEnd = i; + ps = -ps; + ypos = 2; + continue; + } + + if (ps < 0 && i === segmentStart + ps) { + // done with the reverse sweep + ctx.fill(); + areaOpen = false; + ps = -ps; + i = segmentStart = segmentEnd + ps; + continue; + } + } + + if (x1 == null || x2 == null) { + continue; + } + + // clip x values + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) { + continue; + } + + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) { + continue; + } + + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) { + continue; + } + + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) { + continue; + } + + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (!areaOpen) { + // open area + ctx.beginPath(); + ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom)); + areaOpen = true; + } + + // now first check the case where both is outside + if (y1 >= axisy.max && y2 >= axisy.max) { + ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max)); + continue; + } else if (y1 <= axisy.min && y2 <= axisy.min) { + ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min)); + continue; + } + + // else it's a bit more complicated, there might + // be a flat maxed out rectangle first, then a + // triangular cutout or reverse; to find these + // keep track of the current x values + var x1old = x1, + x2old = x2; + + // clip the y values, without shortcutting, we + // go through all cases in turn + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) { + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) { + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) { + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) { + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // if the x value was changed we got a rectangle + // to fill + if (x1 !== x1old) { + ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1)); + // it goes to (x1, y1), but we fill that below + } + + // fill triangular section, this sometimes result + // in redundant points if (x1, y1) hasn't changed + // from previous line to, but we just ignore that + ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); + + // fill the other rectangle if it's there + if (x2 !== x2old) { + ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); + ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2)); + } + } + } + + /** + - drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) + + This function is used for drawing lines or area fill. In case the series has line decimation function + attached, before starting to draw, as an optimization the points will first be decimated. + + The series parameter contains the series to be drawn on ctx context. The plotOffset, plotWidth and + plotHeight are the corresponding parameters of flot used to determine the drawing surface. + The function getColorOrGradient is used to compute the fill style of lines and area. + */ + function drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) { + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + ctx.lineJoin = "round"; + + if (series.lines.dashes && ctx.setLineDash) { + ctx.setLineDash(series.lines.dashes); + } + + var datapoints = { + format: series.datapoints.format, + points: series.datapoints.points, + pointsize: series.datapoints.pointsize + }; + + if (series.decimate) { + datapoints.points = series.decimate(series, series.xaxis.min, series.xaxis.max, plotWidth, series.yaxis.min, series.yaxis.max, plotHeight); + } + + var lw = series.lines.lineWidth; + + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight, getColorOrGradient); + if (fillStyle) { + ctx.fillStyle = fillStyle; + plotLineArea(datapoints, series.xaxis, series.yaxis, series.lines.fillTowards || 0, ctx); + } + + if (lw > 0) { + plotLine(datapoints, 0, 0, series.xaxis, series.yaxis, ctx); + } + + ctx.restore(); + } + + /** + - drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) + + This function is used for drawing points using a given symbol. In case the series has points decimation + function attached, before starting to draw, as an optimization the points will first be decimated. + + The series parameter contains the series to be drawn on ctx context. The plotOffset, plotWidth and + plotHeight are the corresponding parameters of flot used to determine the drawing surface. + The function drawSymbol is used to compute and draw the symbol chosen for the points. + */ + function drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) { + function drawCircle(ctx, x, y, radius, shadow, fill) { + ctx.moveTo(x + radius, y); + ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false); + } + drawCircle.fill = true; + function plotPoints(datapoints, radius, fill, offset, shadow, axisx, axisy, drawSymbolFn) { + var points = datapoints.points, + ps = datapoints.pointsize; + + ctx.beginPath(); + for (var i = 0; i < points.length; i += ps) { + var x = points[i], + y = points[i + 1]; + if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) { + continue; + } + + x = axisx.p2c(x); + y = axisy.p2c(y) + offset; + + drawSymbolFn(ctx, x, y, radius, shadow, fill); + } + if (drawSymbolFn.fill && !shadow) { + ctx.fill(); + } + ctx.stroke(); + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var datapoints = { + format: series.datapoints.format, + points: series.datapoints.points, + pointsize: series.datapoints.pointsize + }; + + if (series.decimatePoints) { + datapoints.points = series.decimatePoints(series, series.xaxis.min, series.xaxis.max, plotWidth, series.yaxis.min, series.yaxis.max, plotHeight); + } + + var lw = series.points.lineWidth, + radius = series.points.radius, + symbol = series.points.symbol, + drawSymbolFn; + + if (symbol === 'circle') { + drawSymbolFn = drawCircle; + } else if (typeof symbol === 'string' && drawSymbol && drawSymbol[symbol]) { + drawSymbolFn = drawSymbol[symbol]; + } else if (typeof drawSymbol === 'function') { + drawSymbolFn = drawSymbol; + } + + // If the user sets the line width to 0, we change it to a very + // small value. A line width of 0 seems to force the default of 1. + + if (lw === 0) { + lw = 0.0001; + } + + ctx.lineWidth = lw; + ctx.fillStyle = getFillStyle(series.points, series.color, null, null, getColorOrGradient); + ctx.strokeStyle = series.color; + plotPoints(datapoints, radius, + true, 0, false, + series.xaxis, series.yaxis, drawSymbolFn); + ctx.restore(); + } + + function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) { + var left = x + barLeft, + right = x + barRight, + bottom = b, top = y, + drawLeft, drawRight, drawTop, drawBottom = false, + tmp; + + drawLeft = drawRight = drawTop = true; + + // in horizontal mode, we start the bar from the left + // instead of from the bottom so it appears to be + // horizontal rather than vertical + if (horizontal) { + drawBottom = drawRight = drawTop = true; + drawLeft = false; + left = b; + right = x; + top = y + barLeft; + bottom = y + barRight; + + // account for negative bars + if (right < left) { + tmp = right; + right = left; + left = tmp; + drawLeft = true; + drawRight = false; + } + } + else { + drawLeft = drawRight = drawTop = true; + drawBottom = false; + left = x + barLeft; + right = x + barRight; + bottom = b; + top = y; + + // account for negative bars + if (top < bottom) { + tmp = top; + top = bottom; + bottom = tmp; + drawBottom = true; + drawTop = false; + } + } + + // clip + if (right < axisx.min || left > axisx.max || + top < axisy.min || bottom > axisy.max) { + return; + } + + if (left < axisx.min) { + left = axisx.min; + drawLeft = false; + } + + if (right > axisx.max) { + right = axisx.max; + drawRight = false; + } + + if (bottom < axisy.min) { + bottom = axisy.min; + drawBottom = false; + } + + if (top > axisy.max) { + top = axisy.max; + drawTop = false; + } + + left = axisx.p2c(left); + bottom = axisy.p2c(bottom); + right = axisx.p2c(right); + top = axisy.p2c(top); + + // fill the bar + if (fillStyleCallback) { + c.fillStyle = fillStyleCallback(bottom, top); + c.fillRect(left, top, right - left, bottom - top) + } + + // draw outline + if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) { + c.beginPath(); + + // FIXME: inline moveTo is buggy with excanvas + c.moveTo(left, bottom); + if (drawLeft) { + c.lineTo(left, top); + } else { + c.moveTo(left, top); + } + + if (drawTop) { + c.lineTo(right, top); + } else { + c.moveTo(right, top); + } + + if (drawRight) { + c.lineTo(right, bottom); + } else { + c.moveTo(right, bottom); + } + + if (drawBottom) { + c.lineTo(left, bottom); + } else { + c.moveTo(left, bottom); + } + + c.stroke(); + } + } + + /** + - drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) + + This function is used for drawing series represented as bars. In case the series has decimation + function attached, before starting to draw, as an optimization the points will first be decimated. + + The series parameter contains the series to be drawn on ctx context. The plotOffset, plotWidth and + plotHeight are the corresponding parameters of flot used to determine the drawing surface. + The function getColorOrGradient is used to compute the fill style of bars. + */ + function drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) { + function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) { + var points = datapoints.points, + ps = datapoints.pointsize, + fillTowards = series.bars.fillTowards || 0, + calculatedBottom = fillTowards > axisy.min ? Math.min(axisy.max, fillTowards) : axisy.min; + + for (var i = 0; i < points.length; i += ps) { + if (points[i] == null) { + continue; + } + + // Use third point as bottom if pointsize is 3 + var bottom = ps === 3 ? points[i + 2] : calculatedBottom; + drawBar(points[i], points[i + 1], bottom, barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth); + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var datapoints = { + format: series.datapoints.format, + points: series.datapoints.points, + pointsize: series.datapoints.pointsize + }; + + if (series.decimate) { + datapoints.points = series.decimate(series, series.xaxis.min, series.xaxis.max, plotWidth); + } + + ctx.lineWidth = series.bars.lineWidth; + ctx.strokeStyle = series.color; + + var barLeft; + var barWidth = series.bars.barWidth[0] || series.bars.barWidth; + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -barWidth; + break; + default: + barLeft = -barWidth / 2; + } + + var fillStyleCallback = series.bars.fill ? function(bottom, top) { + return getFillStyle(series.bars, series.color, bottom, top, getColorOrGradient); + } : null; + + plotBars(datapoints, barLeft, barLeft + barWidth, fillStyleCallback, series.xaxis, series.yaxis); + ctx.restore(); + } + + function getFillStyle(filloptions, seriesColor, bottom, top, getColorOrGradient) { + var fill = filloptions.fill; + if (!fill) { + return null; + } + + if (filloptions.fillColor) { + return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor); + } + + var c = $.color.parse(seriesColor); + c.a = typeof fill === "number" ? fill : 0.4; + c.normalize(); + return c.toString(); + } + + this.drawSeriesLines = drawSeriesLines; + this.drawSeriesPoints = drawSeriesPoints; + this.drawSeriesBars = drawSeriesBars; + this.drawBar = drawBar; + }; + + $.plot.drawSeries = new DrawSeries(); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.errorbars.js b/extern/phmap/benchmark/js/jquery.flot.errorbars.js new file mode 100644 index 0000000..956562e --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.errorbars.js @@ -0,0 +1,375 @@ +/* Flot plugin for plotting error bars. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +Error bars are used to show standard deviation and other statistical +properties in a plot. + +* Created by Rui Pereira - rui (dot) pereira (at) gmail (dot) com + +This plugin allows you to plot error-bars over points. Set "errorbars" inside +the points series to the axis name over which there will be error values in +your data array (*even* if you do not intend to plot them later, by setting +"show: null" on xerr/yerr). + +The plugin supports these options: + + series: { + points: { + errorbars: "x" or "y" or "xy", + xerr: { + show: null/false or true, + asymmetric: null/false or true, + upperCap: null or "-" or function, + lowerCap: null or "-" or function, + color: null or color, + radius: null or number + }, + yerr: { same options as xerr } + } + } + +Each data point array is expected to be of the type: + + "x" [ x, y, xerr ] + "y" [ x, y, yerr ] + "xy" [ x, y, xerr, yerr ] + +Where xerr becomes xerr_lower,xerr_upper for the asymmetric error case, and +equivalently for yerr. Eg., a datapoint for the "xy" case with symmetric +error-bars on X and asymmetric on Y would be: + + [ x, y, xerr, yerr_lower, yerr_upper ] + +By default no end caps are drawn. Setting upperCap and/or lowerCap to "-" will +draw a small cap perpendicular to the error bar. They can also be set to a +user-defined drawing function, with (ctx, x, y, radius) as parameters, as eg. + + function drawSemiCircle( ctx, x, y, radius ) { + ctx.beginPath(); + ctx.arc( x, y, radius, 0, Math.PI, false ); + ctx.moveTo( x - radius, y ); + ctx.lineTo( x + radius, y ); + ctx.stroke(); + } + +Color and radius both default to the same ones of the points series if not +set. The independent radius parameter on xerr/yerr is useful for the case when +we may want to add error-bars to a line, without showing the interconnecting +points (with radius: 0), and still showing end caps on the error-bars. +shadowSize and lineWidth are derived as well from the points series. + +*/ + +(function ($) { + var options = { + series: { + points: { + errorbars: null, //should be 'x', 'y' or 'xy' + xerr: {err: 'x', show: null, asymmetric: null, upperCap: null, lowerCap: null, color: null, radius: null}, + yerr: {err: 'y', show: null, asymmetric: null, upperCap: null, lowerCap: null, color: null, radius: null} + } + } + }; + + function processRawData(plot, series, data, datapoints) { + if (!series.points.errorbars) { + return; + } + + // x,y values + var format = [ + { x: true, number: true, required: true }, + { y: true, number: true, required: true } + ]; + + var errors = series.points.errorbars; + // error bars - first X then Y + if (errors === 'x' || errors === 'xy') { + // lower / upper error + if (series.points.xerr.asymmetric) { + format.push({ x: true, number: true, required: true }); + format.push({ x: true, number: true, required: true }); + } else { + format.push({ x: true, number: true, required: true }); + } + } + if (errors === 'y' || errors === 'xy') { + // lower / upper error + if (series.points.yerr.asymmetric) { + format.push({ y: true, number: true, required: true }); + format.push({ y: true, number: true, required: true }); + } else { + format.push({ y: true, number: true, required: true }); + } + } + datapoints.format = format; + } + + function parseErrors(series, i) { + var points = series.datapoints.points; + + // read errors from points array + var exl = null, + exu = null, + eyl = null, + eyu = null; + var xerr = series.points.xerr, + yerr = series.points.yerr; + + var eb = series.points.errorbars; + // error bars - first X + if (eb === 'x' || eb === 'xy') { + if (xerr.asymmetric) { + exl = points[i + 2]; + exu = points[i + 3]; + if (eb === 'xy') { + if (yerr.asymmetric) { + eyl = points[i + 4]; + eyu = points[i + 5]; + } else { + eyl = points[i + 4]; + } + } + } else { + exl = points[i + 2]; + if (eb === 'xy') { + if (yerr.asymmetric) { + eyl = points[i + 3]; + eyu = points[i + 4]; + } else { + eyl = points[i + 3]; + } + } + } + // only Y + } else { + if (eb === 'y') { + if (yerr.asymmetric) { + eyl = points[i + 2]; + eyu = points[i + 3]; + } else { + eyl = points[i + 2]; + } + } + } + + // symmetric errors? + if (exu == null) exu = exl; + if (eyu == null) eyu = eyl; + + var errRanges = [exl, exu, eyl, eyu]; + // nullify if not showing + if (!xerr.show) { + errRanges[0] = null; + errRanges[1] = null; + } + if (!yerr.show) { + errRanges[2] = null; + errRanges[3] = null; + } + return errRanges; + } + + function drawSeriesErrors(plot, ctx, s) { + var points = s.datapoints.points, + ps = s.datapoints.pointsize, + ax = [s.xaxis, s.yaxis], + radius = s.points.radius, + err = [s.points.xerr, s.points.yerr], + tmp; + + //sanity check, in case some inverted axis hack is applied to flot + var invertX = false; + if (ax[0].p2c(ax[0].max) < ax[0].p2c(ax[0].min)) { + invertX = true; + tmp = err[0].lowerCap; + err[0].lowerCap = err[0].upperCap; + err[0].upperCap = tmp; + } + + var invertY = false; + if (ax[1].p2c(ax[1].min) < ax[1].p2c(ax[1].max)) { + invertY = true; + tmp = err[1].lowerCap; + err[1].lowerCap = err[1].upperCap; + err[1].upperCap = tmp; + } + + for (var i = 0; i < s.datapoints.points.length; i += ps) { + //parse + var errRanges = parseErrors(s, i); + + //cycle xerr & yerr + for (var e = 0; e < err.length; e++) { + var minmax = [ax[e].min, ax[e].max]; + + //draw this error? + if (errRanges[e * err.length]) { + //data coordinates + var x = points[i], + y = points[i + 1]; + + //errorbar ranges + var upper = [x, y][e] + errRanges[e * err.length + 1], + lower = [x, y][e] - errRanges[e * err.length]; + + //points outside of the canvas + if (err[e].err === 'x') { + if (y > ax[1].max || y < ax[1].min || upper < ax[0].min || lower > ax[0].max) { + continue; + } + } + + if (err[e].err === 'y') { + if (x > ax[0].max || x < ax[0].min || upper < ax[1].min || lower > ax[1].max) { + continue; + } + } + + // prevent errorbars getting out of the canvas + var drawUpper = true, + drawLower = true; + + if (upper > minmax[1]) { + drawUpper = false; + upper = minmax[1]; + } + if (lower < minmax[0]) { + drawLower = false; + lower = minmax[0]; + } + + //sanity check, in case some inverted axis hack is applied to flot + if ((err[e].err === 'x' && invertX) || (err[e].err === 'y' && invertY)) { + //swap coordinates + tmp = lower; + lower = upper; + upper = tmp; + tmp = drawLower; + drawLower = drawUpper; + drawUpper = tmp; + tmp = minmax[0]; + minmax[0] = minmax[1]; + minmax[1] = tmp; + } + + // convert to pixels + x = ax[0].p2c(x); + y = ax[1].p2c(y); + upper = ax[e].p2c(upper); + lower = ax[e].p2c(lower); + minmax[0] = ax[e].p2c(minmax[0]); + minmax[1] = ax[e].p2c(minmax[1]); + + //same style as points by default + var lw = err[e].lineWidth ? err[e].lineWidth : s.points.lineWidth, + sw = s.points.shadowSize != null ? s.points.shadowSize : s.shadowSize; + + //shadow as for points + if (lw > 0 && sw > 0) { + var w = sw / 2; + ctx.lineWidth = w; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + drawError(ctx, err[e], x, y, upper, lower, drawUpper, drawLower, radius, w + w / 2, minmax); + + ctx.strokeStyle = "rgba(0,0,0,0.2)"; + drawError(ctx, err[e], x, y, upper, lower, drawUpper, drawLower, radius, w / 2, minmax); + } + + ctx.strokeStyle = err[e].color + ? err[e].color + : s.color; + ctx.lineWidth = lw; + //draw it + drawError(ctx, err[e], x, y, upper, lower, drawUpper, drawLower, radius, 0, minmax); + } + } + } + } + + function drawError(ctx, err, x, y, upper, lower, drawUpper, drawLower, radius, offset, minmax) { + //shadow offset + y += offset; + upper += offset; + lower += offset; + + // error bar - avoid plotting over circles + if (err.err === 'x') { + if (upper > x + radius) drawPath(ctx, [[upper, y], [Math.max(x + radius, minmax[0]), y]]); + else drawUpper = false; + + if (lower < x - radius) drawPath(ctx, [[Math.min(x - radius, minmax[1]), y], [lower, y]]); + else drawLower = false; + } else { + if (upper < y - radius) drawPath(ctx, [[x, upper], [x, Math.min(y - radius, minmax[0])]]); + else drawUpper = false; + + if (lower > y + radius) drawPath(ctx, [[x, Math.max(y + radius, minmax[1])], [x, lower]]); + else drawLower = false; + } + + //internal radius value in errorbar, allows to plot radius 0 points and still keep proper sized caps + //this is a way to get errorbars on lines without visible connecting dots + radius = err.radius != null + ? err.radius + : radius; + + // upper cap + if (drawUpper) { + if (err.upperCap === '-') { + if (err.err === 'x') drawPath(ctx, [[upper, y - radius], [upper, y + radius]]); + else drawPath(ctx, [[x - radius, upper], [x + radius, upper]]); + } else if ($.isFunction(err.upperCap)) { + if (err.err === 'x') err.upperCap(ctx, upper, y, radius); + else err.upperCap(ctx, x, upper, radius); + } + } + // lower cap + if (drawLower) { + if (err.lowerCap === '-') { + if (err.err === 'x') drawPath(ctx, [[lower, y - radius], [lower, y + radius]]); + else drawPath(ctx, [[x - radius, lower], [x + radius, lower]]); + } else if ($.isFunction(err.lowerCap)) { + if (err.err === 'x') err.lowerCap(ctx, lower, y, radius); + else err.lowerCap(ctx, x, lower, radius); + } + } + } + + function drawPath(ctx, pts) { + ctx.beginPath(); + ctx.moveTo(pts[0][0], pts[0][1]); + for (var p = 1; p < pts.length; p++) { + ctx.lineTo(pts[p][0], pts[p][1]); + } + + ctx.stroke(); + } + + function draw(plot, ctx) { + var plotOffset = plot.getPlotOffset(); + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + $.each(plot.getData(), function (i, s) { + if (s.points.errorbars && (s.points.xerr.show || s.points.yerr.show)) { + drawSeriesErrors(plot, ctx, s); + } + }); + ctx.restore(); + } + + function init(plot) { + plot.hooks.processRawData.push(processRawData); + plot.hooks.draw.push(draw); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'errorbars', + version: '1.0' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.fillbetween.js b/extern/phmap/benchmark/js/jquery.flot.fillbetween.js new file mode 100644 index 0000000..96cb292 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.fillbetween.js @@ -0,0 +1,254 @@ +/* Flot plugin for computing bottoms for filled line and bar charts. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The case: you've got two series that you want to fill the area between. In Flot +terms, you need to use one as the fill bottom of the other. You can specify the +bottom of each data point as the third coordinate manually, or you can use this +plugin to compute it for you. + +In order to name the other series, you need to give it an id, like this: + + var dataset = [ + { data: [ ... ], id: "foo" } , // use default bottom + { data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom + ]; + + $.plot($("#placeholder"), dataset, { lines: { show: true, fill: true }}); + +As a convenience, if the id given is a number that doesn't appear as an id in +the series, it is interpreted as the index in the array instead (so fillBetween: +0 can also mean the first series). + +Internally, the plugin modifies the datapoints in each series. For line series, +extra data points might be inserted through interpolation. Note that at points +where the bottom line is not defined (due to a null point or start/end of line), +the current line will show a gap too. The algorithm comes from the +jquery.flot.stack.js plugin, possibly some code could be shared. + +*/ + +(function ($) { + var options = { + series: { + fillBetween: null // or number + } + }; + + function init(plot) { + function findBottomSeries(s, allseries) { + var i; + + for (i = 0; i < allseries.length; ++i) { + if (allseries[ i ].id === s.fillBetween) { + return allseries[ i ]; + } + } + + if (typeof s.fillBetween === "number") { + if (s.fillBetween < 0 || s.fillBetween >= allseries.length) { + return null; + } + return allseries[ s.fillBetween ]; + } + + return null; + } + + function computeFormat(plot, s, data, datapoints) { + if (s.fillBetween == null) { + return; + } + + format = datapoints.format; + var plotHasId = function(id) { + var plotData = plot.getData(); + for (i = 0; i < plotData.length; i++) { + if (plotData[i].id === id) { + return true; + } + } + + return false; + } + + if (!format) { + format = []; + + format.push({ + x: true, + number: true, + computeRange: s.xaxis.options.autoScale !== 'none', + required: true + }); + format.push({ + y: true, + number: true, + computeRange: s.yaxis.options.autoScale !== 'none', + required: true + }); + + if (s.fillBetween !== undefined && s.fillBetween !== '' && plotHasId(s.fillBetween) && s.fillBetween !== s.id) { + format.push({ + x: false, + y: true, + number: true, + required: false, + computeRange: s.yaxis.options.autoScale !== 'none', + defaultValue: 0 + }); + } + + datapoints.format = format; + } + } + + function computeFillBottoms(plot, s, datapoints) { + if (s.fillBetween == null) { + return; + } + + var other = findBottomSeries(s, plot.getData()); + + if (!other) { + return; + } + + var ps = datapoints.pointsize, + points = datapoints.points, + otherps = other.datapoints.pointsize, + otherpoints = other.datapoints.points, + newpoints = [], + px, py, intery, qx, qy, bottom, + withlines = s.lines.show, + withbottom = ps > 2 && datapoints.format[2].y, + withsteps = withlines && s.lines.steps, + fromgap = true, + i = 0, + j = 0, + l, m; + + while (true) { + if (i >= points.length) { + break; + } + + l = newpoints.length; + + if (points[ i ] == null) { + // copy gaps + for (m = 0; m < ps; ++m) { + newpoints.push(points[ i + m ]); + } + + i += ps; + } else if (j >= otherpoints.length) { + // for lines, we can't use the rest of the points + if (!withlines) { + for (m = 0; m < ps; ++m) { + newpoints.push(points[ i + m ]); + } + } + + i += ps; + } else if (otherpoints[ j ] == null) { + // oops, got a gap + for (m = 0; m < ps; ++m) { + newpoints.push(null); + } + + fromgap = true; + j += otherps; + } else { + // cases where we actually got two points + px = points[ i ]; + py = points[ i + 1 ]; + qx = otherpoints[ j ]; + qy = otherpoints[ j + 1 ]; + bottom = 0; + + if (px === qx) { + for (m = 0; m < ps; ++m) { + newpoints.push(points[ i + m ]); + } + + //newpoints[ l + 1 ] += qy; + bottom = qy; + + i += ps; + j += otherps; + } else if (px > qx) { + // we got past point below, might need to + // insert interpolated extra point + + if (withlines && i > 0 && points[ i - ps ] != null) { + intery = py + (points[ i - ps + 1 ] - py) * (qx - px) / (points[ i - ps ] - px); + newpoints.push(qx); + newpoints.push(intery); + for (m = 2; m < ps; ++m) { + newpoints.push(points[ i + m ]); + } + bottom = qy; + } + + j += otherps; + } else { + // px < qx + // if we come from a gap, we just skip this point + + if (fromgap && withlines) { + i += ps; + continue; + } + + for (m = 0; m < ps; ++m) { + newpoints.push(points[ i + m ]); + } + + // we might be able to interpolate a point below, + // this can give us a better y + + if (withlines && j > 0 && otherpoints[ j - otherps ] != null) { + bottom = qy + (otherpoints[ j - otherps + 1 ] - qy) * (px - qx) / (otherpoints[ j - otherps ] - qx); + } + + //newpoints[l + 1] += bottom; + + i += ps; + } + + fromgap = false; + + if (l !== newpoints.length && withbottom) { + newpoints[ l + 2 ] = bottom; + } + } + + // maintain the line steps invariant + + if (withsteps && l !== newpoints.length && l > 0 && + newpoints[ l ] !== null && + newpoints[ l ] !== newpoints[ l - ps ] && + newpoints[ l + 1 ] !== newpoints[ l - ps + 1 ]) { + for (m = 0; m < ps; ++m) { + newpoints[ l + ps + m ] = newpoints[ l + m ]; + } + newpoints[ l + 1 ] = newpoints[ l - ps + 1 ]; + } + } + + datapoints.points = newpoints; + } + + plot.hooks.processRawData.push(computeFormat); + plot.hooks.processDatapoints.push(computeFillBottoms); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: "fillbetween", + version: "1.0" + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.flatdata.js b/extern/phmap/benchmark/js/jquery.flot.flatdata.js new file mode 100644 index 0000000..b91d168 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.flatdata.js @@ -0,0 +1,47 @@ +/* Support for flat 1D data series. + +A 1D flat data series is a data series in the form of a regular 1D array. The +main reason for using a flat data series is that it performs better, consumes +less memory and generates less garbage collection than the regular flot format. + +Example: + + plot.setData([[[0,0], [1,1], [2,2], [3,3]]]); // regular flot format + plot.setData([{flatdata: true, data: [0, 1, 2, 3]}]); // flatdata format + +Set series.flatdata to true to enable this plugin. + +You can use series.start to specify the starting index of the series (default is 0) +You can use series.step to specify the interval between consecutive indexes of the series (default is 1) +*/ + +/* global jQuery*/ + +(function ($) { + 'use strict'; + + function process1DRawData(plot, series, data, datapoints) { + if (series.flatdata === true) { + var start = series.start || 0; + var step = typeof series.step === 'number' ? series.step : 1; + datapoints.pointsize = 2; + for (var i = 0, j = 0; i < data.length; i++, j += 2) { + datapoints.points[j] = start + (i * step); + datapoints.points[j + 1] = data[i]; + } + if (datapoints.points !== undefined) { + datapoints.points.length = data.length * 2; + } else { + datapoints.points = []; + } + } + } + + $.plot.plugins.push({ + init: function(plot) { + plot.hooks.processRawData.push(process1DRawData); + }, + name: 'flatdata', + version: '0.0.2' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.hover.js b/extern/phmap/benchmark/js/jquery.flot.hover.js new file mode 100644 index 0000000..4f0f08e --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.hover.js @@ -0,0 +1,346 @@ +/* global jQuery */ + +/** +## jquery.flot.hover.js + +This plugin is used for mouse hover and tap on a point of plot series. +It supports the following options: +```js +grid: { + hoverable: false, //to trigger plothover event on mouse hover or tap on a point + clickable: false //to trigger plotclick event on mouse hover +} +``` + +It listens to native mouse move event or click, as well as artificial generated +tap and touchevent. + +When the mouse is over a point or a tap on a point is performed, that point or +the correscponding bar will be highlighted and a "plothover" event will be generated. + +Custom "touchevent" is triggered when any touch interaction is made. Hover plugin +handles this events by unhighlighting all of the previously highlighted points and generates +"plothovercleanup" event to notify any part that is handling plothover (for exemple to cleanup +the tooltip from webcharts). +*/ + +(function($) { + 'use strict'; + + var options = { + grid: { + hoverable: false, + clickable: false + } + }; + + var browser = $.plot.browser; + + function init(plot) { + plot.hooks.processOptions.push(initHover); + } + + function initHover(plot, options) { + var highlights = []; + + var eventType = { + click: 'click', + hover: 'hover' + } + + var lastMouseMoveEvent = plot.getPlaceholder()[0].lastMouseMoveEvent; + + plot.highlight = highlight; + plot.unhighlight = unhighlight; + + function bindEvents(plot, eventHolder) { + var o = plot.getOptions(); + + if (o.grid.hoverable || o.grid.clickable) { + eventHolder[0].addEventListener('touchevent', triggerCleanupEvent, false); + eventHolder[0].addEventListener('tap', tap.generatePlothoverEvent, false); + } + + if (options.grid.clickable) { + eventHolder.click(onClick); + } + + if (options.grid.hoverable) { + eventHolder.mousemove(onMouseMove); + + // Use bind, rather than .mouseleave, because we officially + // still support jQuery 1.2.6, which doesn't define a shortcut + // for mouseenter or mouseleave. This was a bug/oversight that + // was fixed somewhere around 1.3.x. We can return to using + // .mouseleave when we drop support for 1.2.6. + + eventHolder.bind("mouseleave", onMouseLeave); + } + } + + function shutdown(plot, eventHolder) { + eventHolder[0].removeEventListener('tap', tap.generatePlothoverEvent); + eventHolder[0].removeEventListener('tap', triggerCleanupEvent); + eventHolder.unbind("mousemove", onMouseMove); + eventHolder.unbind("mouseleave", onMouseLeave); + eventHolder.unbind("click", onClick); + highlights = []; + } + + function doTriggerClickHoverEvent(event, eventType, searchDistance) { + var series = plot.getData(); + if (event !== undefined + && series.length > 0 + && series[0].xaxis.c2p !== undefined + && series[0].yaxis.c2p !== undefined) { + var eventToTrigger = "plot" + eventType; + var seriesFlag = eventType + "able"; + triggerClickHoverEvent(eventToTrigger, event, + function(i) { + return series[i][seriesFlag] !== false; + }, searchDistance); + } + } + + var tap = { + generatePlothoverEvent: function (e) { + var o = plot.getOptions(), + newEvent = new CustomEvent('mouseevent'); + + //transform from touch event to mouse event format + newEvent.pageX = e.detail.changedTouches[0].pageX; + newEvent.pageY = e.detail.changedTouches[0].pageY; + newEvent.clientX = e.detail.changedTouches[0].clientX; + newEvent.clientY = e.detail.changedTouches[0].clientY; + + if (o.grid.hoverable) { + doTriggerClickHoverEvent(newEvent, eventType.hover, 30); + } + return false; + } + }; + + if (options.grid.hoverable || options.grid.clickable) { + plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); + plot.hooks.drawOverlay.push(drawOverlay); + plot.hooks.processRawData.push(processRawData); + } + + function onMouseMove(e) { + lastMouseMoveEvent = e; + plot.getPlaceholder()[0].lastMouseMoveEvent = e; + doTriggerClickHoverEvent(e, eventType.hover); + } + + function onMouseLeave(e) { + lastMouseMoveEvent = undefined; + plot.getPlaceholder()[0].lastMouseMoveEvent = undefined; + triggerClickHoverEvent("plothover", e, + function(i) { + return false; + }); + } + + function onClick(e) { + doTriggerClickHoverEvent(e, eventType.click); + } + + function triggerCleanupEvent() { + plot.unhighlight(); + plot.getPlaceholder().trigger('plothovercleanup'); + } + + // trigger click or hover event (they send the same parameters + // so we share their code) + function triggerClickHoverEvent(eventname, event, seriesFilter, searchDistance) { + var options = plot.getOptions(), + offset = plot.offset(), + page = browser.getPageXY(event), + canvasX = page.X - offset.left, + canvasY = page.Y - offset.top, + pos = plot.c2p({ + left: canvasX, + top: canvasY + }), + distance = searchDistance !== undefined ? searchDistance : options.grid.mouseActiveRadius; + + pos.pageX = page.X; + pos.pageY = page.Y; + + var item = plot.findNearbyItem(canvasX, canvasY, seriesFilter, distance); + + if (item) { + // fill in mouse pos for any listeners out there + item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left, 10); + item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top, 10); + } + + if (options.grid.autoHighlight) { + // clear auto-highlights + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if ((h.auto === eventname && + !(item && h.series === item.series && + h.point[0] === item.datapoint[0] && + h.point[1] === item.datapoint[1])) || !item) { + unhighlight(h.series, h.point); + } + } + + if (item) { + highlight(item.series, item.datapoint, eventname); + } + } + + plot.getPlaceholder().trigger(eventname, [pos, item]); + } + + function highlight(s, point, auto) { + if (typeof s === "number") { + s = plot.getData()[s]; + } + + if (typeof point === "number") { + var ps = s.datapoints.pointsize; + point = s.datapoints.points.slice(ps * point, ps * (point + 1)); + } + + var i = indexOfHighlight(s, point); + if (i === -1) { + highlights.push({ + series: s, + point: point, + auto: auto + }); + + plot.triggerRedrawOverlay(); + } else if (!auto) { + highlights[i].auto = false; + } + } + + function unhighlight(s, point) { + if (s == null && point == null) { + highlights = []; + plot.triggerRedrawOverlay(); + return; + } + + if (typeof s === "number") { + s = plot.getData()[s]; + } + + if (typeof point === "number") { + var ps = s.datapoints.pointsize; + point = s.datapoints.points.slice(ps * point, ps * (point + 1)); + } + + var i = indexOfHighlight(s, point); + if (i !== -1) { + highlights.splice(i, 1); + + plot.triggerRedrawOverlay(); + } + } + + function indexOfHighlight(s, p) { + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.series === s && + h.point[0] === p[0] && + h.point[1] === p[1]) { + return i; + } + } + + return -1; + } + + function processRawData() { + triggerCleanupEvent(); + doTriggerClickHoverEvent(lastMouseMoveEvent, eventType.hover); + } + + function drawOverlay(plot, octx, overlay) { + var plotOffset = plot.getPlotOffset(), + i, hi; + + octx.save(); + octx.translate(plotOffset.left, plotOffset.top); + for (i = 0; i < highlights.length; ++i) { + hi = highlights[i]; + + if (hi.series.bars.show) drawBarHighlight(hi.series, hi.point, octx); + else drawPointHighlight(hi.series, hi.point, octx, plot); + } + octx.restore(); + } + } + + function drawPointHighlight(series, point, octx, plot) { + var x = point[0], + y = point[1], + axisx = series.xaxis, + axisy = series.yaxis, + highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(); + + if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) { + return; + } + + var pointRadius = series.points.radius + series.points.lineWidth / 2; + octx.lineWidth = pointRadius; + octx.strokeStyle = highlightColor; + var radius = 1.5 * pointRadius; + x = axisx.p2c(x); + y = axisy.p2c(y); + + octx.beginPath(); + var symbol = series.points.symbol; + if (symbol === 'circle') { + octx.arc(x, y, radius, 0, 2 * Math.PI, false); + } else if (typeof symbol === 'string' && plot.drawSymbol && plot.drawSymbol[symbol]) { + plot.drawSymbol[symbol](octx, x, y, radius, false); + } + + octx.closePath(); + octx.stroke(); + } + + function drawBarHighlight(series, point, octx) { + var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(), + fillStyle = highlightColor, + barLeft; + + var barWidth = series.bars.barWidth[0] || series.bars.barWidth; + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -barWidth; + break; + default: + barLeft = -barWidth / 2; + } + + octx.lineWidth = series.bars.lineWidth; + octx.strokeStyle = highlightColor; + + var fillTowards = series.bars.fillTowards || 0, + bottom = fillTowards > series.yaxis.min ? Math.min(series.yaxis.max, fillTowards) : series.yaxis.min; + + $.plot.drawSeries.drawBar(point[0], point[1], point[2] || bottom, barLeft, barLeft + barWidth, + function() { + return fillStyle; + }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'hover', + version: '0.1' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.image.js b/extern/phmap/benchmark/js/jquery.flot.image.js new file mode 100644 index 0000000..ae98fb4 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.image.js @@ -0,0 +1,249 @@ +/* Flot plugin for plotting images. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The data syntax is [ [ image, x1, y1, x2, y2 ], ... ] where (x1, y1) and +(x2, y2) are where you intend the two opposite corners of the image to end up +in the plot. Image must be a fully loaded Javascript image (you can make one +with new Image()). If the image is not complete, it's skipped when plotting. + +There are two helpers included for retrieving images. The easiest work the way +that you put in URLs instead of images in the data, like this: + + [ "myimage.png", 0, 0, 10, 10 ] + +Then call $.plot.image.loadData( data, options, callback ) where data and +options are the same as you pass in to $.plot. This loads the images, replaces +the URLs in the data with the corresponding images and calls "callback" when +all images are loaded (or failed loading). In the callback, you can then call +$.plot with the data set. See the included example. + +A more low-level helper, $.plot.image.load(urls, callback) is also included. +Given a list of URLs, it calls callback with an object mapping from URL to +Image object when all images are loaded or have failed loading. + +The plugin supports these options: + + series: { + images: { + show: boolean + anchor: "corner" or "center" + alpha: [ 0, 1 ] + } + } + +They can be specified for a specific series: + + $.plot( $("#placeholder"), [{ + data: [ ... ], + images: { ... } + ]) + +Note that because the data format is different from usual data points, you +can't use images with anything else in a specific data series. + +Setting "anchor" to "center" causes the pixels in the image to be anchored at +the corner pixel centers inside of at the pixel corners, effectively letting +half a pixel stick out to each side in the plot. + +A possible future direction could be support for tiling for large images (like +Google Maps). + +*/ + +(function ($) { + var options = { + series: { + images: { + show: false, + alpha: 1, + anchor: "corner" // or "center" + } + } + }; + + $.plot.image = {}; + + $.plot.image.loadDataImages = function (series, options, callback) { + var urls = [], points = []; + + var defaultShow = options.series.images.show; + + $.each(series, function (i, s) { + if (!(defaultShow || s.images.show)) { + return; + } + + if (s.data) { + s = s.data; + } + + $.each(s, function (i, p) { + if (typeof p[0] === "string") { + urls.push(p[0]); + points.push(p); + } + }); + }); + + $.plot.image.load(urls, function (loadedImages) { + $.each(points, function (i, p) { + var url = p[0]; + if (loadedImages[url]) { + p[0] = loadedImages[url]; + } + }); + + callback(); + }); + } + + $.plot.image.load = function (urls, callback) { + var missing = urls.length, loaded = {}; + if (missing === 0) { + callback({}); + } + + $.each(urls, function (i, url) { + var handler = function () { + --missing; + loaded[url] = this; + + if (missing === 0) { + callback(loaded); + } + }; + + $('').load(handler).error(handler).attr('src', url); + }); + }; + + function drawSeries(plot, ctx, series) { + var plotOffset = plot.getPlotOffset(); + + if (!series.images || !series.images.show) { + return; + } + + var points = series.datapoints.points, + ps = series.datapoints.pointsize; + + for (var i = 0; i < points.length; i += ps) { + var img = points[i], + x1 = points[i + 1], y1 = points[i + 2], + x2 = points[i + 3], y2 = points[i + 4], + xaxis = series.xaxis, yaxis = series.yaxis, + tmp; + + // actually we should check img.complete, but it + // appears to be a somewhat unreliable indicator in + // IE6 (false even after load event) + if (!img || img.width <= 0 || img.height <= 0) { + continue; + } + + if (x1 > x2) { + tmp = x2; + x2 = x1; + x1 = tmp; + } + if (y1 > y2) { + tmp = y2; + y2 = y1; + y1 = tmp; + } + + // if the anchor is at the center of the pixel, expand the + // image by 1/2 pixel in each direction + if (series.images.anchor === "center") { + tmp = 0.5 * (x2 - x1) / (img.width - 1); + x1 -= tmp; + x2 += tmp; + tmp = 0.5 * (y2 - y1) / (img.height - 1); + y1 -= tmp; + y2 += tmp; + } + + // clip + if (x1 === x2 || y1 === y2 || + x1 >= xaxis.max || x2 <= xaxis.min || + y1 >= yaxis.max || y2 <= yaxis.min) { + continue; + } + + var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height; + if (x1 < xaxis.min) { + sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1); + x1 = xaxis.min; + } + + if (x2 > xaxis.max) { + sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1); + x2 = xaxis.max; + } + + if (y1 < yaxis.min) { + sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1); + y1 = yaxis.min; + } + + if (y2 > yaxis.max) { + sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1); + y2 = yaxis.max; + } + + x1 = xaxis.p2c(x1); + x2 = xaxis.p2c(x2); + y1 = yaxis.p2c(y1); + y2 = yaxis.p2c(y2); + + // the transformation may have swapped us + if (x1 > x2) { + tmp = x2; + x2 = x1; + x1 = tmp; + } + if (y1 > y2) { + tmp = y2; + y2 = y1; + y1 = tmp; + } + + tmp = ctx.globalAlpha; + ctx.globalAlpha *= series.images.alpha; + ctx.drawImage(img, + sx1, sy1, sx2 - sx1, sy2 - sy1, + x1 + plotOffset.left, y1 + plotOffset.top, + x2 - x1, y2 - y1); + ctx.globalAlpha = tmp; + } + } + + function processRawData(plot, series, data, datapoints) { + if (!series.images.show) { + return; + } + + // format is Image, x1, y1, x2, y2 (opposite corners) + datapoints.format = [ + { required: true }, + { x: true, number: true, required: true }, + { y: true, number: true, required: true }, + { x: true, number: true, required: true }, + { y: true, number: true, required: true } + ]; + } + + function init(plot) { + plot.hooks.processRawData.push(processRawData); + plot.hooks.drawSeries.push(drawSeries); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'image', + version: '1.1' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.js b/extern/phmap/benchmark/js/jquery.flot.js new file mode 100644 index 0000000..9469ced --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.js @@ -0,0 +1,2785 @@ +/* Javascript plotting library for jQuery, version 1.0.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ + +// the actual Flot code +(function($) { + "use strict"; + + var Canvas = window.Flot.Canvas; + + function defaultTickGenerator(axis) { + var ticks = [], + start = $.plot.saturated.saturate($.plot.saturated.floorInBase(axis.min, axis.tickSize)), + i = 0, + v = Number.NaN, + prev; + + if (start === -Number.MAX_VALUE) { + ticks.push(start); + start = $.plot.saturated.floorInBase(axis.min + axis.tickSize, axis.tickSize); + } + + do { + prev = v; + //v = start + i * axis.tickSize; + v = $.plot.saturated.multiplyAdd(axis.tickSize, i, start); + ticks.push(v); + ++i; + } while (v < axis.max && v !== prev); + + return ticks; + } + + function defaultTickFormatter(value, axis, precision) { + var oldTickDecimals = axis.tickDecimals, + expPosition = ("" + value).indexOf("e"); + + if (expPosition !== -1) { + return expRepTickFormatter(value, axis, precision); + } + + if (precision > 0) { + axis.tickDecimals = precision; + } + + var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1, + formatted = "" + Math.round(value * factor) / factor; + + // If tickDecimals was specified, ensure that we have exactly that + // much precision; otherwise default to the value's own precision. + if (axis.tickDecimals != null) { + var decimal = formatted.indexOf("."), + decimalPrecision = decimal === -1 ? 0 : formatted.length - decimal - 1; + if (decimalPrecision < axis.tickDecimals) { + var decimals = ("" + factor).substr(1, axis.tickDecimals - decimalPrecision); + formatted = (decimalPrecision ? formatted : formatted + ".") + decimals; + } + } + + axis.tickDecimals = oldTickDecimals; + return formatted; + }; + + function expRepTickFormatter(value, axis, precision) { + var expPosition = ("" + value).indexOf("e"), + exponentValue = parseInt(("" + value).substr(expPosition + 1)), + tenExponent = expPosition !== -1 ? exponentValue : (value > 0 ? Math.floor(Math.log(value) / Math.LN10) : 0), + roundWith = Math.pow(10, tenExponent), + x = value / roundWith; + + if (precision) { + var updatedPrecision = recomputePrecision(value, precision); + return (value / roundWith).toFixed(updatedPrecision) + 'e' + tenExponent; + } + + if (axis.tickDecimals > 0) { + return x.toFixed(recomputePrecision(value, axis.tickDecimals)) + 'e' + tenExponent; + } + return x.toFixed() + 'e' + tenExponent; + } + + function recomputePrecision(num, precision) { + //for numbers close to zero, the precision from flot will be a big number + //while for big numbers, the precision will be negative + var log10Value = Math.log(Math.abs(num)) * Math.LOG10E, + newPrecision = Math.abs(log10Value + precision); + + return newPrecision <= 20 ? Math.floor(newPrecision) : 20; + } + + /////////////////////////////////////////////////////////////////////////// + // The top-level container for the entire plot. + function Plot(placeholder, data_, options_, plugins) { + // data is on the form: + // [ series1, series2 ... ] + // where series is either just the data as [ [x1, y1], [x2, y2], ... ] + // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... } + + var series = [], + options = { + // the color theme used for graphs + colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"], + xaxis: { + show: null, // null = auto-detect, true = always, false = never + position: "bottom", // or "top" + mode: null, // null or "time" + font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" } + color: null, // base color, labels, ticks + tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)" + transform: null, // null or f: number -> number to transform axis + inverseTransform: null, // if transform is set, this should be the inverse function + min: null, // min. value to show, null means set automatically + max: null, // max. value to show, null means set automatically + autoScaleMargin: null, // margin in % to add if autoScale option is on "loose" mode, + autoScale: "exact", // Available modes: "none", "loose", "exact", "sliding-window" + windowSize: null, // null or number. This is the size of sliding-window. + growOnly: null, // grow only, useful for smoother auto-scale, the scales will grow to accomodate data but won't shrink back. + ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks + tickFormatter: null, // fn: number -> string + showTickLabels: "major", // "none", "endpoints", "major", "all" + labelWidth: null, // size of tick labels in pixels + labelHeight: null, + reserveSpace: null, // whether to reserve space even if axis isn't shown + tickLength: null, // size in pixels of major tick marks + showMinorTicks: null, // true = show minor tick marks, false = hide minor tick marks + showTicks: null, // true = show tick marks, false = hide all tick marks + gridLines: null, // true = show grid lines, false = hide grid lines + alignTicksWithAxis: null, // axis number or null for no sync + tickDecimals: null, // no. of decimals, null means auto + tickSize: null, // number or [number, "unit"] + minTickSize: null, // number or [number, "unit"] + offset: { below: 0, above: 0 }, // the plot drawing offset. this is calculated by the flot.navigate for each axis + boxPosition: { centerX: 0, centerY: 0 } //position of the axis on the corresponding axis box + }, + yaxis: { + autoScaleMargin: 0.02, // margin in % to add if autoScale option is on "loose" mode + autoScale: "loose", // Available modes: "none", "loose", "exact" + growOnly: null, // grow only, useful for smoother auto-scale, the scales will grow to accomodate data but won't shrink back. + position: "left", // or "right" + showTickLabels: "major", // "none", "endpoints", "major", "all" + offset: { below: 0, above: 0 }, // the plot drawing offset. this is calculated by the flot.navigate for each axis + boxPosition: { centerX: 0, centerY: 0 } //position of the axis on the corresponding axis box + }, + xaxes: [], + yaxes: [], + series: { + points: { + show: false, + radius: 3, + lineWidth: 2, // in pixels + fill: true, + fillColor: "#ffffff", + symbol: 'circle' // or callback + }, + lines: { + // we don't put in show: false so we can see + // whether lines were actively disabled + lineWidth: 1, // in pixels + fill: false, + fillColor: null, + steps: false + // Omit 'zero', so we can later default its value to + // match that of the 'fill' option. + }, + bars: { + show: false, + lineWidth: 2, // in pixels + // barWidth: number or [number, absolute] + // when 'absolute' is false, 'number' is relative to the minimum distance between points for the series + // when 'absolute' is true, 'number' is considered to be in units of the x-axis + horizontal: false, + barWidth: 0.8, + fill: true, + fillColor: null, + align: "left", // "left", "right", or "center" + zero: true + }, + shadowSize: 3, + highlightColor: null + }, + grid: { + show: true, + aboveData: false, + color: "#545454", // primary color used for outline and labels + backgroundColor: null, // null for transparent, else color + borderColor: null, // set if different from the grid color + tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)" + margin: 0, // distance from the canvas edge to the grid + labelMargin: 5, // in pixels + axisMargin: 8, // in pixels + borderWidth: 1, // in pixels + minBorderMargin: null, // in pixels, null means taken from points radius + markings: null, // array of ranges or fn: axes -> array of ranges + markingsColor: "#f4f4f4", + markingsLineWidth: 2, + // interactive stuff + clickable: false, + hoverable: false, + autoHighlight: true, // highlight in case mouse is near + mouseActiveRadius: 15 // how far the mouse can be away to activate an item + }, + interaction: { + redrawOverlayInterval: 1000 / 60 // time between updates, -1 means in same flow + }, + hooks: {} + }, + surface = null, // the canvas for the plot itself + overlay = null, // canvas for interactive stuff on top of plot + eventHolder = null, // jQuery object that events should be bound to + ctx = null, + octx = null, + xaxes = [], + yaxes = [], + plotOffset = { + left: 0, + right: 0, + top: 0, + bottom: 0 + }, + plotWidth = 0, + plotHeight = 0, + hooks = { + processOptions: [], + processRawData: [], + processDatapoints: [], + processOffset: [], + setupGrid: [], + adjustSeriesDataRange: [], + setRange: [], + drawBackground: [], + drawSeries: [], + drawAxis: [], + draw: [], + axisReserveSpace: [], + bindEvents: [], + drawOverlay: [], + resize: [], + shutdown: [] + }, + plot = this; + + var eventManager = {}; + + // interactive features + + var redrawTimeout = null; + + // public functions + plot.setData = setData; + plot.setupGrid = setupGrid; + plot.draw = draw; + plot.getPlaceholder = function() { + return placeholder; + }; + plot.getCanvas = function() { + return surface.element; + }; + plot.getSurface = function() { + return surface; + }; + plot.getEventHolder = function() { + return eventHolder[0]; + }; + plot.getPlotOffset = function() { + return plotOffset; + }; + plot.width = function() { + return plotWidth; + }; + plot.height = function() { + return plotHeight; + }; + plot.offset = function() { + var o = eventHolder.offset(); + o.left += plotOffset.left; + o.top += plotOffset.top; + return o; + }; + plot.getData = function() { + return series; + }; + plot.getAxes = function() { + var res = {}; + $.each(xaxes.concat(yaxes), function(_, axis) { + if (axis) { + res[axis.direction + (axis.n !== 1 ? axis.n : "") + "axis"] = axis; + } + }); + return res; + }; + plot.getXAxes = function() { + return xaxes; + }; + plot.getYAxes = function() { + return yaxes; + }; + plot.c2p = canvasToCartesianAxisCoords; + plot.p2c = cartesianAxisToCanvasCoords; + plot.getOptions = function() { + return options; + }; + plot.triggerRedrawOverlay = triggerRedrawOverlay; + plot.pointOffset = function(point) { + return { + left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left, 10), + top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top, 10) + }; + }; + plot.shutdown = shutdown; + plot.destroy = function() { + shutdown(); + placeholder.removeData("plot").empty(); + + series = []; + options = null; + surface = null; + overlay = null; + eventHolder = null; + ctx = null; + octx = null; + xaxes = []; + yaxes = []; + hooks = null; + plot = null; + }; + + plot.resize = function() { + var width = placeholder.width(), + height = placeholder.height(); + surface.resize(width, height); + overlay.resize(width, height); + + executeHooks(hooks.resize, [width, height]); + }; + + plot.clearTextCache = function () { + surface.clearCache(); + overlay.clearCache(); + }; + + plot.autoScaleAxis = autoScaleAxis; + plot.computeRangeForDataSeries = computeRangeForDataSeries; + plot.adjustSeriesDataRange = adjustSeriesDataRange; + plot.findNearbyItem = findNearbyItem; + plot.findNearbyInterpolationPoint = findNearbyInterpolationPoint; + plot.computeValuePrecision = computeValuePrecision; + plot.computeTickSize = computeTickSize; + plot.addEventHandler = addEventHandler; + + // public attributes + plot.hooks = hooks; + + // initialize + var MINOR_TICKS_COUNT_CONSTANT = $.plot.uiConstants.MINOR_TICKS_COUNT_CONSTANT; + var TICK_LENGTH_CONSTANT = $.plot.uiConstants.TICK_LENGTH_CONSTANT; + initPlugins(plot); + setupCanvases(); + parseOptions(options_); + setData(data_); + setupGrid(true); + draw(); + bindEvents(); + + function executeHooks(hook, args) { + args = [plot].concat(args); + for (var i = 0; i < hook.length; ++i) { + hook[i].apply(this, args); + } + } + + function initPlugins() { + // References to key classes, allowing plugins to modify them + + var classes = { + Canvas: Canvas + }; + + for (var i = 0; i < plugins.length; ++i) { + var p = plugins[i]; + p.init(plot, classes); + if (p.options) { + $.extend(true, options, p.options); + } + } + } + + function parseOptions(opts) { + $.extend(true, options, opts); + + // $.extend merges arrays, rather than replacing them. When less + // colors are provided than the size of the default palette, we + // end up with those colors plus the remaining defaults, which is + // not expected behavior; avoid it by replacing them here. + + if (opts && opts.colors) { + options.colors = opts.colors; + } + + if (options.xaxis.color == null) { + options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + } + + if (options.yaxis.color == null) { + options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + } + + if (options.xaxis.tickColor == null) { + // grid.tickColor for back-compatibility + options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color; + } + + if (options.yaxis.tickColor == null) { + // grid.tickColor for back-compatibility + options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color; + } + + if (options.grid.borderColor == null) { + options.grid.borderColor = options.grid.color; + } + + if (options.grid.tickColor == null) { + options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + } + + // Fill in defaults for axis options, including any unspecified + // font-spec fields, if a font-spec was provided. + + // If no x/y axis options were provided, create one of each anyway, + // since the rest of the code assumes that they exist. + + var i, axisOptions, axisCount, + fontSize = placeholder.css("font-size"), + fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 13, + fontDefaults = { + style: placeholder.css("font-style"), + size: Math.round(0.8 * fontSizeDefault), + variant: placeholder.css("font-variant"), + weight: placeholder.css("font-weight"), + family: placeholder.css("font-family") + }; + + axisCount = options.xaxes.length || 1; + for (i = 0; i < axisCount; ++i) { + axisOptions = options.xaxes[i]; + if (axisOptions && !axisOptions.tickColor) { + axisOptions.tickColor = axisOptions.color; + } + + axisOptions = $.extend(true, {}, options.xaxis, axisOptions); + options.xaxes[i] = axisOptions; + + if (axisOptions.font) { + axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } + } + } + + axisCount = options.yaxes.length || 1; + for (i = 0; i < axisCount; ++i) { + axisOptions = options.yaxes[i]; + if (axisOptions && !axisOptions.tickColor) { + axisOptions.tickColor = axisOptions.color; + } + + axisOptions = $.extend(true, {}, options.yaxis, axisOptions); + options.yaxes[i] = axisOptions; + + if (axisOptions.font) { + axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } + } + } + + // save options on axes for future reference + for (i = 0; i < options.xaxes.length; ++i) { + getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i]; + } + + for (i = 0; i < options.yaxes.length; ++i) { + getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i]; + } + + //process boxPosition options used for axis.box size + $.each(allAxes(), function(_, axis) { + axis.boxPosition = axis.options.boxPosition || {centerX: 0, centerY: 0}; + }); + + // add hooks from options + for (var n in hooks) { + if (options.hooks[n] && options.hooks[n].length) { + hooks[n] = hooks[n].concat(options.hooks[n]); + } + } + + executeHooks(hooks.processOptions, [options]); + } + + function setData(d) { + var oldseries = series; + series = parseData(d); + fillInSeriesOptions(); + processData(oldseries); + } + + function parseData(d) { + var res = []; + for (var i = 0; i < d.length; ++i) { + var s = $.extend(true, {}, options.series); + + if (d[i].data != null) { + s.data = d[i].data; // move the data instead of deep-copy + delete d[i].data; + + $.extend(true, s, d[i]); + + d[i].data = s.data; + } else { + s.data = d[i]; + } + + res.push(s); + } + + return res; + } + + function axisNumber(obj, coord) { + var a = obj[coord + "axis"]; + if (typeof a === "object") { + // if we got a real axis, extract number + a = a.n; + } + + if (typeof a !== "number") { + a = 1; // default to first axis + } + + return a; + } + + function allAxes() { + // return flat array without annoying null entries + return xaxes.concat(yaxes).filter(function(a) { + return a; + }); + } + + // canvas to axis for cartesian axes + function canvasToCartesianAxisCoords(pos) { + // return an object with x/y corresponding to all used axes + var res = {}, + i, axis; + for (i = 0; i < xaxes.length; ++i) { + axis = xaxes[i]; + if (axis && axis.used) { + res["x" + axis.n] = axis.c2p(pos.left); + } + } + + for (i = 0; i < yaxes.length; ++i) { + axis = yaxes[i]; + if (axis && axis.used) { + res["y" + axis.n] = axis.c2p(pos.top); + } + } + + if (res.x1 !== undefined) { + res.x = res.x1; + } + + if (res.y1 !== undefined) { + res.y = res.y1; + } + + return res; + } + + // axis to canvas for cartesian axes + function cartesianAxisToCanvasCoords(pos) { + // get canvas coords from the first pair of x/y found in pos + var res = {}, + i, axis, key; + + for (i = 0; i < xaxes.length; ++i) { + axis = xaxes[i]; + if (axis && axis.used) { + key = "x" + axis.n; + if (pos[key] == null && axis.n === 1) { + key = "x"; + } + + if (pos[key] != null) { + res.left = axis.p2c(pos[key]); + break; + } + } + } + + for (i = 0; i < yaxes.length; ++i) { + axis = yaxes[i]; + if (axis && axis.used) { + key = "y" + axis.n; + if (pos[key] == null && axis.n === 1) { + key = "y"; + } + + if (pos[key] != null) { + res.top = axis.p2c(pos[key]); + break; + } + } + } + + return res; + } + + function getOrCreateAxis(axes, number) { + if (!axes[number - 1]) { + axes[number - 1] = { + n: number, // save the number for future reference + direction: axes === xaxes ? "x" : "y", + options: $.extend(true, {}, axes === xaxes ? options.xaxis : options.yaxis) + }; + } + + return axes[number - 1]; + } + + function fillInSeriesOptions() { + var neededColors = series.length, + maxIndex = -1, + i; + + // Subtract the number of series that already have fixed colors or + // color indexes from the number that we still need to generate. + + for (i = 0; i < series.length; ++i) { + var sc = series[i].color; + if (sc != null) { + neededColors--; + if (typeof sc === "number" && sc > maxIndex) { + maxIndex = sc; + } + } + } + + // If any of the series have fixed color indexes, then we need to + // generate at least as many colors as the highest index. + + if (neededColors <= maxIndex) { + neededColors = maxIndex + 1; + } + + // Generate all the colors, using first the option colors and then + // variations on those colors once they're exhausted. + + var c, colors = [], + colorPool = options.colors, + colorPoolSize = colorPool.length, + variation = 0, + definedColors = Math.max(0, series.length - neededColors); + + for (i = 0; i < neededColors; i++) { + c = $.color.parse(colorPool[(definedColors + i) % colorPoolSize] || "#666"); + + // Each time we exhaust the colors in the pool we adjust + // a scaling factor used to produce more variations on + // those colors. The factor alternates negative/positive + // to produce lighter/darker colors. + + // Reset the variation after every few cycles, or else + // it will end up producing only white or black colors. + + if (i % colorPoolSize === 0 && i) { + if (variation >= 0) { + if (variation < 0.5) { + variation = -variation - 0.2; + } else variation = 0; + } else variation = -variation; + } + + colors[i] = c.scale('rgb', 1 + variation); + } + + // Finalize the series options, filling in their colors + + var colori = 0, + s; + for (i = 0; i < series.length; ++i) { + s = series[i]; + + // assign colors + if (s.color == null) { + s.color = colors[colori].toString(); + ++colori; + } else if (typeof s.color === "number") { + s.color = colors[s.color].toString(); + } + + // turn on lines automatically in case nothing is set + if (s.lines.show == null) { + var v, show = true; + for (v in s) { + if (s[v] && s[v].show) { + show = false; + break; + } + } + + if (show) { + s.lines.show = true; + } + } + + // If nothing was provided for lines.zero, default it to match + // lines.fill, since areas by default should extend to zero. + + if (s.lines.zero == null) { + s.lines.zero = !!s.lines.fill; + } + + // setup axes + s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x")); + s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y")); + } + } + + function processData(prevSeries) { + var topSentry = Number.POSITIVE_INFINITY, + bottomSentry = Number.NEGATIVE_INFINITY, + i, j, k, m, + s, points, ps, val, f, p, + data, format; + + function updateAxis(axis, min, max) { + if (min < axis.datamin && min !== -Infinity) { + axis.datamin = min; + } + + if (max > axis.datamax && max !== Infinity) { + axis.datamax = max; + } + } + + function reusePoints(prevSeries, i) { + if (prevSeries && prevSeries[i] && prevSeries[i].datapoints && prevSeries[i].datapoints.points) { + return prevSeries[i].datapoints.points; + } + + return []; + } + + $.each(allAxes(), function(_, axis) { + // init axis + if (axis.options.growOnly !== true) { + axis.datamin = topSentry; + axis.datamax = bottomSentry; + } else { + if (axis.datamin === undefined) { + axis.datamin = topSentry; + } + if (axis.datamax === undefined) { + axis.datamax = bottomSentry; + } + } + axis.used = false; + }); + + for (i = 0; i < series.length; ++i) { + s = series[i]; + s.datapoints = { + points: [] + }; + + if (s.datapoints.points.length === 0) { + s.datapoints.points = reusePoints(prevSeries, i); + } + + executeHooks(hooks.processRawData, [s, s.data, s.datapoints]); + } + + // first pass: clean and copy data + for (i = 0; i < series.length; ++i) { + s = series[i]; + + data = s.data; + format = s.datapoints.format; + + if (!format) { + format = []; + // find out how to copy + format.push({ + x: true, + y: false, + number: true, + required: true, + computeRange: s.xaxis.options.autoScale !== 'none', + defaultValue: null + }); + + format.push({ + x: false, + y: true, + number: true, + required: true, + computeRange: s.yaxis.options.autoScale !== 'none', + defaultValue: null + }); + + if (s.stack || s.bars.show || (s.lines.show && s.lines.fill)) { + var expectedPs = s.datapoints.pointsize != null ? s.datapoints.pointsize : (s.data && s.data[0] && s.data[0].length ? s.data[0].length : 3); + if (expectedPs > 2) { + format.push({ + x: false, + y: true, + number: true, + required: false, + computeRange: s.yaxis.options.autoScale !== 'none', + defaultValue: 0 + }); + } + } + + s.datapoints.format = format; + } + + s.xaxis.used = s.yaxis.used = true; + + if (s.datapoints.pointsize != null) continue; // already filled in + + s.datapoints.pointsize = format.length; + ps = s.datapoints.pointsize; + points = s.datapoints.points; + + var insertSteps = s.lines.show && s.lines.steps; + + for (j = k = 0; j < data.length; ++j, k += ps) { + p = data[j]; + + var nullify = p == null; + if (!nullify) { + for (m = 0; m < ps; ++m) { + val = p[m]; + f = format[m]; + + if (f) { + if (f.number && val != null) { + val = +val; // convert to number + if (isNaN(val)) { + val = null; + } + } + + if (val == null) { + if (f.required) nullify = true; + + if (f.defaultValue != null) val = f.defaultValue; + } + } + + points[k + m] = val; + } + } + + if (nullify) { + for (m = 0; m < ps; ++m) { + val = points[k + m]; + if (val != null) { + f = format[m]; + // extract min/max info + if (f.computeRange) { + if (f.x) { + updateAxis(s.xaxis, val, val); + } + if (f.y) { + updateAxis(s.yaxis, val, val); + } + } + } + points[k + m] = null; + } + } else { + // a little bit of line specific stuff that + // perhaps shouldn't be here, but lacking + // better means... + if (insertSteps && k > 0 && + points[k - ps] != null && + points[k - ps] !== points[k] && + points[k - ps + 1] !== points[k + 1]) { + // copy the point to make room for a middle point + for (m = 0; m < ps; ++m) { + points[k + ps + m] = points[k + m]; + } + + // middle point has same y + points[k + 1] = points[k - ps + 1]; + + // we've added a point, better reflect that + k += ps; + } + } + } + + points.length = k; //trims the internal buffer to the correct length + } + + // give the hooks a chance to run + for (i = 0; i < series.length; ++i) { + s = series[i]; + + executeHooks(hooks.processDatapoints, [s, s.datapoints]); + } + + // second pass: find datamax/datamin for auto-scaling + for (i = 0; i < series.length; ++i) { + s = series[i]; + format = s.datapoints.format; + + if (format.every(function (f) { return !f.computeRange; })) { + continue; + } + + var range = plot.adjustSeriesDataRange(s, + plot.computeRangeForDataSeries(s)); + + executeHooks(hooks.adjustSeriesDataRange, [s, range]); + + updateAxis(s.xaxis, range.xmin, range.xmax); + updateAxis(s.yaxis, range.ymin, range.ymax); + } + + $.each(allAxes(), function(_, axis) { + if (axis.datamin === topSentry) { + axis.datamin = null; + } + + if (axis.datamax === bottomSentry) { + axis.datamax = null; + } + }); + } + + function setupCanvases() { + // Make sure the placeholder is clear of everything except canvases + // from a previous plot in this container that we'll try to re-use. + + placeholder.css("padding", 0) // padding messes up the positioning + .children().filter(function() { + return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base'); + }).remove(); + + if (placeholder.css("position") === 'static') { + placeholder.css("position", "relative"); // for positioning labels and overlay + } + + surface = new Canvas("flot-base", placeholder[0]); + overlay = new Canvas("flot-overlay", placeholder[0]); // overlay canvas for interactive features + + ctx = surface.context; + octx = overlay.context; + + // define which element we're listening for events on + eventHolder = $(overlay.element).unbind(); + + // If we're re-using a plot object, shut down the old one + + var existing = placeholder.data("plot"); + + if (existing) { + existing.shutdown(); + overlay.clear(); + } + + // save in case we get replotted + placeholder.data("plot", plot); + } + + function bindEvents() { + executeHooks(hooks.bindEvents, [eventHolder]); + } + + function addEventHandler(event, handler, eventHolder, priority) { + var key = eventHolder + event; + var eventList = eventManager[key] || []; + + eventList.push({"event": event, "handler": handler, "eventHolder": eventHolder, "priority": priority}); + eventList.sort((a, b) => b.priority - a.priority ); + eventList.forEach( eventData => { + eventData.eventHolder.unbind(eventData.event, eventData.handler); + eventData.eventHolder.bind(eventData.event, eventData.handler); + }); + + eventManager[key] = eventList; + } + + function shutdown() { + if (redrawTimeout) { + clearTimeout(redrawTimeout); + } + + executeHooks(hooks.shutdown, [eventHolder]); + } + + function setTransformationHelpers(axis) { + // set helper functions on the axis, assumes plot area + // has been computed already + + function identity(x) { + return x; + } + + var s, m, t = axis.options.transform || identity, + it = axis.options.inverseTransform; + + // precompute how much the axis is scaling a point + // in canvas space + if (axis.direction === "x") { + if (isFinite(t(axis.max) - t(axis.min))) { + s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min)); + } else { + s = axis.scale = 1 / Math.abs($.plot.saturated.delta(t(axis.min), t(axis.max), plotWidth)); + } + m = Math.min(t(axis.max), t(axis.min)); + } else { + if (isFinite(t(axis.max) - t(axis.min))) { + s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min)); + } else { + s = axis.scale = 1 / Math.abs($.plot.saturated.delta(t(axis.min), t(axis.max), plotHeight)); + } + s = -s; + m = Math.max(t(axis.max), t(axis.min)); + } + + // data point to canvas coordinate + if (t === identity) { + // slight optimization + axis.p2c = function(p) { + if (isFinite(p - m)) { + return (p - m) * s; + } else { + return (p / 4 - m / 4) * s * 4; + } + }; + } else { + axis.p2c = function(p) { + var tp = t(p); + + if (isFinite(tp - m)) { + return (tp - m) * s; + } else { + return (tp / 4 - m / 4) * s * 4; + } + }; + } + + // canvas coordinate to data point + if (!it) { + axis.c2p = function(c) { + return m + c / s; + }; + } else { + axis.c2p = function(c) { + return it(m + c / s); + }; + } + } + + function measureTickLabels(axis) { + var opts = axis.options, + ticks = opts.showTickLabels !== 'none' && axis.ticks ? axis.ticks : [], + showMajorTickLabels = opts.showTickLabels === 'major' || opts.showTickLabels === 'all', + showEndpointsTickLabels = opts.showTickLabels === 'endpoints' || opts.showTickLabels === 'all', + labelWidth = opts.labelWidth || 0, + labelHeight = opts.labelHeight || 0, + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = opts.font || "flot-tick-label tickLabel"; + + for (var i = 0; i < ticks.length; ++i) { + var t = ticks[i]; + var label = t.label; + + if (!t.label || + (showMajorTickLabels === false && i > 0 && i < ticks.length - 1) || + (showEndpointsTickLabels === false && (i === 0 || i === ticks.length - 1))) { + continue; + } + + if (typeof t.label === 'object') { + label = t.label.name; + } + + var info = surface.getTextInfo(layer, label, font); + + labelWidth = Math.max(labelWidth, info.width); + labelHeight = Math.max(labelHeight, info.height); + } + + axis.labelWidth = opts.labelWidth || labelWidth; + axis.labelHeight = opts.labelHeight || labelHeight; + } + + function allocateAxisBoxFirstPhase(axis) { + // find the bounding box of the axis by looking at label + // widths/heights and ticks, make room by diminishing the + // plotOffset; this first phase only looks at one + // dimension per axis, the other dimension depends on the + // other axes so will have to wait + + // here reserve additional space + executeHooks(hooks.axisReserveSpace, [axis]); + + var lw = axis.labelWidth, + lh = axis.labelHeight, + pos = axis.options.position, + isXAxis = axis.direction === "x", + tickLength = axis.options.tickLength, + showTicks = axis.options.showTicks, + showMinorTicks = axis.options.showMinorTicks, + gridLines = axis.options.gridLines, + axisMargin = options.grid.axisMargin, + padding = options.grid.labelMargin, + innermost = true, + outermost = true, + found = false; + + // Determine the axis's position in its direction and on its side + + $.each(isXAxis ? xaxes : yaxes, function(i, a) { + if (a && (a.show || a.reserveSpace)) { + if (a === axis) { + found = true; + } else if (a.options.position === pos) { + if (found) { + outermost = false; + } else { + innermost = false; + } + } + } + }); + + // The outermost axis on each side has no margin + if (outermost) { + axisMargin = 0; + } + + // Set the default tickLength if necessary + if (tickLength == null) { + tickLength = TICK_LENGTH_CONSTANT; + } + + // By default, major tick marks are visible + if (showTicks == null) { + showTicks = true; + } + + // By default, minor tick marks are visible + if (showMinorTicks == null) { + showMinorTicks = true; + } + + // By default, grid lines are visible + if (gridLines == null) { + if (innermost) { + gridLines = true; + } else { + gridLines = false; + } + } + + if (!isNaN(+tickLength)) { + padding += showTicks ? +tickLength : 0; + } + + if (isXAxis) { + lh += padding; + + if (pos === "bottom") { + plotOffset.bottom += lh + axisMargin; + axis.box = { + top: surface.height - plotOffset.bottom, + height: lh + }; + } else { + axis.box = { + top: plotOffset.top + axisMargin, + height: lh + }; + plotOffset.top += lh + axisMargin; + } + } else { + lw += padding; + + if (pos === "left") { + axis.box = { + left: plotOffset.left + axisMargin, + width: lw + }; + plotOffset.left += lw + axisMargin; + } else { + plotOffset.right += lw + axisMargin; + axis.box = { + left: surface.width - plotOffset.right, + width: lw + }; + } + } + + // save for future reference + axis.position = pos; + axis.tickLength = tickLength; + axis.showMinorTicks = showMinorTicks; + axis.showTicks = showTicks; + axis.gridLines = gridLines; + axis.box.padding = padding; + axis.innermost = innermost; + } + + function allocateAxisBoxSecondPhase(axis) { + // now that all axis boxes have been placed in one + // dimension, we can set the remaining dimension coordinates + if (axis.direction === "x") { + axis.box.left = plotOffset.left - axis.labelWidth / 2; + axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth; + } else { + axis.box.top = plotOffset.top - axis.labelHeight / 2; + axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight; + } + } + + function adjustLayoutForThingsStickingOut() { + // possibly adjust plot offset to ensure everything stays + // inside the canvas and isn't clipped off + + var minMargin = options.grid.minBorderMargin, + i; + + // check stuff from the plot (FIXME: this should just read + // a value from the series, otherwise it's impossible to + // customize) + if (minMargin == null) { + minMargin = 0; + for (i = 0; i < series.length; ++i) { + minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth / 2)); + } + } + + var a, offset = {}, + margins = { + left: minMargin, + right: minMargin, + top: minMargin, + bottom: minMargin + }; + + // check axis labels, note we don't check the actual + // labels but instead use the overall width/height to not + // jump as much around with replots + $.each(allAxes(), function(_, axis) { + if (axis.reserveSpace && axis.ticks && axis.ticks.length) { + if (axis.direction === "x") { + margins.left = Math.max(margins.left, axis.labelWidth / 2); + margins.right = Math.max(margins.right, axis.labelWidth / 2); + } else { + margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2); + margins.top = Math.max(margins.top, axis.labelHeight / 2); + } + } + }); + + for (a in margins) { + offset[a] = margins[a] - plotOffset[a]; + } + $.each(xaxes.concat(yaxes), function(_, axis) { + alignAxisWithGrid(axis, offset, function (offset) { + return offset > 0; + }); + }); + + plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left)); + plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right)); + plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top)); + plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom)); + } + + function alignAxisWithGrid(axis, offset, isValid) { + if (axis.direction === "x") { + if (axis.position === "bottom" && isValid(offset.bottom)) { + axis.box.top -= Math.ceil(offset.bottom); + } + if (axis.position === "top" && isValid(offset.top)) { + axis.box.top += Math.ceil(offset.top); + } + } else { + if (axis.position === "left" && isValid(offset.left)) { + axis.box.left += Math.ceil(offset.left); + } + if (axis.position === "right" && isValid(offset.right)) { + axis.box.left -= Math.ceil(offset.right); + } + } + } + + function setupGrid(autoScale) { + var i, a, axes = allAxes(), + showGrid = options.grid.show; + + // Initialize the plot's offset from the edge of the canvas + + for (a in plotOffset) { + plotOffset[a] = 0; + } + + executeHooks(hooks.processOffset, [plotOffset]); + + // If the grid is visible, add its border width to the offset + for (a in plotOffset) { + if (typeof (options.grid.borderWidth) === "object") { + plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0; + } else { + plotOffset[a] += showGrid ? options.grid.borderWidth : 0; + } + } + + $.each(axes, function(_, axis) { + var axisOpts = axis.options; + axis.show = axisOpts.show == null ? axis.used : axisOpts.show; + axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace; + setupTickFormatter(axis); + executeHooks(hooks.setRange, [axis, autoScale]); + setRange(axis, autoScale); + }); + + if (showGrid) { + plotWidth = surface.width - plotOffset.left - plotOffset.right; + plotHeight = surface.height - plotOffset.bottom - plotOffset.top; + + var allocatedAxes = $.grep(axes, function(axis) { + return axis.show || axis.reserveSpace; + }); + + $.each(allocatedAxes, function(_, axis) { + // make the ticks + setupTickGeneration(axis); + setMajorTicks(axis); + snapRangeToTicks(axis, axis.ticks); + + //for computing the endpoints precision, transformationHelpers are needed + setTransformationHelpers(axis); + setEndpointTicks(axis, series); + + // find labelWidth/Height for axis + measureTickLabels(axis); + }); + + // with all dimensions calculated, we can compute the + // axis bounding boxes, start from the outside + // (reverse order) + for (i = allocatedAxes.length - 1; i >= 0; --i) { + allocateAxisBoxFirstPhase(allocatedAxes[i]); + } + + // make sure we've got enough space for things that + // might stick out + adjustLayoutForThingsStickingOut(); + + $.each(allocatedAxes, function(_, axis) { + allocateAxisBoxSecondPhase(axis); + }); + } + + //adjust axis and plotOffset according to grid.margins + if (options.grid.margin) { + for (a in plotOffset) { + var margin = options.grid.margin || 0; + plotOffset[a] += typeof margin === "number" ? margin : (margin[a] || 0); + } + $.each(xaxes.concat(yaxes), function(_, axis) { + alignAxisWithGrid(axis, options.grid.margin, function(offset) { + return offset !== undefined && offset !== null; + }); + }); + } + + //after adjusting the axis, plot width and height will be modified + plotWidth = surface.width - plotOffset.left - plotOffset.right; + plotHeight = surface.height - plotOffset.bottom - plotOffset.top; + + // now we got the proper plot dimensions, we can compute the scaling + $.each(axes, function(_, axis) { + setTransformationHelpers(axis); + }); + + if (showGrid) { + drawAxisLabels(); + } + + executeHooks(hooks.setupGrid, []); + } + + function widenMinMax(minimum, maximum) { + var min = (minimum === undefined ? null : minimum); + var max = (maximum === undefined ? null : maximum); + var delta = max - min; + if (delta === 0.0) { + // degenerate case + var widen = max === 0 ? 1 : 0.01; + var wmin = null; + if (min == null) { + wmin -= widen; + } + + // always widen max if we couldn't widen min to ensure we + // don't fall into min == max which doesn't work + if (max == null || min != null) { + max += widen; + } + + if (wmin != null) { + min = wmin; + } + } + + return { + min: min, + max: max + }; + } + + function autoScaleAxis(axis) { + var opts = axis.options, + min = opts.min, + max = opts.max, + datamin = axis.datamin, + datamax = axis.datamax, + delta; + + switch (opts.autoScale) { + case "none": + min = +(opts.min != null ? opts.min : datamin); + max = +(opts.max != null ? opts.max : datamax); + break; + case "loose": + if (datamin != null && datamax != null) { + min = datamin; + max = datamax; + delta = $.plot.saturated.saturate(max - min); + var margin = ((typeof opts.autoScaleMargin === 'number') ? opts.autoScaleMargin : 0.02); + min = $.plot.saturated.saturate(min - delta * margin); + max = $.plot.saturated.saturate(max + delta * margin); + + // make sure we don't go below zero if all values are positive + if (min < 0 && datamin >= 0) { + min = 0; + } + } else { + min = opts.min; + max = opts.max; + } + break; + case "exact": + min = (datamin != null ? datamin : opts.min); + max = (datamax != null ? datamax : opts.max); + break; + case "sliding-window": + if (datamax > max) { + // move the window to fit the new data, + // keeping the axis range constant + max = datamax; + min = Math.max(datamax - (opts.windowSize || 100), min); + } + break; + } + + var widenedMinMax = widenMinMax(min, max); + min = widenedMinMax.min; + max = widenedMinMax.max; + + // grow loose or grow exact supported + if (opts.growOnly === true && opts.autoScale !== "none" && opts.autoScale !== "sliding-window") { + min = (min < datamin) ? min : (datamin !== null ? datamin : min); + max = (max > datamax) ? max : (datamax !== null ? datamax : max); + } + + axis.autoScaledMin = min; + axis.autoScaledMax = max; + } + + function setRange(axis, autoScale) { + var min = typeof axis.options.min === 'number' ? axis.options.min : axis.min, + max = typeof axis.options.max === 'number' ? axis.options.max : axis.max, + plotOffset = axis.options.offset; + + if (autoScale) { + autoScaleAxis(axis); + min = axis.autoScaledMin; + max = axis.autoScaledMax; + } + + min = (min != null ? min : -1) + (plotOffset.below || 0); + max = (max != null ? max : 1) + (plotOffset.above || 0); + + if (min > max) { + var tmp = min; + min = max; + max = tmp; + axis.options.offset = { above: 0, below: 0 }; + } + + axis.min = $.plot.saturated.saturate(min); + axis.max = $.plot.saturated.saturate(max); + } + + function computeValuePrecision (min, max, direction, ticks, tickDecimals) { + var noTicks = fixupNumberOfTicks(direction, surface, ticks); + + var delta = $.plot.saturated.delta(min, max, noTicks), + dec = -Math.floor(Math.log(delta) / Math.LN10); + + //if it is called with tickDecimals, then the precision should not be greather then that + if (tickDecimals && dec > tickDecimals) { + dec = tickDecimals; + } + + var magn = Math.pow(10, -dec), + norm = delta / magn; + + if (norm > 2.25 && norm < 3 && (dec + 1) <= tickDecimals) { + //we need an extra decimals when tickSize is 2.5 + ++dec; + } + + return isFinite(dec) ? dec : 0; + }; + + function computeTickSize (min, max, noTicks, tickDecimals) { + var delta = $.plot.saturated.delta(min, max, noTicks), + dec = -Math.floor(Math.log(delta) / Math.LN10); + + //if it is called with tickDecimals, then the precision should not be greather then that + if (tickDecimals && dec > tickDecimals) { + dec = tickDecimals; + } + + var magn = Math.pow(10, -dec), + norm = delta / magn, // norm is between 1.0 and 10.0 + size; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + if (norm > 2.25 && (tickDecimals == null || (dec + 1) <= tickDecimals)) { + size = 2.5; + } + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + return size; + } + + function getAxisTickSize(min, max, direction, options, tickDecimals) { + var noTicks; + + if (typeof options.ticks === "number" && options.ticks > 0) { + noTicks = options.ticks; + } else { + // heuristic based on the model a*sqrt(x) fitted to + // some data points that seemed reasonable + noTicks = 0.3 * Math.sqrt(direction === "x" ? surface.width : surface.height); + } + + var size = computeTickSize(min, max, noTicks, tickDecimals); + + if (options.minTickSize != null && size < options.minTickSize) { + size = options.minTickSize; + } + + return options.tickSize || size; + }; + + function fixupNumberOfTicks(direction, surface, ticksOption) { + var noTicks; + + if (typeof ticksOption === "number" && ticksOption > 0) { + noTicks = ticksOption; + } else { + noTicks = 0.3 * Math.sqrt(direction === "x" ? surface.width : surface.height); + } + + return noTicks; + } + + function setupTickFormatter(axis) { + var opts = axis.options; + if (!axis.tickFormatter) { + if (typeof opts.tickFormatter === 'function') { + axis.tickFormatter = function() { + var args = Array.prototype.slice.call(arguments); + return "" + opts.tickFormatter.apply(null, args); + }; + } else { + axis.tickFormatter = defaultTickFormatter; + } + } + } + + function setupTickGeneration(axis) { + var opts = axis.options; + var noTicks; + + noTicks = fixupNumberOfTicks(axis.direction, surface, opts.ticks); + + axis.delta = $.plot.saturated.delta(axis.min, axis.max, noTicks); + var precision = plot.computeValuePrecision(axis.min, axis.max, axis.direction, noTicks, opts.tickDecimals); + + axis.tickDecimals = Math.max(0, opts.tickDecimals != null ? opts.tickDecimals : precision); + axis.tickSize = getAxisTickSize(axis.min, axis.max, axis.direction, opts, opts.tickDecimals); + + // Flot supports base-10 axes; any other mode else is handled by a plug-in, + // like flot.time.js. + + if (!axis.tickGenerator) { + if (typeof opts.tickGenerator === 'function') { + axis.tickGenerator = opts.tickGenerator; + } else { + axis.tickGenerator = defaultTickGenerator; + } + } + + if (opts.alignTicksWithAxis != null) { + var otherAxis = (axis.direction === "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1]; + if (otherAxis && otherAxis.used && otherAxis !== axis) { + // consider snapping min/max to outermost nice ticks + var niceTicks = axis.tickGenerator(axis, plot); + if (niceTicks.length > 0) { + if (opts.min == null) { + axis.min = Math.min(axis.min, niceTicks[0]); + } + + if (opts.max == null && niceTicks.length > 1) { + axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]); + } + } + + axis.tickGenerator = function(axis) { + // copy ticks, scaled to this axis + var ticks = [], + v, i; + for (i = 0; i < otherAxis.ticks.length; ++i) { + v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min); + v = axis.min + v * (axis.max - axis.min); + ticks.push(v); + } + return ticks; + }; + + // we might need an extra decimal since forced + // ticks don't necessarily fit naturally + if (!axis.mode && opts.tickDecimals == null) { + var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1), + ts = axis.tickGenerator(axis, plot); + + // only proceed if the tick interval rounded + // with an extra decimal doesn't give us a + // zero at end + if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec)))) { + axis.tickDecimals = extraDec; + } + } + } + } + } + + function setMajorTicks(axis) { + var oticks = axis.options.ticks, + ticks = []; + if (oticks == null || (typeof oticks === "number" && oticks > 0)) { + ticks = axis.tickGenerator(axis, plot); + } else if (oticks) { + if ($.isFunction(oticks)) { + // generate the ticks + ticks = oticks(axis); + } else { + ticks = oticks; + } + } + + // clean up/labelify the supplied ticks, copy them over + var i, v; + axis.ticks = []; + for (i = 0; i < ticks.length; ++i) { + var label = null; + var t = ticks[i]; + if (typeof t === "object") { + v = +t[0]; + if (t.length > 1) { + label = t[1]; + } + } else { + v = +t; + } + + if (!isNaN(v)) { + axis.ticks.push( + newTick(v, label, axis, 'major')); + } + } + } + + function newTick(v, label, axis, type) { + if (label === null) { + switch (type) { + case 'min': + case 'max': + //improving the precision of endpoints + var precision = getEndpointPrecision(v, axis); + label = isFinite(precision) ? axis.tickFormatter(v, axis, precision, plot) : axis.tickFormatter(v, axis, precision, plot); + break; + case 'major': + label = axis.tickFormatter(v, axis, undefined, plot); + } + } + return { + v: v, + label: label + }; + } + + function snapRangeToTicks(axis, ticks) { + if (axis.options.autoScale === "loose" && ticks.length > 0) { + // snap to ticks + axis.min = Math.min(axis.min, ticks[0].v); + axis.max = Math.max(axis.max, ticks[ticks.length - 1].v); + } + } + + function getEndpointPrecision(value, axis) { + var canvas1 = Math.floor(axis.p2c(value)), + canvas2 = axis.direction === "x" ? canvas1 + 1 : canvas1 - 1, + point1 = axis.c2p(canvas1), + point2 = axis.c2p(canvas2), + precision = computeValuePrecision(point1, point2, axis.direction, 1); + + return precision; + } + + function setEndpointTicks(axis, series) { + if (isValidEndpointTick(axis, series)) { + axis.ticks.unshift(newTick(axis.min, null, axis, 'min')); + axis.ticks.push(newTick(axis.max, null, axis, 'max')); + } + } + + function isValidEndpointTick(axis, series) { + if (axis.options.showTickLabels === 'endpoints') { + return true; + } + if (axis.options.showTickLabels === 'all') { + var associatedSeries = series.filter(function(s) { + return s.xaxis === axis; + }), + notAllBarSeries = associatedSeries.some(function(s) { + return !s.bars.show; + }); + return associatedSeries.length === 0 || notAllBarSeries; + } + if (axis.options.showTickLabels === 'major' || axis.options.showTickLabels === 'none') { + return false; + } + } + + function draw() { + surface.clear(); + executeHooks(hooks.drawBackground, [ctx]); + + var grid = options.grid; + + // draw background, if any + if (grid.show && grid.backgroundColor) { + drawBackground(); + } + + if (grid.show && !grid.aboveData) { + drawGrid(); + } + + for (var i = 0; i < series.length; ++i) { + executeHooks(hooks.drawSeries, [ctx, series[i], i, getColorOrGradient]); + drawSeries(series[i]); + } + + executeHooks(hooks.draw, [ctx]); + + if (grid.show && grid.aboveData) { + drawGrid(); + } + + surface.render(); + + // A draw implies that either the axes or data have changed, so we + // should probably update the overlay highlights as well. + triggerRedrawOverlay(); + } + + function extractRange(ranges, coord) { + var axis, from, to, key, axes = allAxes(); + + for (var i = 0; i < axes.length; ++i) { + axis = axes[i]; + if (axis.direction === coord) { + key = coord + axis.n + "axis"; + if (!ranges[key] && axis.n === 1) { + // support x1axis as xaxis + key = coord + "axis"; + } + + if (ranges[key]) { + from = ranges[key].from; + to = ranges[key].to; + break; + } + } + } + + // backwards-compat stuff - to be removed in future + if (!ranges[key]) { + axis = coord === "x" ? xaxes[0] : yaxes[0]; + from = ranges[coord + "1"]; + to = ranges[coord + "2"]; + } + + // auto-reverse as an added bonus + if (from != null && to != null && from > to) { + var tmp = from; + from = to; + to = tmp; + } + + return { + from: from, + to: to, + axis: axis + }; + } + + function drawBackground() { + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)"); + ctx.fillRect(0, 0, plotWidth, plotHeight); + ctx.restore(); + } + + function drawMarkings() { + // draw markings + var markings = options.grid.markings, + axes; + + if (markings) { + if ($.isFunction(markings)) { + axes = plot.getAxes(); + // xmin etc. is backwards compatibility, to be + // removed in the future + axes.xmin = axes.xaxis.min; + axes.xmax = axes.xaxis.max; + axes.ymin = axes.yaxis.min; + axes.ymax = axes.yaxis.max; + + markings = markings(axes); + } + + var i; + for (i = 0; i < markings.length; ++i) { + var m = markings[i], + xrange = extractRange(m, "x"), + yrange = extractRange(m, "y"); + + // fill in missing + if (xrange.from == null) { + xrange.from = xrange.axis.min; + } + + if (xrange.to == null) { + xrange.to = xrange.axis.max; + } + + if (yrange.from == null) { + yrange.from = yrange.axis.min; + } + + if (yrange.to == null) { + yrange.to = yrange.axis.max; + } + + // clip + if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max || + yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) { + continue; + } + + xrange.from = Math.max(xrange.from, xrange.axis.min); + xrange.to = Math.min(xrange.to, xrange.axis.max); + yrange.from = Math.max(yrange.from, yrange.axis.min); + yrange.to = Math.min(yrange.to, yrange.axis.max); + + var xequal = xrange.from === xrange.to, + yequal = yrange.from === yrange.to; + + if (xequal && yequal) { + continue; + } + + // then draw + xrange.from = Math.floor(xrange.axis.p2c(xrange.from)); + xrange.to = Math.floor(xrange.axis.p2c(xrange.to)); + yrange.from = Math.floor(yrange.axis.p2c(yrange.from)); + yrange.to = Math.floor(yrange.axis.p2c(yrange.to)); + + if (xequal || yequal) { + var lineWidth = m.lineWidth || options.grid.markingsLineWidth, + subPixel = lineWidth % 2 ? 0.5 : 0; + ctx.beginPath(); + ctx.strokeStyle = m.color || options.grid.markingsColor; + ctx.lineWidth = lineWidth; + if (xequal) { + ctx.moveTo(xrange.to + subPixel, yrange.from); + ctx.lineTo(xrange.to + subPixel, yrange.to); + } else { + ctx.moveTo(xrange.from, yrange.to + subPixel); + ctx.lineTo(xrange.to, yrange.to + subPixel); + } + ctx.stroke(); + } else { + ctx.fillStyle = m.color || options.grid.markingsColor; + ctx.fillRect(xrange.from, yrange.to, + xrange.to - xrange.from, + yrange.from - yrange.to); + } + } + } + } + + function findEdges(axis) { + var box = axis.box, + x = 0, + y = 0; + + // find the edges + if (axis.direction === "x") { + x = 0; + y = box.top - plotOffset.top + (axis.position === "top" ? box.height : 0); + } else { + y = 0; + x = box.left - plotOffset.left + (axis.position === "left" ? box.width : 0) + axis.boxPosition.centerX; + } + + return { + x: x, + y: y + }; + }; + + function alignPosition(lineWidth, pos) { + return ((lineWidth % 2) !== 0) ? Math.floor(pos) + 0.5 : pos; + }; + + function drawTickBar(axis) { + ctx.lineWidth = 1; + var edges = findEdges(axis), + x = edges.x, + y = edges.y; + + // draw tick bar + if (axis.show) { + var xoff = 0, + yoff = 0; + + ctx.strokeStyle = axis.options.color; + ctx.beginPath(); + if (axis.direction === "x") { + xoff = plotWidth + 1; + } else { + yoff = plotHeight + 1; + } + + if (axis.direction === "x") { + y = alignPosition(ctx.lineWidth, y); + } else { + x = alignPosition(ctx.lineWidth, x); + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff); + ctx.stroke(); + } + }; + + function drawTickMarks(axis) { + var t = axis.tickLength, + minorTicks = axis.showMinorTicks, + minorTicksNr = MINOR_TICKS_COUNT_CONSTANT, + edges = findEdges(axis), + x = edges.x, + y = edges.y, + i = 0; + + // draw major tick marks + ctx.strokeStyle = axis.options.color; + ctx.beginPath(); + + for (i = 0; i < axis.ticks.length; ++i) { + var v = axis.ticks[i].v, + xoff = 0, + yoff = 0, + xminor = 0, + yminor = 0, + j; + + if (!isNaN(v) && v >= axis.min && v <= axis.max) { + if (axis.direction === "x") { + x = axis.p2c(v); + yoff = t; + + if (axis.position === "top") { + yoff = -yoff; + } + } else { + y = axis.p2c(v); + xoff = t; + + if (axis.position === "left") { + xoff = -xoff; + } + } + + if (axis.direction === "x") { + x = alignPosition(ctx.lineWidth, x); + } else { + y = alignPosition(ctx.lineWidth, y); + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff); + } + + //draw minor tick marks + if (minorTicks === true && i < axis.ticks.length - 1) { + var v1 = axis.ticks[i].v, + v2 = axis.ticks[i + 1].v, + step = (v2 - v1) / (minorTicksNr + 1); + + for (j = 1; j <= minorTicksNr; j++) { + // compute minor tick position + if (axis.direction === "x") { + yminor = t / 2; // minor ticks are half length + x = alignPosition(ctx.lineWidth, axis.p2c(v1 + j * step)) + + if (axis.position === "top") { + yminor = -yminor; + } + + // don't go over the plot borders + if ((x < 0) || (x > plotWidth)) { + continue; + } + } else { + xminor = t / 2; // minor ticks are half length + y = alignPosition(ctx.lineWidth, axis.p2c(v1 + j * step)); + + if (axis.position === "left") { + xminor = -xminor; + } + + // don't go over the plot borders + if ((y < 0) || (y > plotHeight)) { + continue; + } + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xminor, y + yminor); + } + } + } + + ctx.stroke(); + }; + + function drawGridLines(axis) { + // check if the line will be overlapped with a border + var overlappedWithBorder = function (value) { + var bw = options.grid.borderWidth; + return (((typeof bw === "object" && bw[axis.position] > 0) || bw > 0) && (value === axis.min || value === axis.max)); + }; + + ctx.strokeStyle = options.grid.tickColor; + ctx.beginPath(); + var i; + for (i = 0; i < axis.ticks.length; ++i) { + var v = axis.ticks[i].v, + xoff = 0, + yoff = 0, + x = 0, + y = 0; + + if (isNaN(v) || v < axis.min || v > axis.max) continue; + + // skip those lying on the axes if we got a border + if (overlappedWithBorder(v)) continue; + + if (axis.direction === "x") { + x = axis.p2c(v); + y = plotHeight; + yoff = -plotHeight; + } else { + x = 0; + y = axis.p2c(v); + xoff = plotWidth; + } + + if (axis.direction === "x") { + x = alignPosition(ctx.lineWidth, x); + } else { + y = alignPosition(ctx.lineWidth, y); + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff); + } + + ctx.stroke(); + }; + + function drawBorder() { + // If either borderWidth or borderColor is an object, then draw the border + // line by line instead of as one rectangle + var bw = options.grid.borderWidth, + bc = options.grid.borderColor; + + if (typeof bw === "object" || typeof bc === "object") { + if (typeof bw !== "object") { + bw = { + top: bw, + right: bw, + bottom: bw, + left: bw + }; + } + if (typeof bc !== "object") { + bc = { + top: bc, + right: bc, + bottom: bc, + left: bc + }; + } + + if (bw.top > 0) { + ctx.strokeStyle = bc.top; + ctx.lineWidth = bw.top; + ctx.beginPath(); + ctx.moveTo(0 - bw.left, 0 - bw.top / 2); + ctx.lineTo(plotWidth, 0 - bw.top / 2); + ctx.stroke(); + } + + if (bw.right > 0) { + ctx.strokeStyle = bc.right; + ctx.lineWidth = bw.right; + ctx.beginPath(); + ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top); + ctx.lineTo(plotWidth + bw.right / 2, plotHeight); + ctx.stroke(); + } + + if (bw.bottom > 0) { + ctx.strokeStyle = bc.bottom; + ctx.lineWidth = bw.bottom; + ctx.beginPath(); + ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2); + ctx.lineTo(0, plotHeight + bw.bottom / 2); + ctx.stroke(); + } + + if (bw.left > 0) { + ctx.strokeStyle = bc.left; + ctx.lineWidth = bw.left; + ctx.beginPath(); + ctx.moveTo(0 - bw.left / 2, plotHeight + bw.bottom); + ctx.lineTo(0 - bw.left / 2, 0); + ctx.stroke(); + } + } else { + ctx.lineWidth = bw; + ctx.strokeStyle = options.grid.borderColor; + ctx.strokeRect(-bw / 2, -bw / 2, plotWidth + bw, plotHeight + bw); + } + }; + + function drawGrid() { + var axes, bw; + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + drawMarkings(); + + axes = allAxes(); + bw = options.grid.borderWidth; + + for (var j = 0; j < axes.length; ++j) { + var axis = axes[j]; + + if (!axis.show) { + continue; + } + + drawTickBar(axis); + if (axis.showTicks === true) { + drawTickMarks(axis); + } + + if (axis.gridLines === true) { + drawGridLines(axis, bw); + } + } + + // draw border + if (bw) { + drawBorder(); + } + + ctx.restore(); + } + + function drawAxisLabels() { + $.each(allAxes(), function(_, axis) { + var box = axis.box, + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = axis.options.font || "flot-tick-label tickLabel", + i, x, y, halign, valign, info, + margin = 3, + nullBox = {x: NaN, y: NaN, width: NaN, height: NaN}, newLabelBox, labelBoxes = [], + overlapping = function(x11, y11, x12, y12, x21, y21, x22, y22) { + return ((x11 <= x21 && x21 <= x12) || (x21 <= x11 && x11 <= x22)) && + ((y11 <= y21 && y21 <= y12) || (y21 <= y11 && y11 <= y22)); + }, + overlapsOtherLabels = function(newLabelBox, previousLabelBoxes) { + return previousLabelBoxes.some(function(labelBox) { + return overlapping( + newLabelBox.x, newLabelBox.y, newLabelBox.x + newLabelBox.width, newLabelBox.y + newLabelBox.height, + labelBox.x, labelBox.y, labelBox.x + labelBox.width, labelBox.y + labelBox.height); + }); + }, + drawAxisLabel = function (tick, labelBoxes) { + if (!tick || !tick.label || tick.v < axis.min || tick.v > axis.max) { + return nullBox; + } + + info = surface.getTextInfo(layer, tick.label, font); + + if (axis.direction === "x") { + halign = "center"; + x = plotOffset.left + axis.p2c(tick.v); + if (axis.position === "bottom") { + y = box.top + box.padding - axis.boxPosition.centerY; + } else { + y = box.top + box.height - box.padding + axis.boxPosition.centerY; + valign = "bottom"; + } + newLabelBox = {x: x - info.width / 2 - margin, y: y - margin, width: info.width + 2 * margin, height: info.height + 2 * margin}; + } else { + valign = "middle"; + y = plotOffset.top + axis.p2c(tick.v); + if (axis.position === "left") { + x = box.left + box.width - box.padding - axis.boxPosition.centerX; + halign = "right"; + } else { + x = box.left + box.padding + axis.boxPosition.centerX; + } + newLabelBox = {x: x - info.width / 2 - margin, y: y - margin, width: info.width + 2 * margin, height: info.height + 2 * margin}; + } + + if (overlapsOtherLabels(newLabelBox, labelBoxes)) { + return nullBox; + } + + surface.addText(layer, x, y, tick.label, font, null, null, halign, valign); + + return newLabelBox; + }; + + // Remove text before checking for axis.show and ticks.length; + // otherwise plugins, like flot-tickrotor, that draw their own + // tick labels will end up with both theirs and the defaults. + + surface.removeText(layer); + + executeHooks(hooks.drawAxis, [axis, surface]); + + if (!axis.show) { + return; + } + + switch (axis.options.showTickLabels) { + case 'none': + break; + case 'endpoints': + labelBoxes.push(drawAxisLabel(axis.ticks[0], labelBoxes)); + labelBoxes.push(drawAxisLabel(axis.ticks[axis.ticks.length - 1], labelBoxes)); + break; + case 'major': + labelBoxes.push(drawAxisLabel(axis.ticks[0], labelBoxes)); + labelBoxes.push(drawAxisLabel(axis.ticks[axis.ticks.length - 1], labelBoxes)); + for (i = 1; i < axis.ticks.length - 1; ++i) { + labelBoxes.push(drawAxisLabel(axis.ticks[i], labelBoxes)); + } + break; + case 'all': + labelBoxes.push(drawAxisLabel(axis.ticks[0], [])); + labelBoxes.push(drawAxisLabel(axis.ticks[axis.ticks.length - 1], labelBoxes)); + for (i = 1; i < axis.ticks.length - 1; ++i) { + labelBoxes.push(drawAxisLabel(axis.ticks[i], labelBoxes)); + } + break; + } + }); + } + + function drawSeries(series) { + if (series.lines.show) { + $.plot.drawSeries.drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, plot.drawSymbol, getColorOrGradient); + } + + if (series.bars.show) { + $.plot.drawSeries.drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, plot.drawSymbol, getColorOrGradient); + } + + if (series.points.show) { + $.plot.drawSeries.drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, plot.drawSymbol, getColorOrGradient); + } + } + + function computeRangeForDataSeries(series, force, isValid) { + var points = series.datapoints.points, + ps = series.datapoints.pointsize, + format = series.datapoints.format, + topSentry = Number.POSITIVE_INFINITY, + bottomSentry = Number.NEGATIVE_INFINITY, + range = { + xmin: topSentry, + ymin: topSentry, + xmax: bottomSentry, + ymax: bottomSentry + }; + + for (var j = 0; j < points.length; j += ps) { + if (points[j] === null) { + continue; + } + + if (typeof (isValid) === 'function' && !isValid(points[j])) { + continue; + } + + for (var m = 0; m < ps; ++m) { + var val = points[j + m], + f = format[m]; + if (f === null || f === undefined) { + continue; + } + + if (typeof (isValid) === 'function' && !isValid(val)) { + continue; + } + + if ((!force && !f.computeRange) || val === Infinity || val === -Infinity) { + continue; + } + + if (f.x === true) { + if (val < range.xmin) { + range.xmin = val; + } + + if (val > range.xmax) { + range.xmax = val; + } + } + + if (f.y === true) { + if (val < range.ymin) { + range.ymin = val; + } + + if (val > range.ymax) { + range.ymax = val; + } + } + } + } + + return range; + }; + + function adjustSeriesDataRange(series, range) { + if (series.bars.show) { + // make sure we got room for the bar on the dancing floor + var delta; + + // update bar width if needed + var useAbsoluteBarWidth = series.bars.barWidth[1]; + if (series.datapoints && series.datapoints.points && !useAbsoluteBarWidth) { + computeBarWidth(series); + } + + var barWidth = series.bars.barWidth[0] || series.bars.barWidth; + switch (series.bars.align) { + case "left": + delta = 0; + break; + case "right": + delta = -barWidth; + break; + default: + delta = -barWidth / 2; + } + + if (series.bars.horizontal) { + range.ymin += delta; + range.ymax += delta + barWidth; + } + else { + range.xmin += delta; + range.xmax += delta + barWidth; + } + } + + if ((series.bars.show && series.bars.zero) || (series.lines.show && series.lines.zero)) { + var ps = series.datapoints.pointsize; + + // make sure the 0 point is included in the computed y range when requested + if (ps <= 2) { + /*if ps > 0 the points were already taken into account for autoScale */ + range.ymin = Math.min(0, range.ymin); + range.ymax = Math.max(0, range.ymax); + } + } + + return range; + }; + + function computeBarWidth(series) { + var pointsize = series.datapoints.pointsize, minDistance = Number.MAX_VALUE, + distance = series.datapoints.points[pointsize] - series.datapoints.points[0] || 1; + + if (isFinite(distance)) { + minDistance = distance; + } + for (var j = pointsize; j < series.datapoints.points.length - pointsize; j += pointsize) { + distance = Math.abs(series.datapoints.points[pointsize + j] - series.datapoints.points[j]); + if (distance < minDistance && isFinite(distance)) { + minDistance = distance; + } + } + + if (typeof series.bars.barWidth === "number") { + series.bars.barWidth = series.bars.barWidth * minDistance; + } else { + series.bars.barWidth[0] = series.bars.barWidth[0] * minDistance; + } + } + + // returns the data item the mouse is over/ the cursor is closest to, or null if none is found + function findNearbyItem(mouseX, mouseY, seriesFilter, radius, computeDistance) { + var i, j, + item = null, + smallestDistance = radius * radius + 1; + + for (var i = series.length - 1; i >= 0; --i) { + if (!seriesFilter(i)) continue; + + var s = series[i]; + if (!s.datapoints) return; + + if (s.lines.show || s.points.show) { + var found = findNearbyPoint(s, mouseX, mouseY, radius, smallestDistance, computeDistance); + if (found) { + smallestDistance = found.distance; + item = [i, found.dataIndex]; + } + } + + if (s.bars.show && !item) { // no other point can be nearby + var foundIndex = findNearbyBar(s, mouseX, mouseY); + if (foundIndex) item = [i, foundIndex]; + } + } + + if (item) { + i = item[0]; + j = item[1]; + var ps = series[i].datapoints.pointsize; + + return { + datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps), + dataIndex: j, + series: series[i], + seriesIndex: i + }; + } + + return null; + } + + function findNearbyPoint (series, mouseX, mouseY, maxDistance, smallestDistance, computeDistance) { + var mx = series.xaxis.c2p(mouseX), + my = series.yaxis.c2p(mouseY), + maxx = maxDistance / series.xaxis.scale, + maxy = maxDistance / series.yaxis.scale, + points = series.datapoints.points, + ps = series.datapoints.pointsize; + + // with inverse transforms, we can't use the maxx/maxy + // optimization, sadly + if (series.xaxis.options.inverseTransform) { + maxx = Number.MAX_VALUE; + } + + if (series.yaxis.options.inverseTransform) { + maxy = Number.MAX_VALUE; + } + + var found = null; + for (var j = 0; j < points.length; j += ps) { + var x = points[j]; + var y = points[j + 1]; + if (x == null) { + continue; + } + + if (x - mx > maxx || x - mx < -maxx || + y - my > maxy || y - my < -maxy) { + continue; + } + + // We have to calculate distances in pixels, not in + // data units, because the scales of the axes may be different + var dx = Math.abs(series.xaxis.p2c(x) - mouseX); + var dy = Math.abs(series.yaxis.p2c(y) - mouseY); + var dist = computeDistance ? computeDistance(dx, dy) : dx * dx + dy * dy; + + // use <= to ensure last point takes precedence + // (last generally means on top of) + if (dist < smallestDistance) { + smallestDistance = dist; + found = { dataIndex: j / ps, distance: dist }; + } + } + + return found; + } + + function findNearbyBar (series, mouseX, mouseY) { + var barLeft, barRight, + barWidth = series.bars.barWidth[0] || series.bars.barWidth, + mx = series.xaxis.c2p(mouseX), + my = series.yaxis.c2p(mouseY), + points = series.datapoints.points, + ps = series.datapoints.pointsize; + + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -barWidth; + break; + default: + barLeft = -barWidth / 2; + } + + barRight = barLeft + barWidth; + + var fillTowards = series.bars.fillTowards || 0; + var bottom = fillTowards > series.yaxis.min ? Math.min(series.yaxis.max, fillTowards) : series.yaxis.min; + + var foundIndex = null; + for (var j = 0; j < points.length; j += ps) { + var x = points[j], y = points[j + 1]; + if (x == null) + continue; + + // for a bar graph, the cursor must be inside the bar + if (series.bars.horizontal ? + (mx <= Math.max(bottom, x) && mx >= Math.min(bottom, x) && + my >= y + barLeft && my <= y + barRight) : + (mx >= x + barLeft && mx <= x + barRight && + my >= Math.min(bottom, y) && my <= Math.max(bottom, y))) + foundIndex = j / ps; + } + + return foundIndex; + } + + function findNearbyInterpolationPoint(posX, posY, seriesFilter) { + var i, j, dist, dx, dy, ps, + item, + smallestDistance = Number.MAX_VALUE; + + for (i = 0; i < series.length; ++i) { + if (!seriesFilter(i)) { + continue; + } + var points = series[i].datapoints.points; + ps = series[i].datapoints.pointsize; + + // if the data is coming from positive -> negative, reverse the comparison + const comparer = points[points.length - ps] < points[0] + ? function (x1, x2) { return x1 > x2 } + : function (x1, x2) { return x2 > x1 }; + + // do not interpolate outside the bounds of the data. + if (comparer(posX, points[0])) { + continue; + } + + // Find the nearest points, x-wise + for (j = ps; j < points.length; j += ps) { + if (comparer(posX, points[j])) { + break; + } + } + + // Now Interpolate + var y, + p1x = points[j - ps], + p1y = points[j - ps + 1], + p2x = points[j], + p2y = points[j + 1]; + + if ((p1x === undefined) || (p2x === undefined) || + (p1y === undefined) || (p2y === undefined)) { + continue; + } + + if (p1x === p2x) { + y = p2y + } else { + y = p1y + (p2y - p1y) * (posX - p1x) / (p2x - p1x); + } + + posY = y; + + dx = Math.abs(series[i].xaxis.p2c(p2x) - posX); + dy = Math.abs(series[i].yaxis.p2c(p2y) - posY); + dist = dx * dx + dy * dy; + + if (dist < smallestDistance) { + smallestDistance = dist; + item = [posX, posY, i, j]; + } + } + + if (item) { + i = item[2]; + j = item[3]; + ps = series[i].datapoints.pointsize; + points = series[i].datapoints.points; + p1x = points[j - ps]; + p1y = points[j - ps + 1]; + p2x = points[j]; + p2y = points[j + 1]; + + return { + datapoint: [item[0], item[1]], + leftPoint: [p1x, p1y], + rightPoint: [p2x, p2y], + seriesIndex: i + }; + } + + return null; + } + + function triggerRedrawOverlay() { + var t = options.interaction.redrawOverlayInterval; + if (t === -1) { // skip event queue + drawOverlay(); + return; + } + + if (!redrawTimeout) { + redrawTimeout = setTimeout(function() { + drawOverlay(plot); + }, t); + } + } + + function drawOverlay(plot) { + redrawTimeout = null; + + if (!octx) { + return; + } + overlay.clear(); + executeHooks(hooks.drawOverlay, [octx, overlay]); + var event = new CustomEvent('onDrawingDone'); + plot.getEventHolder().dispatchEvent(event); + } + + function getColorOrGradient(spec, bottom, top, defaultColor) { + if (typeof spec === "string") { + return spec; + } else { + // assume this is a gradient spec; IE currently only + // supports a simple vertical gradient properly, so that's + // what we support too + var gradient = ctx.createLinearGradient(0, top, 0, bottom); + + for (var i = 0, l = spec.colors.length; i < l; ++i) { + var c = spec.colors[i]; + if (typeof c !== "string") { + var co = $.color.parse(defaultColor); + if (c.brightness != null) { + co = co.scale('rgb', c.brightness); + } + + if (c.opacity != null) { + co.a *= c.opacity; + } + + c = co.toString(); + } + gradient.addColorStop(i / (l - 1), c); + } + + return gradient; + } + } + } + + // Add the plot function to the top level of the jQuery object + + $.plot = function(placeholder, data, options) { + var plot = new Plot($(placeholder), data, options, $.plot.plugins); + return plot; + }; + + $.plot.version = "1.0.3"; + + $.plot.plugins = []; + + // Also add the plot function as a chainable property + $.fn.plot = function(data, options) { + return this.each(function() { + $.plot(this, data, options); + }); + }; + + $.plot.linearTickGenerator = defaultTickGenerator; + $.plot.defaultTickFormatter = defaultTickFormatter; + $.plot.expRepTickFormatter = expRepTickFormatter; +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.legend.js b/extern/phmap/benchmark/js/jquery.flot.legend.js new file mode 100644 index 0000000..3a6ae15 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.legend.js @@ -0,0 +1,395 @@ +/* Flot plugin for drawing legends. + +*/ + +(function($) { + var defaultOptions = { + legend: { + show: false, + labelFormatter: null, // fn: string -> string + container: null, // container (as jQuery object) to put legend in, null means default on top of graph + position: 'ne', // position of default legend container within plot + margin: 5, // distance from grid edge to default legend container within plot + sorted: null // default to no legend sorting + } + }; + + function insertLegend(plot, options, placeholder, legendEntries) { + // clear before redraw + if (options.legend.container != null) { + $(options.legend.container).html(''); + } else { + placeholder.find('.legend').remove(); + } + + if (!options.legend.show) { + return; + } + + // Save the legend entries in legend options + var entries = options.legend.legendEntries = legendEntries, + plotOffset = options.legend.plotOffset = plot.getPlotOffset(), + html = [], + entry, labelHtml, iconHtml, + maxLabelLength = 0, + j = 0, + pos = "", + p = options.legend.position, + m = options.legend.margin, + shape = { + name: '', + label: '', + xPos: '', + yPos: '' + }; + + html[j++] = ''; + html[j++] = ''; + html[j++] = svgShapeDefs; + + // Generate html for icons and labels from a list of entries + for (var i = 0; i < entries.length; ++i) { + entry = entries[i]; + iconHtml = ''; + shape.label = entry.label; + shape.xPos = '0em'; + shape.yPos = i * 1.5 + 'em'; + // area + if (entry.options.lines.show && entry.options.lines.fill) { + shape.name = 'area'; + shape.fillColor = entry.color; + iconHtml += getEntryIconHtml(shape); + } + // bars + if (entry.options.bars.show) { + shape.name = 'bar'; + shape.fillColor = entry.color; + iconHtml += getEntryIconHtml(shape); + } + // lines + if (entry.options.lines.show && !entry.options.lines.fill) { + shape.name = 'line'; + shape.strokeColor = entry.color; + shape.strokeWidth = entry.options.lines.lineWidth; + iconHtml += getEntryIconHtml(shape); + } + // points + if (entry.options.points.show) { + shape.name = entry.options.points.symbol; + shape.strokeColor = entry.color; + shape.fillColor = entry.options.points.fillColor; + shape.strokeWidth = entry.options.points.lineWidth; + iconHtml += getEntryIconHtml(shape); + } + + maxLabelLength = maxLabelLength < shape.label.length ? shape.label.length : maxLabelLength; + labelHtml = '' + shape.label + '' + html[j++] = '' + iconHtml + labelHtml + ''; + } + + html[j++] = ''; + if (m[0] == null) { + m = [m, m]; + } + + if (p.charAt(0) === 'n') { + pos += 'top:' + (m[1] + plotOffset.top) + 'px;'; + } else if (p.charAt(0) === 's') { + pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;'; + } + + if (p.charAt(1) === 'e') { + pos += 'right:' + (m[0] + plotOffset.right) + 'px;'; + } else if (p.charAt(1) === 'w') { + pos += 'left:' + (m[0] + plotOffset.left) + 'px;'; + } + + var legendEl, + width = 3 + maxLabelLength / 2, + height = entries.length * 1.6; + if (!options.legend.container) { + legendEl = $('
' + html.join('') + '
').appendTo(placeholder); + legendEl.css('width', width + 'em'); + legendEl.css('height', height + 'em'); + legendEl.css('pointerEvents', 'none'); + } else { + legendEl = $(html.join('')).appendTo(options.legend.container)[0]; + options.legend.container.style.width = width + 'em'; + options.legend.container.style.height = height + 'em'; + } + } + + // Generate html for a shape + function getEntryIconHtml(shape) { + var html = '', + name = shape.name, + x = shape.xPos, + y = shape.yPos, + fill = shape.fillColor, + stroke = shape.strokeColor, + width = shape.strokeWidth; + switch (name) { + case 'circle': + html = ''; + break; + case 'diamond': + html = ''; + break; + case 'cross': + html = ''; + break; + case 'rectangle': + html = ''; + break; + case 'plus': + html = ''; + break; + case 'bar': + html = ''; + break; + case 'area': + html = ''; + break; + case 'line': + html = ''; + break; + default: + // default is circle + html = ''; + } + + return html; + } + + // Define svg symbols for shapes + var svgShapeDefs = '' + + '' + + '' + + '' + + '' + + + '' + + '' + + '' + + + '' + + '' + + '' + + + '' + + '' + + '' + + '' + + '' + + '' + + + '' + + '' + + '' + + '' + + '' + + '' + + + '' + + '' + + '' + + '' + + '' + + '' + + + '' + + '' + + '' + + '' + + '' + + '' + + + '' + + '' + + '' + + '' + + '' + + '' + + ''; + + // Generate a list of legend entries in their final order + function getLegendEntries(series, labelFormatter, sorted) { + var lf = labelFormatter, + legendEntries = series.map(function(s, i) { + return { + label: (lf ? lf(s.label, s) : s.label) || 'Plot ' + (i + 1), + color: s.color, + options: { + lines: s.lines, + points: s.points, + bars: s.bars + } + }; + }); + + // Sort the legend using either the default or a custom comparator + if (sorted) { + if ($.isFunction(sorted)) { + legendEntries.sort(sorted); + } else if (sorted === 'reverse') { + legendEntries.reverse(); + } else { + var ascending = (sorted !== 'descending'); + legendEntries.sort(function(a, b) { + return a.label === b.label + ? 0 + : ((a.label < b.label) !== ascending ? 1 : -1 // Logical XOR + ); + }); + } + } + + return legendEntries; + } + + // return false if opts1 same as opts2 + function checkOptions(opts1, opts2) { + for (var prop in opts1) { + if (opts1.hasOwnProperty(prop)) { + if (opts1[prop] !== opts2[prop]) { + return true; + } + } + } + return false; + } + + // Compare two lists of legend entries + function shouldRedraw(oldEntries, newEntries) { + if (!oldEntries || !newEntries) { + return true; + } + + if (oldEntries.length !== newEntries.length) { + return true; + } + var i, newEntry, oldEntry, newOpts, oldOpts; + for (i = 0; i < newEntries.length; i++) { + newEntry = newEntries[i]; + oldEntry = oldEntries[i]; + + if (newEntry.label !== oldEntry.label) { + return true; + } + + if (newEntry.color !== oldEntry.color) { + return true; + } + + // check for changes in lines options + newOpts = newEntry.options.lines; + oldOpts = oldEntry.options.lines; + if (checkOptions(newOpts, oldOpts)) { + return true; + } + + // check for changes in points options + newOpts = newEntry.options.points; + oldOpts = oldEntry.options.points; + if (checkOptions(newOpts, oldOpts)) { + return true; + } + + // check for changes in bars options + newOpts = newEntry.options.bars; + oldOpts = oldEntry.options.bars; + if (checkOptions(newOpts, oldOpts)) { + return true; + } + } + + return false; + } + + function init(plot) { + plot.hooks.setupGrid.push(function (plot) { + var options = plot.getOptions(); + var series = plot.getData(), + labelFormatter = options.legend.labelFormatter, + oldEntries = options.legend.legendEntries, + oldPlotOffset = options.legend.plotOffset, + newEntries = getLegendEntries(series, labelFormatter, options.legend.sorted), + newPlotOffset = plot.getPlotOffset(); + + if (shouldRedraw(oldEntries, newEntries) || + checkOptions(oldPlotOffset, newPlotOffset)) { + insertLegend(plot, options, plot.getPlaceholder(), newEntries); + } + }); + } + + $.plot.plugins.push({ + init: init, + options: defaultOptions, + name: 'legend', + version: '1.0' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.logaxis.js b/extern/phmap/benchmark/js/jquery.flot.logaxis.js new file mode 100644 index 0000000..8622f73 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.logaxis.js @@ -0,0 +1,296 @@ +/* Pretty handling of log axes. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Copyright (c) 2015 Ciprian Ceteras cipix2000@gmail.com. +Copyright (c) 2017 Raluca Portase +Licensed under the MIT license. + +Set axis.mode to "log" to enable. +*/ + +/* global jQuery*/ + +/** +## jquery.flot.logaxis +This plugin is used to create logarithmic axis. This includes tick generation, +formatters and transformers to and from logarithmic representation. + +### Methods and hooks +*/ + +(function ($) { + 'use strict'; + + var options = { + xaxis: {} + }; + + /*tick generators and formatters*/ + var PREFERRED_LOG_TICK_VALUES = computePreferedLogTickValues(Number.MAX_VALUE, 10), + EXTENDED_LOG_TICK_VALUES = computePreferedLogTickValues(Number.MAX_VALUE, 4); + + function computePreferedLogTickValues(endLimit, rangeStep) { + var log10End = Math.floor(Math.log(endLimit) * Math.LOG10E) - 1, + log10Start = -log10End, + val, range, vals = []; + + for (var power = log10Start; power <= log10End; power++) { + range = Math.pow(10, power); + for (var mult = 1; mult < 9; mult += rangeStep) { + val = range * mult; + vals.push(val); + } + } + return vals; + } + + /** + - logTickGenerator(plot, axis, noTicks) + + Generates logarithmic ticks, depending on axis range. + In case the number of ticks that can be generated is less than the expected noTicks/4, + a linear tick generation is used. + */ + var logTickGenerator = function (plot, axis, noTicks) { + var ticks = [], + minIdx = -1, + maxIdx = -1, + surface = plot.getCanvas(), + logTickValues = PREFERRED_LOG_TICK_VALUES, + min = clampAxis(axis, plot), + max = axis.max; + + if (!noTicks) { + noTicks = 0.3 * Math.sqrt(axis.direction === "x" ? surface.width : surface.height); + } + + PREFERRED_LOG_TICK_VALUES.some(function (val, i) { + if (val >= min) { + minIdx = i; + return true; + } else { + return false; + } + }); + + PREFERRED_LOG_TICK_VALUES.some(function (val, i) { + if (val >= max) { + maxIdx = i; + return true; + } else { + return false; + } + }); + + if (maxIdx === -1) { + maxIdx = PREFERRED_LOG_TICK_VALUES.length - 1; + } + + if (maxIdx - minIdx <= noTicks / 4 && logTickValues.length !== EXTENDED_LOG_TICK_VALUES.length) { + //try with multiple of 5 for tick values + logTickValues = EXTENDED_LOG_TICK_VALUES; + minIdx *= 2; + maxIdx *= 2; + } + + var lastDisplayed = null, + inverseNoTicks = 1 / noTicks, + tickValue, pixelCoord, tick; + + // Count the number of tick values would appear, if we can get at least + // nTicks / 4 accept them. + if (maxIdx - minIdx >= noTicks / 4) { + for (var idx = maxIdx; idx >= minIdx; idx--) { + tickValue = logTickValues[idx]; + pixelCoord = (Math.log(tickValue) - Math.log(min)) / (Math.log(max) - Math.log(min)); + tick = tickValue; + + if (lastDisplayed === null) { + lastDisplayed = { + pixelCoord: pixelCoord, + idealPixelCoord: pixelCoord + }; + } else { + if (Math.abs(pixelCoord - lastDisplayed.pixelCoord) >= inverseNoTicks) { + lastDisplayed = { + pixelCoord: pixelCoord, + idealPixelCoord: lastDisplayed.idealPixelCoord - inverseNoTicks + }; + } else { + tick = null; + } + } + + if (tick) { + ticks.push(tick); + } + } + // Since we went in backwards order. + ticks.reverse(); + } else { + var tickSize = plot.computeTickSize(min, max, noTicks), + customAxis = {min: min, max: max, tickSize: tickSize}; + ticks = $.plot.linearTickGenerator(customAxis); + } + + return ticks; + }; + + var clampAxis = function (axis, plot) { + var min = axis.min, + max = axis.max; + + if (min <= 0) { + //for empty graph if axis.min is not strictly positive make it 0.1 + if (axis.datamin === null) { + min = axis.min = 0.1; + } else { + min = processAxisOffset(plot, axis); + } + + if (max < min) { + axis.max = axis.datamax !== null ? axis.datamax : axis.options.max; + axis.options.offset.below = 0; + axis.options.offset.above = 0; + } + } + + return min; + } + + /** + - logTickFormatter(value, axis, precision) + + This is the corresponding tickFormatter of the logaxis. + For a number greater that 10^6 or smaller than 10^(-3), this will be drawn + with e representation + */ + var logTickFormatter = function (value, axis, precision) { + var tenExponent = value > 0 ? Math.floor(Math.log(value) / Math.LN10) : 0; + + if (precision) { + if ((tenExponent >= -4) && (tenExponent <= 7)) { + return $.plot.defaultTickFormatter(value, axis, precision); + } else { + return $.plot.expRepTickFormatter(value, axis, precision); + } + } + if ((tenExponent >= -4) && (tenExponent <= 7)) { + //if we have float numbers, return a limited length string(ex: 0.0009 is represented as 0.000900001) + var formattedValue = tenExponent < 0 ? value.toFixed(-tenExponent) : value.toFixed(tenExponent + 2); + if (formattedValue.indexOf('.') !== -1) { + var lastZero = formattedValue.lastIndexOf('0'); + + while (lastZero === formattedValue.length - 1) { + formattedValue = formattedValue.slice(0, -1); + lastZero = formattedValue.lastIndexOf('0'); + } + + //delete the dot if is last + if (formattedValue.indexOf('.') === formattedValue.length - 1) { + formattedValue = formattedValue.slice(0, -1); + } + } + return formattedValue; + } else { + return $.plot.expRepTickFormatter(value, axis); + } + }; + + /*logaxis caracteristic functions*/ + var logTransform = function (v) { + if (v < PREFERRED_LOG_TICK_VALUES[0]) { + v = PREFERRED_LOG_TICK_VALUES[0]; + } + + return Math.log(v); + }; + + var logInverseTransform = function (v) { + return Math.exp(v); + }; + + var invertedTransform = function (v) { + return -v; + } + + var invertedLogTransform = function (v) { + return -logTransform(v); + } + + var invertedLogInverseTransform = function (v) { + return logInverseTransform(-v); + } + + /** + - setDataminRange(plot, axis) + + It is used for clamping the starting point of a logarithmic axis. + This will set the axis datamin range to 0.1 or to the first datapoint greater then 0. + The function is usefull since the logarithmic representation can not show + values less than or equal to 0. + */ + function setDataminRange(plot, axis) { + if (axis.options.mode === 'log' && axis.datamin <= 0) { + if (axis.datamin === null) { + axis.datamin = 0.1; + } else { + axis.datamin = processAxisOffset(plot, axis); + } + } + } + + function processAxisOffset(plot, axis) { + var series = plot.getData(), + range = series + .filter(function(series) { + return series.xaxis === axis || series.yaxis === axis; + }) + .map(function(series) { + return plot.computeRangeForDataSeries(series, null, isValid); + }), + min = axis.direction === 'x' ? Math.min(0.1, range[0].xmin) : Math.min(0.1, range[0].ymin); + + axis.min = min; + + return min; + } + + function isValid(a) { + return a > 0; + } + + function init(plot) { + plot.hooks.processOptions.push(function (plot) { + $.each(plot.getAxes(), function (axisName, axis) { + var opts = axis.options; + if (opts.mode === 'log') { + axis.tickGenerator = function (axis) { + var noTicks = 11; + return logTickGenerator(plot, axis, noTicks); + }; + if (typeof axis.options.tickFormatter !== 'function') { + axis.options.tickFormatter = logTickFormatter; + } + axis.options.transform = opts.inverted ? invertedLogTransform : logTransform; + axis.options.inverseTransform = opts.inverted ? invertedLogInverseTransform : logInverseTransform; + axis.options.autoScaleMargin = 0; + plot.hooks.setRange.push(setDataminRange); + } else if (opts.inverted) { + axis.options.transform = invertedTransform; + axis.options.inverseTransform = invertedTransform; + } + }); + }); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'log', + version: '0.1' + }); + + $.plot.logTicksGenerator = logTickGenerator; + $.plot.logTickFormatter = logTickFormatter; +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.navigate.js b/extern/phmap/benchmark/js/jquery.flot.navigate.js new file mode 100644 index 0000000..1c3ce37 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.navigate.js @@ -0,0 +1,781 @@ +/* Flot plugin for adding the ability to pan and zoom the plot. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Copyright (c) 2016 Ciprian Ceteras. +Copyright (c) 2017 Raluca Portase. +Licensed under the MIT license. + +*/ + +/** +## jquery.flot.navigate.js + +This flot plugin is used for adding the ability to pan and zoom the plot. +A higher level overview is available at [interactions](interactions.md) documentation. + +The default behaviour is scrollwheel up/down to zoom in, drag +to pan. The plugin defines plot.zoom({ center }), plot.zoomOut() and +plot.pan( offset ) so you easily can add custom controls. It also fires +"plotpan" and "plotzoom" events, useful for synchronizing plots. + +The plugin supports these options: +```js + zoom: { + interactive: false, + active: false, + amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out) + } + + pan: { + interactive: false, + active: false, + cursor: "move", // CSS mouse cursor value used when dragging, e.g. "pointer" + frameRate: 60, + mode: "smart" // enable smart pan mode + } + + xaxis: { + axisZoom: true, //zoom axis when mouse over it is allowed + plotZoom: true, //zoom axis is allowed for plot zoom + axisPan: true, //pan axis when mouse over it is allowed + plotPan: true //pan axis is allowed for plot pan + } + + yaxis: { + axisZoom: true, //zoom axis when mouse over it is allowed + plotZoom: true, //zoom axis is allowed for plot zoom + axisPan: true, //pan axis when mouse over it is allowed + plotPan: true //pan axis is allowed for plot pan + } +``` +**interactive** enables the built-in drag/click behaviour. If you enable +interactive for pan, then you'll have a basic plot that supports moving +around; the same for zoom. + +**active** is true after a touch tap on plot. This enables plot navigation. +Once activated, zoom and pan cannot be deactivated. When the plot becomes active, +"plotactivated" event is triggered. + +**amount** specifies the default amount to zoom in (so 1.5 = 150%) relative to +the current viewport. + +**cursor** is a standard CSS mouse cursor string used for visual feedback to the +user when dragging. + +**frameRate** specifies the maximum number of times per second the plot will +update itself while the user is panning around on it (set to null to disable +intermediate pans, the plot will then not update until the mouse button is +released). + +**mode** a string specifies the pan mode for mouse interaction. Accepted values: +'manual': no pan hint or direction snapping; +'smart': The graph shows pan hint bar and the pan movement will snap +to one direction when the drag direction is close to it; +'smartLock'. The graph shows pan hint bar and the pan movement will always +snap to a direction that the drag diorection started with. + +Example API usage: +```js + plot = $.plot(...); + + // zoom default amount in on the pixel ( 10, 20 ) + plot.zoom({ center: { left: 10, top: 20 } }); + + // zoom out again + plot.zoomOut({ center: { left: 10, top: 20 } }); + + // zoom 200% in on the pixel (10, 20) + plot.zoom({ amount: 2, center: { left: 10, top: 20 } }); + + // pan 100 pixels to the left (changing x-range in a positive way) and 20 down + plot.pan({ left: -100, top: 20 }) +``` + +Here, "center" specifies where the center of the zooming should happen. Note +that this is defined in pixel space, not the space of the data points (you can +use the p2c helpers on the axes in Flot to help you convert between these). + +**amount** is the amount to zoom the viewport relative to the current range, so +1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out). You +can set the default in the options. +*/ + +/* eslint-enable */ +(function($) { + 'use strict'; + + var options = { + zoom: { + interactive: false, + active: false, + amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out) + }, + pan: { + interactive: false, + active: false, + cursor: "move", + frameRate: 60, + mode: 'smart' + }, + xaxis: { + axisZoom: true, //zoom axis when mouse over it is allowed + plotZoom: true, //zoom axis is allowed for plot zoom + axisPan: true, //pan axis when mouse over it is allowed + plotPan: true //pan axis is allowed for plot pan + }, + yaxis: { + axisZoom: true, + plotZoom: true, + axisPan: true, + plotPan: true + } + }; + + var saturated = $.plot.saturated; + var browser = $.plot.browser; + var SNAPPING_CONSTANT = $.plot.uiConstants.SNAPPING_CONSTANT; + var PANHINT_LENGTH_CONSTANT = $.plot.uiConstants.PANHINT_LENGTH_CONSTANT; + + function init(plot) { + plot.hooks.processOptions.push(initNevigation); + } + + function initNevigation(plot, options) { + var panAxes = null; + var canDrag = false; + var useManualPan = options.pan.mode === 'manual', + smartPanLock = options.pan.mode === 'smartLock', + useSmartPan = smartPanLock || options.pan.mode === 'smart'; + + function onZoomClick(e, zoomOut, amount) { + var page = browser.getPageXY(e); + + var c = plot.offset(); + c.left = page.X - c.left; + c.top = page.Y - c.top; + + var ec = plot.getPlaceholder().offset(); + ec.left = page.X - ec.left; + ec.top = page.Y - ec.top; + + var axes = plot.getXAxes().concat(plot.getYAxes()).filter(function (axis) { + var box = axis.box; + if (box !== undefined) { + return (ec.left > box.left) && (ec.left < box.left + box.width) && + (ec.top > box.top) && (ec.top < box.top + box.height); + } + }); + + if (axes.length === 0) { + axes = undefined; + } + + if (zoomOut) { + plot.zoomOut({ + center: c, + axes: axes, + amount: amount + }); + } else { + plot.zoom({ + center: c, + axes: axes, + amount: amount + }); + } + } + + var prevCursor = 'default', + panHint = null, + panTimeout = null, + plotState, + prevDragPosition = { x: 0, y: 0 }, + isPanAction = false; + + function onMouseWheel(e, delta) { + var maxAbsoluteDeltaOnMac = 1, + isMacScroll = Math.abs(e.originalEvent.deltaY) <= maxAbsoluteDeltaOnMac, + defaultNonMacScrollAmount = null, + macMagicRatio = 50, + amount = isMacScroll ? 1 + Math.abs(e.originalEvent.deltaY) / macMagicRatio : defaultNonMacScrollAmount; + + if (isPanAction) { + onDragEnd(e); + } + + if (plot.getOptions().zoom.active) { + e.preventDefault(); + onZoomClick(e, delta < 0, amount); + return false; + } + } + + plot.navigationState = function(startPageX, startPageY) { + var axes = this.getAxes(); + var result = {}; + Object.keys(axes).forEach(function(axisName) { + var axis = axes[axisName]; + result[axisName] = { + navigationOffset: { below: axis.options.offset.below || 0, + above: axis.options.offset.above || 0}, + axisMin: axis.min, + axisMax: axis.max, + diagMode: false + } + }); + + result.startPageX = startPageX || 0; + result.startPageY = startPageY || 0; + return result; + } + + function onMouseDown(e) { + canDrag = true; + } + + function onMouseUp(e) { + canDrag = false; + } + + function isLeftMouseButtonPressed(e) { + return e.button === 0; + } + + function onDragStart(e) { + if (!canDrag || !isLeftMouseButtonPressed(e)) { + return false; + } + + isPanAction = true; + var page = browser.getPageXY(e); + + var ec = plot.getPlaceholder().offset(); + ec.left = page.X - ec.left; + ec.top = page.Y - ec.top; + + panAxes = plot.getXAxes().concat(plot.getYAxes()).filter(function (axis) { + var box = axis.box; + if (box !== undefined) { + return (ec.left > box.left) && (ec.left < box.left + box.width) && + (ec.top > box.top) && (ec.top < box.top + box.height); + } + }); + + if (panAxes.length === 0) { + panAxes = undefined; + } + + var c = plot.getPlaceholder().css('cursor'); + if (c) { + prevCursor = c; + } + + plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor); + + if (useSmartPan) { + plotState = plot.navigationState(page.X, page.Y); + } else if (useManualPan) { + prevDragPosition.x = page.X; + prevDragPosition.y = page.Y; + } + } + + function onDrag(e) { + var page = browser.getPageXY(e); + var frameRate = plot.getOptions().pan.frameRate; + + if (frameRate === -1) { + if (useSmartPan) { + plot.smartPan({ + x: plotState.startPageX - page.X, + y: plotState.startPageY - page.Y + }, plotState, panAxes, false, smartPanLock); + } else if (useManualPan) { + plot.pan({ + left: prevDragPosition.x - page.X, + top: prevDragPosition.y - page.Y, + axes: panAxes + }); + prevDragPosition.x = page.X; + prevDragPosition.y = page.Y; + } + return; + } + + if (panTimeout || !frameRate) return; + + panTimeout = setTimeout(function() { + if (useSmartPan) { + plot.smartPan({ + x: plotState.startPageX - page.X, + y: plotState.startPageY - page.Y + }, plotState, panAxes, false, smartPanLock); + } else if (useManualPan) { + plot.pan({ + left: prevDragPosition.x - page.X, + top: prevDragPosition.y - page.Y, + axes: panAxes + }); + prevDragPosition.x = page.X; + prevDragPosition.y = page.Y; + } + + panTimeout = null; + }, 1 / frameRate * 1000); + } + + function onDragEnd(e) { + if (panTimeout) { + clearTimeout(panTimeout); + panTimeout = null; + } + + isPanAction = false; + var page = browser.getPageXY(e); + + plot.getPlaceholder().css('cursor', prevCursor); + + if (useSmartPan) { + plot.smartPan({ + x: plotState.startPageX - page.X, + y: plotState.startPageY - page.Y + }, plotState, panAxes, false, smartPanLock); + plot.smartPan.end(); + } else if (useManualPan) { + plot.pan({ + left: prevDragPosition.x - page.X, + top: prevDragPosition.y - page.Y, + axes: panAxes + }); + prevDragPosition.x = 0; + prevDragPosition.y = 0; + } + } + + function onDblClick(e) { + plot.activate(); + + var axes = plot.getTouchedAxis(e.clientX, e.clientY), + event; + if (axes[0]) { + event = new $.Event('re-center', { detail: { + axisTouched: axes[0] + }}); + } else { + event = new $.Event('re-center', {detail: e}); + } + plot.getPlaceholder().trigger(event); + } + + function onClick(e) { + plot.activate(); + + if (isPanAction) { + onDragEnd(e); + } + + return false; + } + + plot.activate = function() { + var o = plot.getOptions(); + if (!o.pan.active || !o.zoom.active) { + o.pan.active = true; + o.zoom.active = true; + plot.getPlaceholder().trigger("plotactivated", [plot]); + } + } + + function bindEvents(plot, eventHolder) { + var o = plot.getOptions(); + if (o.zoom.interactive) { + eventHolder.mousewheel(onMouseWheel); + } + + if (o.pan.interactive) { + plot.addEventHandler("dragstart", onDragStart, eventHolder, 0); + plot.addEventHandler("drag", onDrag, eventHolder, 0); + plot.addEventHandler("dragend", onDragEnd, eventHolder, 0); + eventHolder.bind("mousedown", onMouseDown); + eventHolder.bind("mouseup", onMouseUp); + } + + eventHolder.dblclick(onDblClick); + eventHolder.click(onClick); + } + + plot.zoomOut = function(args) { + if (!args) { + args = {}; + } + + if (!args.amount) { + args.amount = plot.getOptions().zoom.amount; + } + + args.amount = 1 / args.amount; + plot.zoom(args); + }; + + plot.zoom = function(args) { + if (!args) { + args = {}; + } + + var c = args.center, + amount = args.amount || plot.getOptions().zoom.amount, + w = plot.width(), + h = plot.height(), + axes = args.axes || plot.getAxes(); + + if (!c) { + c = { + left: w / 2, + top: h / 2 + }; + } + + var xf = c.left / w, + yf = c.top / h, + minmax = { + x: { + min: c.left - xf * w / amount, + max: c.left + (1 - xf) * w / amount + }, + y: { + min: c.top - yf * h / amount, + max: c.top + (1 - yf) * h / amount + } + }; + + for (var key in axes) { + if (!axes.hasOwnProperty(key)) { + continue; + } + + var axis = axes[key], + opts = axis.options, + min = minmax[axis.direction].min, + max = minmax[axis.direction].max, + navigationOffset = axis.options.offset; + + //skip axis without axisZoom when zooming only on certain axis or axis without plotZoom for zoom on entire plot + if ((!opts.axisZoom && args.axes) || (!args.axes && !opts.plotZoom)) { + continue; + } + + min = $.plot.saturated.saturate(axis.c2p(min)); + max = $.plot.saturated.saturate(axis.c2p(max)); + if (min > max) { + // make sure min < max + var tmp = min; + min = max; + max = tmp; + } + + var offsetBelow = $.plot.saturated.saturate(navigationOffset.below - (axis.min - min)); + var offsetAbove = $.plot.saturated.saturate(navigationOffset.above - (axis.max - max)); + opts.offset = { below: offsetBelow, above: offsetAbove }; + }; + + plot.setupGrid(true); + plot.draw(); + + if (!args.preventEvent) { + plot.getPlaceholder().trigger("plotzoom", [plot, args]); + } + }; + + plot.pan = function(args) { + var delta = { + x: +args.left, + y: +args.top + }; + + if (isNaN(delta.x)) delta.x = 0; + if (isNaN(delta.y)) delta.y = 0; + + $.each(args.axes || plot.getAxes(), function(_, axis) { + var opts = axis.options, + d = delta[axis.direction]; + + //skip axis without axisPan when panning only on certain axis or axis without plotPan for pan the entire plot + if ((!opts.axisPan && args.axes) || (!opts.plotPan && !args.axes)) { + return; + } + + if (d !== 0) { + var navigationOffsetBelow = saturated.saturate(axis.c2p(axis.p2c(axis.min) + d) - axis.c2p(axis.p2c(axis.min))), + navigationOffsetAbove = saturated.saturate(axis.c2p(axis.p2c(axis.max) + d) - axis.c2p(axis.p2c(axis.max))); + + if (!isFinite(navigationOffsetBelow)) { + navigationOffsetBelow = 0; + } + + if (!isFinite(navigationOffsetAbove)) { + navigationOffsetAbove = 0; + } + + opts.offset = { + below: saturated.saturate(navigationOffsetBelow + (opts.offset.below || 0)), + above: saturated.saturate(navigationOffsetAbove + (opts.offset.above || 0)) + }; + } + }); + + plot.setupGrid(true); + plot.draw(); + if (!args.preventEvent) { + plot.getPlaceholder().trigger("plotpan", [plot, args]); + } + }; + + plot.recenter = function(args) { + $.each(args.axes || plot.getAxes(), function(_, axis) { + if (args.axes) { + if (this.direction === 'x') { + axis.options.offset = { below: 0 }; + } else if (this.direction === 'y') { + axis.options.offset = { above: 0 }; + } + } else { + axis.options.offset = { below: 0, above: 0 }; + } + }); + plot.setupGrid(true); + plot.draw(); + }; + + var shouldSnap = function(delta) { + return (Math.abs(delta.y) < SNAPPING_CONSTANT && Math.abs(delta.x) >= SNAPPING_CONSTANT) || + (Math.abs(delta.x) < SNAPPING_CONSTANT && Math.abs(delta.y) >= SNAPPING_CONSTANT); + } + + // adjust delta so the pan action is constrained on the vertical or horizontal direction + // it the movements in the other direction are small + var adjustDeltaToSnap = function(delta) { + if (Math.abs(delta.x) < SNAPPING_CONSTANT && Math.abs(delta.y) >= SNAPPING_CONSTANT) { + return {x: 0, y: delta.y}; + } + + if (Math.abs(delta.y) < SNAPPING_CONSTANT && Math.abs(delta.x) >= SNAPPING_CONSTANT) { + return {x: delta.x, y: 0}; + } + + return delta; + } + + var lockedDirection = null; + var lockDeltaDirection = function(delta) { + if (!lockedDirection && Math.max(Math.abs(delta.x), Math.abs(delta.y)) >= SNAPPING_CONSTANT) { + lockedDirection = Math.abs(delta.x) < Math.abs(delta.y) ? 'y' : 'x'; + } + + switch (lockedDirection) { + case 'x': + return { x: delta.x, y: 0 }; + case 'y': + return { x: 0, y: delta.y }; + default: + return { x: 0, y: 0 }; + } + } + + var isDiagonalMode = function(delta) { + if (Math.abs(delta.x) > 0 && Math.abs(delta.y) > 0) { + return true; + } + return false; + } + + var restoreAxisOffset = function(axes, initialState, delta) { + var axis; + Object.keys(axes).forEach(function(axisName) { + axis = axes[axisName]; + if (delta[axis.direction] === 0) { + axis.options.offset.below = initialState[axisName].navigationOffset.below; + axis.options.offset.above = initialState[axisName].navigationOffset.above; + } + }); + } + + var prevDelta = { x: 0, y: 0 }; + plot.smartPan = function(delta, initialState, panAxes, preventEvent, smartLock) { + var snap = smartLock ? true : shouldSnap(delta), + axes = plot.getAxes(), + opts; + delta = smartLock ? lockDeltaDirection(delta) : adjustDeltaToSnap(delta); + + if (isDiagonalMode(delta)) { + initialState.diagMode = true; + } + + if (snap && initialState.diagMode === true) { + initialState.diagMode = false; + restoreAxisOffset(axes, initialState, delta); + } + + if (snap) { + panHint = { + start: { + x: initialState.startPageX - plot.offset().left + plot.getPlotOffset().left, + y: initialState.startPageY - plot.offset().top + plot.getPlotOffset().top + }, + end: { + x: initialState.startPageX - delta.x - plot.offset().left + plot.getPlotOffset().left, + y: initialState.startPageY - delta.y - plot.offset().top + plot.getPlotOffset().top + } + } + } else { + panHint = { + start: { + x: initialState.startPageX - plot.offset().left + plot.getPlotOffset().left, + y: initialState.startPageY - plot.offset().top + plot.getPlotOffset().top + }, + end: false + } + } + + if (isNaN(delta.x)) delta.x = 0; + if (isNaN(delta.y)) delta.y = 0; + + if (panAxes) { + axes = panAxes; + } + + var axis, axisMin, axisMax, p, d; + Object.keys(axes).forEach(function(axisName) { + axis = axes[axisName]; + axisMin = axis.min; + axisMax = axis.max; + opts = axis.options; + + d = delta[axis.direction]; + p = prevDelta[axis.direction]; + + //skip axis without axisPan when panning only on certain axis or axis without plotPan for pan the entire plot + if ((!opts.axisPan && panAxes) || (!panAxes && !opts.plotPan)) { + return; + } + + if (d !== 0) { + var navigationOffsetBelow = saturated.saturate(axis.c2p(axis.p2c(axisMin) - (p - d)) - axis.c2p(axis.p2c(axisMin))), + navigationOffsetAbove = saturated.saturate(axis.c2p(axis.p2c(axisMax) - (p - d)) - axis.c2p(axis.p2c(axisMax))); + + if (!isFinite(navigationOffsetBelow)) { + navigationOffsetBelow = 0; + } + + if (!isFinite(navigationOffsetAbove)) { + navigationOffsetAbove = 0; + } + + axis.options.offset.below = saturated.saturate(navigationOffsetBelow + (axis.options.offset.below || 0)); + axis.options.offset.above = saturated.saturate(navigationOffsetAbove + (axis.options.offset.above || 0)); + } + }); + + prevDelta = delta; + plot.setupGrid(true); + plot.draw(); + + if (!preventEvent) { + plot.getPlaceholder().trigger("plotpan", [plot, delta, panAxes, initialState]); + } + }; + + plot.smartPan.end = function() { + panHint = null; + lockedDirection = null; + prevDelta = { x: 0, y: 0 }; + plot.triggerRedrawOverlay(); + } + + function shutdown(plot, eventHolder) { + eventHolder.unbind("mousewheel", onMouseWheel); + eventHolder.unbind("mousedown", onMouseDown); + eventHolder.unbind("mouseup", onMouseUp); + eventHolder.unbind("dragstart", onDragStart); + eventHolder.unbind("drag", onDrag); + eventHolder.unbind("dragend", onDragEnd); + eventHolder.unbind("dblclick", onDblClick); + eventHolder.unbind("click", onClick); + + if (panTimeout) clearTimeout(panTimeout); + } + + function drawOverlay(plot, ctx) { + if (panHint) { + ctx.strokeStyle = 'rgba(96, 160, 208, 0.7)'; + ctx.lineWidth = 2; + ctx.lineJoin = "round"; + var startx = Math.round(panHint.start.x), + starty = Math.round(panHint.start.y), + endx, endy; + + if (panAxes) { + if (panAxes[0].direction === 'x') { + endy = Math.round(panHint.start.y); + endx = Math.round(panHint.end.x); + } else if (panAxes[0].direction === 'y') { + endx = Math.round(panHint.start.x); + endy = Math.round(panHint.end.y); + } + } else { + endx = Math.round(panHint.end.x); + endy = Math.round(panHint.end.y); + } + + ctx.beginPath(); + + if (panHint.end === false) { + ctx.moveTo(startx, starty - PANHINT_LENGTH_CONSTANT); + ctx.lineTo(startx, starty + PANHINT_LENGTH_CONSTANT); + + ctx.moveTo(startx + PANHINT_LENGTH_CONSTANT, starty); + ctx.lineTo(startx - PANHINT_LENGTH_CONSTANT, starty); + } else { + var dirX = starty === endy; + + ctx.moveTo(startx - (dirX ? 0 : PANHINT_LENGTH_CONSTANT), starty - (dirX ? PANHINT_LENGTH_CONSTANT : 0)); + ctx.lineTo(startx + (dirX ? 0 : PANHINT_LENGTH_CONSTANT), starty + (dirX ? PANHINT_LENGTH_CONSTANT : 0)); + + ctx.moveTo(startx, starty); + ctx.lineTo(endx, endy); + + ctx.moveTo(endx - (dirX ? 0 : PANHINT_LENGTH_CONSTANT), endy - (dirX ? PANHINT_LENGTH_CONSTANT : 0)); + ctx.lineTo(endx + (dirX ? 0 : PANHINT_LENGTH_CONSTANT), endy + (dirX ? PANHINT_LENGTH_CONSTANT : 0)); + } + + ctx.stroke(); + } + } + + plot.getTouchedAxis = function(touchPointX, touchPointY) { + var ec = plot.getPlaceholder().offset(); + ec.left = touchPointX - ec.left; + ec.top = touchPointY - ec.top; + + var axis = plot.getXAxes().concat(plot.getYAxes()).filter(function (axis) { + var box = axis.box; + if (box !== undefined) { + return (ec.left > box.left) && (ec.left < box.left + box.width) && + (ec.top > box.top) && (ec.top < box.top + box.height); + } + }); + + return axis; + } + + plot.hooks.drawOverlay.push(drawOverlay); + plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'navigate', + version: '1.3' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.pie.js b/extern/phmap/benchmark/js/jquery.flot.pie.js new file mode 100644 index 0000000..ec734a1 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.pie.js @@ -0,0 +1,786 @@ +/* Flot plugin for rendering pie charts. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin assumes that each series has a single data value, and that each +value is a positive integer or zero. Negative numbers don't make sense for a +pie chart, and have unpredictable results. The values do NOT need to be +passed in as percentages; the plugin will calculate the total and per-slice +percentages internally. + +* Created by Brian Medendorp + +* Updated with contributions from btburnett3, Anthony Aragues and Xavi Ivars + +The plugin supports these options: + + series: { + pie: { + show: true/false + radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto' + innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect + startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result + tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show) + offset: { + top: integer value to move the pie up or down + left: integer value to move the pie left or right, or 'auto' + }, + stroke: { + color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF') + width: integer pixel width of the stroke + }, + label: { + show: true/false, or 'auto' + formatter: a user-defined function that modifies the text/style of the label text + radius: 0-1 for percentage of fullsize, or a specified pixel length + background: { + color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000') + opacity: 0-1 + }, + threshold: 0-1 for the percentage value at which to hide labels (if they're too small) + }, + combine: { + threshold: 0-1 for the percentage value at which to combine slices (if they're too small) + color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined + label: any text value of what the combined slice should be labeled + } + highlight: { + opacity: 0-1 + } + } + } + +More detail and specific examples can be found in the included HTML file. + +*/ + +(function($) { + // Maximum redraw attempts when fitting labels within the plot + + var REDRAW_ATTEMPTS = 10; + + // Factor by which to shrink the pie when fitting labels within the plot + + var REDRAW_SHRINK = 0.95; + + function init(plot) { + var canvas = null, + target = null, + options = null, + maxRadius = null, + centerLeft = null, + centerTop = null, + processed = false, + ctx = null; + + // interactive variables + + var highlights = []; + + // add hook to determine if pie plugin in enabled, and then perform necessary operations + + plot.hooks.processOptions.push(function(plot, options) { + if (options.series.pie.show) { + options.grid.show = false; + + // set labels.show + + if (options.series.pie.label.show === "auto") { + if (options.legend.show) { + options.series.pie.label.show = false; + } else { + options.series.pie.label.show = true; + } + } + + // set radius + + if (options.series.pie.radius === "auto") { + if (options.series.pie.label.show) { + options.series.pie.radius = 3 / 4; + } else { + options.series.pie.radius = 1; + } + } + + // ensure sane tilt + + if (options.series.pie.tilt > 1) { + options.series.pie.tilt = 1; + } else if (options.series.pie.tilt < 0) { + options.series.pie.tilt = 0; + } + } + }); + + plot.hooks.bindEvents.push(function(plot, eventHolder) { + var options = plot.getOptions(); + if (options.series.pie.show) { + if (options.grid.hoverable) { + eventHolder.unbind("mousemove").mousemove(onMouseMove); + } + if (options.grid.clickable) { + eventHolder.unbind("click").click(onClick); + } + } + }); + + plot.hooks.processDatapoints.push(function(plot, series, data, datapoints) { + var options = plot.getOptions(); + if (options.series.pie.show) { + processDatapoints(plot, series, data, datapoints); + } + }); + + plot.hooks.drawOverlay.push(function(plot, octx) { + var options = plot.getOptions(); + if (options.series.pie.show) { + drawOverlay(plot, octx); + } + }); + + plot.hooks.draw.push(function(plot, newCtx) { + var options = plot.getOptions(); + if (options.series.pie.show) { + draw(plot, newCtx); + } + }); + + function processDatapoints(plot, series, datapoints) { + if (!processed) { + processed = true; + canvas = plot.getCanvas(); + target = $(canvas).parent(); + options = plot.getOptions(); + plot.setData(combine(plot.getData())); + } + } + + function combine(data) { + var total = 0, + combined = 0, + numCombined = 0, + color = options.series.pie.combine.color, + newdata = [], + i, + value; + + // Fix up the raw data from Flot, ensuring the data is numeric + + for (i = 0; i < data.length; ++i) { + value = data[i].data; + + // If the data is an array, we'll assume that it's a standard + // Flot x-y pair, and are concerned only with the second value. + + // Note how we use the original array, rather than creating a + // new one; this is more efficient and preserves any extra data + // that the user may have stored in higher indexes. + + if ($.isArray(value) && value.length === 1) { + value = value[0]; + } + + if ($.isArray(value)) { + // Equivalent to $.isNumeric() but compatible with jQuery < 1.7 + if (!isNaN(parseFloat(value[1])) && isFinite(value[1])) { + value[1] = +value[1]; + } else { + value[1] = 0; + } + } else if (!isNaN(parseFloat(value)) && isFinite(value)) { + value = [1, +value]; + } else { + value = [1, 0]; + } + + data[i].data = [value]; + } + + // Sum up all the slices, so we can calculate percentages for each + + for (i = 0; i < data.length; ++i) { + total += data[i].data[0][1]; + } + + // Count the number of slices with percentages below the combine + // threshold; if it turns out to be just one, we won't combine. + + for (i = 0; i < data.length; ++i) { + value = data[i].data[0][1]; + if (value / total <= options.series.pie.combine.threshold) { + combined += value; + numCombined++; + if (!color) { + color = data[i].color; + } + } + } + + for (i = 0; i < data.length; ++i) { + value = data[i].data[0][1]; + if (numCombined < 2 || value / total > options.series.pie.combine.threshold) { + newdata.push( + $.extend(data[i], { /* extend to allow keeping all other original data values + and using them e.g. in labelFormatter. */ + data: [[1, value]], + color: data[i].color, + label: data[i].label, + angle: value * Math.PI * 2 / total, + percent: value / (total / 100) + }) + ); + } + } + + if (numCombined > 1) { + newdata.push({ + data: [[1, combined]], + color: color, + label: options.series.pie.combine.label, + angle: combined * Math.PI * 2 / total, + percent: combined / (total / 100) + }); + } + + return newdata; + } + + function draw(plot, newCtx) { + if (!target) { + return; // if no series were passed + } + + var canvasWidth = plot.getPlaceholder().width(), + canvasHeight = plot.getPlaceholder().height(), + legendWidth = target.children().filter(".legend").children().width() || 0; + + ctx = newCtx; + + // WARNING: HACK! REWRITE THIS CODE AS SOON AS POSSIBLE! + + // When combining smaller slices into an 'other' slice, we need to + // add a new series. Since Flot gives plugins no way to modify the + // list of series, the pie plugin uses a hack where the first call + // to processDatapoints results in a call to setData with the new + // list of series, then subsequent processDatapoints do nothing. + + // The plugin-global 'processed' flag is used to control this hack; + // it starts out false, and is set to true after the first call to + // processDatapoints. + + // Unfortunately this turns future setData calls into no-ops; they + // call processDatapoints, the flag is true, and nothing happens. + + // To fix this we'll set the flag back to false here in draw, when + // all series have been processed, so the next sequence of calls to + // processDatapoints once again starts out with a slice-combine. + // This is really a hack; in 0.9 we need to give plugins a proper + // way to modify series before any processing begins. + + processed = false; + + // calculate maximum radius and center point + maxRadius = Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2; + centerTop = canvasHeight / 2 + options.series.pie.offset.top; + centerLeft = canvasWidth / 2; + + if (options.series.pie.offset.left === "auto") { + if (options.legend.position.match("w")) { + centerLeft += legendWidth / 2; + } else { + centerLeft -= legendWidth / 2; + } + if (centerLeft < maxRadius) { + centerLeft = maxRadius; + } else if (centerLeft > canvasWidth - maxRadius) { + centerLeft = canvasWidth - maxRadius; + } + } else { + centerLeft += options.series.pie.offset.left; + } + + var slices = plot.getData(), + attempts = 0; + + // Keep shrinking the pie's radius until drawPie returns true, + // indicating that all the labels fit, or we try too many times. + do { + if (attempts > 0) { + maxRadius *= REDRAW_SHRINK; + } + attempts += 1; + clear(); + if (options.series.pie.tilt <= 0.8) { + drawShadow(); + } + } while (!drawPie() && attempts < REDRAW_ATTEMPTS) + + if (attempts >= REDRAW_ATTEMPTS) { + clear(); + target.prepend("
Could not draw pie with labels contained inside canvas
"); + } + + if (plot.setSeries && plot.insertLegend) { + plot.setSeries(slices); + plot.insertLegend(); + } + + // we're actually done at this point, just defining internal functions at this point + function clear() { + ctx.clearRect(0, 0, canvasWidth, canvasHeight); + target.children().filter(".pieLabel, .pieLabelBackground").remove(); + } + + function drawShadow() { + var shadowLeft = options.series.pie.shadow.left; + var shadowTop = options.series.pie.shadow.top; + var edge = 10; + var alpha = options.series.pie.shadow.alpha; + var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; + + if (radius >= canvasWidth / 2 - shadowLeft || radius * options.series.pie.tilt >= canvasHeight / 2 - shadowTop || radius <= edge) { + return; // shadow would be outside canvas, so don't draw it + } + + ctx.save(); + ctx.translate(shadowLeft, shadowTop); + ctx.globalAlpha = alpha; + ctx.fillStyle = "#000"; + + // center and rotate to starting position + ctx.translate(centerLeft, centerTop); + ctx.scale(1, options.series.pie.tilt); + + //radius -= edge; + for (var i = 1; i <= edge; i++) { + ctx.beginPath(); + ctx.arc(0, 0, radius, 0, Math.PI * 2, false); + ctx.fill(); + radius -= i; + } + + ctx.restore(); + } + + function drawPie() { + var startAngle = Math.PI * options.series.pie.startAngle; + var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; + var i; + // center and rotate to starting position + + ctx.save(); + ctx.translate(centerLeft, centerTop); + ctx.scale(1, options.series.pie.tilt); + //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera + + // draw slices + ctx.save(); + + var currentAngle = startAngle; + for (i = 0; i < slices.length; ++i) { + slices[i].startAngle = currentAngle; + drawSlice(slices[i].angle, slices[i].color, true); + } + + ctx.restore(); + + // draw slice outlines + if (options.series.pie.stroke.width > 0) { + ctx.save(); + ctx.lineWidth = options.series.pie.stroke.width; + currentAngle = startAngle; + for (i = 0; i < slices.length; ++i) { + drawSlice(slices[i].angle, options.series.pie.stroke.color, false); + } + + ctx.restore(); + } + + // draw donut hole + drawDonutHole(ctx); + + ctx.restore(); + + // Draw the labels, returning true if they fit within the plot + if (options.series.pie.label.show) { + return drawLabels(); + } else return true; + + function drawSlice(angle, color, fill) { + if (angle <= 0 || isNaN(angle)) { + return; + } + + if (fill) { + ctx.fillStyle = color; + } else { + ctx.strokeStyle = color; + ctx.lineJoin = "round"; + } + + ctx.beginPath(); + if (Math.abs(angle - Math.PI * 2) > 0.000000001) { + ctx.moveTo(0, 0); // Center of the pie + } + + //ctx.arc(0, 0, radius, 0, angle, false); // This doesn't work properly in Opera + ctx.arc(0, 0, radius, currentAngle, currentAngle + angle / 2, false); + ctx.arc(0, 0, radius, currentAngle + angle / 2, currentAngle + angle, false); + ctx.closePath(); + //ctx.rotate(angle); // This doesn't work properly in Opera + currentAngle += angle; + + if (fill) { + ctx.fill(); + } else { + ctx.stroke(); + } + } + + function drawLabels() { + var currentAngle = startAngle; + var radius = options.series.pie.label.radius > 1 ? options.series.pie.label.radius : maxRadius * options.series.pie.label.radius; + + for (var i = 0; i < slices.length; ++i) { + if (slices[i].percent >= options.series.pie.label.threshold * 100) { + if (!drawLabel(slices[i], currentAngle, i)) { + return false; + } + } + currentAngle += slices[i].angle; + } + + return true; + + function drawLabel(slice, startAngle, index) { + if (slice.data[0][1] === 0) { + return true; + } + + // format label text + var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter; + + if (lf) { + text = lf(slice.label, slice); + } else { + text = slice.label; + } + + if (plf) { + text = plf(text, slice); + } + + var halfAngle = ((startAngle + slice.angle) + startAngle) / 2; + var x = centerLeft + Math.round(Math.cos(halfAngle) * radius); + var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt; + + var html = "" + text + ""; + target.append(html); + + var label = target.children("#pieLabel" + index); + var labelTop = (y - label.height() / 2); + var labelLeft = (x - label.width() / 2); + + label.css("top", labelTop); + label.css("left", labelLeft); + + // check to make sure that the label is not outside the canvas + if (0 - labelTop > 0 || 0 - labelLeft > 0 || canvasHeight - (labelTop + label.height()) < 0 || canvasWidth - (labelLeft + label.width()) < 0) { + return false; + } + + if (options.series.pie.label.background.opacity !== 0) { + // put in the transparent background separately to avoid blended labels and label boxes + var c = options.series.pie.label.background.color; + if (c == null) { + c = slice.color; + } + + var pos = "top:" + labelTop + "px;left:" + labelLeft + "px;"; + $("
") + .css("opacity", options.series.pie.label.background.opacity) + .insertBefore(label); + } + + return true; + } // end individual label function + } // end drawLabels function + } // end drawPie function + } // end draw function + + // Placed here because it needs to be accessed from multiple locations + + function drawDonutHole(layer) { + if (options.series.pie.innerRadius > 0) { + // subtract the center + layer.save(); + var innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius; + layer.globalCompositeOperation = "destination-out"; // this does not work with excanvas, but it will fall back to using the stroke color + layer.beginPath(); + layer.fillStyle = options.series.pie.stroke.color; + layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false); + layer.fill(); + layer.closePath(); + layer.restore(); + + // add inner stroke + layer.save(); + layer.beginPath(); + layer.strokeStyle = options.series.pie.stroke.color; + layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false); + layer.stroke(); + layer.closePath(); + layer.restore(); + + // TODO: add extra shadow inside hole (with a mask) if the pie is tilted. + } + } + + //-- Additional Interactive related functions -- + + function isPointInPoly(poly, pt) { + for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i) { + ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || + (poly[j][1] <= pt[1] && pt[1] < poly[i][1])) && + (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0]) && + (c = !c); + } + return c; + } + + function findNearbySlice(mouseX, mouseY) { + var slices = plot.getData(), + options = plot.getOptions(), + radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius, + x, y; + + for (var i = 0; i < slices.length; ++i) { + var s = slices[i]; + if (s.pie.show) { + ctx.save(); + ctx.beginPath(); + ctx.moveTo(0, 0); // Center of the pie + //ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here. + ctx.arc(0, 0, radius, s.startAngle, s.startAngle + s.angle / 2, false); + ctx.arc(0, 0, radius, s.startAngle + s.angle / 2, s.startAngle + s.angle, false); + ctx.closePath(); + x = mouseX - centerLeft; + y = mouseY - centerTop; + + if (ctx.isPointInPath) { + if (ctx.isPointInPath(mouseX - centerLeft, mouseY - centerTop)) { + ctx.restore(); + return { + datapoint: [s.percent, s.data], + dataIndex: 0, + series: s, + seriesIndex: i + }; + } + } else { + // excanvas for IE doesn;t support isPointInPath, this is a workaround. + var p1X = radius * Math.cos(s.startAngle), + p1Y = radius * Math.sin(s.startAngle), + p2X = radius * Math.cos(s.startAngle + s.angle / 4), + p2Y = radius * Math.sin(s.startAngle + s.angle / 4), + p3X = radius * Math.cos(s.startAngle + s.angle / 2), + p3Y = radius * Math.sin(s.startAngle + s.angle / 2), + p4X = radius * Math.cos(s.startAngle + s.angle / 1.5), + p4Y = radius * Math.sin(s.startAngle + s.angle / 1.5), + p5X = radius * Math.cos(s.startAngle + s.angle), + p5Y = radius * Math.sin(s.startAngle + s.angle), + arrPoly = [[0, 0], [p1X, p1Y], [p2X, p2Y], [p3X, p3Y], [p4X, p4Y], [p5X, p5Y]], + arrPoint = [x, y]; + + // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt? + + if (isPointInPoly(arrPoly, arrPoint)) { + ctx.restore(); + return { + datapoint: [s.percent, s.data], + dataIndex: 0, + series: s, + seriesIndex: i + }; + } + } + + ctx.restore(); + } + } + + return null; + } + + function onMouseMove(e) { + triggerClickHoverEvent("plothover", e); + } + + function onClick(e) { + triggerClickHoverEvent("plotclick", e); + } + + // trigger click or hover event (they send the same parameters so we share their code) + + function triggerClickHoverEvent(eventname, e) { + var offset = plot.offset(); + var canvasX = parseInt(e.pageX - offset.left); + var canvasY = parseInt(e.pageY - offset.top); + var item = findNearbySlice(canvasX, canvasY); + + if (options.grid.autoHighlight) { + // clear auto-highlights + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.auto === eventname && !(item && h.series === item.series)) { + unhighlight(h.series); + } + } + } + + // highlight the slice + + if (item) { + highlight(item.series, eventname); + } + + // trigger any hover bind events + + var pos = { pageX: e.pageX, pageY: e.pageY }; + target.trigger(eventname, [pos, item]); + } + + function highlight(s, auto) { + //if (typeof s == "number") { + // s = series[s]; + //} + + var i = indexOfHighlight(s); + + if (i === -1) { + highlights.push({ series: s, auto: auto }); + plot.triggerRedrawOverlay(); + } else if (!auto) { + highlights[i].auto = false; + } + } + + function unhighlight(s) { + if (s == null) { + highlights = []; + plot.triggerRedrawOverlay(); + } + + //if (typeof s == "number") { + // s = series[s]; + //} + + var i = indexOfHighlight(s); + + if (i !== -1) { + highlights.splice(i, 1); + plot.triggerRedrawOverlay(); + } + } + + function indexOfHighlight(s) { + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.series === s) { + return i; + } + } + return -1; + } + + function drawOverlay(plot, octx) { + var options = plot.getOptions(); + var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; + + octx.save(); + octx.translate(centerLeft, centerTop); + octx.scale(1, options.series.pie.tilt); + + for (var i = 0; i < highlights.length; ++i) { + drawHighlight(highlights[i].series); + } + + drawDonutHole(octx); + + octx.restore(); + + function drawHighlight(series) { + if (series.angle <= 0 || isNaN(series.angle)) { + return; + } + + //octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString(); + octx.fillStyle = "rgba(255, 255, 255, " + options.series.pie.highlight.opacity + ")"; // this is temporary until we have access to parseColor + octx.beginPath(); + if (Math.abs(series.angle - Math.PI * 2) > 0.000000001) { + octx.moveTo(0, 0); // Center of the pie + } + octx.arc(0, 0, radius, series.startAngle, series.startAngle + series.angle / 2, false); + octx.arc(0, 0, radius, series.startAngle + series.angle / 2, series.startAngle + series.angle, false); + octx.closePath(); + octx.fill(); + } + } + } // end init (plugin body) + + // define pie specific options and their default values + var options = { + series: { + pie: { + show: false, + radius: "auto", // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value) + innerRadius: 0, /* for donut */ + startAngle: 3 / 2, + tilt: 1, + shadow: { + left: 5, // shadow left offset + top: 15, // shadow top offset + alpha: 0.02 // shadow alpha + }, + offset: { + top: 0, + left: "auto" + }, + stroke: { + color: "#fff", + width: 1 + }, + label: { + show: "auto", + formatter: function(label, slice) { + return "
" + label + "
" + Math.round(slice.percent) + "%
"; + }, // formatter function + radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value) + background: { + color: null, + opacity: 0 + }, + threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow) + }, + combine: { + threshold: -1, // percentage at which to combine little slices into one larger slice + color: null, // color to give the new slice (auto-generated if null) + label: "Other" // label to give the new slice + }, + highlight: { + //color: "#fff", // will add this functionality once parseColor is available + opacity: 0.5 + } + } + } + }; + + $.plot.plugins.push({ + init: init, + options: options, + name: "pie", + version: "1.1" + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.resize.js b/extern/phmap/benchmark/js/jquery.flot.resize.js new file mode 100644 index 0000000..930c68e --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.resize.js @@ -0,0 +1,60 @@ +/* eslint-disable */ +/* Flot plugin for automatically redrawing plots as the placeholder resizes. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +It works by listening for changes on the placeholder div (through the jQuery +resize event plugin) - if the size changes, it will redraw the plot. + +There are no options. If you need to disable the plugin for some plots, you +can just fix the size of their placeholders. + +*/ + +/* Inline dependency: + * jQuery resize event - v1.1 - 3/14/2010 + * http://benalman.com/projects/jquery-resize-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function($,e,t){"$:nomunge";var i=[],n=$.resize=$.extend($.resize,{}),a,r=false,s="setTimeout",u="resize",m=u+"-special-event",o="pendingDelay",l="activeDelay",f="throttleWindow";n[o]=200;n[l]=20;n[f]=true;$.event.special[u]={setup:function(){if(!n[f]&&this[s]){return false}var e=$(this);i.push(this);e.data(m,{w:e.width(),h:e.height()});if(i.length===1){a=t;h()}},teardown:function(){if(!n[f]&&this[s]){return false}var e=$(this);for(var t=i.length-1;t>=0;t--){if(i[t]==this){i.splice(t,1);break}}e.removeData(m);if(!i.length){if(r){cancelAnimationFrame(a)}else{clearTimeout(a)}a=null}},add:function(e){if(!n[f]&&this[s]){return false}var i;function a(e,n,a){var r=$(this),s=r.data(m)||{};s.w=n!==t?n:r.width();s.h=a!==t?a:r.height();i.apply(this,arguments)}if($.isFunction(e)){i=e;return a}else{i=e.handler;e.handler=a}}};function h(t){if(r===true){r=t||1}for(var s=i.length-1;s>=0;s--){var l=$(i[s]);if(l[0]==e||l.is(":visible")){var f=l.width(),c=l.height(),d=l.data(m);if(d&&(f!==d.w||c!==d.h)){l.trigger(u,[d.w=f,d.h=c]);r=t||true}}else{d=l.data(m);d.w=0;d.h=0}}if(a!==null){if(r&&(t==null||t-r<1e3)){a=e.requestAnimationFrame(h)}else{a=setTimeout(h,n[o]);r=false}}}if(!e.requestAnimationFrame){e.requestAnimationFrame=function(){return e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(t,i){return e.setTimeout(function(){t((new Date).getTime())},n[l])}}()}if(!e.cancelAnimationFrame){e.cancelAnimationFrame=function(){return e.webkitCancelRequestAnimationFrame||e.mozCancelRequestAnimationFrame||e.oCancelRequestAnimationFrame||e.msCancelRequestAnimationFrame||clearTimeout}()}})(jQuery,this); + +/* eslint-enable */ +(function ($) { + var options = { }; // no options + + function init(plot) { + function onResize() { + var placeholder = plot.getPlaceholder(); + + // somebody might have hidden us and we can't plot + // when we don't have the dimensions + if (placeholder.width() === 0 || placeholder.height() === 0) return; + + plot.resize(); + plot.setupGrid(); + plot.draw(); + } + + function bindEvents(plot, eventHolder) { + plot.getPlaceholder().resize(onResize); + } + + function shutdown(plot, eventHolder) { + plot.getPlaceholder().unbind("resize", onResize); + } + + plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'resize', + version: '1.0' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.saturated.js b/extern/phmap/benchmark/js/jquery.flot.saturated.js new file mode 100644 index 0000000..34b9c50 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.saturated.js @@ -0,0 +1,43 @@ +(function ($) { + 'use strict'; + var saturated = { + saturate: function (a) { + if (a === Infinity) { + return Number.MAX_VALUE; + } + + if (a === -Infinity) { + return -Number.MAX_VALUE; + } + + return a; + }, + delta: function(min, max, noTicks) { + return ((max - min) / noTicks) === Infinity ? (max / noTicks - min / noTicks) : (max - min) / noTicks + }, + multiply: function (a, b) { + return saturated.saturate(a * b); + }, + // returns c * bInt * a. Beahves properly in the case where c is negative + // and bInt * a is bigger that Number.MAX_VALUE (Infinity) + multiplyAdd: function (a, bInt, c) { + if (isFinite(a * bInt)) { + return saturated.saturate(a * bInt + c); + } else { + var result = c; + + for (var i = 0; i < bInt; i++) { + result += a; + } + + return saturated.saturate(result); + } + }, + // round to nearby lower multiple of base + floorInBase: function(n, base) { + return base * Math.floor(n / base); + } + }; + + $.plot.saturated = saturated; +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.selection.js b/extern/phmap/benchmark/js/jquery.flot.selection.js new file mode 100644 index 0000000..c14625a --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.selection.js @@ -0,0 +1,504 @@ +/* Flot plugin for selecting regions of a plot. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + +selection: { + mode: null or "x" or "y" or "xy" or "smart", + color: color, + shape: "round" or "miter" or "bevel", + minSize: number of pixels +} + +Selection support is enabled by setting the mode to one of "x", "y" or "xy". +In "x" mode, the user will only be able to specify the x range, similarly for +"y" mode. For "xy", the selection becomes a rectangle where both ranges can be +specified. "color" is color of the selection (if you need to change the color +later on, you can get to it with plot.getOptions().selection.color). "shape" +is the shape of the corners of the selection. + +"minSize" is the minimum size a selection can be in pixels. This value can +be customized to determine the smallest size a selection can be and still +have the selection rectangle be displayed. When customizing this value, the +fact that it refers to pixels, not axis units must be taken into account. +Thus, for example, if there is a bar graph in time mode with BarWidth set to 1 +minute, setting "minSize" to 1 will not make the minimum selection size 1 +minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent +"plotunselected" events from being fired when the user clicks the mouse without +dragging. + +When selection support is enabled, a "plotselected" event will be emitted on +the DOM element you passed into the plot function. The event handler gets a +parameter with the ranges selected on the axes, like this: + + placeholder.bind( "plotselected", function( event, ranges ) { + alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to) + // similar for yaxis - with multiple axes, the extra ones are in + // x2axis, x3axis, ... + }); + +The "plotselected" event is only fired when the user has finished making the +selection. A "plotselecting" event is fired during the process with the same +parameters as the "plotselected" event, in case you want to know what's +happening while it's happening, + +A "plotunselected" event with no arguments is emitted when the user clicks the +mouse to remove the selection. As stated above, setting "minSize" to 0 will +destroy this behavior. + +The plugin allso adds the following methods to the plot object: + +- setSelection( ranges, preventEvent ) + + Set the selection rectangle. The passed in ranges is on the same form as + returned in the "plotselected" event. If the selection mode is "x", you + should put in either an xaxis range, if the mode is "y" you need to put in + an yaxis range and both xaxis and yaxis if the selection mode is "xy", like + this: + + setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } }); + + setSelection will trigger the "plotselected" event when called. If you don't + want that to happen, e.g. if you're inside a "plotselected" handler, pass + true as the second parameter. If you are using multiple axes, you can + specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of + xaxis, the plugin picks the first one it sees. + +- clearSelection( preventEvent ) + + Clear the selection rectangle. Pass in true to avoid getting a + "plotunselected" event. + +- getSelection() + + Returns the current selection in the same format as the "plotselected" + event. If there's currently no selection, the function returns null. + +*/ + +(function ($) { + function init(plot) { + var selection = { + first: {x: -1, y: -1}, + second: {x: -1, y: -1}, + show: false, + currentMode: 'xy', + active: false + }; + + var SNAPPING_CONSTANT = $.plot.uiConstants.SNAPPING_CONSTANT; + + // FIXME: The drag handling implemented here should be + // abstracted out, there's some similar code from a library in + // the navigation plugin, this should be massaged a bit to fit + // the Flot cases here better and reused. Doing this would + // make this plugin much slimmer. + var savedhandlers = {}; + + var mouseUpHandler = null; + + function onMouseMove(e) { + if (selection.active) { + updateSelection(e); + + plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]); + } + } + + function onMouseDown(e) { + // only accept left-click + if (e.which !== 1) return; + + // cancel out any text selections + document.body.focus(); + + // prevent text selection and drag in old-school browsers + if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) { + savedhandlers.onselectstart = document.onselectstart; + document.onselectstart = function () { return false; }; + } + if (document.ondrag !== undefined && savedhandlers.ondrag == null) { + savedhandlers.ondrag = document.ondrag; + document.ondrag = function () { return false; }; + } + + setSelectionPos(selection.first, e); + + selection.active = true; + + // this is a bit silly, but we have to use a closure to be + // able to whack the same handler again + mouseUpHandler = function (e) { onMouseUp(e); }; + + $(document).one("mouseup", mouseUpHandler); + } + + function onMouseUp(e) { + mouseUpHandler = null; + + // revert drag stuff for old-school browsers + if (document.onselectstart !== undefined) { + document.onselectstart = savedhandlers.onselectstart; + } + + if (document.ondrag !== undefined) { + document.ondrag = savedhandlers.ondrag; + } + + // no more dragging + selection.active = false; + updateSelection(e); + + if (selectionIsSane()) { + triggerSelectedEvent(); + } else { + // this counts as a clear + plot.getPlaceholder().trigger("plotunselected", [ ]); + plot.getPlaceholder().trigger("plotselecting", [ null ]); + } + + return false; + } + + function getSelection() { + if (!selectionIsSane()) return null; + + if (!selection.show) return null; + + var r = {}, + c1 = {x: selection.first.x, y: selection.first.y}, + c2 = {x: selection.second.x, y: selection.second.y}; + + if (selectionDirection(plot) === 'x') { + c1.y = 0; + c2.y = plot.height(); + } + + if (selectionDirection(plot) === 'y') { + c1.x = 0; + c2.x = plot.width(); + } + + $.each(plot.getAxes(), function (name, axis) { + if (axis.used) { + var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]); + r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) }; + } + }); + return r; + } + + function triggerSelectedEvent() { + var r = getSelection(); + + plot.getPlaceholder().trigger("plotselected", [ r ]); + + // backwards-compat stuff, to be removed in future + if (r.xaxis && r.yaxis) { + plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]); + } + } + + function clamp(min, value, max) { + return value < min ? min : (value > max ? max : value); + } + + function selectionDirection(plot) { + var o = plot.getOptions(); + + if (o.selection.mode === 'smart') { + return selection.currentMode; + } else { + return o.selection.mode; + } + } + + function updateMode(pos) { + if (selection.first) { + var delta = { + x: pos.x - selection.first.x, + y: pos.y - selection.first.y + }; + + if (Math.abs(delta.x) < SNAPPING_CONSTANT) { + selection.currentMode = 'y'; + } else if (Math.abs(delta.y) < SNAPPING_CONSTANT) { + selection.currentMode = 'x'; + } else { + selection.currentMode = 'xy'; + } + } + } + + function setSelectionPos(pos, e) { + var offset = plot.getPlaceholder().offset(); + var plotOffset = plot.getPlotOffset(); + pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width()); + pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height()); + + if (pos !== selection.first) updateMode(pos); + + if (selectionDirection(plot) === "y") { + pos.x = pos === selection.first ? 0 : plot.width(); + } + + if (selectionDirection(plot) === "x") { + pos.y = pos === selection.first ? 0 : plot.height(); + } + } + + function updateSelection(pos) { + if (pos.pageX == null) return; + + setSelectionPos(selection.second, pos); + if (selectionIsSane()) { + selection.show = true; + plot.triggerRedrawOverlay(); + } else clearSelection(true); + } + + function clearSelection(preventEvent) { + if (selection.show) { + selection.show = false; + selection.currentMode = ''; + plot.triggerRedrawOverlay(); + if (!preventEvent) { + plot.getPlaceholder().trigger("plotunselected", [ ]); + } + } + } + + // function taken from markings support in Flot + function extractRange(ranges, coord) { + var axis, from, to, key, axes = plot.getAxes(); + + for (var k in axes) { + axis = axes[k]; + if (axis.direction === coord) { + key = coord + axis.n + "axis"; + if (!ranges[key] && axis.n === 1) { + // support x1axis as xaxis + key = coord + "axis"; + } + + if (ranges[key]) { + from = ranges[key].from; + to = ranges[key].to; + break; + } + } + } + + // backwards-compat stuff - to be removed in future + if (!ranges[key]) { + axis = coord === "x" ? plot.getXAxes()[0] : plot.getYAxes()[0]; + from = ranges[coord + "1"]; + to = ranges[coord + "2"]; + } + + // auto-reverse as an added bonus + if (from != null && to != null && from > to) { + var tmp = from; + from = to; + to = tmp; + } + + return { from: from, to: to, axis: axis }; + } + + function setSelection(ranges, preventEvent) { + var range; + + if (selectionDirection(plot) === "y") { + selection.first.x = 0; + selection.second.x = plot.width(); + } else { + range = extractRange(ranges, "x"); + selection.first.x = range.axis.p2c(range.from); + selection.second.x = range.axis.p2c(range.to); + } + + if (selectionDirection(plot) === "x") { + selection.first.y = 0; + selection.second.y = plot.height(); + } else { + range = extractRange(ranges, "y"); + selection.first.y = range.axis.p2c(range.from); + selection.second.y = range.axis.p2c(range.to); + } + + selection.show = true; + plot.triggerRedrawOverlay(); + if (!preventEvent && selectionIsSane()) { + triggerSelectedEvent(); + } + } + + function selectionIsSane() { + var minSize = plot.getOptions().selection.minSize; + return Math.abs(selection.second.x - selection.first.x) >= minSize && + Math.abs(selection.second.y - selection.first.y) >= minSize; + } + + plot.clearSelection = clearSelection; + plot.setSelection = setSelection; + plot.getSelection = getSelection; + + plot.hooks.bindEvents.push(function(plot, eventHolder) { + var o = plot.getOptions(); + if (o.selection.mode != null) { + eventHolder.mousemove(onMouseMove); + eventHolder.mousedown(onMouseDown); + } + }); + + function drawSelectionDecorations(ctx, x, y, w, h, oX, oY, mode) { + var spacing = 3; + var fullEarWidth = 15; + var earWidth = Math.max(0, Math.min(fullEarWidth, w / 2 - 2, h / 2 - 2)); + ctx.fillStyle = '#ffffff'; + + if (mode === 'xy') { + ctx.beginPath(); + ctx.moveTo(x, y + earWidth); + ctx.lineTo(x - 3, y + earWidth); + ctx.lineTo(x - 3, y - 3); + ctx.lineTo(x + earWidth, y - 3); + ctx.lineTo(x + earWidth, y); + ctx.lineTo(x, y); + ctx.closePath(); + + ctx.moveTo(x, y + h - earWidth); + ctx.lineTo(x - 3, y + h - earWidth); + ctx.lineTo(x - 3, y + h + 3); + ctx.lineTo(x + earWidth, y + h + 3); + ctx.lineTo(x + earWidth, y + h); + ctx.lineTo(x, y + h); + ctx.closePath(); + + ctx.moveTo(x + w, y + earWidth); + ctx.lineTo(x + w + 3, y + earWidth); + ctx.lineTo(x + w + 3, y - 3); + ctx.lineTo(x + w - earWidth, y - 3); + ctx.lineTo(x + w - earWidth, y); + ctx.lineTo(x + w, y); + ctx.closePath(); + + ctx.moveTo(x + w, y + h - earWidth); + ctx.lineTo(x + w + 3, y + h - earWidth); + ctx.lineTo(x + w + 3, y + h + 3); + ctx.lineTo(x + w - earWidth, y + h + 3); + ctx.lineTo(x + w - earWidth, y + h); + ctx.lineTo(x + w, y + h); + ctx.closePath(); + + ctx.stroke(); + ctx.fill(); + } + + x = oX; + y = oY; + + if (mode === 'x') { + ctx.beginPath(); + ctx.moveTo(x, y + fullEarWidth); + ctx.lineTo(x, y - fullEarWidth); + ctx.lineTo(x - spacing, y - fullEarWidth); + ctx.lineTo(x - spacing, y + fullEarWidth); + ctx.closePath(); + + ctx.moveTo(x + w, y + fullEarWidth); + ctx.lineTo(x + w, y - fullEarWidth); + ctx.lineTo(x + w + spacing, y - fullEarWidth); + ctx.lineTo(x + w + spacing, y + fullEarWidth); + ctx.closePath(); + ctx.stroke(); + ctx.fill(); + } + + if (mode === 'y') { + ctx.beginPath(); + + ctx.moveTo(x - fullEarWidth, y); + ctx.lineTo(x + fullEarWidth, y); + ctx.lineTo(x + fullEarWidth, y - spacing); + ctx.lineTo(x - fullEarWidth, y - spacing); + ctx.closePath(); + + ctx.moveTo(x - fullEarWidth, y + h); + ctx.lineTo(x + fullEarWidth, y + h); + ctx.lineTo(x + fullEarWidth, y + h + spacing); + ctx.lineTo(x - fullEarWidth, y + h + spacing); + ctx.closePath(); + ctx.stroke(); + ctx.fill(); + } + } + + plot.hooks.drawOverlay.push(function (plot, ctx) { + // draw selection + if (selection.show && selectionIsSane()) { + var plotOffset = plot.getPlotOffset(); + var o = plot.getOptions(); + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var c = $.color.parse(o.selection.color); + + ctx.strokeStyle = c.scale('a', 1).toString(); + ctx.lineWidth = 1; + ctx.lineJoin = o.selection.shape; + ctx.fillStyle = c.scale('a', 0.4).toString(); + + var x = Math.min(selection.first.x, selection.second.x) + 0.5, + oX = x, + y = Math.min(selection.first.y, selection.second.y) + 0.5, + oY = y, + w = Math.abs(selection.second.x - selection.first.x) - 1, + h = Math.abs(selection.second.y - selection.first.y) - 1; + + if (selectionDirection(plot) === 'x') { + h += y; + y = 0; + } + + if (selectionDirection(plot) === 'y') { + w += x; + x = 0; + } + + ctx.fillRect(0, 0, plot.width(), plot.height()); + ctx.clearRect(x, y, w, h); + drawSelectionDecorations(ctx, x, y, w, h, oX, oY, selectionDirection(plot)); + + ctx.restore(); + } + }); + + plot.hooks.shutdown.push(function (plot, eventHolder) { + eventHolder.unbind("mousemove", onMouseMove); + eventHolder.unbind("mousedown", onMouseDown); + + if (mouseUpHandler) { + $(document).unbind("mouseup", mouseUpHandler); + } + }); + } + + $.plot.plugins.push({ + init: init, + options: { + selection: { + mode: null, // one of null, "x", "y" or "xy" + color: "#888888", + shape: "round", // one of "round", "miter", or "bevel" + minSize: 5 // minimum number of pixels + } + }, + name: 'selection', + version: '1.1' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.stack.js b/extern/phmap/benchmark/js/jquery.flot.stack.js new file mode 100644 index 0000000..f4b88e7 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.stack.js @@ -0,0 +1,220 @@ +/* Flot plugin for stacking data sets rather than overlaying them. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin assumes the data is sorted on x (or y if stacking horizontally). +For line charts, it is assumed that if a line has an undefined gap (from a +null point), then the line above it should have the same gap - insert zeros +instead of "null" if you want another behaviour. This also holds for the start +and end of the chart. Note that stacking a mix of positive and negative values +in most instances doesn't make sense (so it looks weird). + +Two or more series are stacked when their "stack" attribute is set to the same +key (which can be any number or string or just "true"). To specify the default +stack, you can set the stack option like this: + + series: { + stack: null/false, true, or a key (number/string) + } + +You can also specify it for a single series, like this: + + $.plot( $("#placeholder"), [{ + data: [ ... ], + stack: true + }]) + +The stacking order is determined by the order of the data series in the array +(later series end up on top of the previous). + +Internally, the plugin modifies the datapoints in each series, adding an +offset to the y value. For line series, extra data points are inserted through +interpolation. If there's a second y value, it's also adjusted (e.g for bar +charts or filled areas). + +*/ + +(function ($) { + var options = { + series: { stack: null } // or number/string + }; + + function init(plot) { + function findMatchingSeries(s, allseries) { + var res = null; + for (var i = 0; i < allseries.length; ++i) { + if (s === allseries[i]) break; + + if (allseries[i].stack === s.stack) { + res = allseries[i]; + } + } + + return res; + } + + function addBottomPoints (s, datapoints) { + var formattedPoints = []; + for (var i = 0; i < datapoints.points.length; i += 2) { + formattedPoints.push(datapoints.points[i]); + formattedPoints.push(datapoints.points[i + 1]); + formattedPoints.push(0); + } + + datapoints.format.push({ + x: false, + y: true, + number: true, + required: false, + computeRange: s.yaxis.options.autoScale !== 'none', + defaultValue: 0 + }); + datapoints.points = formattedPoints; + datapoints.pointsize = 3; + } + + function stackData(plot, s, datapoints) { + if (s.stack == null || s.stack === false) return; + + var needsBottom = s.bars.show || (s.lines.show && s.lines.fill); + var hasBottom = datapoints.pointsize > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y); + // Series data is missing bottom points - need to format + if (needsBottom && !hasBottom) { + addBottomPoints(s, datapoints); + } + + var other = findMatchingSeries(s, plot.getData()); + if (!other) return; + + var ps = datapoints.pointsize, + points = datapoints.points, + otherps = other.datapoints.pointsize, + otherpoints = other.datapoints.points, + newpoints = [], + px, py, intery, qx, qy, bottom, + withlines = s.lines.show, + horizontal = s.bars.horizontal, + withsteps = withlines && s.lines.steps, + fromgap = true, + keyOffset = horizontal ? 1 : 0, + accumulateOffset = horizontal ? 0 : 1, + i = 0, j = 0, l, m; + + while (true) { + if (i >= points.length) break; + + l = newpoints.length; + + if (points[i] == null) { + // copy gaps + for (m = 0; m < ps; ++m) { + newpoints.push(points[i + m]); + } + + i += ps; + } else if (j >= otherpoints.length) { + // for lines, we can't use the rest of the points + if (!withlines) { + for (m = 0; m < ps; ++m) { + newpoints.push(points[i + m]); + } + } + + i += ps; + } else if (otherpoints[j] == null) { + // oops, got a gap + for (m = 0; m < ps; ++m) { + newpoints.push(null); + } + + fromgap = true; + j += otherps; + } else { + // cases where we actually got two points + px = points[i + keyOffset]; + py = points[i + accumulateOffset]; + qx = otherpoints[j + keyOffset]; + qy = otherpoints[j + accumulateOffset]; + bottom = 0; + + if (px === qx) { + for (m = 0; m < ps; ++m) { + newpoints.push(points[i + m]); + } + + newpoints[l + accumulateOffset] += qy; + bottom = qy; + + i += ps; + j += otherps; + } else if (px > qx) { + // we got past point below, might need to + // insert interpolated extra point + if (withlines && i > 0 && points[i - ps] != null) { + intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px); + newpoints.push(qx); + newpoints.push(intery + qy); + for (m = 2; m < ps; ++m) { + newpoints.push(points[i + m]); + } + + bottom = qy; + } + + j += otherps; + } else { // px < qx + if (fromgap && withlines) { + // if we come from a gap, we just skip this point + i += ps; + continue; + } + + for (m = 0; m < ps; ++m) { + newpoints.push(points[i + m]); + } + + // we might be able to interpolate a point below, + // this can give us a better y + if (withlines && j > 0 && otherpoints[j - otherps] != null) { + bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx); + } + + newpoints[l + accumulateOffset] += bottom; + + i += ps; + } + + fromgap = false; + + if (l !== newpoints.length && needsBottom) { + newpoints[l + 2] += bottom; + } + } + + // maintain the line steps invariant + if (withsteps && l !== newpoints.length && l > 0 && + newpoints[l] !== null && + newpoints[l] !== newpoints[l - ps] && + newpoints[l + 1] !== newpoints[l - ps + 1]) { + for (m = 0; m < ps; ++m) { + newpoints[l + ps + m] = newpoints[l + m]; + } + + newpoints[l + 1] = newpoints[l - ps + 1]; + } + } + + datapoints.points = newpoints; + } + + plot.hooks.processDatapoints.push(stackData); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'stack', + version: '1.2' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.symbol.js b/extern/phmap/benchmark/js/jquery.flot.symbol.js new file mode 100644 index 0000000..0e06513 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.symbol.js @@ -0,0 +1,98 @@ +/* Flot plugin that adds some extra symbols for plotting points. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The symbols are accessed as strings through the standard symbol options: + + series: { + points: { + symbol: "square" // or "diamond", "triangle", "cross", "plus", "ellipse", "rectangle" + } + } + +*/ + +(function ($) { + // we normalize the area of each symbol so it is approximately the + // same as a circle of the given radius + + var square = function (ctx, x, y, radius, shadow) { + // pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2 + var size = radius * Math.sqrt(Math.PI) / 2; + ctx.rect(x - size, y - size, size + size, size + size); + }, + rectangle = function (ctx, x, y, radius, shadow) { + // pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2 + var size = radius * Math.sqrt(Math.PI) / 2; + ctx.rect(x - size, y - size, size + size, size + size); + }, + diamond = function (ctx, x, y, radius, shadow) { + // pi * r^2 = 2s^2 => s = r * sqrt(pi/2) + var size = radius * Math.sqrt(Math.PI / 2); + ctx.moveTo(x - size, y); + ctx.lineTo(x, y - size); + ctx.lineTo(x + size, y); + ctx.lineTo(x, y + size); + ctx.lineTo(x - size, y); + ctx.lineTo(x, y - size); + }, + triangle = function (ctx, x, y, radius, shadow) { + // pi * r^2 = 1/2 * s^2 * sin (pi / 3) => s = r * sqrt(2 * pi / sin(pi / 3)) + var size = radius * Math.sqrt(2 * Math.PI / Math.sin(Math.PI / 3)); + var height = size * Math.sin(Math.PI / 3); + ctx.moveTo(x - size / 2, y + height / 2); + ctx.lineTo(x + size / 2, y + height / 2); + if (!shadow) { + ctx.lineTo(x, y - height / 2); + ctx.lineTo(x - size / 2, y + height / 2); + ctx.lineTo(x + size / 2, y + height / 2); + } + }, + cross = function (ctx, x, y, radius, shadow) { + // pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2 + var size = radius * Math.sqrt(Math.PI) / 2; + ctx.moveTo(x - size, y - size); + ctx.lineTo(x + size, y + size); + ctx.moveTo(x - size, y + size); + ctx.lineTo(x + size, y - size); + }, + ellipse = function(ctx, x, y, radius, shadow, fill) { + if (!shadow) { + ctx.moveTo(x + radius, y); + ctx.arc(x, y, radius, 0, Math.PI * 2, false); + } + }, + plus = function (ctx, x, y, radius, shadow) { + var size = radius * Math.sqrt(Math.PI / 2); + ctx.moveTo(x - size, y); + ctx.lineTo(x + size, y); + ctx.moveTo(x, y + size); + ctx.lineTo(x, y - size); + }, + handlers = { + square: square, + rectangle: rectangle, + diamond: diamond, + triangle: triangle, + cross: cross, + ellipse: ellipse, + plus: plus + }; + + square.fill = true; + rectangle.fill = true; + diamond.fill = true; + triangle.fill = true; + ellipse.fill = true; + + function init(plot) { + plot.drawSymbol = handlers; + } + + $.plot.plugins.push({ + init: init, + name: 'symbols', + version: '1.0' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.threshold.js b/extern/phmap/benchmark/js/jquery.flot.threshold.js new file mode 100644 index 0000000..db5a59c --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.threshold.js @@ -0,0 +1,143 @@ +/* Flot plugin for thresholding data. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + + series: { + threshold: { + below: number + color: colorspec + } + } + +It can also be applied to a single series, like this: + + $.plot( $("#placeholder"), [{ + data: [ ... ], + threshold: { ... } + }]) + +An array can be passed for multiple thresholding, like this: + + threshold: [{ + below: number1 + color: color1 + },{ + below: number2 + color: color2 + }] + +These multiple threshold objects can be passed in any order since they are +sorted by the processing function. + +The data points below "below" are drawn with the specified color. This makes +it easy to mark points below 0, e.g. for budget data. + +Internally, the plugin works by splitting the data into two series, above and +below the threshold. The extra series below the threshold will have its label +cleared and the special "originSeries" attribute set to the original series. +You may need to check for this in hover events. + +*/ + +(function ($) { + var options = { + series: { threshold: null } // or { below: number, color: color spec} + }; + + function init(plot) { + function thresholdData(plot, s, datapoints, below, color) { + var ps = datapoints.pointsize, i, x, y, p, prevp, + thresholded = $.extend({}, s); // note: shallow copy + + thresholded.datapoints = { points: [], pointsize: ps, format: datapoints.format }; + thresholded.label = null; + thresholded.color = color; + thresholded.threshold = null; + thresholded.originSeries = s; + thresholded.data = []; + + var origpoints = datapoints.points, + addCrossingPoints = s.lines.show; + + var threspoints = []; + var newpoints = []; + var m; + + for (i = 0; i < origpoints.length; i += ps) { + x = origpoints[i]; + y = origpoints[i + 1]; + + prevp = p; + if (y < below) p = threspoints; + else p = newpoints; + + if (addCrossingPoints && prevp !== p && + x !== null && i > 0 && + origpoints[i - ps] != null) { + var interx = x + (below - y) * (x - origpoints[i - ps]) / (y - origpoints[i - ps + 1]); + prevp.push(interx); + prevp.push(below); + for (m = 2; m < ps; ++m) { + prevp.push(origpoints[i + m]); + } + + p.push(null); // start new segment + p.push(null); + for (m = 2; m < ps; ++m) { + p.push(origpoints[i + m]); + } + + p.push(interx); + p.push(below); + for (m = 2; m < ps; ++m) { + p.push(origpoints[i + m]); + } + } + + p.push(x); + p.push(y); + for (m = 2; m < ps; ++m) { + p.push(origpoints[i + m]); + } + } + + datapoints.points = newpoints; + thresholded.datapoints.points = threspoints; + + if (thresholded.datapoints.points.length > 0) { + var origIndex = $.inArray(s, plot.getData()); + // Insert newly-generated series right after original one (to prevent it from becoming top-most) + plot.getData().splice(origIndex + 1, 0, thresholded); + } + + // FIXME: there are probably some edge cases left in bars + } + + function processThresholds(plot, s, datapoints) { + if (!s.threshold) return; + if (s.threshold instanceof Array) { + s.threshold.sort(function(a, b) { + return a.below - b.below; + }); + + $(s.threshold).each(function(i, th) { + thresholdData(plot, s, datapoints, th.below, th.color); + }); + } else { + thresholdData(plot, s, datapoints, s.threshold.below, s.threshold.color); + } + } + + plot.hooks.processDatapoints.push(processThresholds); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'threshold', + version: '1.2' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.time.js b/extern/phmap/benchmark/js/jquery.flot.time.js new file mode 100644 index 0000000..3dac995 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.time.js @@ -0,0 +1,460 @@ +/* Pretty handling of time axes. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +Set axis.mode to "time" to enable. See the section "Time series data" in +API.txt for details. +*/ + +(function($) { + 'use strict'; + + var options = { + xaxis: { + timezone: null, // "browser" for local to the client or timezone for timezone-js + timeformat: null, // format string to use + twelveHourClock: false, // 12 or 24 time in time mode + monthNames: null, // list of names of months + timeBase: 'seconds' // are the values in milliseconds or seconds + }, + yaxis: { + timeBase: 'seconds' + } + }; + + var floorInBase = $.plot.saturated.floorInBase; + + // Returns a string with the date d formatted according to fmt. + // A subset of the Open Group's strftime format is supported. + + function formatDate(d, fmt, monthNames, dayNames) { + if (typeof d.strftime === "function") { + return d.strftime(fmt); + } + + var leftPad = function(n, pad) { + n = "" + n; + pad = "" + (pad == null ? "0" : pad); + return n.length == 1 ? pad + n : n; + }; + + var r = []; + var escape = false; + var hours = d.getHours(); + var isAM = hours < 12; + + if (!monthNames) { + monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + } + + if (!dayNames) { + dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + } + + var hours12; + if (hours > 12) { + hours12 = hours - 12; + } else if (hours == 0) { + hours12 = 12; + } else { + hours12 = hours; + } + + for (var i = 0; i < fmt.length; ++i) { + var c = fmt.charAt(i); + + if (escape) { + switch (c) { + case 'a': c = "" + dayNames[d.getDay()]; break; + case 'b': c = "" + monthNames[d.getMonth()]; break; + case 'd': c = leftPad(d.getDate()); break; + case 'e': c = leftPad(d.getDate(), " "); break; + case 'h': // For back-compat with 0.7; remove in 1.0 + case 'H': c = leftPad(hours); break; + case 'I': c = leftPad(hours12); break; + case 'l': c = leftPad(hours12, " "); break; + case 'm': c = leftPad(d.getMonth() + 1); break; + case 'M': c = leftPad(d.getMinutes()); break; + // quarters not in Open Group's strftime specification + case 'q': + c = "" + (Math.floor(d.getMonth() / 3) + 1); break; + case 'S': c = leftPad(d.getSeconds()); break; + case 'y': c = leftPad(d.getFullYear() % 100); break; + case 'Y': c = "" + d.getFullYear(); break; + case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break; + case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break; + case 'w': c = "" + d.getDay(); break; + } + r.push(c); + escape = false; + } else { + if (c == "%") { + escape = true; + } else { + r.push(c); + } + } + } + + return r.join(""); + } + + // To have a consistent view of time-based data independent of which time + // zone the client happens to be in we need a date-like object independent + // of time zones. This is done through a wrapper that only calls the UTC + // versions of the accessor methods. + + function makeUtcWrapper(d) { + function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) { + sourceObj[sourceMethod] = function() { + return targetObj[targetMethod].apply(targetObj, arguments); + }; + } + + var utc = { + date: d + }; + + // support strftime, if found + if (d.strftime !== undefined) { + addProxyMethod(utc, "strftime", d, "strftime"); + } + + addProxyMethod(utc, "getTime", d, "getTime"); + addProxyMethod(utc, "setTime", d, "setTime"); + + var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"]; + + for (var p = 0; p < props.length; p++) { + addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]); + addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]); + } + + return utc; + } + + // select time zone strategy. This returns a date-like object tied to the + // desired timezone + function dateGenerator(ts, opts) { + var maxDateValue = 8640000000000000; + + if (opts && opts.timeBase === 'seconds') { + ts *= 1000; + } + + if (ts > maxDateValue) { + ts = maxDateValue; + } else if (ts < -maxDateValue) { + ts = -maxDateValue; + } + + if (opts.timezone === "browser") { + return new Date(ts); + } else if (!opts.timezone || opts.timezone === "utc") { + return makeUtcWrapper(new Date(ts)); + } else if (typeof timezoneJS !== "undefined" && typeof timezoneJS.Date !== "undefined") { + var d = new timezoneJS.Date(); + // timezone-js is fickle, so be sure to set the time zone before + // setting the time. + d.setTimezone(opts.timezone); + d.setTime(ts); + return d; + } else { + return makeUtcWrapper(new Date(ts)); + } + } + + // map of app. size of time units in milliseconds + var timeUnitSizeSeconds = { + "millisecond": 0.001, + "second": 1, + "minute": 60, + "hour": 60 * 60, + "day": 24 * 60 * 60, + "month": 30 * 24 * 60 * 60, + "quarter": 3 * 30 * 24 * 60 * 60, + "year": 365.2425 * 24 * 60 * 60 + }; + + var timeUnitSizeMilliseconds = { + "millisecond": 1, + "second": 1000, + "minute": 60 * 1000, + "hour": 60 * 60 * 1000, + "day": 24 * 60 * 60 * 1000, + "month": 30 * 24 * 60 * 60 * 1000, + "quarter": 3 * 30 * 24 * 60 * 60 * 1000, + "year": 365.2425 * 24 * 60 * 60 * 1000 + }; + + // the allowed tick sizes, after 1 year we use + // an integer algorithm + + var baseSpec = [ + [1, "millisecond"], [2, "millisecond"], [5, "millisecond"], [10, "millisecond"], + [25, "millisecond"], [50, "millisecond"], [100, "millisecond"], [250, "millisecond"], [500, "millisecond"], + [1, "second"], [2, "second"], [5, "second"], [10, "second"], + [30, "second"], + [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], + [30, "minute"], + [1, "hour"], [2, "hour"], [4, "hour"], + [8, "hour"], [12, "hour"], + [1, "day"], [2, "day"], [3, "day"], + [0.25, "month"], [0.5, "month"], [1, "month"], + [2, "month"] + ]; + + // we don't know which variant(s) we'll need yet, but generating both is + // cheap + + var specMonths = baseSpec.concat([[3, "month"], [6, "month"], + [1, "year"]]); + var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"], + [1, "year"]]); + + + function dateTickGenerator(axis) { + var opts = axis.options, + ticks = [], + d = dateGenerator(axis.min, opts), + minSize = 0; + + // make quarter use a possibility if quarters are + // mentioned in either of these options + var spec = (opts.tickSize && opts.tickSize[1] === + "quarter") || + (opts.minTickSize && opts.minTickSize[1] === + "quarter") ? specQuarters : specMonths; + + var timeUnitSize = opts.timeBase === 'seconds' ? timeUnitSizeSeconds : timeUnitSizeMilliseconds; + + if (opts.minTickSize !== null && opts.minTickSize !== undefined) { + if (typeof opts.tickSize === "number") { + minSize = opts.tickSize; + } else { + minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]]; + } + } + + for (var i = 0; i < spec.length - 1; ++i) { + if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]] + + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2 && + spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) { + break; + } + } + + var size = spec[i][0]; + var unit = spec[i][1]; + // special-case the possibility of several years + if (unit === "year") { + // if given a minTickSize in years, just use it, + // ensuring that it's an integer + + if (opts.minTickSize !== null && opts.minTickSize !== undefined && opts.minTickSize[1] === "year") { + size = Math.floor(opts.minTickSize[0]); + } else { + var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10)); + var norm = (axis.delta / timeUnitSize.year) / magn; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + } + + // minimum size for years is 1 + + if (size < 1) { + size = 1; + } + } + + axis.tickSize = opts.tickSize || [size, unit]; + var tickSize = axis.tickSize[0]; + unit = axis.tickSize[1]; + + var step = tickSize * timeUnitSize[unit]; + + if (unit === "millisecond") { + d.setMilliseconds(floorInBase(d.getMilliseconds(), tickSize)); + } else if (unit === "second") { + d.setSeconds(floorInBase(d.getSeconds(), tickSize)); + } else if (unit === "minute") { + d.setMinutes(floorInBase(d.getMinutes(), tickSize)); + } else if (unit === "hour") { + d.setHours(floorInBase(d.getHours(), tickSize)); + } else if (unit === "month") { + d.setMonth(floorInBase(d.getMonth(), tickSize)); + } else if (unit === "quarter") { + d.setMonth(3 * floorInBase(d.getMonth() / 3, + tickSize)); + } else if (unit === "year") { + d.setFullYear(floorInBase(d.getFullYear(), tickSize)); + } + + // reset smaller components + + if (step >= timeUnitSize.second) { + d.setMilliseconds(0); + } + + if (step >= timeUnitSize.minute) { + d.setSeconds(0); + } + if (step >= timeUnitSize.hour) { + d.setMinutes(0); + } + if (step >= timeUnitSize.day) { + d.setHours(0); + } + if (step >= timeUnitSize.day * 4) { + d.setDate(1); + } + if (step >= timeUnitSize.month * 2) { + d.setMonth(floorInBase(d.getMonth(), 3)); + } + if (step >= timeUnitSize.quarter * 2) { + d.setMonth(floorInBase(d.getMonth(), 6)); + } + if (step >= timeUnitSize.year) { + d.setMonth(0); + } + + var carry = 0; + var v = Number.NaN; + var v1000; + var prev; + do { + prev = v; + v1000 = d.getTime(); + if (opts && opts.timeBase === 'seconds') { + v = v1000 / 1000; + } else { + v = v1000; + } + + ticks.push(v); + + if (unit === "month" || unit === "quarter") { + if (tickSize < 1) { + // a bit complicated - we'll divide the + // month/quarter up but we need to take + // care of fractions so we don't end up in + // the middle of a day + d.setDate(1); + var start = d.getTime(); + d.setMonth(d.getMonth() + + (unit === "quarter" ? 3 : 1)); + var end = d.getTime(); + d.setTime((v + carry * timeUnitSize.hour + (end - start) * tickSize)); + carry = d.getHours(); + d.setHours(0); + } else { + d.setMonth(d.getMonth() + + tickSize * (unit === "quarter" ? 3 : 1)); + } + } else if (unit === "year") { + d.setFullYear(d.getFullYear() + tickSize); + } else { + if (opts.timeBase === 'seconds') { + d.setTime((v + step) * 1000); + } else { + d.setTime(v + step); + } + } + } while (v < axis.max && v !== prev); + + return ticks; + }; + + function init(plot) { + plot.hooks.processOptions.push(function (plot) { + $.each(plot.getAxes(), function(axisName, axis) { + var opts = axis.options; + if (opts.mode === "time") { + axis.tickGenerator = dateTickGenerator; + + axis.tickFormatter = function (v, axis) { + var d = dateGenerator(v, axis.options); + + // first check global format + if (opts.timeformat != null) { + return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames); + } + + // possibly use quarters if quarters are mentioned in + // any of these places + var useQuarters = (axis.options.tickSize && + axis.options.tickSize[1] == "quarter") || + (axis.options.minTickSize && + axis.options.minTickSize[1] == "quarter"); + + var timeUnitSize = opts.timeBase === 'seconds' ? timeUnitSizeSeconds : timeUnitSizeMilliseconds; + + var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]]; + var span = axis.max - axis.min; + var suffix = (opts.twelveHourClock) ? " %p" : ""; + var hourCode = (opts.twelveHourClock) ? "%I" : "%H"; + var fmt; + + if (t < timeUnitSize.minute) { + fmt = hourCode + ":%M:%S" + suffix; + } else if (t < timeUnitSize.day) { + if (span < 2 * timeUnitSize.day) { + fmt = hourCode + ":%M" + suffix; + } else { + fmt = "%b %d " + hourCode + ":%M" + suffix; + } + } else if (t < timeUnitSize.month) { + fmt = "%b %d"; + } else if ((useQuarters && t < timeUnitSize.quarter) || + (!useQuarters && t < timeUnitSize.year)) { + if (span < timeUnitSize.year) { + fmt = "%b"; + } else { + fmt = "%b %Y"; + } + } else if (useQuarters && t < timeUnitSize.year) { + if (span < timeUnitSize.year) { + fmt = "Q%q"; + } else { + fmt = "Q%q %Y"; + } + } else { + fmt = "%Y"; + } + + var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames); + + return rt; + }; + } + }); + }); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'time', + version: '1.0' + }); + + // Time-axis support used to be in Flot core, which exposed the + // formatDate function on the plot object. Various plugins depend + // on the function, so we need to re-expose it here. + + $.plot.formatDate = formatDate; + $.plot.dateGenerator = dateGenerator; + $.plot.dateTickGenerator = dateTickGenerator; + $.plot.makeUtcWrapper = makeUtcWrapper; +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.touch.js b/extern/phmap/benchmark/js/jquery.flot.touch.js new file mode 100644 index 0000000..e5153bf --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.touch.js @@ -0,0 +1,322 @@ + +/* global jQuery */ + +(function($) { + 'use strict'; + + var options = { + pan: { + enableTouch: false + } + }; + + function init(plot) { + plot.hooks.processOptions.push(initTouchNavigation); + } + + function initTouchNavigation(plot, options) { + var gestureState = { + twoTouches: false, + currentTapStart: { x: 0, y: 0 }, + currentTapEnd: { x: 0, y: 0 }, + prevTap: { x: 0, y: 0 }, + currentTap: { x: 0, y: 0 }, + interceptedLongTap: false, + allowEventPropagation: false, + prevTapTime: null, + tapStartTime: null, + longTapTriggerId: null + }, + maxDistanceBetweenTaps = 20, + maxIntervalBetweenTaps = 500, + maxLongTapDistance = 20, + minLongTapDuration = 1500, + pressedTapDuration = 125, + mainEventHolder; + + function interpretGestures(e) { + var o = plot.getOptions(); + + if (!o.pan.active && !o.zoom.active) { + return; + } + + updateOnMultipleTouches(e); + mainEventHolder.dispatchEvent(new CustomEvent('touchevent', { detail: e })); + + if (isPinchEvent(e)) { + executeAction(e, 'pinch'); + } else { + executeAction(e, 'pan'); + if (!wasPinchEvent(e)) { + if (isDoubleTap(e)) { + executeAction(e, 'doubleTap'); + } + executeAction(e, 'tap'); + executeAction(e, 'longTap'); + } + } + } + + function executeAction(e, gesture) { + switch (gesture) { + case 'pan': + pan[e.type](e); + break; + case 'pinch': + pinch[e.type](e); + break; + case 'doubleTap': + doubleTap.onDoubleTap(e); + break; + case 'longTap': + longTap[e.type](e); + break; + case 'tap': + tap[e.type](e); + break; + default: + break; + } + } + + function bindEvents(plot, eventHolder) { + mainEventHolder = eventHolder[0]; + eventHolder[0].addEventListener('touchstart', interpretGestures, false); + eventHolder[0].addEventListener('touchmove', interpretGestures, false); + eventHolder[0].addEventListener('touchend', interpretGestures, false); + } + + function shutdown(plot, eventHolder) { + eventHolder[0].removeEventListener('touchstart', interpretGestures); + eventHolder[0].removeEventListener('touchmove', interpretGestures); + eventHolder[0].removeEventListener('touchend', interpretGestures); + if (gestureState.longTapTriggerId) { + clearTimeout(gestureState.longTapTriggerId); + gestureState.longTapTriggerId = null; + } + } + + var pan = { + touchstart: function(e) { + updatePrevForDoubleTap(); + updateCurrentForDoubleTap(e); + updateStateForLongTapStart(e); + + mainEventHolder.dispatchEvent(new CustomEvent('panstart', { detail: e })); + }, + + touchmove: function(e) { + preventEventPropagation(e); + + updateCurrentForDoubleTap(e); + updateStateForLongTapEnd(e); + + if (!gestureState.allowEventPropagation) { + mainEventHolder.dispatchEvent(new CustomEvent('pandrag', { detail: e })); + } + }, + + touchend: function(e) { + preventEventPropagation(e); + + if (wasPinchEvent(e)) { + mainEventHolder.dispatchEvent(new CustomEvent('pinchend', { detail: e })); + mainEventHolder.dispatchEvent(new CustomEvent('panstart', { detail: e })); + } else if (noTouchActive(e)) { + mainEventHolder.dispatchEvent(new CustomEvent('panend', { detail: e })); + } + } + }; + + var pinch = { + touchstart: function(e) { + mainEventHolder.dispatchEvent(new CustomEvent('pinchstart', { detail: e })); + }, + + touchmove: function(e) { + preventEventPropagation(e); + gestureState.twoTouches = isPinchEvent(e); + if (!gestureState.allowEventPropagation) { + mainEventHolder.dispatchEvent(new CustomEvent('pinchdrag', { detail: e })); + } + }, + + touchend: function(e) { + preventEventPropagation(e); + } + }; + + var doubleTap = { + onDoubleTap: function(e) { + preventEventPropagation(e); + mainEventHolder.dispatchEvent(new CustomEvent('doubletap', { detail: e })); + } + }; + + var longTap = { + touchstart: function(e) { + longTap.waitForLongTap(e); + }, + + touchmove: function(e) { + }, + + touchend: function(e) { + if (gestureState.longTapTriggerId) { + clearTimeout(gestureState.longTapTriggerId); + gestureState.longTapTriggerId = null; + } + }, + + isLongTap: function(e) { + var currentTime = new Date().getTime(), + tapDuration = currentTime - gestureState.tapStartTime; + if (tapDuration >= minLongTapDuration && !gestureState.interceptedLongTap) { + if (distance(gestureState.currentTapStart.x, gestureState.currentTapStart.y, gestureState.currentTapEnd.x, gestureState.currentTapEnd.y) < maxLongTapDistance) { + gestureState.interceptedLongTap = true; + return true; + } + } + return false; + }, + + waitForLongTap: function(e) { + var longTapTrigger = function() { + if (longTap.isLongTap(e)) { + mainEventHolder.dispatchEvent(new CustomEvent('longtap', { detail: e })); + } + gestureState.longTapTriggerId = null; + }; + if (!gestureState.longTapTriggerId) { + gestureState.longTapTriggerId = setTimeout(longTapTrigger, minLongTapDuration); + } + } + }; + + var tap = { + touchstart: function(e) { + gestureState.tapStartTime = new Date().getTime(); + }, + + touchmove: function(e) { + }, + + touchend: function(e) { + if (tap.isTap(e)) { + mainEventHolder.dispatchEvent(new CustomEvent('tap', { detail: e })); + preventEventPropagation(e); + } + }, + + isTap: function(e) { + var currentTime = new Date().getTime(), + tapDuration = currentTime - gestureState.tapStartTime; + if (tapDuration <= pressedTapDuration) { + if (distance(gestureState.currentTapStart.x, gestureState.currentTapStart.y, gestureState.currentTapEnd.x, gestureState.currentTapEnd.y) < maxLongTapDistance) { + return true; + } + } + return false; + } + }; + + if (options.pan.enableTouch === true) { + plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); + }; + + function updatePrevForDoubleTap() { + gestureState.prevTap = { + x: gestureState.currentTap.x, + y: gestureState.currentTap.y + }; + }; + + function updateCurrentForDoubleTap(e) { + gestureState.currentTap = { + x: e.touches[0].pageX, + y: e.touches[0].pageY + }; + } + + function updateStateForLongTapStart(e) { + gestureState.tapStartTime = new Date().getTime(); + gestureState.interceptedLongTap = false; + gestureState.currentTapStart = { + x: e.touches[0].pageX, + y: e.touches[0].pageY + }; + gestureState.currentTapEnd = { + x: e.touches[0].pageX, + y: e.touches[0].pageY + }; + }; + + function updateStateForLongTapEnd(e) { + gestureState.currentTapEnd = { + x: e.touches[0].pageX, + y: e.touches[0].pageY + }; + }; + + function isDoubleTap(e) { + var currentTime = new Date().getTime(), + intervalBetweenTaps = currentTime - gestureState.prevTapTime; + + if (intervalBetweenTaps >= 0 && intervalBetweenTaps < maxIntervalBetweenTaps) { + if (distance(gestureState.prevTap.x, gestureState.prevTap.y, gestureState.currentTap.x, gestureState.currentTap.y) < maxDistanceBetweenTaps) { + e.firstTouch = gestureState.prevTap; + e.secondTouch = gestureState.currentTap; + return true; + } + } + gestureState.prevTapTime = currentTime; + return false; + } + + function preventEventPropagation(e) { + if (!gestureState.allowEventPropagation) { + e.preventDefault(); + e.stopPropagation(); + } + } + + function distance(x1, y1, x2, y2) { + return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + } + + function noTouchActive(e) { + return (e.touches && e.touches.length === 0); + } + + function wasPinchEvent(e) { + return (gestureState.twoTouches && e.touches.length === 1); + } + + function updateOnMultipleTouches(e) { + if (e.touches.length >= 3) { + gestureState.allowEventPropagation = true; + } else { + gestureState.allowEventPropagation = false; + } + } + + function isPinchEvent(e) { + if (e.touches && e.touches.length >= 2) { + if (e.touches[0].target === plot.getEventHolder() && + e.touches[1].target === plot.getEventHolder()) { + return true; + } + } + return false; + } + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'navigateTouch', + version: '0.3' + }); +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.touchNavigate.js b/extern/phmap/benchmark/js/jquery.flot.touchNavigate.js new file mode 100644 index 0000000..b467b2e --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.touchNavigate.js @@ -0,0 +1,340 @@ +/* global jQuery */ + +(function($) { + 'use strict'; + + var options = { + pan: { + enableTouch: false, + touchMode: 'manual' + } + }; + + var ZOOM_DISTANCE_MARGIN = $.plot.uiConstants.ZOOM_DISTANCE_MARGIN; + + function init(plot) { + plot.hooks.processOptions.push(initTouchNavigation); + } + + function initTouchNavigation(plot, options) { + var gestureState = { + zoomEnable: false, + prevDistance: null, + prevTapTime: 0, + prevPanPosition: { x: 0, y: 0 }, + prevTapPosition: { x: 0, y: 0 } + }, + navigationState = { + prevTouchedAxis: 'none', + currentTouchedAxis: 'none', + touchedAxis: null, + navigationConstraint: 'unconstrained', + initialState: null, + }, + useManualPan = options.pan.touchMode === 'manual', + smartPanLock = options.pan.touchMode === 'smartLock', + useSmartPan = smartPanLock || options.pan.touchMode === 'smart', + pan, pinch, doubleTap; + + function bindEvents(plot, eventHolder) { + var o = plot.getOptions(); + + if (o.pan.interactive) { + eventHolder[0].addEventListener('panstart', pan.start, false); + eventHolder[0].addEventListener('pandrag', pan.drag, false); + eventHolder[0].addEventListener('panend', pan.end, false); + eventHolder[0].addEventListener('pinchstart', pinch.start, false); + eventHolder[0].addEventListener('pinchdrag', pinch.drag, false); + eventHolder[0].addEventListener('pinchend', pinch.end, false); + eventHolder[0].addEventListener('doubletap', doubleTap.recenterPlot, false); + } + } + + function shutdown(plot, eventHolder) { + eventHolder[0].removeEventListener('panstart', pan.start); + eventHolder[0].removeEventListener('pandrag', pan.drag); + eventHolder[0].removeEventListener('panend', pan.end); + eventHolder[0].removeEventListener('pinchstart', pinch.start); + eventHolder[0].removeEventListener('pinchdrag', pinch.drag); + eventHolder[0].removeEventListener('pinchend', pinch.end); + eventHolder[0].removeEventListener('doubletap', doubleTap.recenterPlot); + } + + pan = { + start: function(e) { + presetNavigationState(e, 'pan', gestureState); + updateData(e, 'pan', gestureState, navigationState); + + if (useSmartPan) { + var point = getPoint(e, 'pan'); + navigationState.initialState = plot.navigationState(point.x, point.y); + } + }, + + drag: function(e) { + presetNavigationState(e, 'pan', gestureState); + + if (useSmartPan) { + var point = getPoint(e, 'pan'); + plot.smartPan({ + x: navigationState.initialState.startPageX - point.x, + y: navigationState.initialState.startPageY - point.y + }, navigationState.initialState, navigationState.touchedAxis, false, smartPanLock); + } else if (useManualPan) { + plot.pan({ + left: -delta(e, 'pan', gestureState).x, + top: -delta(e, 'pan', gestureState).y, + axes: navigationState.touchedAxis + }); + updatePrevPanPosition(e, 'pan', gestureState, navigationState); + } + }, + + end: function(e) { + presetNavigationState(e, 'pan', gestureState); + + if (useSmartPan) { + plot.smartPan.end(); + } + + if (wasPinchEvent(e, gestureState)) { + updateprevPanPosition(e, 'pan', gestureState, navigationState); + } + } + }; + + var pinchDragTimeout; + pinch = { + start: function(e) { + if (pinchDragTimeout) { + clearTimeout(pinchDragTimeout); + pinchDragTimeout = null; + } + presetNavigationState(e, 'pinch', gestureState); + setPrevDistance(e, gestureState); + updateData(e, 'pinch', gestureState, navigationState); + }, + + drag: function(e) { + if (pinchDragTimeout) { + return; + } + pinchDragTimeout = setTimeout(function() { + presetNavigationState(e, 'pinch', gestureState); + plot.pan({ + left: -delta(e, 'pinch', gestureState).x, + top: -delta(e, 'pinch', gestureState).y, + axes: navigationState.touchedAxis + }); + updatePrevPanPosition(e, 'pinch', gestureState, navigationState); + + var dist = pinchDistance(e); + + if (gestureState.zoomEnable || Math.abs(dist - gestureState.prevDistance) > ZOOM_DISTANCE_MARGIN) { + zoomPlot(plot, e, gestureState, navigationState); + + //activate zoom mode + gestureState.zoomEnable = true; + } + pinchDragTimeout = null; + }, 1000 / 60); + }, + + end: function(e) { + if (pinchDragTimeout) { + clearTimeout(pinchDragTimeout); + pinchDragTimeout = null; + } + presetNavigationState(e, 'pinch', gestureState); + gestureState.prevDistance = null; + } + }; + + doubleTap = { + recenterPlot: function(e) { + if (e && e.detail && e.detail.type === 'touchmove') { + // do not recenter during touch moving; + return; + } + recenterPlotOnDoubleTap(plot, e, gestureState, navigationState); + } + }; + + if (options.pan.enableTouch === true) { + plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); + } + + function presetNavigationState(e, gesture, gestureState) { + navigationState.touchedAxis = getAxis(plot, e, gesture, navigationState); + if (noAxisTouched(navigationState)) { + navigationState.navigationConstraint = 'unconstrained'; + } else { + navigationState.navigationConstraint = 'axisConstrained'; + } + } + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'navigateTouch', + version: '0.3' + }); + + function recenterPlotOnDoubleTap(plot, e, gestureState, navigationState) { + checkAxesForDoubleTap(plot, e, navigationState); + if ((navigationState.currentTouchedAxis === 'x' && navigationState.prevTouchedAxis === 'x') || + (navigationState.currentTouchedAxis === 'y' && navigationState.prevTouchedAxis === 'y') || + (navigationState.currentTouchedAxis === 'none' && navigationState.prevTouchedAxis === 'none')) { + plot.recenter({ axes: navigationState.touchedAxis }); + } + } + + function checkAxesForDoubleTap(plot, e, navigationState) { + var axis = plot.getTouchedAxis(e.detail.firstTouch.x, e.detail.firstTouch.y); + if (axis[0] !== undefined) { + navigationState.prevTouchedAxis = axis[0].direction; + } + + axis = plot.getTouchedAxis(e.detail.secondTouch.x, e.detail.secondTouch.y); + if (axis[0] !== undefined) { + navigationState.touchedAxis = axis; + navigationState.currentTouchedAxis = axis[0].direction; + } + + if (noAxisTouched(navigationState)) { + navigationState.touchedAxis = null; + navigationState.prevTouchedAxis = 'none'; + navigationState.currentTouchedAxis = 'none'; + } + } + + function zoomPlot(plot, e, gestureState, navigationState) { + var offset = plot.offset(), + center = { + left: 0, + top: 0 + }, + zoomAmount = pinchDistance(e) / gestureState.prevDistance, + dist = pinchDistance(e); + + center.left = getPoint(e, 'pinch').x - offset.left; + center.top = getPoint(e, 'pinch').y - offset.top; + + // send the computed touched axis to the zoom function so that it only zooms on that one + plot.zoom({ + center: center, + amount: zoomAmount, + axes: navigationState.touchedAxis + }); + gestureState.prevDistance = dist; + } + + function wasPinchEvent(e, gestureState) { + return (gestureState.zoomEnable && e.detail.touches.length === 1); + } + + function getAxis(plot, e, gesture, navigationState) { + if (e.type === 'pinchstart') { + var axisTouch1 = plot.getTouchedAxis(e.detail.touches[0].pageX, e.detail.touches[0].pageY); + var axisTouch2 = plot.getTouchedAxis(e.detail.touches[1].pageX, e.detail.touches[1].pageY); + + if (axisTouch1.length === axisTouch2.length && axisTouch1.toString() === axisTouch2.toString()) { + return axisTouch1; + } + } else if (e.type === 'panstart') { + return plot.getTouchedAxis(e.detail.touches[0].pageX, e.detail.touches[0].pageY); + } else if (e.type === 'pinchend') { + //update axis since instead on pinch, a pan event is made + return plot.getTouchedAxis(e.detail.touches[0].pageX, e.detail.touches[0].pageY); + } else { + return navigationState.touchedAxis; + } + } + + function noAxisTouched(navigationState) { + return (!navigationState.touchedAxis || navigationState.touchedAxis.length === 0); + } + + function setPrevDistance(e, gestureState) { + gestureState.prevDistance = pinchDistance(e); + } + + function updateData(e, gesture, gestureState, navigationState) { + var axisDir, + point = getPoint(e, gesture); + + switch (navigationState.navigationConstraint) { + case 'unconstrained': + navigationState.touchedAxis = null; + gestureState.prevTapPosition = { + x: gestureState.prevPanPosition.x, + y: gestureState.prevPanPosition.y + }; + gestureState.prevPanPosition = { + x: point.x, + y: point.y + }; + break; + case 'axisConstrained': + axisDir = navigationState.touchedAxis[0].direction; + navigationState.currentTouchedAxis = axisDir; + gestureState.prevTapPosition[axisDir] = gestureState.prevPanPosition[axisDir]; + gestureState.prevPanPosition[axisDir] = point[axisDir]; + break; + default: + break; + } + } + + function distance(x1, y1, x2, y2) { + return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + } + + function pinchDistance(e) { + var t1 = e.detail.touches[0], + t2 = e.detail.touches[1]; + return distance(t1.pageX, t1.pageY, t2.pageX, t2.pageY); + } + + function updatePrevPanPosition(e, gesture, gestureState, navigationState) { + var point = getPoint(e, gesture); + + switch (navigationState.navigationConstraint) { + case 'unconstrained': + gestureState.prevPanPosition.x = point.x; + gestureState.prevPanPosition.y = point.y; + break; + case 'axisConstrained': + gestureState.prevPanPosition[navigationState.currentTouchedAxis] = + point[navigationState.currentTouchedAxis]; + break; + default: + break; + } + } + + function delta(e, gesture, gestureState) { + var point = getPoint(e, gesture); + + return { + x: point.x - gestureState.prevPanPosition.x, + y: point.y - gestureState.prevPanPosition.y + } + } + + function getPoint(e, gesture) { + if (gesture === 'pinch') { + return { + x: (e.detail.touches[0].pageX + e.detail.touches[1].pageX) / 2, + y: (e.detail.touches[0].pageY + e.detail.touches[1].pageY) / 2 + } + } else { + return { + x: e.detail.touches[0].pageX, + y: e.detail.touches[0].pageY + } + } + } +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.flot.uiConstants.js b/extern/phmap/benchmark/js/jquery.flot.uiConstants.js new file mode 100644 index 0000000..627847d --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.flot.uiConstants.js @@ -0,0 +1,10 @@ +(function ($) { + 'use strict'; + $.plot.uiConstants = { + SNAPPING_CONSTANT: 20, + PANHINT_LENGTH_CONSTANT: 10, + MINOR_TICKS_COUNT_CONSTANT: 4, + TICK_LENGTH_CONSTANT: 10, + ZOOM_DISTANCE_MARGIN: 25 + }; +})(jQuery); diff --git a/extern/phmap/benchmark/js/jquery.js b/extern/phmap/benchmark/js/jquery.js new file mode 100644 index 0000000..f9f969a --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.js @@ -0,0 +1,9473 @@ +/*! + * jQuery JavaScript Library v1.8.3 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: Tue Nov 13 2012 08:20:33 GMT-0500 (Eastern Standard Time) + */ +/* eslint-disable */ +(function( window, undefined ) { +var + // A central reference to the root jQuery(document) + rootjQuery, + + // The deferred used on DOM ready + readyList, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + location = window.location, + navigator = window.navigator, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // Save a reference to some core methods + core_push = Array.prototype.push, + core_slice = Array.prototype.slice, + core_indexOf = Array.prototype.indexOf, + core_toString = Object.prototype.toString, + core_hasOwn = Object.prototype.hasOwnProperty, + core_trim = String.prototype.trim, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Used for matching numbers + core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source, + + // Used for detecting and trimming whitespace + core_rnotwhite = /\S/, + core_rspace = /\s+/, + + // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // The ready event handler and self cleanup method + DOMContentLoaded = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + } else if ( document.readyState === "complete" ) { + // we're here because readyState === "complete" in oldIE + // which is good enough for us to call the dom ready! + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context && context.nodeType ? context.ownerDocument || context : document ); + + // scripts is true for back-compat + selector = jQuery.parseHTML( match[1], doc, true ); + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + this.attr.call( selector, context, true ); + } + + return jQuery.merge( this, selector ); + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.8.3", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return core_slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( core_slice.apply( this, arguments ), + "slice", core_slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: core_push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ core_toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !core_hasOwn.call(obj, "constructor") && + !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + // data: string of html + // context (optional): If specified, the fragment will be created in this context, defaults to document + // scripts (optional): If true, will include scripts passed in the html string + parseHTML: function( data, context, scripts ) { + var parsed; + if ( !data || typeof data !== "string" ) { + return null; + } + if ( typeof context === "boolean" ) { + scripts = context; + context = 0; + } + context = context || document; + + // Single tag + if ( (parsed = rsingleTag.exec( data )) ) { + return [ context.createElement( parsed[1] ) ]; + } + + parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); + return jQuery.merge( [], + (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); + }, + + parseJSON: function( data ) { + if ( !data || typeof data !== "string") { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && core_rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var name, + i = 0, + length = obj.length, + isObj = length === undefined || jQuery.isFunction( obj ); + + if ( args ) { + if ( isObj ) { + for ( name in obj ) { + if ( callback.apply( obj[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( obj[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in obj ) { + if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: core_trim && !core_trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + core_trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var type, + ret = results || []; + + if ( arr != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + type = jQuery.type( arr ); + + if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { + core_push.call( ret, arr ); + } else { + jQuery.merge( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( core_indexOf ) { + return core_indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var l = second.length, + i = first.length, + j = 0; + + if ( typeof l === "number" ) { + for ( ; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var retVal, + ret = [], + i = 0, + length = elems.length; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, + ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = core_slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; + + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); + } + chainable = 1; + + // Sets one value + } else if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = pass === undefined && jQuery.isFunction( value ); + + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } + } + + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + } +}); + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready, 1 ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.split( core_rspace ), function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + return jQuery.inArray( fn, list ) > -1; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( list && ( !fired || stack ) ) { + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var action = tuple[ 0 ], + fn = fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? + function() { + var returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + } : + newDefer[ action ] + ); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] = list.fire + deferred[ tuple[0] ] = list.fire; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = core_slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; + if( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + fragment, + eventName, + i, + isSupported, + clickFn, + div = document.createElement("div"); + + // Setup + div.setAttribute( "className", "t" ); + div.innerHTML = "
a"; + + // Support tests won't run in some limited or non-browser environments + all = div.getElementsByTagName("*"); + a = div.getElementsByTagName("a")[ 0 ]; + if ( !all || !a || !all.length ) { + return {}; + } + + // First batch of tests + select = document.createElement("select"); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName("input")[ 0 ]; + + a.style.cssText = "top:1px;float:left;opacity:.5"; + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.5/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form (#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode + boxModel: ( document.compatMode === "CSS1Compat" ), + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + boxSizingReliable: true, + pixelPosition: false + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", clickFn = function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent("onclick"); + div.detachEvent( "onclick", clickFn ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute( "type", "radio" ); + support.radioValue = input.value === "t"; + + input.setAttribute( "checked", "checked" ); + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: true, + change: true, + focusin: true + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + // Run tests that need a body at doc ready + jQuery(function() { + var container, div, tds, marginDiv, + divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + container = document.createElement("div"); + container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
t
"; + tds = div.getElementsByTagName("td"); + tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check box-sizing and margin behavior + div.innerHTML = ""; + div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; + support.boxSizing = ( div.offsetWidth === 4 ); + support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); + + // NOTE: To any future maintainer, we've window.getComputedStyle + // because jsdom on node.js will break without it. + if ( window.getComputedStyle ) { + support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; + support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + marginDiv = document.createElement("div"); + marginDiv.style.cssText = div.style.cssText = divReset; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); + } + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.innerHTML = ""; + div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = "block"; + div.style.overflow = "visible"; + div.innerHTML = "
"; + div.firstChild.style.width = "5px"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + + container.style.zoom = 1; + } + + // Null elements to avoid leaks in IE + body.removeChild( container ); + container = div = tds = marginDiv = null; + }); + + // Null elements to avoid leaks in IE + fragment.removeChild( div ); + all = a = select = opt = input = fragment = div = null; + + return support; +})(); +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + deletedIds: [], + + // Remove at next major release (1.9/2.0) + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + } else if ( jQuery.support.deleteExpando || cache != cache.window ) { + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; + + // nodes accept data unless otherwise specified; rejection can be conditional + return !noData || noData !== true && elem.getAttribute("classid") === noData; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( !name.indexOf( "data-" ) ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + parts = key.split( ".", 2 ); + parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } + + parts[1] = value; + this.each(function() { + var self = jQuery( this ); + + self.triggerHandler( "setData" + part, parts ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + part, parts ); + }); + }, null, value, arguments.length > 1, null, false ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery.removeData( elem, type + "queue", true ); + jQuery.removeData( elem, key, true ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var nodeHook, boolHook, fixSpecified, + rclass = /[\t\r\n]/g, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea|)$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( core_rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var removes, className, elem, c, cl, i, l; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + if ( (value && typeof value === "string") || value === undefined ) { + removes = ( value || "" ).split( core_rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + if ( elem.nodeType === 1 && elem.className ) { + + className = (" " + elem.className + " ").replace( rclass, " " ); + + // loop over each item in the removal list + for ( c = 0, cl = removes.length; c < cl; c++ ) { + // Remove until there is nothing to remove, + while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) { + className = className.replace( " " + removes[ c ] + " " , " " ); + } + } + elem.className = value ? jQuery.trim( className ) : ""; + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( core_rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space separated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var val, + self = jQuery(this); + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + one ? index : 0; + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // oldIE doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + // Don't return options that are disabled or in a disabled optgroup + ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && + ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 + attrFn: {}, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, value + "" ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, isBool, + i = 0; + + if ( value && elem.nodeType === 1 ) { + + attrNames = value.split( core_rspace ); + + for ( ; i < attrNames.length; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + isBool = rboolean.test( name ); + + // See #9699 for explanation of this approach (setting first, then removal) + // Do not do this for boolean attributes (see #10870) + if ( !isBool ) { + jQuery.attr( elem, name, "" ); + } + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( isBool && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true, + coords: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? + ret.value : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.value = value + "" ); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, + rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var t, tns, type, origType, namespaces, origCount, + j, events, special, eventType, handleObj, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, "events", true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, + type = event.type || event, + namespaces = []; + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + for ( old = elem; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old === (elem.ownerDocument || document) ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related, + handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = core_slice.call( arguments ), + run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, + handlerQueue = []; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.disabled !== true || event.type !== "click" ) { + selMatch = {}; + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) + event.metaKey = !!event.metaKey; + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === "undefined" ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "_submit_attached" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "_submit_attached", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "_change_attached", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://sizzlejs.com/ + */ +(function( window, undefined ) { + +var cachedruns, + assertGetIdNotName, + Expr, + getText, + isXML, + contains, + compile, + sortOrder, + hasDuplicate, + outermostContext, + + baseHasDuplicate = true, + strundefined = "undefined", + + expando = ( "sizcache" + Math.random() ).replace( ".", "" ), + + Token = String, + document = window.document, + docElem = document.documentElement, + dirruns = 0, + done = 0, + pop = [].pop, + push = [].push, + slice = [].slice, + // Use a stripped-down indexOf if a native one is unavailable + indexOf = [].indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + // Augment a function for special use by Sizzle + markFunction = function( fn, value ) { + fn[ expando ] = value == null || value; + return fn; + }, + + createCache = function() { + var cache = {}, + keys = []; + + return markFunction(function( key, value ) { + // Only keep the most recent entries + if ( keys.push( key ) > Expr.cacheLength ) { + delete cache[ keys.shift() ]; + } + + // Retrieve with (key + " ") to avoid collision with native Object.prototype properties (see Issue #157) + return (cache[ key + " " ] = value); + }, cache ); + }, + + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + + // Regex + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + operators = "([*^$|!~]?=)", + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments not in parens/brackets, + // then attribute selectors and non-pseudos (denoted by :), + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)", + + // For matchExpr.POS and matchExpr.needsContext + pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), + rpseudo = new RegExp( pseudos ), + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, + + rnot = /^:not/, + rsibling = /[\x20\t\r\n\f]*[+~]/, + rendsWithNot = /:not\($/, + + rheader = /h\d/i, + rinputs = /input|select|textarea|button/i, + + rbackslash = /\\(?!\\)/g, + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "POS": new RegExp( pos, "i" ), + "CHILD": new RegExp( "^:(only|nth|first|last)-child(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + // For use in libraries implementing .is() + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) + }, + + // Support + + // Used for testing something on an element + assert = function( fn ) { + var div = document.createElement("div"); + + try { + return fn( div ); + } catch (e) { + return false; + } finally { + // release memory in IE + div = null; + } + }, + + // Check if getElementsByTagName("*") returns only elements + assertTagNameNoComments = assert(function( div ) { + div.appendChild( document.createComment("") ); + return !div.getElementsByTagName("*").length; + }), + + // Check if getAttribute returns normalized href attributes + assertHrefNotNormalized = assert(function( div ) { + div.innerHTML = ""; + return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && + div.firstChild.getAttribute("href") === "#"; + }), + + // Check if attributes should be retrieved by attribute nodes + assertAttributes = assert(function( div ) { + div.innerHTML = ""; + var type = typeof div.lastChild.getAttribute("multiple"); + // IE8 returns a string for some attributes even when not present + return type !== "boolean" && type !== "string"; + }), + + // Check if getElementsByClassName can be trusted + assertUsableClassName = assert(function( div ) { + // Opera can't find a second classname (in 9.6) + div.innerHTML = ""; + if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { + return false; + } + + // Safari 3.2 caches class attributes and doesn't catch changes + div.lastChild.className = "e"; + return div.getElementsByClassName("e").length === 2; + }), + + // Check if getElementById returns elements by name + // Check if getElementsByName privileges form controls or returns elements by ID + assertUsableName = assert(function( div ) { + // Inject content + div.id = expando + 0; + div.innerHTML = "
"; + docElem.insertBefore( div, docElem.firstChild ); + + // Test + var pass = document.getElementsByName && + // buggy browsers will return fewer than the correct 2 + document.getElementsByName( expando ).length === 2 + + // buggy browsers will return more than the correct 0 + document.getElementsByName( expando + 0 ).length; + assertGetIdNotName = !document.getElementById( expando ); + + // Cleanup + docElem.removeChild( div ); + + return pass; + }); + +// If slice is not available, provide a backup +try { + slice.call( docElem.childNodes, 0 )[0].nodeType; +} catch ( e ) { + slice = function( i ) { + var elem, + results = []; + for ( ; (elem = this[i]); i++ ) { + results.push( elem ); + } + return results; + }; +} + +function Sizzle( selector, context, results, seed ) { + results = results || []; + context = context || document; + var match, elem, xml, m, + nodeType = context.nodeType; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( nodeType !== 1 && nodeType !== 9 ) { + return []; + } + + xml = isXML( context ); + + if ( !xml && !seed ) { + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { + push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); + return results; + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed, xml ); +} + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + return Sizzle( expr, null, null, [ elem ] ).length > 0; +}; + +// Returns a function to use in pseudos for input types +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +// Returns a function to use in pseudos for buttons +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +// Returns a function to use in pseudos for positionals +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (see #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + } else { + + // If no nodeType, this is expected to be an array + for ( ; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } + return ret; +}; + +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +// Element contains another +contains = Sizzle.contains = docElem.contains ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); + } : + docElem.compareDocumentPosition ? + function( a, b ) { + return b && !!( a.compareDocumentPosition( b ) & 16 ); + } : + function( a, b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + return false; + }; + +Sizzle.attr = function( elem, name ) { + var val, + xml = isXML( elem ); + + if ( !xml ) { + name = name.toLowerCase(); + } + if ( (val = Expr.attrHandle[ name ]) ) { + return val( elem ); + } + if ( xml || assertAttributes ) { + return elem.getAttribute( name ); + } + val = elem.getAttributeNode( name ); + return val ? + typeof elem[ name ] === "boolean" ? + elem[ name ] ? name : null : + val.specified ? val.value : null : + null; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + // IE6/7 return a modified href + attrHandle: assertHrefNotNormalized ? + {} : + { + "href": function( elem ) { + return elem.getAttribute( "href", 2 ); + }, + "type": function( elem ) { + return elem.getAttribute("type"); + } + }, + + find: { + "ID": assertGetIdNotName ? + function( id, context, xml ) { + if ( typeof context.getElementById !== strundefined && !xml ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + } : + function( id, context, xml ) { + if ( typeof context.getElementById !== strundefined && !xml ) { + var m = context.getElementById( id ); + + return m ? + m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? + [m] : + undefined : + []; + } + }, + + "TAG": assertTagNameNoComments ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + var elem, + tmp = [], + i = 0; + + for ( ; (elem = results[i]); i++ ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }, + + "NAME": assertUsableName && function( tag, context ) { + if ( typeof context.getElementsByName !== strundefined ) { + return context.getElementsByName( name ); + } + }, + + "CLASS": assertUsableClassName && function( className, context, xml ) { + if ( typeof context.getElementsByClassName !== strundefined && !xml ) { + return context.getElementsByClassName( className ); + } + } + }, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( rbackslash, "" ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 3 xn-component of xn+y argument ([+-]?\d*n|) + 4 sign of xn-component + 5 x of xn-component + 6 sign of y-component + 7 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1] === "nth" ) { + // nth-child requires argument + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); + match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); + + // other types prohibit arguments + } else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var unquoted, excess; + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + if ( match[3] ) { + match[2] = match[3]; + } else if ( (unquoted = match[4]) ) { + // Only check arguments that contain a pseudo + if ( rpseudo.test(unquoted) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + unquoted = unquoted.slice( 0, excess ); + match[0] = match[0].slice( 0, excess ); + } + match[2] = unquoted; + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + "ID": assertGetIdNotName ? + function( id ) { + id = id.replace( rbackslash, "" ); + return function( elem ) { + return elem.getAttribute("id") === id; + }; + } : + function( id ) { + id = id.replace( rbackslash, "" ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === id; + }; + }, + + "TAG": function( nodeName ) { + if ( nodeName === "*" ) { + return function() { return true; }; + } + nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); + + return function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ expando ][ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem, context ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.substr( result.length - check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, argument, first, last ) { + + if ( type === "nth" ) { + return function( elem ) { + var node, diff, + parent = elem.parentNode; + + if ( first === 1 && last === 0 ) { + return true; + } + + if ( parent ) { + diff = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + diff++; + if ( elem === node ) { + break; + } + } + } + } + + // Incorporate the offset (or cast to NaN), then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + }; + } + + return function( elem ) { + var node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + /* falls through */ + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), + // not comment, processing instructions, or others + // Thanks to Diego Perini for the nodeName shortcut + // Greater than "@" means alpha characters (specifically not starting with "#" or "?") + var nodeType; + elem = elem.firstChild; + while ( elem ) { + if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { + return false; + } + elem = elem.nextSibling; + } + return true; + }, + + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "text": function( elem ) { + var type, attr; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && + (type = elem.type) === "text" && + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); + }, + + // Input types + "radio": createInputPseudo("radio"), + "checkbox": createInputPseudo("checkbox"), + "file": createInputPseudo("file"), + "password": createInputPseudo("password"), + "image": createInputPseudo("image"), + + "submit": createButtonPseudo("submit"), + "reset": createButtonPseudo("reset"), + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "focus": function( elem ) { + var doc = elem.ownerDocument; + return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + "active": function( elem ) { + return elem === elem.ownerDocument.activeElement; + }, + + // Positional types + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + for ( var i = 0; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + for ( var i = 1; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + for ( var i = argument < 0 ? argument + length : argument; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + for ( var i = argument < 0 ? argument + length : argument; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +function siblingCheck( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; +} + +sortOrder = docElem.compareDocumentPosition ? + function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? + a.compareDocumentPosition : + a.compareDocumentPosition(b) & 4 + ) ? -1 : 1; + } : + function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + +// Always assume the presence of duplicates if sort doesn't +// pass them to our comparison function (as in Google Chrome). +[0, 0].sort( sortOrder ); +baseHasDuplicate = !hasDuplicate; + +// Document sorting and removing duplicates +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + i = 1, + j = 0; + + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( ; (elem = results[i]); i++ ) { + if ( elem === results[ i - 1 ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ expando ][ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( tokens = [] ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + tokens.push( matched = new Token( match.shift() ) ); + soFar = soFar.slice( matched.length ); + + // Cast descendant combinators to space + matched.type = match[0].replace( rtrim, " " ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + + tokens.push( matched = new Token( match.shift() ) ); + soFar = soFar.slice( matched.length ); + matched.type = type; + matched.matches = match; + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && combinator.dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( !xml ) { + var cache, + dirkey = dirruns + " " + doneName + " ", + cachedkey = dirkey + cachedruns; + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + if ( (cache = elem[ expando ]) === cachedkey ) { + return elem.sizset; + } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { + if ( elem.sizset ) { + return elem; + } + } else { + elem[ expando ] = cachedkey; + if ( matcher( elem, context, xml ) ) { + elem.sizset = true; + return elem; + } + elem.sizset = false; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + if ( matcher( elem, context, xml ) ) { + return elem; + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && tokens.slice( 0, i - 1 ).join("").replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && tokens.join("") + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, expandContext ) { + var elem, j, matcher, + setMatched = [], + matchedCount = 0, + i = "0", + unmatched = seed && [], + outermost = expandContext != null, + contextBackup = outermostContext, + // We must always have either seed elements or context + elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), + // Nested matchers should use non-integer dirruns + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E); + + if ( outermost ) { + outermostContext = context !== document && context; + cachedruns = superMatcher.el; + } + + // Add elements passing elementMatchers directly to results + for ( ; (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + for ( j = 0; (matcher = elementMatchers[j]); j++ ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + cachedruns = ++superMatcher.el; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + for ( j = 0; (matcher = setMatchers[j]); j++ ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + superMatcher.el = 0; + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ expando ][ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function select( selector, context, results, seed, xml ) { + var i, tokens, token, type, find, + match = tokenize( selector ), + j = match.length; + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && !xml && + Expr.relative[ tokens[1].type ] ) { + + context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0]; + if ( !context ) { + return results; + } + + selector = selector.slice( tokens.shift().length ); + } + + // Fetch a seed set for right-to-left matching + for ( i = matchExpr["POS"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( rbackslash, "" ), + rsibling.test( tokens[0].type ) && context.parentNode || context, + xml + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && tokens.join(""); + if ( !selector ) { + push.apply( results, slice.call( seed, 0 ) ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + xml, + results, + rsibling.test( selector ) + ); + return results; +} + +if ( document.querySelectorAll ) { + (function() { + var disconnectedMatch, + oldSelect = select, + rescape = /'|\\/g, + rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, + + // qSa(:focus) reports false when true (Chrome 21), no need to also add to buggyMatches since matches checks buggyQSA + // A support test would require too much code (would include document ready) + rbuggyQSA = [ ":focus" ], + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + // A support test would require too much code (would include document ready) + // just skip matchesSelector for :active + rbuggyMatches = [ ":active" ], + matches = docElem.matchesSelector || + docElem.mozMatchesSelector || + docElem.webkitMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector; + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explictly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // IE8 - Some boolean attributes are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here (do not put tests after this one) + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + + // Opera 10-12/IE9 - ^= $= *= and empty values + // Should not select anything + div.innerHTML = "

"; + if ( div.querySelectorAll("[test^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here (do not put tests after this one) + div.innerHTML = ""; + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push(":enabled", ":disabled"); + } + }); + + // rbuggyQSA always contains :focus, so no need for a length check + rbuggyQSA = /* rbuggyQSA.length && */ new RegExp( rbuggyQSA.join("|") ); + + select = function( selector, context, results, seed, xml ) { + // Only use querySelectorAll when not filtering, + // when this is not xml, + // and when no QSA bugs apply + if ( !seed && !xml && !rbuggyQSA.test( selector ) ) { + var groups, i, + old = true, + nid = expando, + newContext = context, + newSelector = context.nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + groups[i].join(""); + } + newContext = rsibling.test( selector ) && context.parentNode || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, slice.call( newContext.querySelectorAll( + newSelector + ), 0 ) ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + + return oldSelect( selector, context, results, seed, xml ); + }; + + if ( matches ) { + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + try { + matches.call( div, "[test!='']:sizzle" ); + rbuggyMatches.push( "!=", pseudos ); + } catch ( e ) {} + }); + + // rbuggyMatches always contains :active and :focus, so no need for a length check + rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); + + Sizzle.matchesSelector = function( elem, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + // rbuggyMatches always contains :active, so no need for an existence check + if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && !rbuggyQSA.test( expr ) ) { + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, null, null, [ elem ] ).length > 0; + }; + } + })(); +} + +// Deprecated +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Back-compat +function setFilters() {} +Expr.filters = setFilters.prototype = Expr.pseudos; +Expr.setFilters = new setFilters(); + +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})( window ); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prev(?:Until|All))/, + isSimple = /^.[^:#\[\.,]*$/, + rneedsContext = jQuery.expr.match.needsContext, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var i, l, length, n, r, ret, + self = this; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + ret = this.pushStack( "", "find", selector ); + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + rneedsContext.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + ret = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + cur = this[i]; + + while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + } + cur = cur.parentNode; + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +jQuery.fn.andSelf = jQuery.fn.addBack; + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( this.length > 1 && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /]", "i"), + rcheckableType = /^(?:checkbox|radio)$/, + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*\s*$/g, + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, +// unless wrapped in a div with non-breaking characters in front of it. +if ( !jQuery.support.htmlSerialize ) { + wrapMap._default = [ 1, "X
", "
" ]; +} + +jQuery.fn.extend({ + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + }, + + append: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 ) { + this.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 ) { + this.insertBefore( elem, this.firstChild ); + } + }); + }, + + before: function() { + if ( !isDisconnected( this[0] ) ) { + return this.domManip(arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this ); + }); + } + + if ( arguments.length ) { + var set = jQuery.clean( arguments ); + return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); + } + }, + + after: function() { + if ( !isDisconnected( this[0] ) ) { + return this.domManip(arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + } + + if ( arguments.length ) { + var set = jQuery.clean( arguments ); + return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); + } + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName("*") ); + jQuery.cleanData( [ elem ] ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName("*") ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName( "*" ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function( value ) { + if ( !isDisconnected( this[0] ) ) { + // Make sure that the elements are removed from the DOM before they are inserted + // this can help fix replacing a parent with child elements + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this), old = self.html(); + self.replaceWith( value.call( this, i, old ) ); + }); + } + + if ( typeof value !== "string" ) { + value = jQuery( value ).detach(); + } + + return this.each(function() { + var next = this.nextSibling, + parent = this.parentNode; + + jQuery( this ).remove(); + + if ( next ) { + jQuery(next).before( value ); + } else { + jQuery(parent).append( value ); + } + }); + } + + return this.length ? + this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : + this; + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, table, callback ) { + + // Flatten any nested arrays + args = [].concat.apply( [], args ); + + var results, first, fragment, iNoClone, + i = 0, + value = args[0], + scripts = [], + l = this.length; + + // We can't cloneNode fragments that contain checked, in WebKit + if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { + return this.each(function() { + jQuery(this).domManip( args, table, callback ); + }); + } + + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + args[0] = value.call( this, i, table ? self.html() : undefined ); + self.domManip( args, table, callback ); + }); + } + + if ( this[0] ) { + results = jQuery.buildFragment( args, this, scripts ); + fragment = results.fragment; + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + table = table && jQuery.nodeName( first, "tr" ); + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + // Fragments from the fragment cache must always be cloned and never used in place. + for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { + callback.call( + table && jQuery.nodeName( this[i], "table" ) ? + findOrAppend( this[i], "tbody" ) : + this[i], + i === iNoClone ? + fragment : + jQuery.clone( fragment, true, true ) + ); + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + + if ( scripts.length ) { + jQuery.each( scripts, function( i, elem ) { + if ( elem.src ) { + if ( jQuery.ajax ) { + jQuery.ajax({ + url: elem.src, + type: "GET", + dataType: "script", + async: false, + global: false, + "throws": true + }); + } else { + jQuery.error("no ajax"); + } + } else { + jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } + }); + } + } + + return this; + } +}); + +function findOrAppend( elem, tag ) { + return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function cloneFixAttributes( src, dest ) { + var nodeName; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + // clearAttributes removes the attributes, which we don't want, + // but also removes the attachEvent events, which we *do* want + if ( dest.clearAttributes ) { + dest.clearAttributes(); + } + + // mergeAttributes, in contrast, only merges back on the + // original attributes, not the events + if ( dest.mergeAttributes ) { + dest.mergeAttributes( src ); + } + + nodeName = dest.nodeName.toLowerCase(); + + if ( nodeName === "object" ) { + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + + // IE blanks contents when cloning scripts + } else if ( nodeName === "script" && dest.text !== src.text ) { + dest.text = src.text; + } + + // Event data gets referenced instead of copied if the expando + // gets copied too + dest.removeAttribute( jQuery.expando ); +} + +jQuery.buildFragment = function( args, context, scripts ) { + var fragment, cacheable, cachehit, + first = args[ 0 ]; + + // Set context from what may come in as undefined or a jQuery collection or a node + // Updated to fix #12266 where accessing context[0] could throw an exception in IE9/10 & + // also doubles as fix for #8950 where plain objects caused createDocumentFragment exception + context = context || document; + context = !context.nodeType && context[0] || context; + context = context.ownerDocument || context; + + // Only cache "small" (1/2 KB) HTML strings that are associated with the main document + // Cloning options loses the selected state, so don't cache them + // IE 6 doesn't like it when you put or elements in a fragment + // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache + // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 + if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && + first.charAt(0) === "<" && !rnocache.test( first ) && + (jQuery.support.checkClone || !rchecked.test( first )) && + (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { + + // Mark cacheable and look for a hit + cacheable = true; + fragment = jQuery.fragments[ first ]; + cachehit = fragment !== undefined; + } + + if ( !fragment ) { + fragment = context.createDocumentFragment(); + jQuery.clean( args, context, fragment, scripts ); + + // Update the cache, but only store false + // unless this is a second parsing of the same content + if ( cacheable ) { + jQuery.fragments[ first ] = cachehit && fragment; + } + } + + return { fragment: fragment, cacheable: cacheable }; +}; + +jQuery.fragments = {}; + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + l = insert.length, + parent = this.length === 1 && this[0].parentNode; + + if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { + insert[ original ]( this[0] ); + return this; + } else { + for ( ; i < l; i++ ) { + elems = ( i > 0 ? this.clone(true) : this ).get(); + jQuery( insert[i] )[ original ]( elems ); + ret = ret.concat( elems ); + } + + return this.pushStack( ret, name, insert.selector ); + } + }; +}); + +function getAll( elem ) { + if ( typeof elem.getElementsByTagName !== "undefined" ) { + return elem.getElementsByTagName( "*" ); + + } else if ( typeof elem.querySelectorAll !== "undefined" ) { + return elem.querySelectorAll( "*" ); + + } else { + return []; + } +} + +// Used in clean, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var srcElements, + destElements, + i, + clone; + + if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + // IE copies events bound via attachEvent when using cloneNode. + // Calling detachEvent on the clone will also remove the events + // from the original. In order to get around this, we use some + // proprietary methods to clear the events. Thanks to MooTools + // guys for this hotness. + + cloneFixAttributes( elem, clone ); + + // Using Sizzle here is crazy slow, so we use getElementsByTagName instead + srcElements = getAll( elem ); + destElements = getAll( clone ); + + // Weird iteration because IE will replace the length property + // with an element if you are cloning the body and one of the + // elements on the page has a name or id of "length" + for ( i = 0; srcElements[i]; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + cloneFixAttributes( srcElements[i], destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + cloneCopyEvent( elem, clone ); + + if ( deepDataAndEvents ) { + srcElements = getAll( elem ); + destElements = getAll( clone ); + + for ( i = 0; srcElements[i]; ++i ) { + cloneCopyEvent( srcElements[i], destElements[i] ); + } + } + } + + srcElements = destElements = null; + + // Return the cloned set + return clone; + }, + + clean: function( elems, context, fragment, scripts ) { + var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, + safe = context === document && safeFragment, + ret = []; + + // Ensure that context is a document + if ( !context || typeof context.createDocumentFragment === "undefined" ) { + context = document; + } + + // Use the already-created safe fragment if context permits + for ( i = 0; (elem = elems[i]) != null; i++ ) { + if ( typeof elem === "number" ) { + elem += ""; + } + + if ( !elem ) { + continue; + } + + // Convert html string into DOM nodes + if ( typeof elem === "string" ) { + if ( !rhtml.test( elem ) ) { + elem = context.createTextNode( elem ); + } else { + // Ensure a safe container in which to render the html + safe = safe || createSafeFragment( context ); + div = context.createElement("div"); + safe.appendChild( div ); + + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(rxhtmlTag, "<$1>"); + + // Go to html and back, then peel off extra wrappers + tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + depth = wrap[0]; + div.innerHTML = wrap[1] + elem + wrap[2]; + + // Move to the right depth + while ( depth-- ) { + div = div.lastChild; + } + + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { + + // String was a , *may* have spurious + hasBody = rtbody.test(elem); + tbody = tag === "table" && !hasBody ? + div.firstChild && div.firstChild.childNodes : + + // String was a bare or + wrap[1] === "
" && !hasBody ? + div.childNodes : + []; + + for ( j = tbody.length - 1; j >= 0 ; --j ) { + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { + tbody[ j ].parentNode.removeChild( tbody[ j ] ); + } + } + } + + // IE completely kills leading whitespace when innerHTML is used + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + } + + elem = div.childNodes; + + // Take out of fragment container (we need a fresh div each time) + div.parentNode.removeChild( div ); + } + } + + if ( elem.nodeType ) { + ret.push( elem ); + } else { + jQuery.merge( ret, elem ); + } + } + + // Fix #11356: Clear elements from safeFragment + if ( div ) { + elem = div = safe = null; + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !jQuery.support.appendChecked ) { + for ( i = 0; (elem = ret[i]) != null; i++ ) { + if ( jQuery.nodeName( elem, "input" ) ) { + fixDefaultChecked( elem ); + } else if ( typeof elem.getElementsByTagName !== "undefined" ) { + jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); + } + } + } + + // Append elements to a provided document fragment + if ( fragment ) { + // Special handling of each script element + handleScript = function( elem ) { + // Check if we consider it executable + if ( !elem.type || rscriptType.test( elem.type ) ) { + // Detach the script and store it in the scripts array (if provided) or the fragment + // Return truthy to indicate that it has been handled + return scripts ? + scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : + fragment.appendChild( elem ); + } + }; + + for ( i = 0; (elem = ret[i]) != null; i++ ) { + // Check if we're done after handling an executable script + if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { + // Append to fragment and handle embedded scripts + fragment.appendChild( elem ); + if ( typeof elem.getElementsByTagName !== "undefined" ) { + // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration + jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); + + // Splice the scripts into ret after their former ancestor and advance our index beyond them + ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); + i += jsTags.length; + } + } + } + } + + return ret; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var data, id, elem, type, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = jQuery.support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + jQuery.deletedIds.push( id ); + } + } + } + } + } +}); +// Limit scope pollution from any deprecated API +(function() { + +var matched, browser; + +// Use of jQuery.browser is frowned upon. +// More details: http://api.jquery.com/jQuery.browser +// jQuery.uaMatch maintained for back-compat +jQuery.uaMatch = function( ua ) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || + /(webkit)[ \/]([\w.]+)/.exec( ua ) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || + /(msie) ([\w.]+)/.exec( ua ) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; +}; + +matched = jQuery.uaMatch( navigator.userAgent ); +browser = {}; + +if ( matched.browser ) { + browser[ matched.browser ] = true; + browser.version = matched.version; +} + +// Chrome is Webkit, but Webkit is also Safari. +if ( browser.chrome ) { + browser.webkit = true; +} else if ( browser.webkit ) { + browser.safari = true; +} + +jQuery.browser = browser; + +jQuery.sub = function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; +}; + +})(); +var curCSS, iframe, iframeDoc, + ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity=([^)]*)/, + rposition = /^(top|right|bottom|left)$/, + // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rmargin = /^margin/, + rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), + rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), + rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), + elemdisplay = { BODY: "block" }, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: 0, + fontWeight: 400 + }, + + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], + + eventsToggle = jQuery.fn.toggle; + +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + +function isHidden( elem, el ) { + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); +} + +function showHide( elements, show ) { + var elem, display, + values = [], + index = 0, + length = elements.length; + + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + values[ index ] = jQuery._data( elem, "olddisplay" ); + if ( show ) { + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !values[ index ] && elem.style.display === "none" ) { + elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); + } + } else { + display = curCSS( elem, "display" ); + + if ( !values[ index ] && display !== "none" ) { + jQuery._data( elem, "olddisplay", display ); + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( index = 0; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + if ( !show || elem.style.display === "none" || elem.style.display === "" ) { + elem.style.display = show ? values[ index ] || "" : "none"; + } + } + + return elements; +} + +jQuery.fn.extend({ + css: function( name, value ) { + return jQuery.access( this, function( elem, name, value ) { + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + }, + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state, fn2 ) { + var bool = typeof state === "boolean"; + + if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { + return eventsToggle.apply( this, arguments ); + } + + return this.each(function() { + if ( bool ? state : isHidden( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + }); + } +}); + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + + } + } + } + }, + + // Exclude the following css properties to add px + cssNumber: { + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // Make sure that NaN and null values aren't set. See: #7116 + if ( value == null || type === "number" && isNaN( value ) ) { + return; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, numeric, extra ) { + var val, num, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name ); + } + + //convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Return, converting to number if forced or a qualifier was provided and val looks numeric + if ( numeric || extra !== undefined ) { + num = parseFloat( val ); + return numeric || jQuery.isNumeric( num ) ? num || 0 : val; + } + return val; + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; + } +}); + +// NOTE: To any future maintainer, we've window.getComputedStyle +// because jsdom on node.js will break without it. +if ( window.getComputedStyle ) { + curCSS = function( elem, name ) { + var ret, width, minWidth, maxWidth, + computed = window.getComputedStyle( elem, null ), + style = elem.style; + + if ( computed ) { + + // getPropertyValue is only needed for .css('filter') in IE9, see #12537 + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right + // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels + // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret; + }; +} else if ( document.documentElement.currentStyle ) { + curCSS = function( elem, name ) { + var left, rsLeft, + ret = elem.currentStyle && elem.currentStyle[ name ], + style = elem.style; + + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && style[ name ] ) { + ret = style[ name ]; + } + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + // but not position css attributes, as those are proportional to the parent element instead + // and we can't measure the parent instead because it might trigger a "stacking dolls" problem + if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { + + // Remember the original values + left = style.left; + rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + elem.runtimeStyle.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : ret; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + elem.runtimeStyle.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +function setPositiveNumber( elem, value, subtract ) { + var matches = rnumsplit.exec( value ); + return matches ? + Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + // If we already have the right measurement, avoid augmentation + 4 : + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + // both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + // we use jQuery.css instead of curCSS here + // because of the reliableMarginRight CSS hook! + val += jQuery.css( elem, extra + cssExpand[ i ], true ); + } + + // From this point on we use curCSS for maximum performance (relevant in animations) + if ( isBorderBox ) { + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; + } + + // at this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + } else { + // at this point, extra isn't content, so add padding + val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; + + // at this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + valueIsBorderBox = true, + isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; + + // some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // we need the check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox + ) + ) + "px"; +} + + +// Try to determine the default display value of an element +function css_defaultDisplay( nodeName ) { + if ( elemdisplay[ nodeName ] ) { + return elemdisplay[ nodeName ]; + } + + var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), + display = elem.css("display"); + elem.remove(); + + // If the simple way fails, + // get element's real default display by attaching it to a temp iframe + if ( display === "none" || display === "" ) { + // Use the already-created iframe if possible + iframe = document.body.appendChild( + iframe || jQuery.extend( document.createElement("iframe"), { + frameBorder: 0, + width: 0, + height: 0 + }) + ); + + // Create a cacheable copy of the iframe document on first call. + // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML + // document to it; WebKit & Firefox won't allow reusing the iframe document. + if ( !iframeDoc || !iframe.createElement ) { + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; + iframeDoc.write(""); + iframeDoc.close(); + } + + elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); + + display = curCSS( elem, "display" ); + document.body.removeChild( iframe ); + } + + // Store the correct default display + elemdisplay[ nodeName ] = display; + + return display; +} + +jQuery.each([ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + // certain elements can have dimension info if we invisibly show them + // however, it must have a current display style that would benefit from this + if ( elem.offsetWidth === 0 && rdisplayswap.test( curCSS( elem, "display" ) ) ) { + return jQuery.swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + }); + } else { + return getWidthOrHeight( elem, name, extra ); + } + } + }, + + set: function( elem, value, extra ) { + return setPositiveNumber( elem, value, extra ? + augmentWidthOrHeight( + elem, + name, + extra, + jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" + ) : 0 + ); + } + }; +}); + +if ( !jQuery.support.opacity ) { + jQuery.cssHooks.opacity = { + get: function( elem, computed ) { + // IE uses filters for opacity + return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? + ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : + computed ? "1" : ""; + }, + + set: function( elem, value ) { + var style = elem.style, + currentStyle = elem.currentStyle, + opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", + filter = currentStyle && currentStyle.filter || style.filter || ""; + + // IE has trouble with opacity if it does not have layout + // Force it by setting the zoom level + style.zoom = 1; + + // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 + if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && + style.removeAttribute ) { + + // Setting style.filter to null, "" & " " still leave "filter:" in the cssText + // if "filter:" is present at all, clearType is disabled, we want to avoid this + // style.removeAttribute is IE Only, but so apparently is this code path... + style.removeAttribute( "filter" ); + + // if there there is no filter style applied in a css rule, we are done + if ( currentStyle && !currentStyle.filter ) { + return; + } + } + + // otherwise, set new filter values + style.filter = ralpha.test( filter ) ? + filter.replace( ralpha, opacity ) : + filter + " " + opacity; + } + }; +} + +// These hooks cannot be added until DOM ready because the support test +// for it is not run until after DOM ready +jQuery(function() { + if ( !jQuery.support.reliableMarginRight ) { + jQuery.cssHooks.marginRight = { + get: function( elem, computed ) { + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + // Work around by temporarily setting element display to inline-block + return jQuery.swap( elem, { "display": "inline-block" }, function() { + if ( computed ) { + return curCSS( elem, "marginRight" ); + } + }); + } + }; + } + + // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 + // getComputedStyle returns percent when specified for top/left/bottom/right + // rather than make the css module depend on the offset module, we just check for it here + if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { + jQuery.each( [ "top", "left" ], function( i, prop ) { + jQuery.cssHooks[ prop ] = { + get: function( elem, computed ) { + if ( computed ) { + var ret = curCSS( elem, prop ); + // if curCSS returns percentage, fallback to offset + return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; + } + } + }; + }); + } + +}); + +if ( jQuery.expr && jQuery.expr.filters ) { + jQuery.expr.filters.hidden = function( elem ) { + return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); + }; + + jQuery.expr.filters.visible = function( elem ) { + return !jQuery.expr.filters.hidden( elem ); + }; +} + +// These hooks are used by animate to expand properties +jQuery.each({ + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i, + + // assumes a single number if not a string + parts = typeof value === "string" ? value.split(" ") : [ value ], + expanded = {}; + + for ( i = 0; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +}); +var r20 = /%20/g, + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, + rselectTextarea = /^(?:select|textarea)/i; + +jQuery.fn.extend({ + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map(function(){ + return this.elements ? jQuery.makeArray( this.elements ) : this; + }) + .filter(function(){ + return this.name && !this.disabled && + ( this.checked || rselectTextarea.test( this.nodeName ) || + rinput.test( this.type ) ); + }) + .map(function( i, elem ){ + var val = jQuery( this ).val(); + + return val == null ? + null : + jQuery.isArray( val ) ? + jQuery.map( val, function( val, i ){ + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }) : + { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }).get(); + } +}); + +//Serialize an array of form elements or a set of +//key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, value ) { + // If value is a function, invoke it and return its value + value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); + s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); + }; + + // Set traditional to true for jQuery <= 1.3.2 behavior. + if ( traditional === undefined ) { + traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + }); + + } else { + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ).replace( r20, "+" ); +}; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( jQuery.isArray( obj ) ) { + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + // If array item is non-scalar (array or object), encode its + // numeric index to resolve deserialization ambiguity issues. + // Note that rack (as of 1.0.0) can't currently deserialize + // nested arrays properly, and attempting to do so may cause + // a server error. Possible fixes are to modify rack's + // deserialization algorithm or to provide an option or flag + // to force array serialization to be shallow. + buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); + } + }); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + // Serialize scalar item. + add( prefix, obj ); + } +} +var + // Document location + ajaxLocParts, + ajaxLocation, + + rhash = /#.*$/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + rquery = /\?/, + rscript = /)<[^<]*)*<\/script>/gi, + rts = /([?&])_=[^&]*/, + rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, + + // Keep a copy of the old load method + _load = jQuery.fn.load, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = ["*/"] + ["*"]; + +// #8138, IE may throw an exception when accessing +// a field from window.location if document.domain has been set +try { + ajaxLocation = location.href; +} catch( e ) { + // Use the href attribute of an A element + // since IE will modify it given document.location + ajaxLocation = document.createElement( "a" ); + ajaxLocation.href = ""; + ajaxLocation = ajaxLocation.href; +} + +// Segment location into parts +ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, list, placeBefore, + dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), + i = 0, + length = dataTypes.length; + + if ( jQuery.isFunction( func ) ) { + // For each dataType in the dataTypeExpression + for ( ; i < length; i++ ) { + dataType = dataTypes[ i ]; + // We control if we're asked to add before + // any existing element + placeBefore = /^\+/.test( dataType ); + if ( placeBefore ) { + dataType = dataType.substr( 1 ) || "*"; + } + list = structure[ dataType ] = structure[ dataType ] || []; + // then we add to the structure accordingly + list[ placeBefore ? "unshift" : "push" ]( func ); + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, + dataType /* internal */, inspected /* internal */ ) { + + dataType = dataType || options.dataTypes[ 0 ]; + inspected = inspected || {}; + + inspected[ dataType ] = true; + + var selection, + list = structure[ dataType ], + i = 0, + length = list ? list.length : 0, + executeOnly = ( structure === prefilters ); + + for ( ; i < length && ( executeOnly || !selection ); i++ ) { + selection = list[ i ]( options, originalOptions, jqXHR ); + // If we got redirected to another dataType + // we try there if executing only and not done already + if ( typeof selection === "string" ) { + if ( !executeOnly || inspected[ selection ] ) { + selection = undefined; + } else { + options.dataTypes.unshift( selection ); + selection = inspectPrefiltersOrTransports( + structure, options, originalOptions, jqXHR, selection, inspected ); + } + } + } + // If we're only executing or nothing was selected + // we try the catchall dataType if not done already + if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { + selection = inspectPrefiltersOrTransports( + structure, options, originalOptions, jqXHR, "*", inspected ); + } + // unnecessary when only executing (prefilters) + // but it'll be ignored by the caller in that case + return selection; +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } +} + +jQuery.fn.load = function( url, params, callback ) { + if ( typeof url !== "string" && _load ) { + return _load.apply( this, arguments ); + } + + // Don't do a request if no elements are being requested + if ( !this.length ) { + return this; + } + + var selector, type, response, + self = this, + off = url.indexOf(" "); + + if ( off >= 0 ) { + selector = url.slice( off, url.length ); + url = url.slice( 0, off ); + } + + // If it's a function + if ( jQuery.isFunction( params ) ) { + + // We assume that it's the callback + callback = params; + params = undefined; + + // Otherwise, build a param string + } else if ( params && typeof params === "object" ) { + type = "POST"; + } + + // Request the remote document + jQuery.ajax({ + url: url, + + // if "type" variable is undefined, then "GET" method will be used + type: type, + dataType: "html", + data: params, + complete: function( jqXHR, status ) { + if ( callback ) { + self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); + } + } + }).done(function( responseText ) { + + // Save response for use in complete callback + response = arguments; + + // See if a selector was specified + self.html( selector ? + + // Create a dummy div to hold the results + jQuery("
") + + // inject the contents of the document in, removing the scripts + // to avoid any 'Permission Denied' errors in IE + .append( responseText.replace( rscript, "" ) ) + + // Locate the specified elements + .find( selector ) : + + // If not, just inject the full result + responseText ); + + }); + + return this; +}; + +// Attach a bunch of functions for handling common AJAX events +jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ + jQuery.fn[ o ] = function( f ){ + return this.on( o, f ); + }; +}); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + // shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + return jQuery.ajax({ + type: method, + url: url, + data: data, + success: callback, + dataType: type + }); + }; +}); + +jQuery.extend({ + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + if ( settings ) { + // Building a settings object + ajaxExtend( target, jQuery.ajaxSettings ); + } else { + // Extending ajaxSettings + settings = target; + target = jQuery.ajaxSettings; + } + ajaxExtend( target, settings ); + return target; + }, + + ajaxSettings: { + url: ajaxLocation, + isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), + global: true, + type: "GET", + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + processData: true, + async: true, + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + xml: "application/xml, text/xml", + html: "text/html", + text: "text/plain", + json: "application/json, text/javascript", + "*": allTypes + }, + + contents: { + xml: /xml/, + html: /html/, + json: /json/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText" + }, + + // List of data converters + // 1) key format is "source_type destination_type" (a single space in-between) + // 2) the catchall symbol "*" can be used for source_type + converters: { + + // Convert anything to text + "* text": window.String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": jQuery.parseJSON, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + context: true, + url: true + } + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var // ifModified key + ifModifiedKey, + // Response headers + responseHeadersString, + responseHeaders, + // transport + transport, + // timeout handle + timeoutTimer, + // Cross-domain detection vars + parts, + // To know if global events are to be dispatched + fireGlobals, + // Loop variable + i, + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + // Callbacks context + callbackContext = s.context || s, + // Context for global events + // It's the callbackContext if one was provided in the options + // and if it's a DOM node or a jQuery collection + globalEventContext = callbackContext !== s && + ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? + jQuery( callbackContext ) : jQuery.event, + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + // Status-dependent callbacks + statusCode = s.statusCode || {}, + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + // The jqXHR state + state = 0, + // Default abort message + strAbort = "canceled", + // Fake xhr + jqXHR = { + + readyState: 0, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( !state ) { + var lname = name.toLowerCase(); + name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Raw string + getAllResponseHeaders: function() { + return state === 2 ? responseHeadersString : null; + }, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( state === 2 ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match === undefined ? null : match; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( !state ) { + s.mimeType = type; + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + statusText = statusText || strAbort; + if ( transport ) { + transport.abort( statusText ); + } + done( 0, statusText ); + return this; + } + }; + + // Callback for when everything is done + // It is defined here because jslint complains if it is declared + // at the end of the function (which would be more logical and readable) + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Called once + if ( state === 2 ) { + return; + } + + // State is "done" now + state = 2; + + // Clear timeout if it exists + if ( timeoutTimer ) { + clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // If successful, handle type chaining + if ( status >= 200 && status < 300 || status === 304 ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + + modified = jqXHR.getResponseHeader("Last-Modified"); + if ( modified ) { + jQuery.lastModified[ ifModifiedKey ] = modified; + } + modified = jqXHR.getResponseHeader("Etag"); + if ( modified ) { + jQuery.etag[ ifModifiedKey ] = modified; + } + } + + // If not modified + if ( status === 304 ) { + + statusText = "notmodified"; + isSuccess = true; + + // If we have data + } else { + + isSuccess = ajaxConvert( s, response ); + statusText = isSuccess.state; + success = isSuccess.data; + error = isSuccess.error; + isSuccess = !error; + } + } else { + // We extract error from statusText + // then normalize statusText and status for non-aborts + error = statusText; + if ( !statusText || status ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + // Attach deferreds + deferred.promise( jqXHR ); + jqXHR.success = jqXHR.done; + jqXHR.error = jqXHR.fail; + jqXHR.complete = completeDeferred.add; + + // Status-dependent callbacks + jqXHR.statusCode = function( map ) { + if ( map ) { + var tmp; + if ( state < 2 ) { + for ( tmp in map ) { + statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; + } + } else { + tmp = map[ jqXHR.status ]; + jqXHR.always( tmp ); + } + } + return this; + }; + + // Remove hash character (#7531: and string promotion) + // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) + // We also use the url parameter if available + s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); + + // Extract dataTypes list + s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); + + // A cross-domain request is in order when we have a protocol:host:port mismatch + if ( s.crossDomain == null ) { + parts = rurl.exec( s.url.toLowerCase() ); + s.crossDomain = !!( parts && + ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] || + ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != + ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) + ); + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( state === 2 ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + fireGlobals = s.global; + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // If data is available, append data to url + if ( s.data ) { + s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Get ifModifiedKey before adding the anti-cache parameter + ifModifiedKey = s.url; + + // Add anti-cache in url if needed + if ( s.cache === false ) { + + var ts = jQuery.now(), + // try replacing _= if it is there + ret = s.url.replace( rts, "$1_=" + ts ); + + // if nothing was replaced, add timestamp to the end + s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + ifModifiedKey = ifModifiedKey || s.url; + if ( jQuery.lastModified[ ifModifiedKey ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); + } + if ( jQuery.etag[ ifModifiedKey ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); + } + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? + s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { + // Abort if not done already and return + return jqXHR.abort(); + + } + + // aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + for ( i in { success: 1, error: 1, complete: 1 } ) { + jqXHR[ i ]( s[ i ] ); + } + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = setTimeout( function(){ + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + state = 1; + transport.send( requestHeaders, done ); + } catch (e) { + // Propagate exception as error if not done + if ( state < 2 ) { + done( -1, e ); + // Simply rethrow otherwise + } else { + throw e; + } + } + } + + return jqXHR; + }, + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {} + +}); + +/* Handles responses to an ajax request: + * - sets all responseXXX fields accordingly + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes, + responseFields = s.responseFields; + + // Fill responseXXX fields + for ( type in responseFields ) { + if ( type in responses ) { + jqXHR[ responseFields[type] ] = responses[ type ]; + } + } + + // Remove auto dataType and get content-type in the process + while( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +// Chain conversions given the request and the original response +function ajaxConvert( s, response ) { + + var conv, conv2, current, tmp, + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(), + prev = dataTypes[ 0 ], + converters = {}, + i = 0; + + // Apply the dataFilter if provided + if ( s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + // Convert to each sequential dataType, tolerating list modification + for ( ; (current = dataTypes[++i]); ) { + + // There's only work to do if current dataType is non-auto + if ( current !== "*" ) { + + // Convert response if prev dataType is non-auto and differs from current + if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split(" "); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.splice( i--, 0, current ); + } + + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s["throws"] ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; + } + } + } + } + + // Update prev for next iteration + prev = current; + } + } + + return { state: "success", data: response }; +} +var oldCallbacks = [], + rquestion = /\?/, + rjsonp = /(=)\?(?=&|$)|\?\?/, + nonce = jQuery.now(); + +// Default jsonp settings +jQuery.ajaxSetup({ + jsonp: "callback", + jsonpCallback: function() { + var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); + this[ callback ] = true; + return callback; + } +}); + +// Detect, normalize options and install callbacks for jsonp requests +jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { + + var callbackName, overwritten, responseContainer, + data = s.data, + url = s.url, + hasCallback = s.jsonp !== false, + replaceInUrl = hasCallback && rjsonp.test( url ), + replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && + !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && + rjsonp.test( data ); + + // Handle iff the expected data type is "jsonp" or we have a parameter to set + if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { + + // Get callback name, remembering preexisting value associated with it + callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? + s.jsonpCallback() : + s.jsonpCallback; + overwritten = window[ callbackName ]; + + // Insert callback into url or form data + if ( replaceInUrl ) { + s.url = url.replace( rjsonp, "$1" + callbackName ); + } else if ( replaceInData ) { + s.data = data.replace( rjsonp, "$1" + callbackName ); + } else if ( hasCallback ) { + s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; + } + + // Use data converter to retrieve json after script execution + s.converters["script json"] = function() { + if ( !responseContainer ) { + jQuery.error( callbackName + " was not called" ); + } + return responseContainer[ 0 ]; + }; + + // force json dataType + s.dataTypes[ 0 ] = "json"; + + // Install callback + window[ callbackName ] = function() { + responseContainer = arguments; + }; + + // Clean-up function (fires after converters) + jqXHR.always(function() { + // Restore preexisting value + window[ callbackName ] = overwritten; + + // Save back as free + if ( s[ callbackName ] ) { + // make sure that re-using the options doesn't screw things around + s.jsonpCallback = originalSettings.jsonpCallback; + + // save the callback name for future use + oldCallbacks.push( callbackName ); + } + + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( overwritten ) ) { + overwritten( responseContainer[ 0 ] ); + } + + responseContainer = overwritten = undefined; + }); + + // Delegate to script + return "script"; + } +}); +// Install script dataType +jQuery.ajaxSetup({ + accepts: { + script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /javascript|ecmascript/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +}); + +// Handle cache's special case and global +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + s.global = false; + } +}); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function(s) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + + var script, + head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; + + return { + + send: function( _, callback ) { + + script = document.createElement( "script" ); + + script.async = "async"; + + if ( s.scriptCharset ) { + script.charset = s.scriptCharset; + } + + script.src = s.url; + + // Attach handlers for all browsers + script.onload = script.onreadystatechange = function( _, isAbort ) { + + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { + + // Handle memory leak in IE + script.onload = script.onreadystatechange = null; + + // Remove the script + if ( head && script.parentNode ) { + head.removeChild( script ); + } + + // Dereference the script + script = undefined; + + // Callback if not abort + if ( !isAbort ) { + callback( 200, "success" ); + } + } + }; + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709 and #4378). + head.insertBefore( script, head.firstChild ); + }, + + abort: function() { + if ( script ) { + script.onload( 0, 1 ); + } + } + }; + } +}); +var xhrCallbacks, + // #5280: Internet Explorer will keep connections alive if we don't abort on unload + xhrOnUnloadAbort = window.ActiveXObject ? function() { + // Abort all pending requests + for ( var key in xhrCallbacks ) { + xhrCallbacks[ key ]( 0, 1 ); + } + } : false, + xhrId = 0; + +// Functions to create xhrs +function createStandardXHR() { + try { + return new window.XMLHttpRequest(); + } catch( e ) {} +} + +function createActiveXHR() { + try { + return new window.ActiveXObject( "Microsoft.XMLHTTP" ); + } catch( e ) {} +} + +// Create the request object +// (This is still attached to ajaxSettings for backward compatibility) +jQuery.ajaxSettings.xhr = window.ActiveXObject ? + /* Microsoft failed to properly + * implement the XMLHttpRequest in IE7 (can't request local files), + * so we use the ActiveXObject when it is available + * Additionally XMLHttpRequest can be disabled in IE7/IE8 so + * we need a fallback. + */ + function() { + return !this.isLocal && createStandardXHR() || createActiveXHR(); + } : + // For all other browsers, use the standard XMLHttpRequest object + createStandardXHR; + +// Determine support properties +(function( xhr ) { + jQuery.extend( jQuery.support, { + ajax: !!xhr, + cors: !!xhr && ( "withCredentials" in xhr ) + }); +})( jQuery.ajaxSettings.xhr() ); + +// Create transport if the browser can provide an xhr +if ( jQuery.support.ajax ) { + + jQuery.ajaxTransport(function( s ) { + // Cross domain only allowed if supported through XMLHttpRequest + if ( !s.crossDomain || jQuery.support.cors ) { + + var callback; + + return { + send: function( headers, complete ) { + + // Get a new xhr + var handle, i, + xhr = s.xhr(); + + // Open the socket + // Passing null username, generates a login popup on Opera (#2865) + if ( s.username ) { + xhr.open( s.type, s.url, s.async, s.username, s.password ); + } else { + xhr.open( s.type, s.url, s.async ); + } + + // Apply custom fields if provided + if ( s.xhrFields ) { + for ( i in s.xhrFields ) { + xhr[ i ] = s.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( s.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( s.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !s.crossDomain && !headers["X-Requested-With"] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Need an extra try/catch for cross domain requests in Firefox 3 + try { + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + } catch( _ ) {} + + // Do send the request + // This may raise an exception which is actually + // handled in jQuery.ajax (so no try/catch here) + xhr.send( ( s.hasContent && s.data ) || null ); + + // Listener + callback = function( _, isAbort ) { + + var status, + statusText, + responseHeaders, + responses, + xml; + + // Firefox throws exceptions when accessing properties + // of an xhr when a network error occurred + // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) + try { + + // Was never called and is aborted or complete + if ( callback && ( isAbort || xhr.readyState === 4 ) ) { + + // Only called once + callback = undefined; + + // Do not keep as active anymore + if ( handle ) { + xhr.onreadystatechange = jQuery.noop; + if ( xhrOnUnloadAbort ) { + delete xhrCallbacks[ handle ]; + } + } + + // If it's an abort + if ( isAbort ) { + // Abort it manually if needed + if ( xhr.readyState !== 4 ) { + xhr.abort(); + } + } else { + status = xhr.status; + responseHeaders = xhr.getAllResponseHeaders(); + responses = {}; + xml = xhr.responseXML; + + // Construct response list + if ( xml && xml.documentElement /* #4958 */ ) { + responses.xml = xml; + } + + // When requesting binary data, IE6-9 will throw an exception + // on any attempt to access responseText (#11426) + try { + responses.text = xhr.responseText; + } catch( e ) { + } + + // Firefox throws an exception when accessing + // statusText for faulty cross-domain requests + try { + statusText = xhr.statusText; + } catch( e ) { + // We normalize with Webkit giving an empty statusText + statusText = ""; + } + + // Filter status for non standard behaviors + + // If the request is local and we have data: assume a success + // (success with no data won't get notified, that's the best we + // can do given current implementations) + if ( !status && s.isLocal && !s.crossDomain ) { + status = responses.text ? 200 : 404; + // IE - #1450: sometimes returns 1223 when it should be 204 + } else if ( status === 1223 ) { + status = 204; + } + } + } + } catch( firefoxAccessException ) { + if ( !isAbort ) { + complete( -1, firefoxAccessException ); + } + } + + // Call complete if needed + if ( responses ) { + complete( status, statusText, responses, responseHeaders ); + } + }; + + if ( !s.async ) { + // if we're in sync mode we fire the callback + callback(); + } else if ( xhr.readyState === 4 ) { + // (IE6 & IE7) if it's in cache and has been + // retrieved directly we need to fire the callback + setTimeout( callback, 0 ); + } else { + handle = ++xhrId; + if ( xhrOnUnloadAbort ) { + // Create the active xhrs callbacks list if needed + // and attach the unload handler + if ( !xhrCallbacks ) { + xhrCallbacks = {}; + jQuery( window ).unload( xhrOnUnloadAbort ); + } + // Add to list of active xhrs callbacks + xhrCallbacks[ handle ] = callback; + } + xhr.onreadystatechange = callback; + } + }, + + abort: function() { + if ( callback ) { + callback(0,1); + } + } + }; + } + }); +} +var fxNow, timerId, + rfxtypes = /^(?:toggle|show|hide)$/, + rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), + rrun = /queueHooks$/, + animationPrefilters = [ defaultPrefilter ], + tweeners = { + "*": [function( prop, value ) { + var end, unit, + tween = this.createTween( prop, value ), + parts = rfxnum.exec( value ), + target = tween.cur(), + start = +target || 0, + scale = 1, + maxIterations = 20; + + if ( parts ) { + end = +parts[2]; + unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + + // We need to compute starting value + if ( unit !== "px" && start ) { + // Iteratively approximate from a nonzero starting point + // Prefer the current property, because this process will be trivial if it uses the same units + // Fallback to end or a simple constant + start = jQuery.css( tween.elem, prop, true ) || end || 1; + + do { + // If previous iteration zeroed out, double until we get *something* + // Use a string for doubling factor so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + start = start / scale; + jQuery.style( tween.elem, prop, start + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // And breaking the loop if scale is unchanged or perfect, or if we've just had enough + } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations ); + } + + tween.unit = unit; + tween.start = start; + // If a +=/-= token was provided, we're doing a relative animation + tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; + } + return tween; + }] + }; + +// Animations created synchronously will run synchronously +function createFxNow() { + setTimeout(function() { + fxNow = undefined; + }, 0 ); + return ( fxNow = jQuery.now() ); +} + +function createTweens( animation, props ) { + jQuery.each( props, function( prop, value ) { + var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( collection[ index ].call( animation, prop, value ) ) { + + // we're done with this property + return; + } + } + }); +} + +function Animation( elem, properties, options ) { + var result, + index = 0, + tweenerIndex = 0, + length = animationPrefilters.length, + deferred = jQuery.Deferred().always( function() { + // don't match elem in the :animated selector + delete tick.elem; + }), + tick = function() { + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length ; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ]); + + if ( percent < 1 && length ) { + return remaining; + } else { + deferred.resolveWith( elem, [ animation ] ); + return false; + } + }, + animation = deferred.promise({ + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { specialEasing: {} }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end, easing ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + // if we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + + for ( ; index < length ; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // resolve when we played the last frame + // otherwise, reject + if ( gotoEnd ) { + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + }), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length ; index++ ) { + result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + return result; + } + } + + createTweens( animation, props ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + jQuery.fx.timer( + jQuery.extend( tick, { + anim: animation, + queue: animation.opts.queue, + elem: elem + }) + ); + + // attach callbacks from options + return animation.progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( jQuery.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // not quite $.extend, this wont overwrite keys already present. + // also - reusing 'index' from above because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.split(" "); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length ; index++ ) { + prop = props[ index ]; + tweeners[ prop ] = tweeners[ prop ] || []; + tweeners[ prop ].unshift( callback ); + } + }, + + prefilter: function( callback, prepend ) { + if ( prepend ) { + animationPrefilters.unshift( callback ); + } else { + animationPrefilters.push( callback ); + } + } +}); + +function defaultPrefilter( elem, props, opts ) { + var index, prop, value, length, dataShow, toggle, tween, hooks, oldfire, + anim = this, + style = elem.style, + orig = {}, + handled = [], + hidden = elem.nodeType && isHidden( elem ); + + // handle queue: false promises + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always(function() { + // doing this makes sure that the complete handler will be called + // before this completes + anim.always(function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + }); + }); + } + + // height/width overflow pass + if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { + // Make sure that nothing sneaks out + // Record all 3 overflow attributes because IE does not + // change the overflow attribute when overflowX and + // overflowY are set to the same value + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Set display property to inline-block for height/width + // animations on inline elements that are having width/height animated + if ( jQuery.css( elem, "display" ) === "inline" && + jQuery.css( elem, "float" ) === "none" ) { + + // inline-level elements accept inline-block; + // block-level elements need to be inline with layout + if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { + style.display = "inline-block"; + + } else { + style.zoom = 1; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + if ( !jQuery.support.shrinkWrapBlocks ) { + anim.done(function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + }); + } + } + + + // show/hide pass + for ( index in props ) { + value = props[ index ]; + if ( rfxtypes.exec( value ) ) { + delete props[ index ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + continue; + } + handled.push( index ); + } + } + + length = handled.length; + if ( length ) { + dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + + // store state if its toggle - enables .stop().toggle() to "reverse" + if ( toggle ) { + dataShow.hidden = !hidden; + } + if ( hidden ) { + jQuery( elem ).show(); + } else { + anim.done(function() { + jQuery( elem ).hide(); + }); + } + anim.done(function() { + var prop; + jQuery.removeData( elem, "fxshow", true ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + }); + for ( index = 0 ; index < length ; index++ ) { + prop = handled[ index ]; + tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); + orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); + + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = tween.start; + if ( hidden ) { + tween.end = tween.start; + tween.start = prop === "width" || prop === "height" ? 1 : 0; + } + } + } + } +} + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || "swing"; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + if ( tween.elem[ tween.prop ] != null && + (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { + return tween.elem[ tween.prop ]; + } + + // passing any value as a 4th parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails + // so, simple values such as "10px" are parsed to Float. + // complex values such as "rotate(1rad)" are returned as is. + result = jQuery.css( tween.elem, tween.prop, false, "" ); + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + // use step hook for back compat - use cssHook if its there - use .style if its + // available and use plain properties where available + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Remove in 2.0 - this supports IE8's panic based approach +// to setting things on disconnected nodes + +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" || + // special check for .toggle( handler, handler, ... ) + ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +}); + +jQuery.fn.extend({ + fadeTo: function( speed, to, easing, callback ) { + + // show any hidden elements after setting opacity to 0 + return this.filter( isHidden ).css( "opacity", 0 ).show() + + // animate to the value specified + .end().animate({ opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations resolve immediately + if ( empty ) { + anim.stop( true ); + } + }; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each(function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = jQuery._data( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // start the next in the queue if the last step wasn't forced + // timers currently will call their complete callbacks, which will dequeue + // but only if they were gotoEnd + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + }); + } +}); + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + attrs = { height: type }, + i = 0; + + // if we include width, step value is 1 to do all cssExpand values, + // if we don't include width, step value is 2 to skip over Left and Right + includeWidth = includeWidth? 1 : 0; + for( ; i < 4 ; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +// Generate shortcuts for custom animations +jQuery.each({ + slideDown: genFx("show"), + slideUp: genFx("hide"), + slideToggle: genFx("toggle"), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +}); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : + opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; + + // normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p*Math.PI ) / 2; + } +}; + +jQuery.timers = []; +jQuery.fx = Tween.prototype.init; +jQuery.fx.tick = function() { + var timer, + timers = jQuery.timers, + i = 0; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + // Checks the timer has not already been removed + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + if ( timer() && jQuery.timers.push( timer ) && !timerId ) { + timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); + } +}; + +jQuery.fx.interval = 13; + +jQuery.fx.stop = function() { + clearInterval( timerId ); + timerId = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + // Default speed + _default: 400 +}; + +// Back Compat <1.8 extension point +jQuery.fx.step = {}; + +if ( jQuery.expr && jQuery.expr.filters ) { + jQuery.expr.filters.animated = function( elem ) { + return jQuery.grep(jQuery.timers, function( fn ) { + return elem === fn.elem; + }).length; + }; +} +var rroot = /^(?:body|html)$/i; + +jQuery.fn.offset = function( options ) { + if ( arguments.length ) { + return options === undefined ? + this : + this.each(function( i ) { + jQuery.offset.setOffset( this, options, i ); + }); + } + + var docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, + box = { top: 0, left: 0 }, + elem = this[ 0 ], + doc = elem && elem.ownerDocument; + + if ( !doc ) { + return; + } + + if ( (body = doc.body) === elem ) { + return jQuery.offset.bodyOffset( elem ); + } + + docElem = doc.documentElement; + + // Make sure it's not a disconnected DOM node + if ( !jQuery.contains( docElem, elem ) ) { + return box; + } + + // If we don't have gBCR, just use 0,0 rather than error + // BlackBerry 5, iOS 3 (original iPhone) + if ( typeof elem.getBoundingClientRect !== "undefined" ) { + box = elem.getBoundingClientRect(); + } + win = getWindow( doc ); + clientTop = docElem.clientTop || body.clientTop || 0; + clientLeft = docElem.clientLeft || body.clientLeft || 0; + scrollTop = win.pageYOffset || docElem.scrollTop; + scrollLeft = win.pageXOffset || docElem.scrollLeft; + return { + top: box.top + scrollTop - clientTop, + left: box.left + scrollLeft - clientLeft + }; +}; + +jQuery.offset = { + + bodyOffset: function( body ) { + var top = body.offsetTop, + left = body.offsetLeft; + + if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { + top += parseFloat( jQuery.css(body, "marginTop") ) || 0; + left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; + } + + return { top: top, left: left }; + }, + + setOffset: function( elem, options, i ) { + var position = jQuery.css( elem, "position" ); + + // set position first, in-case top/left are set even on static elem + if ( position === "static" ) { + elem.style.position = "relative"; + } + + var curElem = jQuery( elem ), + curOffset = curElem.offset(), + curCSSTop = jQuery.css( elem, "top" ), + curCSSLeft = jQuery.css( elem, "left" ), + calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, + props = {}, curPosition = {}, curTop, curLeft; + + // need to be able to calculate position if either top or left is auto and position is either absolute or fixed + if ( calculatePosition ) { + curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; + } + + if ( jQuery.isFunction( options ) ) { + options = options.call( elem, i, curOffset ); + } + + if ( options.top != null ) { + props.top = ( options.top - curOffset.top ) + curTop; + } + if ( options.left != null ) { + props.left = ( options.left - curOffset.left ) + curLeft; + } + + if ( "using" in options ) { + options.using.call( elem, props ); + } else { + curElem.css( props ); + } + } +}; + + +jQuery.fn.extend({ + + position: function() { + if ( !this[0] ) { + return; + } + + var elem = this[0], + + // Get *real* offsetParent + offsetParent = this.offsetParent(), + + // Get correct offsets + offset = this.offset(), + parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; + offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; + + // Add offsetParent borders + parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; + parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + }; + }, + + offsetParent: function() { + return this.map(function() { + var offsetParent = this.offsetParent || document.body; + while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || document.body; + }); + } +}); + + +// Create scrollLeft and scrollTop methods +jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { + var top = /Y/.test( prop ); + + jQuery.fn[ method ] = function( val ) { + return jQuery.access( this, function( elem, method, val ) { + var win = getWindow( elem ); + + if ( val === undefined ) { + return win ? (prop in win) ? win[ prop ] : + win.document.documentElement[ method ] : + elem[ method ]; + } + + if ( win ) { + win.scrollTo( + !top ? val : jQuery( win ).scrollLeft(), + top ? val : jQuery( win ).scrollTop() + ); + + } else { + elem[ method ] = val; + } + }, method, val, arguments.length, null ); + }; +}); + +function getWindow( elem ) { + return jQuery.isWindow( elem ) ? + elem : + elem.nodeType === 9 ? + elem.defaultView || elem.parentWindow : + false; +} +// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods +jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { + jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { + // margin is only for outerHeight, outerWidth + jQuery.fn[ funcName ] = function( margin, value ) { + var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), + extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); + + return jQuery.access( this, function( elem, type, value ) { + var doc; + + if ( jQuery.isWindow( elem ) ) { + // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there + // isn't a whole lot we can do. See pull request at this URL for discussion: + // https://github.com/jquery/jquery/pull/764 + return elem.document.documentElement[ "client" + name ]; + } + + // Get document width or height + if ( elem.nodeType === 9 ) { + doc = elem.documentElement; + + // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest + // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. + return Math.max( + elem.body[ "scroll" + name ], doc[ "scroll" + name ], + elem.body[ "offset" + name ], doc[ "offset" + name ], + doc[ "client" + name ] + ); + } + + return value === undefined ? + // Get width or height on the element, requesting but not forcing parseFloat + jQuery.css( elem, type, value, extra ) : + + // Set width or height on the element + jQuery.style( elem, type, value, extra ); + }, type, chainable ? margin : undefined, chainable, null ); + }; + }); +}); +// Expose jQuery to the global object +window.jQuery = window.$ = jQuery; + +// Expose jQuery as an AMD module, but only for AMD loaders that +// understand the issues with loading multiple versions of jQuery +// in a page that all might call define(). The loader will indicate +// they have special allowances for multiple jQuery versions by +// specifying define.amd.jQuery = true. Register as a named module, +// since jQuery can be concatenated with other files that may use define, +// but not use a proper concatenation script that understands anonymous +// AMD modules. A named AMD is safest and most robust way to register. +// Lowercase jquery is used because AMD module names are derived from +// file names, and jQuery is normally delivered in a lowercase file name. +// Do this after creating the global so that if an AMD module wants to call +// noConflict to hide this version of jQuery, it will work. +if ( typeof define === "function" && define.amd && define.amd.jQuery ) { + define( "jquery", [], function () { return jQuery; } ); +} + +})( window ); diff --git a/extern/phmap/benchmark/js/jquery.mousewheel.js b/extern/phmap/benchmark/js/jquery.mousewheel.js new file mode 100644 index 0000000..a999c63 --- /dev/null +++ b/extern/phmap/benchmark/js/jquery.mousewheel.js @@ -0,0 +1,86 @@ +// Source: https://github.com/jquery/jquery-mousewheel/blob/a06ef4e1a127795606642c55e22d4f2945edc061/jquery.mousewheel.js + +/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) + * Licensed under the MIT License (LICENSE.txt). + * + * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. + * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. + * Thanks to: Seamus Leahy for adding deltaX and deltaY + * + * Version: 3.0.6 + * + * Requires: 1.2.2+ + */ + +(function($) { + +var types = ['DOMMouseScroll', 'mousewheel']; + +if ($.event.fixHooks) { + for ( var i=types.length; i; ) { + $.event.fixHooks[ types[--i] ] = $.event.mouseHooks; + } +} + +$.event.special.mousewheel = { + setup: function() { + if ( this.addEventListener ) { + for ( var i=types.length; i; ) { + this.addEventListener( types[--i], handler, false ); + } + } else { + this.onmousewheel = handler; + } + }, + + teardown: function() { + if ( this.removeEventListener ) { + for ( var i=types.length; i; ) { + this.removeEventListener( types[--i], handler, false ); + } + } else { + this.onmousewheel = null; + } + } +}; + +$.fn.extend({ + mousewheel: function(fn) { + return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); + }, + + unmousewheel: function(fn) { + return this.unbind("mousewheel", fn); + } +}); + + +function handler(event) { + var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0; + event = $.event.fix(orgEvent); + event.type = "mousewheel"; + + // Old school scrollwheel delta + if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; } + if ( orgEvent.detail ) { delta = -orgEvent.detail/3; } + + // New school multidimensional scroll (touchpads) deltas + deltaY = delta; + + // Gecko + if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { + deltaY = 0; + deltaX = -1*delta; + } + + // Webkit + if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; } + if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; } + + // Add event and delta to the front of the arguments + args.unshift(event, delta, deltaX, deltaY); + + return ($.event.dispatch || $.event.handle).apply(this, args); +} + +})(jQuery); diff --git a/extern/phmap/benchmark/make_chart_data.py b/extern/phmap/benchmark/make_chart_data.py new file mode 100644 index 0000000..dc15f72 --- /dev/null +++ b/extern/phmap/benchmark/make_chart_data.py @@ -0,0 +1,151 @@ +# random,1310720,google_dense_hash_map,45621248,0.344362020493 +# random,2621440,glib_hash_table,109867008,1.01163601875 +# random,2621440,stl_unordered_map,130715648,1.73484396935 +# random,2621440,boost_unordered_map,108380160,1.11585187912 +# random,2621440,google_sparse_hash_map,37015552,1.76031804085 +# random,2621440,google_dense_hash_map,79175680,0.504401922226 +# random,5242880,glib_hash_table,210530304,1.86031603813 +# random,5242880,stl_unordered_map,250298368,3.81597208977 +# random,5242880,boost_unordered_map,192184320,2.63760495186 +# random,5242880,google_sparse_hash_map,62066688,3.93570995331 +# random,5242880,google_dense_hash_map,146284544,1.22620105743 +# random,10485760,glib_hash_table,411856896,4.16937494278 +# random,10485760,stl_unordered_map,490430464,7.91806197166 +# random,10485760,boost_unordered_map,359251968,7.52085900307 +# random,10485760,google_sparse_hash_map,111902720,8.11318516731 +# random,10485760,google_dense_hash_map,280502272,2.32930994034 +# random,20971520,glib_hash_table,814510080,8.32456207275 +# random,20971520,stl_unordered_map,971583488,16.1606841087 +# random,20971520,boost_unordered_map,692441088,24.5845990181 +# random,20971520,google_sparse_hash_map,211435520,16.2772600651 +# random,20971520,google_dense_hash_map,548937728,4.85360789299 +# random,41943040,glib_hash_table,1619816448,90.6313672066 + +import sys, json + +lines = [ line.strip() for line in sys.stdin if line.strip() ] + +by_benchtype = {} +benches = {} +programs = {} + +for line in lines: + benchtype, type, nkeys, program, value = line.split(',') + nkeys = int(nkeys) + programs[program] = 1 + + if (type == 'time'): + by_benchtype.setdefault("%s-runtime" % benchtype, {}).setdefault(program, []).append([nkeys, float(value)]) + else: + by_benchtype.setdefault("%s-memory" % benchtype, {}).setdefault(program, []).append([nkeys, int(value)]) + benches[benchtype] = 1 + +proper_names = { + 'std::unordered_map': 'std::unordered_map (1 thread)', + 'spp::sparse_hash_map': 'sparsepp (1 thread, use_spp_alloc)', + 'absl::flat_hash_map': 'absl::flat_hash_map (1 thread)', + 'phmap::flat_hash_map': 'phmap::flat_hash_map', + 'phmap::parallel_flat_hash_map': 'phmap::parallel_flat_hash_map (1 thread)', + 'phmap::parallel_flat_hash_map_mt': 'phmap::parallel_flat_hash_map (8 thread)', + 'absl::parallel_flat_hash_map': 'absl::parallel_flat_hash_map (1 thread)', + 'absl::parallel_flat_hash_map_mt': 'absl::parallel_flat_hash_map (8 threads)', + 'phmap::parallel_flat_hash_map_4': 'phmap::parallel_flat_hash_map (N=4, 8 threads)', + 'phmap::parallel_flat_hash_map_5': 'phmap::parallel_flat_hash_map (N=5, 8 threads)', + 'phmap::parallel_flat_hash_map_6': 'phmap::parallel_flat_hash_map (N=6, 8 threads)' +} + +proper_color = { + 'std::unordered_map': 0, + 'spp::sparse_hash_map': 0, + 'absl::flat_hash_map': 1, + 'phmap::flat_hash_map': 1, + 'phmap::parallel_flat_hash_map': 2, + 'phmap::parallel_flat_hash_map_mt': 2, + 'absl::parallel_flat_hash_map': 3, + 'absl::parallel_flat_hash_map_mt': 3, + 'phmap::parallel_flat_hash_map_4': 3, + 'phmap::parallel_flat_hash_map_5': 4, + 'phmap::parallel_flat_hash_map_6': 5 +} + +bench_titles = { + 'lookup': 'Random Lookup', + 'sequential' : 'Sequential Insert', + 'random' : 'Random Insert', + 'delete' : 'Deletion', + 'sequentialstring' : 'Sequential String Insert', + 'randomstring' : 'Random String Insert', + 'deletestring' : 'String Deletion' + } + +# do them in the desired order to make the legend not overlap the chart data +# too much +program_slugs = [ + 'std::unordered_map', + 'sparsepp', + 'absl::flat_hash_map', + 'phmap::flat_hash_map', + 'absl::parallel_flat_hash_map', + 'phmap::parallel_flat_hash_map', + 'phmap::parallel_flat_hash_map_mt', + 'absl::parallel_flat_hash_map_mt', + 'phmap::parallel_flat_hash_map_4', + 'phmap::parallel_flat_hash_map_5', + 'phmap::parallel_flat_hash_map_6' +] + +chart_data = {} + +for i, (benchtype, programs) in enumerate(by_benchtype.items()): + chart_data[benchtype] = [] + k = programs.keys() + k.sort() + for program in k: + data = programs.get(program, []) + chart_data[benchtype].append({ + 'label': proper_names[program], + 'color': proper_color[program], + 'data': [], + }) + + for k, (nkeys, value) in enumerate(data): + chart_data[benchtype][-1]['data'].append([nkeys, value]) + +html_chart_data = 'chart_data = ' + json.dumps(chart_data) + +## print chart_data['delete-runtime'] + +html_plot_spec = '' +for b in benches.keys(): + html_plot_spec += """ + $.plot($("#{0}-runtime"), chart_data['{0}-runtime'], runtime_settings); + $.plot($("#{0}-memory"), chart_data['{0}-memory'], memory_settings);""".format(b) + +html_div_spec = '' +first = 1 + +for b in benches.keys(): + if 1: + first = 0 + html_div_spec += """ +
{1} (integers): Memory Usage
+
+
number of entries in hash table
+""".format(b, bench_titles[b]) + + html_div_spec += """ +
{1} (integers): Execution Time
+
+
number of entries in hash table
+ +""".format(b, bench_titles[b]) + + + +html_template = file('charts-template.html', 'r').read() + +html_template = html_template.replace('__CHART_DATA_GOES_HERE__', html_chart_data) +html_template = html_template.replace('__PLOT_SPEC_GOES_HERE__', html_plot_spec) +html_template = html_template.replace('__PLOT_DIV_SPEC_GOES_HERE__', html_div_spec) + +file('charts.html', 'w').write(html_template) diff --git a/extern/phmap/benchmark/martinus/Vagrantfile b/extern/phmap/benchmark/martinus/Vagrantfile new file mode 100644 index 0000000..ede95d2 --- /dev/null +++ b/extern/phmap/benchmark/martinus/Vagrantfile @@ -0,0 +1,97 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure("2") do |config| + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + + # Every Vagrant development environment requires a box. You can search for + # boxes at https://atlas.hashicorp.com/search. + config.vm.box = "ubuntu/xenial64" + # sudo apt-get update + # sudo apt-get install -y build-essential + # sudo apt-get install -y cmake + # sudo apt-get install pkg-config zip g++ zlib1g-dev unzip python + # sudo apt-get install -y libboost1.55-dev + # wget https://github.com/bazelbuild/bazel/releases/download/0.22.0/bazel-0.22.0-installer-linux-x86_64.sh + # chmod +x ./bazel-0.22.0-installer-linux-x86_64.sh + # ./bazel-0.22.0-installer-linux-x86_64.sh + # ./bazel-bin/hashtable_benchmarks --benchmark_format=json > benchmark-results.json + + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + # config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + # config.vm.network "forwarded_port", guest: 80, host: 8080 + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + # config.vm.synced_folder "../data", "/vagrant_data" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + # + config.vm.provider "virtualbox" do |vb| + vb.customize ["modifyvm", :id, "--cableconnected1", "on"] + + # Display the VirtualBox GUI when booting the machine + vb.gui = false + + # Customize the amount of memory on the VM: + vb.memory = "16384" + end + # + # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies + # such as FTP and Heroku are also available. See the documentation at + # https://docs.vagrantup.com/v2/push/atlas.html for more information. + # config.push.define "atlas" do |push| + # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" + # end + + # Enable provisioning with a shell script. Additional provisioners such as + # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the + # documentation for more information about their specific syntax and use. + config.vm.provision "shell", inline: <<-SHELL + sudo apt-get update + sudo apt-get install -y build-essential + sudo apt-get install -y cmake + sudo apt-get install -y ninja-build + sudo apt-get install -y pkg-config zip zlib1g-dev unzip python python-pip + # for folly + sudo apt-get install -y libboost-all-dev libevent-dev libdouble-conversion-dev \ + libgoogle-glog-dev libgflags-dev libiberty-dev liblz4-dev liblzma-dev \ + libsnappy-dev zlib1g-dev binutils-dev libjemalloc-dev libssl-dev pkg-config + sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + sudo apt-get install -y python3 python3-pip + sudo apt-get update + sudo apt-get install -y gcc-8 g++-8 + python3 -m pip install --upgrade pip + python3 -m pip install perf + cd /vagrant + git clone --recurse-submodules https://github.com/greg7mdp/map_benchmark.git + ./map_benchmark/tools/build.sh + sudo apt install -y ruby-full + SHELL +end diff --git a/extern/phmap/benchmark/results/output_flat_par b/extern/phmap/benchmark/results/output_flat_par new file mode 100644 index 0000000..dbd9c01 --- /dev/null +++ b/extern/phmap/benchmark/results/output_flat_par @@ -0,0 +1,320 @@ +random,memory,0,phmap::flat_hash_map,15740928 +random,memory,240967,phmap::flat_hash_map,11272192 +random,memory,458751,phmap::flat_hash_map,11272192 +random,memory,458752,phmap::flat_hash_map,29138944 +random,memory,493930,phmap::flat_hash_map,20205568 +random,memory,678845,phmap::flat_hash_map,19087360 +random,memory,917503,phmap::flat_hash_map,19087360 +random,memory,917504,phmap::flat_hash_map,54812672 +random,memory,930488,phmap::flat_hash_map,36945920 +random,memory,1835007,phmap::flat_hash_map,36945920 +random,memory,1835008,phmap::flat_hash_map,108392448 +random,memory,1860950,phmap::flat_hash_map,72667136 +random,memory,3670015,phmap::flat_hash_map,72667136 +random,memory,3670016,phmap::flat_hash_map,215556096 +random,memory,3681610,phmap::flat_hash_map,144109568 +random,memory,7340031,phmap::flat_hash_map,144109568 +random,memory,7340032,phmap::flat_hash_map,429883392 +random,memory,7348393,phmap::flat_hash_map,286994432 +random,time,10000000,phmap::flat_hash_map,0.917000 +random,memory,10000174,phmap::flat_hash_map,286994432 +random,memory,14680063,phmap::flat_hash_map,286994432 +random,memory,14680064,phmap::flat_hash_map,858537984 +random,memory,14680512,phmap::flat_hash_map,572764160 +random,time,20000000,phmap::flat_hash_map,2.199000 +random,memory,20013320,phmap::flat_hash_map,572764160 +random,memory,29360127,phmap::flat_hash_map,572764160 +random,memory,29360128,phmap::flat_hash_map,1715859456 +random,memory,29369210,phmap::flat_hash_map,1144307712 +random,time,30000000,phmap::flat_hash_map,3.818000 +random,memory,30002294,phmap::flat_hash_map,1144307712 +random,time,40000000,phmap::flat_hash_map,5.070000 +random,memory,40010797,phmap::flat_hash_map,1144307712 +random,time,50000000,phmap::flat_hash_map,6.323000 +random,memory,50009729,phmap::flat_hash_map,1144307712 +random,memory,58720255,phmap::flat_hash_map,1144307712 +random,memory,58720256,phmap::flat_hash_map,3430486016 +random,memory,58721491,phmap::flat_hash_map,2287403008 +random,time,60000000,phmap::flat_hash_map,8.700000 +random,memory,60002661,phmap::flat_hash_map,2287403008 +random,time,70000000,phmap::flat_hash_map,10.155000 +random,memory,70010887,phmap::flat_hash_map,2287403008 +random,time,80000000,phmap::flat_hash_map,11.589000 +random,memory,80002681,phmap::flat_hash_map,2287403008 +random,time,90000000,phmap::flat_hash_map,13.020000 +random,memory,90012468,phmap::flat_hash_map,2287403008 +random,time,100000000,phmap::flat_hash_map,14.407000 +random,memory,0,phmap::parallel_flat_hash_map,6688768 +random,memory,228584,phmap::parallel_flat_hash_map,6688768 +random,memory,228585,phmap::parallel_flat_hash_map,8372224 +random,memory,230683,phmap::parallel_flat_hash_map,8372224 +random,memory,230684,phmap::parallel_flat_hash_map,11190272 +random,memory,257042,phmap::parallel_flat_hash_map,11190272 +random,memory,257105,phmap::parallel_flat_hash_map,11751424 +random,memory,456008,phmap::parallel_flat_hash_map,11751424 +random,memory,456009,phmap::parallel_flat_hash_map,13996032 +random,memory,456819,phmap::parallel_flat_hash_map,13582336 +random,memory,458740,phmap::parallel_flat_hash_map,13582336 +random,memory,458741,phmap::parallel_flat_hash_map,15847424 +random,memory,459266,phmap::parallel_flat_hash_map,15847424 +random,memory,459267,phmap::parallel_flat_hash_map,17518592 +random,memory,465267,phmap::parallel_flat_hash_map,17518592 +random,memory,465268,phmap::parallel_flat_hash_map,21155840 +random,memory,494937,phmap::parallel_flat_hash_map,20598784 +random,memory,911236,phmap::parallel_flat_hash_map,20598784 +random,memory,911237,phmap::parallel_flat_hash_map,22835200 +random,memory,913145,phmap::parallel_flat_hash_map,22835200 +random,memory,913146,phmap::parallel_flat_hash_map,25067520 +random,memory,914338,phmap::parallel_flat_hash_map,25067520 +random,memory,914339,phmap::parallel_flat_hash_map,27303936 +random,memory,916480,phmap::parallel_flat_hash_map,27303936 +random,memory,916481,phmap::parallel_flat_hash_map,29536256 +random,memory,916523,phmap::parallel_flat_hash_map,29536256 +random,memory,916524,phmap::parallel_flat_hash_map,30650368 +random,memory,917790,phmap::parallel_flat_hash_map,30650368 +random,memory,917791,phmap::parallel_flat_hash_map,32882688 +random,memory,918474,phmap::parallel_flat_hash_map,32882688 +random,memory,918475,phmap::parallel_flat_hash_map,35115008 +random,memory,924420,phmap::parallel_flat_hash_map,35115008 +random,memory,924421,phmap::parallel_flat_hash_map,37355520 +random,memory,937279,phmap::parallel_flat_hash_map,37355520 +random,memory,937319,phmap::parallel_flat_hash_map,38465536 +random,memory,1826595,phmap::parallel_flat_hash_map,38465536 +random,memory,1826596,phmap::parallel_flat_hash_map,42934272 +random,memory,1827102,phmap::parallel_flat_hash_map,42934272 +random,memory,1827103,phmap::parallel_flat_hash_map,45170688 +random,memory,1828265,phmap::parallel_flat_hash_map,45170688 +random,memory,1828266,phmap::parallel_flat_hash_map,47398912 +random,memory,1831166,phmap::parallel_flat_hash_map,47398912 +random,memory,1831167,phmap::parallel_flat_hash_map,49631232 +random,memory,1831515,phmap::parallel_flat_hash_map,49631232 +random,memory,1831516,phmap::parallel_flat_hash_map,51867648 +random,memory,1833264,phmap::parallel_flat_hash_map,51867648 +random,memory,1833265,phmap::parallel_flat_hash_map,54099968 +random,memory,1833345,phmap::parallel_flat_hash_map,54099968 +random,memory,1833346,phmap::parallel_flat_hash_map,56332288 +random,memory,1835078,phmap::parallel_flat_hash_map,56332288 +random,memory,1835079,phmap::parallel_flat_hash_map,58572800 +random,memory,1836213,phmap::parallel_flat_hash_map,58572800 +random,memory,1836214,phmap::parallel_flat_hash_map,60801024 +random,memory,1836364,phmap::parallel_flat_hash_map,60801024 +random,memory,1836365,phmap::parallel_flat_hash_map,63033344 +random,memory,1836849,phmap::parallel_flat_hash_map,63033344 +random,memory,1836850,phmap::parallel_flat_hash_map,65265664 +random,memory,1838065,phmap::parallel_flat_hash_map,65265664 +random,memory,1838066,phmap::parallel_flat_hash_map,67502080 +random,memory,1839241,phmap::parallel_flat_hash_map,67502080 +random,memory,1839242,phmap::parallel_flat_hash_map,69734400 +random,memory,1839771,phmap::parallel_flat_hash_map,69734400 +random,memory,1839772,phmap::parallel_flat_hash_map,71962624 +random,memory,1844031,phmap::parallel_flat_hash_map,71962624 +random,memory,1844032,phmap::parallel_flat_hash_map,74194944 +random,memory,1844165,phmap::parallel_flat_hash_map,74194944 +random,memory,1844166,phmap::parallel_flat_hash_map,76423168 +random,memory,1849529,phmap::parallel_flat_hash_map,74186752 +random,memory,3656347,phmap::parallel_flat_hash_map,74186752 +random,memory,3656348,phmap::parallel_flat_hash_map,83120128 +random,memory,3658236,phmap::parallel_flat_hash_map,83120128 +random,memory,3658237,phmap::parallel_flat_hash_map,87592960 +random,memory,3660832,phmap::parallel_flat_hash_map,87592960 +random,memory,3660833,phmap::parallel_flat_hash_map,92061696 +random,memory,3663897,phmap::parallel_flat_hash_map,92061696 +random,memory,3663898,phmap::parallel_flat_hash_map,96526336 +random,memory,3668004,phmap::parallel_flat_hash_map,96526336 +random,memory,3668005,phmap::parallel_flat_hash_map,100990976 +random,memory,3668781,phmap::parallel_flat_hash_map,100990976 +random,memory,3668782,phmap::parallel_flat_hash_map,105459712 +random,memory,3669316,phmap::parallel_flat_hash_map,100990976 +random,memory,3669736,phmap::parallel_flat_hash_map,100990976 +random,memory,3669737,phmap::parallel_flat_hash_map,109928448 +random,memory,3670780,phmap::parallel_flat_hash_map,109928448 +random,memory,3670781,phmap::parallel_flat_hash_map,114388992 +random,memory,3671735,phmap::parallel_flat_hash_map,114388992 +random,memory,3671736,phmap::parallel_flat_hash_map,118853632 +random,memory,3672742,phmap::parallel_flat_hash_map,118853632 +random,memory,3672743,phmap::parallel_flat_hash_map,123322368 +random,memory,3672841,phmap::parallel_flat_hash_map,123322368 +random,memory,3672842,phmap::parallel_flat_hash_map,127787008 +random,memory,3674661,phmap::parallel_flat_hash_map,127787008 +random,memory,3674662,phmap::parallel_flat_hash_map,132259840 +random,memory,3675918,phmap::parallel_flat_hash_map,132259840 +random,memory,3675919,phmap::parallel_flat_hash_map,136724480 +random,memory,3676502,phmap::parallel_flat_hash_map,136724480 +random,memory,3676503,phmap::parallel_flat_hash_map,141180928 +random,memory,3676556,phmap::parallel_flat_hash_map,141180928 +random,memory,3676557,phmap::parallel_flat_hash_map,145645568 +random,memory,3679943,phmap::parallel_flat_hash_map,141176832 +random,memory,3682847,phmap::parallel_flat_hash_map,141176832 +random,memory,3682848,phmap::parallel_flat_hash_map,150106112 +random,memory,3701420,phmap::parallel_flat_hash_map,145637376 +random,memory,7323550,phmap::parallel_flat_hash_map,145637376 +random,memory,7323551,phmap::parallel_flat_hash_map,163500032 +random,memory,7325955,phmap::parallel_flat_hash_map,154566656 +random,memory,7326781,phmap::parallel_flat_hash_map,154566656 +random,memory,7326782,phmap::parallel_flat_hash_map,172433408 +random,memory,7327471,phmap::parallel_flat_hash_map,172433408 +random,memory,7327472,phmap::parallel_flat_hash_map,181362688 +random,memory,7328548,phmap::parallel_flat_hash_map,181362688 +random,memory,7328549,phmap::parallel_flat_hash_map,190300160 +random,memory,7331571,phmap::parallel_flat_hash_map,190300160 +random,memory,7331572,phmap::parallel_flat_hash_map,199229440 +random,memory,7333270,phmap::parallel_flat_hash_map,199229440 +random,memory,7333271,phmap::parallel_flat_hash_map,208154624 +random,memory,7336330,phmap::parallel_flat_hash_map,208154624 +random,memory,7336331,phmap::parallel_flat_hash_map,217083904 +random,memory,7338941,phmap::parallel_flat_hash_map,217083904 +random,memory,7338942,phmap::parallel_flat_hash_map,226021376 +random,memory,7339987,phmap::parallel_flat_hash_map,226021376 +random,memory,7339988,phmap::parallel_flat_hash_map,234950656 +random,memory,7340192,phmap::parallel_flat_hash_map,234950656 +random,memory,7340193,phmap::parallel_flat_hash_map,243879936 +random,memory,7340212,phmap::parallel_flat_hash_map,243879936 +random,memory,7340213,phmap::parallel_flat_hash_map,252805120 +random,memory,7340756,phmap::parallel_flat_hash_map,252805120 +random,memory,7340757,phmap::parallel_flat_hash_map,261734400 +random,memory,7353138,phmap::parallel_flat_hash_map,261734400 +random,memory,7353139,phmap::parallel_flat_hash_map,270659584 +random,memory,7355638,phmap::parallel_flat_hash_map,270659584 +random,memory,7355639,phmap::parallel_flat_hash_map,279592960 +random,memory,7358552,phmap::parallel_flat_hash_map,279592960 +random,memory,7358553,phmap::parallel_flat_hash_map,288522240 +random,memory,7363002,phmap::parallel_flat_hash_map,279584768 +random,memory,7364175,phmap::parallel_flat_hash_map,279584768 +random,memory,7364176,phmap::parallel_flat_hash_map,297451520 +random,memory,7379232,phmap::parallel_flat_hash_map,288518144 +random,time,10000000,phmap::parallel_flat_hash_map,1.115000 +random,memory,10001837,phmap::parallel_flat_hash_map,288518144 +random,memory,14641981,phmap::parallel_flat_hash_map,288518144 +random,memory,14641982,phmap::parallel_flat_hash_map,324243456 +random,memory,14649536,phmap::parallel_flat_hash_map,306380800 +random,memory,14658094,phmap::parallel_flat_hash_map,306380800 +random,memory,14658095,phmap::parallel_flat_hash_map,342106112 +random,memory,14663598,phmap::parallel_flat_hash_map,342106112 +random,memory,14663599,phmap::parallel_flat_hash_map,359968768 +random,memory,14667323,phmap::parallel_flat_hash_map,359968768 +random,memory,14667324,phmap::parallel_flat_hash_map,377835520 +random,memory,14668425,phmap::parallel_flat_hash_map,377835520 +random,memory,14668426,phmap::parallel_flat_hash_map,395694080 +random,memory,14669145,phmap::parallel_flat_hash_map,395694080 +random,memory,14669146,phmap::parallel_flat_hash_map,413560832 +random,memory,14669916,phmap::parallel_flat_hash_map,395698176 +random,memory,14673506,phmap::parallel_flat_hash_map,395698176 +random,memory,14673507,phmap::parallel_flat_hash_map,431423488 +random,memory,14676201,phmap::parallel_flat_hash_map,431423488 +random,memory,14676202,phmap::parallel_flat_hash_map,449286144 +random,memory,14681323,phmap::parallel_flat_hash_map,449286144 +random,memory,14681324,phmap::parallel_flat_hash_map,467152896 +random,memory,14684771,phmap::parallel_flat_hash_map,449286144 +random,memory,14686498,phmap::parallel_flat_hash_map,449286144 +random,memory,14686499,phmap::parallel_flat_hash_map,485011456 +random,memory,14691299,phmap::parallel_flat_hash_map,485011456 +random,memory,14691300,phmap::parallel_flat_hash_map,502865920 +random,memory,14694531,phmap::parallel_flat_hash_map,502865920 +random,memory,14694532,phmap::parallel_flat_hash_map,520728576 +random,memory,14696324,phmap::parallel_flat_hash_map,520728576 +random,memory,14696325,phmap::parallel_flat_hash_map,538587136 +random,memory,14701255,phmap::parallel_flat_hash_map,538587136 +random,memory,14701256,phmap::parallel_flat_hash_map,556445696 +random,memory,14702651,phmap::parallel_flat_hash_map,538578944 +random,memory,14704639,phmap::parallel_flat_hash_map,538578944 +random,memory,14704640,phmap::parallel_flat_hash_map,574300160 +random,memory,14707748,phmap::parallel_flat_hash_map,574300160 +random,memory,14707749,phmap::parallel_flat_hash_map,592158720 +random,memory,14711651,phmap::parallel_flat_hash_map,574296064 +random,time,20000000,phmap::parallel_flat_hash_map,2.484000 +random,memory,20006564,phmap::parallel_flat_hash_map,574296064 +random,memory,29321443,phmap::parallel_flat_hash_map,574296064 +random,memory,29321444,phmap::parallel_flat_hash_map,645742592 +random,memory,29322576,phmap::parallel_flat_hash_map,645742592 +random,memory,29322577,phmap::parallel_flat_hash_map,681463808 +random,memory,29331685,phmap::parallel_flat_hash_map,645742592 +random,memory,29333141,phmap::parallel_flat_hash_map,645742592 +random,memory,29333142,phmap::parallel_flat_hash_map,717189120 +random,memory,29336447,phmap::parallel_flat_hash_map,717189120 +random,memory,29336448,phmap::parallel_flat_hash_map,752910336 +random,memory,29345055,phmap::parallel_flat_hash_map,717185024 +random,memory,29352413,phmap::parallel_flat_hash_map,717185024 +random,memory,29352414,phmap::parallel_flat_hash_map,788627456 +random,memory,29357051,phmap::parallel_flat_hash_map,752902144 +random,memory,29357141,phmap::parallel_flat_hash_map,752902144 +random,memory,29357142,phmap::parallel_flat_hash_map,824348672 +random,memory,29359481,phmap::parallel_flat_hash_map,824348672 +random,memory,29359482,phmap::parallel_flat_hash_map,860069888 +random,memory,29362077,phmap::parallel_flat_hash_map,860069888 +random,memory,29362078,phmap::parallel_flat_hash_map,895795200 +random,memory,29366120,phmap::parallel_flat_hash_map,895795200 +random,memory,29366121,phmap::parallel_flat_hash_map,931512320 +random,memory,29368098,phmap::parallel_flat_hash_map,931512320 +random,memory,29368099,phmap::parallel_flat_hash_map,967229440 +random,memory,29368978,phmap::parallel_flat_hash_map,931508224 +random,memory,29373953,phmap::parallel_flat_hash_map,931508224 +random,memory,29373954,phmap::parallel_flat_hash_map,1002954752 +random,memory,29376083,phmap::parallel_flat_hash_map,1002954752 +random,memory,29376084,phmap::parallel_flat_hash_map,1038680064 +random,memory,29378406,phmap::parallel_flat_hash_map,1002950656 +random,memory,29378970,phmap::parallel_flat_hash_map,1002950656 +random,memory,29378971,phmap::parallel_flat_hash_map,1074397184 +random,memory,29380083,phmap::parallel_flat_hash_map,1074397184 +random,memory,29380084,phmap::parallel_flat_hash_map,1110122496 +random,memory,29381250,phmap::parallel_flat_hash_map,1110122496 +random,memory,29381251,phmap::parallel_flat_hash_map,1145839616 +random,memory,29384576,phmap::parallel_flat_hash_map,1110110208 +random,memory,29391514,phmap::parallel_flat_hash_map,1110110208 +random,memory,29391515,phmap::parallel_flat_hash_map,1181556736 +random,memory,29398827,phmap::parallel_flat_hash_map,1145835520 +random,time,30000000,phmap::parallel_flat_hash_map,4.197000 +random,memory,30003726,phmap::parallel_flat_hash_map,1145835520 +random,time,40000000,phmap::parallel_flat_hash_map,5.407000 +random,memory,40004260,phmap::parallel_flat_hash_map,1145835520 +random,time,50000000,phmap::parallel_flat_hash_map,6.651000 +random,memory,50008463,phmap::parallel_flat_hash_map,1145835520 +random,memory,58650774,phmap::parallel_flat_hash_map,1145835520 +random,memory,58650775,phmap::parallel_flat_hash_map,1288724480 +random,memory,58651341,phmap::parallel_flat_hash_map,1217282048 +random,memory,58670748,phmap::parallel_flat_hash_map,1217282048 +random,memory,58670749,phmap::parallel_flat_hash_map,1360171008 +random,memory,58672543,phmap::parallel_flat_hash_map,1288724480 +random,memory,58679343,phmap::parallel_flat_hash_map,1288724480 +random,memory,58679344,phmap::parallel_flat_hash_map,1431609344 +random,memory,58679621,phmap::parallel_flat_hash_map,1431609344 +random,memory,58679622,phmap::parallel_flat_hash_map,1503047680 +random,memory,58681449,phmap::parallel_flat_hash_map,1503047680 +random,memory,58681450,phmap::parallel_flat_hash_map,1574498304 +random,memory,58687442,phmap::parallel_flat_hash_map,1503055872 +random,memory,58716081,phmap::parallel_flat_hash_map,1503055872 +random,memory,58716082,phmap::parallel_flat_hash_map,1645944832 +random,memory,58719988,phmap::parallel_flat_hash_map,1574498304 +random,memory,58720496,phmap::parallel_flat_hash_map,1574498304 +random,memory,58720497,phmap::parallel_flat_hash_map,1717387264 +random,memory,58723911,phmap::parallel_flat_hash_map,1717387264 +random,memory,58723912,phmap::parallel_flat_hash_map,1788841984 +random,memory,58728095,phmap::parallel_flat_hash_map,1717395456 +random,memory,58731608,phmap::parallel_flat_hash_map,1717395456 +random,memory,58731609,phmap::parallel_flat_hash_map,1860280320 +random,memory,58737338,phmap::parallel_flat_hash_map,1860280320 +random,memory,58737339,phmap::parallel_flat_hash_map,1931718656 +random,memory,58737397,phmap::parallel_flat_hash_map,1860272128 +random,memory,58744726,phmap::parallel_flat_hash_map,1860272128 +random,memory,58744727,phmap::parallel_flat_hash_map,2003165184 +random,memory,58746205,phmap::parallel_flat_hash_map,1931718656 +random,memory,58752523,phmap::parallel_flat_hash_map,1931718656 +random,memory,58752524,phmap::parallel_flat_hash_map,2074607616 +random,memory,58753838,phmap::parallel_flat_hash_map,2074607616 +random,memory,58753839,phmap::parallel_flat_hash_map,2146054144 +random,memory,58756083,phmap::parallel_flat_hash_map,2146054144 +random,memory,58756084,phmap::parallel_flat_hash_map,2217496576 +random,memory,58758266,phmap::parallel_flat_hash_map,2217496576 +random,memory,58758267,phmap::parallel_flat_hash_map,2288943104 +random,memory,58760494,phmap::parallel_flat_hash_map,2217492480 +random,memory,58766191,phmap::parallel_flat_hash_map,2217492480 +random,memory,58766192,phmap::parallel_flat_hash_map,2360381440 +random,memory,58773720,phmap::parallel_flat_hash_map,2288934912 +random,time,60000000,phmap::parallel_flat_hash_map,9.067000 +random,memory,60002586,phmap::parallel_flat_hash_map,2288934912 +random,time,70000000,phmap::parallel_flat_hash_map,10.409000 +random,memory,70011900,phmap::parallel_flat_hash_map,2288934912 +random,time,80000000,phmap::parallel_flat_hash_map,11.747000 +random,memory,80002981,phmap::parallel_flat_hash_map,2288934912 +random,time,90000000,phmap::parallel_flat_hash_map,13.091000 +random,memory,90007030,phmap::parallel_flat_hash_map,2288934912 +random,time,100000000,phmap::parallel_flat_hash_map,14.467000 diff --git a/extern/phmap/benchmark/results/output_flat_par_mutex_4 b/extern/phmap/benchmark/results/output_flat_par_mutex_4 new file mode 100644 index 0000000..c22410f --- /dev/null +++ b/extern/phmap/benchmark/results/output_flat_par_mutex_4 @@ -0,0 +1,316 @@ +random,memory,0,phmap::flat_hash_map,15753216 +random,memory,299298,phmap::flat_hash_map,15753216 +random,memory,299585,phmap::flat_hash_map,11284480 +random,memory,458751,phmap::flat_hash_map,11284480 +random,memory,458752,phmap::flat_hash_map,29151232 +random,memory,505180,phmap::flat_hash_map,29151232 +random,memory,505419,phmap::flat_hash_map,20217856 +random,memory,599314,phmap::flat_hash_map,20217856 +random,memory,599573,phmap::flat_hash_map,19095552 +random,memory,917503,phmap::flat_hash_map,19095552 +random,memory,917504,phmap::flat_hash_map,54820864 +random,memory,963390,phmap::flat_hash_map,54820864 +random,memory,963601,phmap::flat_hash_map,36954112 +random,memory,1835007,phmap::flat_hash_map,36954112 +random,memory,1835008,phmap::flat_hash_map,108400640 +random,memory,1860352,phmap::flat_hash_map,108400640 +random,memory,1860468,phmap::flat_hash_map,72675328 +random,memory,3670015,phmap::flat_hash_map,72675328 +random,memory,3670016,phmap::flat_hash_map,215564288 +random,memory,3686835,phmap::flat_hash_map,215564288 +random,memory,3686879,phmap::flat_hash_map,144117760 +random,memory,7340031,phmap::flat_hash_map,144117760 +random,memory,7340032,phmap::flat_hash_map,429891584 +random,memory,7352288,phmap::flat_hash_map,429891584 +random,memory,7352289,phmap::flat_hash_map,287002624 +random,time,10000000,phmap::flat_hash_map,0.923000 +random,memory,10003658,phmap::flat_hash_map,287002624 +random,memory,14680063,phmap::flat_hash_map,287002624 +random,memory,14680064,phmap::flat_hash_map,858554368 +random,memory,14690134,phmap::flat_hash_map,858554368 +random,memory,14690179,phmap::flat_hash_map,572776448 +random,time,20000000,phmap::flat_hash_map,2.224000 +random,memory,20009269,phmap::flat_hash_map,572776448 +random,memory,29360127,phmap::flat_hash_map,572776448 +random,memory,29360128,phmap::flat_hash_map,1715867648 +random,memory,29366940,phmap::flat_hash_map,1715867648 +random,memory,29366994,phmap::flat_hash_map,1144315904 +random,time,30000000,phmap::flat_hash_map,3.846000 +random,memory,30008884,phmap::flat_hash_map,1144315904 +random,time,40000000,phmap::flat_hash_map,5.131000 +random,memory,40002137,phmap::flat_hash_map,1144315904 +random,time,50000000,phmap::flat_hash_map,6.445000 +random,memory,50005385,phmap::flat_hash_map,1144315904 +random,memory,58720255,phmap::flat_hash_map,1144315904 +random,memory,58720256,phmap::flat_hash_map,3430494208 +random,memory,58729667,phmap::flat_hash_map,3430494208 +random,memory,58729713,phmap::flat_hash_map,2287415296 +random,time,60000000,phmap::flat_hash_map,8.827000 +random,memory,60010828,phmap::flat_hash_map,2287415296 +random,time,70000000,phmap::flat_hash_map,10.317000 +random,memory,70006827,phmap::flat_hash_map,2287415296 +random,time,80000000,phmap::flat_hash_map,11.803000 +random,memory,80002090,phmap::flat_hash_map,2287415296 +random,time,90000000,phmap::flat_hash_map,13.277000 +random,memory,90005422,phmap::flat_hash_map,2287415296 +random,time,100000000,phmap::flat_hash_map,14.716000 +random,memory,0,phmap::parallel_flat_hash_map_mt,7884800 +random,memory,229053,phmap::parallel_flat_hash_map_mt,7884800 +random,memory,229054,phmap::parallel_flat_hash_map_mt,12562432 +random,memory,244827,phmap::parallel_flat_hash_map_mt,12562432 +random,memory,244899,phmap::parallel_flat_hash_map_mt,13127680 +random,memory,455707,phmap::parallel_flat_hash_map_mt,13127680 +random,memory,455708,phmap::parallel_flat_hash_map_mt,14254080 +random,memory,457702,phmap::parallel_flat_hash_map_mt,14254080 +random,memory,457703,phmap::parallel_flat_hash_map_mt,14700544 +random,memory,458422,phmap::parallel_flat_hash_map_mt,14700544 +random,memory,458423,phmap::parallel_flat_hash_map_mt,16953344 +random,memory,459497,phmap::parallel_flat_hash_map_mt,16953344 +random,memory,459498,phmap::parallel_flat_hash_map_mt,18644992 +random,memory,460681,phmap::parallel_flat_hash_map_mt,18644992 +random,memory,460682,phmap::parallel_flat_hash_map_mt,21450752 +random,memory,482289,phmap::parallel_flat_hash_map_mt,21450752 +random,memory,482359,phmap::parallel_flat_hash_map_mt,22495232 +random,memory,914327,phmap::parallel_flat_hash_map_mt,22495232 +random,memory,914328,phmap::parallel_flat_hash_map_mt,25849856 +random,memory,914709,phmap::parallel_flat_hash_map_mt,25849856 +random,memory,914710,phmap::parallel_flat_hash_map_mt,29200384 +random,memory,915833,phmap::parallel_flat_hash_map_mt,29200384 +random,memory,915834,phmap::parallel_flat_hash_map_mt,33673216 +random,memory,917742,phmap::parallel_flat_hash_map_mt,33673216 +random,memory,917743,phmap::parallel_flat_hash_map_mt,35905536 +random,memory,920586,phmap::parallel_flat_hash_map_mt,35905536 +random,memory,920587,phmap::parallel_flat_hash_map_mt,37023744 +random,memory,921976,phmap::parallel_flat_hash_map_mt,37023744 +random,memory,921977,phmap::parallel_flat_hash_map_mt,40370176 +random,memory,922650,phmap::parallel_flat_hash_map_mt,41484288 +random,memory,983562,phmap::parallel_flat_hash_map_mt,41484288 +random,memory,1172876,phmap::parallel_flat_hash_map_mt,40366080 +random,memory,1825547,phmap::parallel_flat_hash_map_mt,40366080 +random,memory,1825548,phmap::parallel_flat_hash_map_mt,44834816 +random,memory,1826741,phmap::parallel_flat_hash_map_mt,44834816 +random,memory,1826816,phmap::parallel_flat_hash_map_mt,42598400 +random,memory,1828151,phmap::parallel_flat_hash_map_mt,42598400 +random,memory,1828152,phmap::parallel_flat_hash_map_mt,47067136 +random,memory,1830082,phmap::parallel_flat_hash_map_mt,47067136 +random,memory,1830083,phmap::parallel_flat_hash_map_mt,49295360 +random,memory,1831123,phmap::parallel_flat_hash_map_mt,49295360 +random,memory,1831124,phmap::parallel_flat_hash_map_mt,51531776 +random,memory,1832184,phmap::parallel_flat_hash_map_mt,51531776 +random,memory,1832185,phmap::parallel_flat_hash_map_mt,53760000 +random,memory,1832769,phmap::parallel_flat_hash_map_mt,53760000 +random,memory,1832770,phmap::parallel_flat_hash_map_mt,55996416 +random,memory,1832874,phmap::parallel_flat_hash_map_mt,55996416 +random,memory,1832875,phmap::parallel_flat_hash_map_mt,58228736 +random,memory,1835220,phmap::parallel_flat_hash_map_mt,58228736 +random,memory,1835221,phmap::parallel_flat_hash_map_mt,60465152 +random,memory,1836418,phmap::parallel_flat_hash_map_mt,60465152 +random,memory,1836419,phmap::parallel_flat_hash_map_mt,62701568 +random,memory,1836633,phmap::parallel_flat_hash_map_mt,62701568 +random,memory,1836634,phmap::parallel_flat_hash_map_mt,64929792 +random,memory,1837724,phmap::parallel_flat_hash_map_mt,64929792 +random,memory,1837725,phmap::parallel_flat_hash_map_mt,67158016 +random,memory,1838209,phmap::parallel_flat_hash_map_mt,67158016 +random,memory,1838210,phmap::parallel_flat_hash_map_mt,69394432 +random,memory,1838995,phmap::parallel_flat_hash_map_mt,69394432 +random,memory,1838996,phmap::parallel_flat_hash_map_mt,71622656 +random,memory,1840918,phmap::parallel_flat_hash_map_mt,71622656 +random,memory,1840919,phmap::parallel_flat_hash_map_mt,73859072 +random,memory,1841584,phmap::parallel_flat_hash_map_mt,73859072 +random,memory,1841585,phmap::parallel_flat_hash_map_mt,76095488 +random,memory,1842548,phmap::parallel_flat_hash_map_mt,78323712 +random,memory,1854401,phmap::parallel_flat_hash_map_mt,78323712 +random,memory,2039888,phmap::parallel_flat_hash_map_mt,76087296 +random,memory,3656563,phmap::parallel_flat_hash_map_mt,76091392 +random,memory,3656564,phmap::parallel_flat_hash_map_mt,85028864 +random,memory,3657600,phmap::parallel_flat_hash_map_mt,85028864 +random,memory,3657601,phmap::parallel_flat_hash_map_mt,89497600 +random,memory,3659709,phmap::parallel_flat_hash_map_mt,89497600 +random,memory,3659710,phmap::parallel_flat_hash_map_mt,93958144 +random,memory,3664287,phmap::parallel_flat_hash_map_mt,93958144 +random,memory,3664288,phmap::parallel_flat_hash_map_mt,98418688 +random,memory,3665897,phmap::parallel_flat_hash_map_mt,98418688 +random,memory,3665898,phmap::parallel_flat_hash_map_mt,102879232 +random,memory,3668708,phmap::parallel_flat_hash_map_mt,102879232 +random,memory,3668709,phmap::parallel_flat_hash_map_mt,107347968 +random,memory,3669267,phmap::parallel_flat_hash_map_mt,107347968 +random,memory,3669268,phmap::parallel_flat_hash_map_mt,111816704 +random,memory,3673233,phmap::parallel_flat_hash_map_mt,111816704 +random,memory,3673234,phmap::parallel_flat_hash_map_mt,134148096 +random,memory,3673249,phmap::parallel_flat_hash_map_mt,134148096 +random,memory,3673261,phmap::parallel_flat_hash_map_mt,125210624 +random,memory,3673702,phmap::parallel_flat_hash_map_mt,125210624 +random,memory,3673703,phmap::parallel_flat_hash_map_mt,129679360 +random,memory,3674703,phmap::parallel_flat_hash_map_mt,129679360 +random,memory,3674704,phmap::parallel_flat_hash_map_mt,134139904 +random,memory,3675513,phmap::parallel_flat_hash_map_mt,134139904 +random,memory,3675514,phmap::parallel_flat_hash_map_mt,138600448 +random,memory,3677599,phmap::parallel_flat_hash_map_mt,138600448 +random,memory,3677600,phmap::parallel_flat_hash_map_mt,143073280 +random,memory,3678958,phmap::parallel_flat_hash_map_mt,143073280 +random,memory,3678959,phmap::parallel_flat_hash_map_mt,147537920 +random,memory,3679455,phmap::parallel_flat_hash_map_mt,147537920 +random,memory,3679456,phmap::parallel_flat_hash_map_mt,152006656 +random,memory,3829988,phmap::parallel_flat_hash_map_mt,152006656 +random,memory,3830019,phmap::parallel_flat_hash_map_mt,147537920 +random,memory,7327631,phmap::parallel_flat_hash_map_mt,147537920 +random,memory,7327632,phmap::parallel_flat_hash_map_mt,183267328 +random,memory,7327726,phmap::parallel_flat_hash_map_mt,183267328 +random,memory,7327727,phmap::parallel_flat_hash_map_mt,174333952 +random,memory,7328167,phmap::parallel_flat_hash_map_mt,174333952 +random,memory,7328168,phmap::parallel_flat_hash_map_mt,183263232 +random,memory,7332754,phmap::parallel_flat_hash_map_mt,183263232 +random,memory,7332755,phmap::parallel_flat_hash_map_mt,192196608 +random,memory,7334286,phmap::parallel_flat_hash_map_mt,192196608 +random,memory,7334287,phmap::parallel_flat_hash_map_mt,201121792 +random,memory,7336335,phmap::parallel_flat_hash_map_mt,201121792 +random,memory,7336336,phmap::parallel_flat_hash_map_mt,210059264 +random,memory,7337725,phmap::parallel_flat_hash_map_mt,210059264 +random,memory,7337726,phmap::parallel_flat_hash_map_mt,218984448 +random,memory,7339260,phmap::parallel_flat_hash_map_mt,218984448 +random,memory,7339261,phmap::parallel_flat_hash_map_mt,227909632 +random,memory,7340643,phmap::parallel_flat_hash_map_mt,227909632 +random,memory,7340644,phmap::parallel_flat_hash_map_mt,236838912 +random,memory,7342329,phmap::parallel_flat_hash_map_mt,236838912 +random,memory,7342330,phmap::parallel_flat_hash_map_mt,245776384 +random,memory,7343707,phmap::parallel_flat_hash_map_mt,245776384 +random,memory,7343708,phmap::parallel_flat_hash_map_mt,254709760 +random,memory,7344092,phmap::parallel_flat_hash_map_mt,254709760 +random,memory,7344093,phmap::parallel_flat_hash_map_mt,263639040 +random,memory,7344454,phmap::parallel_flat_hash_map_mt,263639040 +random,memory,7344529,phmap::parallel_flat_hash_map_mt,254705664 +random,memory,7349960,phmap::parallel_flat_hash_map_mt,254705664 +random,memory,7349961,phmap::parallel_flat_hash_map_mt,272572416 +random,memory,7350165,phmap::parallel_flat_hash_map_mt,272572416 +random,memory,7350166,phmap::parallel_flat_hash_map_mt,281497600 +random,memory,7353807,phmap::parallel_flat_hash_map_mt,281497600 +random,memory,7353808,phmap::parallel_flat_hash_map_mt,290430976 +random,memory,7354809,phmap::parallel_flat_hash_map_mt,290430976 +random,memory,7354810,phmap::parallel_flat_hash_map_mt,299356160 +random,memory,7359696,phmap::parallel_flat_hash_map_mt,299356160 +random,memory,7359779,phmap::parallel_flat_hash_map_mt,290422784 +random,time,10000000,phmap::parallel_flat_hash_map_mt,0.788000 +random,memory,10043554,phmap::parallel_flat_hash_map_mt,288821248 +random,memory,14660773,phmap::parallel_flat_hash_map_mt,288821248 +random,memory,14660774,phmap::parallel_flat_hash_map_mt,324546560 +random,memory,14668394,phmap::parallel_flat_hash_map_mt,324546560 +random,memory,14668395,phmap::parallel_flat_hash_map_mt,342409216 +random,memory,14670081,phmap::parallel_flat_hash_map_mt,342409216 +random,memory,14670082,phmap::parallel_flat_hash_map_mt,360271872 +random,memory,14670721,phmap::parallel_flat_hash_map_mt,360271872 +random,memory,14670722,phmap::parallel_flat_hash_map_mt,378126336 +random,memory,14673268,phmap::parallel_flat_hash_map_mt,378126336 +random,memory,14673269,phmap::parallel_flat_hash_map_mt,395984896 +random,memory,14675927,phmap::parallel_flat_hash_map_mt,395984896 +random,memory,14675929,phmap::parallel_flat_hash_map_mt,413843456 +random,memory,14677274,phmap::parallel_flat_hash_map_mt,413843456 +random,memory,14677275,phmap::parallel_flat_hash_map_mt,431706112 +random,memory,14679690,phmap::parallel_flat_hash_map_mt,431706112 +random,memory,14679691,phmap::parallel_flat_hash_map_mt,449564672 +random,memory,14680028,phmap::parallel_flat_hash_map_mt,449564672 +random,memory,14680031,phmap::parallel_flat_hash_map_mt,431702016 +random,memory,14682548,phmap::parallel_flat_hash_map_mt,431702016 +random,memory,14682549,phmap::parallel_flat_hash_map_mt,467423232 +random,memory,14683242,phmap::parallel_flat_hash_map_mt,467423232 +random,memory,14683243,phmap::parallel_flat_hash_map_mt,485289984 +random,memory,14684510,phmap::parallel_flat_hash_map_mt,485289984 +random,memory,14684511,phmap::parallel_flat_hash_map_mt,503152640 +random,memory,14685762,phmap::parallel_flat_hash_map_mt,503152640 +random,memory,14685763,phmap::parallel_flat_hash_map_mt,521015296 +random,memory,14687183,phmap::parallel_flat_hash_map_mt,521015296 +random,memory,14687184,phmap::parallel_flat_hash_map_mt,538873856 +random,memory,14687856,phmap::parallel_flat_hash_map_mt,538873856 +random,memory,14687857,phmap::parallel_flat_hash_map_mt,556740608 +random,memory,14688774,phmap::parallel_flat_hash_map_mt,556740608 +random,memory,14688775,phmap::parallel_flat_hash_map_mt,574595072 +random,memory,14708553,phmap::parallel_flat_hash_map_mt,574595072 +random,memory,14708554,phmap::parallel_flat_hash_map_mt,592453632 +random,memory,14952078,phmap::parallel_flat_hash_map_mt,592453632 +random,memory,14952197,phmap::parallel_flat_hash_map_mt,574582784 +random,time,20000000,phmap::parallel_flat_hash_map_mt,1.615000 +random,memory,20008974,phmap::parallel_flat_hash_map_mt,574586880 +random,memory,29333764,phmap::parallel_flat_hash_map_mt,574586880 +random,memory,29333765,phmap::parallel_flat_hash_map_mt,646033408 +random,memory,29334022,phmap::parallel_flat_hash_map_mt,646033408 +random,memory,29334023,phmap::parallel_flat_hash_map_mt,681766912 +random,memory,29342949,phmap::parallel_flat_hash_map_mt,681766912 +random,memory,29342950,phmap::parallel_flat_hash_map_mt,717488128 +random,memory,29345586,phmap::parallel_flat_hash_map_mt,717488128 +random,memory,29345587,phmap::parallel_flat_hash_map_mt,753205248 +random,memory,29347489,phmap::parallel_flat_hash_map_mt,753205248 +random,memory,29347490,phmap::parallel_flat_hash_map_mt,788930560 +random,memory,29348504,phmap::parallel_flat_hash_map_mt,788930560 +random,memory,29348542,phmap::parallel_flat_hash_map_mt,753209344 +random,memory,29349198,phmap::parallel_flat_hash_map_mt,753209344 +random,memory,29349199,phmap::parallel_flat_hash_map_mt,824655872 +random,memory,29352494,phmap::parallel_flat_hash_map_mt,824655872 +random,memory,29352495,phmap::parallel_flat_hash_map_mt,860377088 +random,memory,29358759,phmap::parallel_flat_hash_map_mt,860377088 +random,memory,29358760,phmap::parallel_flat_hash_map_mt,896094208 +random,memory,29361234,phmap::parallel_flat_hash_map_mt,896094208 +random,memory,29361235,phmap::parallel_flat_hash_map_mt,931811328 +random,memory,29362544,phmap::parallel_flat_hash_map_mt,931811328 +random,memory,29362545,phmap::parallel_flat_hash_map_mt,967536640 +random,memory,29369457,phmap::parallel_flat_hash_map_mt,967536640 +random,memory,29369458,phmap::parallel_flat_hash_map_mt,1003257856 +random,memory,29372921,phmap::parallel_flat_hash_map_mt,1003257856 +random,memory,29372922,phmap::parallel_flat_hash_map_mt,1038979072 +random,memory,29374936,phmap::parallel_flat_hash_map_mt,1038979072 +random,memory,29374937,phmap::parallel_flat_hash_map_mt,1074696192 +random,memory,29383512,phmap::parallel_flat_hash_map_mt,1074696192 +random,memory,29383513,phmap::parallel_flat_hash_map_mt,1110417408 +random,memory,29383512,phmap::parallel_flat_hash_map_mt,1110417408 +random,memory,29383513,phmap::parallel_flat_hash_map_mt,1181863936 +random,memory,29474438,phmap::parallel_flat_hash_map_mt,1181851648 +random,memory,29475679,phmap::parallel_flat_hash_map_mt,1146126336 +random,time,30000000,phmap::parallel_flat_hash_map_mt,2.718000 +random,memory,30039213,phmap::parallel_flat_hash_map_mt,1146114048 +random,time,40000000,phmap::parallel_flat_hash_map_mt,3.314000 +random,memory,40063406,phmap::parallel_flat_hash_map_mt,1146126336 +random,time,50000000,phmap::parallel_flat_hash_map_mt,3.930000 +random,memory,50000796,phmap::parallel_flat_hash_map_mt,1146003456 +random,memory,58662905,phmap::parallel_flat_hash_map_mt,1146118144 +random,memory,58662906,phmap::parallel_flat_hash_map_mt,1289007104 +random,memory,58690501,phmap::parallel_flat_hash_map_mt,1289007104 +random,memory,58690502,phmap::parallel_flat_hash_map_mt,1360453632 +random,memory,58698182,phmap::parallel_flat_hash_map_mt,1360453632 +random,memory,58698183,phmap::parallel_flat_hash_map_mt,1431904256 +random,memory,58704661,phmap::parallel_flat_hash_map_mt,1431904256 +random,memory,58704662,phmap::parallel_flat_hash_map_mt,1503346688 +random,memory,58708120,phmap::parallel_flat_hash_map_mt,1503346688 +random,memory,58708121,phmap::parallel_flat_hash_map_mt,1574785024 +random,memory,58718704,phmap::parallel_flat_hash_map_mt,1574785024 +random,memory,58718705,phmap::parallel_flat_hash_map_mt,1646223360 +random,memory,58720588,phmap::parallel_flat_hash_map_mt,1646223360 +random,memory,58720589,phmap::parallel_flat_hash_map_mt,1860554752 +random,memory,58720613,phmap::parallel_flat_hash_map_mt,1860554752 +random,memory,58720614,phmap::parallel_flat_hash_map_mt,1789112320 +random,memory,58721807,phmap::parallel_flat_hash_map_mt,1789112320 +random,memory,58721808,phmap::parallel_flat_hash_map_mt,1860558848 +random,memory,58722210,phmap::parallel_flat_hash_map_mt,1860558848 +random,memory,58722854,phmap::parallel_flat_hash_map_mt,1789112320 +random,memory,58722853,phmap::parallel_flat_hash_map_mt,1789112320 +random,memory,58722854,phmap::parallel_flat_hash_map_mt,1931997184 +random,memory,58723270,phmap::parallel_flat_hash_map_mt,1931997184 +random,memory,58723271,phmap::parallel_flat_hash_map_mt,2003435520 +random,memory,58725728,phmap::parallel_flat_hash_map_mt,2003435520 +random,memory,58725729,phmap::parallel_flat_hash_map_mt,2074873856 +random,memory,58729127,phmap::parallel_flat_hash_map_mt,2074873856 +random,memory,58729128,phmap::parallel_flat_hash_map_mt,2146328576 +random,memory,58738897,phmap::parallel_flat_hash_map_mt,2146328576 +random,memory,58738898,phmap::parallel_flat_hash_map_mt,2217775104 +random,memory,58747088,phmap::parallel_flat_hash_map_mt,2217775104 +random,memory,58747089,phmap::parallel_flat_hash_map_mt,2289213440 +random,memory,58790495,phmap::parallel_flat_hash_map_mt,2289213440 +random,memory,58790496,phmap::parallel_flat_hash_map_mt,2360659968 +random,memory,58912378,phmap::parallel_flat_hash_map_mt,2360659968 +random,memory,58915332,phmap::parallel_flat_hash_map_mt,2289213440 +random,time,60000000,phmap::parallel_flat_hash_map_mt,5.665000 +random,memory,60121415,phmap::parallel_flat_hash_map_mt,2289217536 +random,time,70000000,phmap::parallel_flat_hash_map_mt,6.304000 +random,memory,70000000,phmap::parallel_flat_hash_map_mt,2289008640 +random,time,80000000,phmap::parallel_flat_hash_map_mt,6.942000 +random,memory,80007185,phmap::parallel_flat_hash_map_mt,2289209344 +random,time,90000000,phmap::parallel_flat_hash_map_mt,7.608000 +random,memory,90008872,phmap::parallel_flat_hash_map_mt,2289201152 +random,time,100000000,phmap::parallel_flat_hash_map_mt,8.286000 diff --git a/extern/phmap/benchmark/results/output_flat_par_mutex_5 b/extern/phmap/benchmark/results/output_flat_par_mutex_5 new file mode 100644 index 0000000..adcfe3d --- /dev/null +++ b/extern/phmap/benchmark/results/output_flat_par_mutex_5 @@ -0,0 +1,315 @@ +random,memory,0,absl::flat_hash_map,15745024 +random,memory,238685,absl::flat_hash_map,15745024 +random,memory,238809,absl::flat_hash_map,11276288 +random,memory,458751,absl::flat_hash_map,11276288 +random,memory,458752,absl::flat_hash_map,29143040 +random,memory,485817,absl::flat_hash_map,29143040 +random,memory,486085,absl::flat_hash_map,20209664 +random,memory,675678,absl::flat_hash_map,20209664 +random,memory,675893,absl::flat_hash_map,19091456 +random,memory,917503,absl::flat_hash_map,19091456 +random,memory,917504,absl::flat_hash_map,54816768 +random,memory,927664,absl::flat_hash_map,54816768 +random,memory,927716,absl::flat_hash_map,36950016 +random,memory,1835007,absl::flat_hash_map,36950016 +random,memory,1835008,absl::flat_hash_map,108396544 +random,memory,1855763,absl::flat_hash_map,108396544 +random,memory,1855867,absl::flat_hash_map,72671232 +random,memory,3670015,absl::flat_hash_map,72671232 +random,memory,3670016,absl::flat_hash_map,215560192 +random,memory,3677233,absl::flat_hash_map,215560192 +random,memory,3677313,absl::flat_hash_map,144113664 +random,memory,7340031,absl::flat_hash_map,144113664 +random,memory,7340032,absl::flat_hash_map,429887488 +random,memory,7344858,absl::flat_hash_map,429887488 +random,memory,7344912,absl::flat_hash_map,286998528 +random,time,10000000,absl::flat_hash_map,0.935000 +random,memory,10007722,absl::flat_hash_map,286998528 +random,memory,14680063,absl::flat_hash_map,286998528 +random,memory,14680064,absl::flat_hash_map,858546176 +random,memory,14682782,absl::flat_hash_map,858546176 +random,memory,14682830,absl::flat_hash_map,572768256 +random,time,20000000,absl::flat_hash_map,2.244000 +random,memory,20010261,absl::flat_hash_map,572768256 +random,memory,29360127,absl::flat_hash_map,572768256 +random,memory,29360128,absl::flat_hash_map,1715859456 +random,memory,29363189,absl::flat_hash_map,1715859456 +random,memory,29363226,absl::flat_hash_map,1144311808 +random,time,30000000,absl::flat_hash_map,3.899000 +random,memory,30008430,absl::flat_hash_map,1144311808 +random,time,40000000,absl::flat_hash_map,5.165000 +random,memory,40003909,absl::flat_hash_map,1144311808 +random,time,50000000,absl::flat_hash_map,6.428000 +random,memory,50001112,absl::flat_hash_map,1144311808 +random,memory,58720255,absl::flat_hash_map,1144311808 +random,memory,58720256,absl::flat_hash_map,3430490112 +random,memory,58728488,absl::flat_hash_map,3430490112 +random,memory,58728529,absl::flat_hash_map,2287411200 +random,time,60000000,absl::flat_hash_map,8.813000 +random,memory,60004544,absl::flat_hash_map,2287411200 +random,time,70000000,absl::flat_hash_map,10.289000 +random,memory,70001141,absl::flat_hash_map,2287411200 +random,time,80000000,absl::flat_hash_map,11.765000 +random,memory,80002276,absl::flat_hash_map,2287411200 +random,time,90000000,absl::flat_hash_map,13.235000 +random,memory,90011453,absl::flat_hash_map,2287411200 +random,time,100000000,absl::flat_hash_map,14.683000 +random,memory,0,absl::parallel_flat_hash_map_mt,8097792 +random,memory,226683,absl::parallel_flat_hash_map_mt,8101888 +random,memory,226684,absl::parallel_flat_hash_map_mt,9236480 +random,memory,233565,absl::parallel_flat_hash_map_mt,9236480 +random,memory,233647,absl::parallel_flat_hash_map_mt,12922880 +random,memory,274958,absl::parallel_flat_hash_map_mt,13205504 +random,memory,454560,absl::parallel_flat_hash_map_mt,13205504 +random,memory,454569,absl::parallel_flat_hash_map_mt,15454208 +random,memory,458135,absl::parallel_flat_hash_map_mt,15454208 +random,memory,458136,absl::parallel_flat_hash_map_mt,20520960 +random,memory,464748,absl::parallel_flat_hash_map_mt,20520960 +random,memory,464749,absl::parallel_flat_hash_map_mt,23891968 +random,memory,585537,absl::parallel_flat_hash_map_mt,24461312 +random,memory,904457,absl::parallel_flat_hash_map_mt,24461312 +random,memory,904458,absl::parallel_flat_hash_map_mt,25587712 +random,memory,906298,absl::parallel_flat_hash_map_mt,25587712 +random,memory,906305,absl::parallel_flat_hash_map_mt,22061056 +random,memory,912070,absl::parallel_flat_hash_map_mt,22061056 +random,memory,912071,absl::parallel_flat_hash_map_mt,25481216 +random,memory,913175,absl::parallel_flat_hash_map_mt,25481216 +random,memory,913176,absl::parallel_flat_hash_map_mt,28229632 +random,memory,916122,absl::parallel_flat_hash_map_mt,28229632 +random,memory,916123,absl::parallel_flat_hash_map_mt,29917184 +random,memory,917759,absl::parallel_flat_hash_map_mt,29917184 +random,memory,917760,absl::parallel_flat_hash_map_mt,31617024 +random,memory,921180,absl::parallel_flat_hash_map_mt,31617024 +random,memory,921181,absl::parallel_flat_hash_map_mt,34426880 +random,memory,923206,absl::parallel_flat_hash_map_mt,34426880 +random,memory,923207,absl::parallel_flat_hash_map_mt,37249024 +random,memory,932268,absl::parallel_flat_hash_map_mt,37249024 +random,memory,932269,absl::parallel_flat_hash_map_mt,39493632 +random,memory,960264,absl::parallel_flat_hash_map_mt,39972864 +random,memory,1818080,absl::parallel_flat_hash_map_mt,39972864 +random,memory,1818081,absl::parallel_flat_hash_map_mt,42213376 +random,memory,1818368,absl::parallel_flat_hash_map_mt,43331584 +random,memory,1824622,absl::parallel_flat_hash_map_mt,44445696 +random,memory,1825724,absl::parallel_flat_hash_map_mt,44445696 +random,memory,1825725,absl::parallel_flat_hash_map_mt,46682112 +random,memory,1827670,absl::parallel_flat_hash_map_mt,47800320 +random,memory,1829247,absl::parallel_flat_hash_map_mt,47800320 +random,memory,1829248,absl::parallel_flat_hash_map_mt,52269056 +random,memory,1833459,absl::parallel_flat_hash_map_mt,52264960 +random,memory,1833460,absl::parallel_flat_hash_map_mt,56733696 +random,memory,1835812,absl::parallel_flat_hash_map_mt,56729600 +random,memory,1835813,absl::parallel_flat_hash_map_mt,60080128 +random,memory,1836350,absl::parallel_flat_hash_map_mt,60080128 +random,memory,1836351,absl::parallel_flat_hash_map_mt,63438848 +random,memory,1837412,absl::parallel_flat_hash_map_mt,64548864 +random,memory,1838938,absl::parallel_flat_hash_map_mt,64548864 +random,memory,1838939,absl::parallel_flat_hash_map_mt,66777088 +random,memory,1839594,absl::parallel_flat_hash_map_mt,67891200 +random,memory,1841385,absl::parallel_flat_hash_map_mt,67891200 +random,memory,1841386,absl::parallel_flat_hash_map_mt,70123520 +random,memory,1843499,absl::parallel_flat_hash_map_mt,70123520 +random,memory,1843500,absl::parallel_flat_hash_map_mt,74596352 +random,memory,1851800,absl::parallel_flat_hash_map_mt,76824576 +random,memory,1881249,absl::parallel_flat_hash_map_mt,76824576 +random,memory,1881322,absl::parallel_flat_hash_map_mt,75706368 +random,memory,3642650,absl::parallel_flat_hash_map_mt,75706368 +random,memory,3642651,absl::parallel_flat_hash_map_mt,80175104 +random,memory,3650189,absl::parallel_flat_hash_map_mt,82411520 +random,memory,3658302,absl::parallel_flat_hash_map_mt,84652032 +random,memory,3659792,absl::parallel_flat_hash_map_mt,86884352 +random,memory,3660327,absl::parallel_flat_hash_map_mt,89116672 +random,memory,3662326,absl::parallel_flat_hash_map_mt,89116672 +random,memory,3662327,absl::parallel_flat_hash_map_mt,95813632 +random,memory,3666371,absl::parallel_flat_hash_map_mt,95817728 +random,memory,3666372,absl::parallel_flat_hash_map_mt,102522880 +random,memory,3667092,absl::parallel_flat_hash_map_mt,104767488 +random,memory,3667485,absl::parallel_flat_hash_map_mt,104767488 +random,memory,3667486,absl::parallel_flat_hash_map_mt,111464448 +random,memory,3668276,absl::parallel_flat_hash_map_mt,111464448 +random,memory,3668277,absl::parallel_flat_hash_map_mt,115920896 +random,memory,3670350,absl::parallel_flat_hash_map_mt,118145024 +random,memory,3671585,absl::parallel_flat_hash_map_mt,120381440 +random,memory,3672959,absl::parallel_flat_hash_map_mt,122617856 +random,memory,3673809,absl::parallel_flat_hash_map_mt,122617856 +random,memory,3673810,absl::parallel_flat_hash_map_mt,129314816 +random,memory,3675897,absl::parallel_flat_hash_map_mt,131547136 +random,memory,3676555,absl::parallel_flat_hash_map_mt,133783552 +random,memory,3676779,absl::parallel_flat_hash_map_mt,136015872 +random,memory,3677839,absl::parallel_flat_hash_map_mt,138244096 +random,memory,3678355,absl::parallel_flat_hash_map_mt,140472320 +random,memory,3678866,absl::parallel_flat_hash_map_mt,142700544 +random,memory,3690202,absl::parallel_flat_hash_map_mt,142700544 +random,memory,3690203,absl::parallel_flat_hash_map_mt,149397504 +random,memory,3722970,absl::parallel_flat_hash_map_mt,149393408 +random,memory,3723091,absl::parallel_flat_hash_map_mt,147161088 +random,memory,7304291,absl::parallel_flat_hash_map_mt,147161088 +random,memory,7304305,absl::parallel_flat_hash_map_mt,156094464 +random,memory,7317618,absl::parallel_flat_hash_map_mt,160567296 +random,memory,7321953,absl::parallel_flat_hash_map_mt,165027840 +random,memory,7324203,absl::parallel_flat_hash_map_mt,169492480 +random,memory,7327095,absl::parallel_flat_hash_map_mt,173953024 +random,memory,7329008,absl::parallel_flat_hash_map_mt,178417664 +random,memory,7330112,absl::parallel_flat_hash_map_mt,182886400 +random,memory,7330870,absl::parallel_flat_hash_map_mt,187346944 +random,memory,7332208,absl::parallel_flat_hash_map_mt,191815680 +random,memory,7332866,absl::parallel_flat_hash_map_mt,196280320 +random,memory,7333480,absl::parallel_flat_hash_map_mt,196280320 +random,memory,7333481,absl::parallel_flat_hash_map_mt,209686528 +random,memory,7336329,absl::parallel_flat_hash_map_mt,214155264 +random,memory,7337014,absl::parallel_flat_hash_map_mt,218624000 +random,memory,7338084,absl::parallel_flat_hash_map_mt,223092736 +random,memory,7338525,absl::parallel_flat_hash_map_mt,227553280 +random,memory,7340267,absl::parallel_flat_hash_map_mt,232026112 +random,memory,7340739,absl::parallel_flat_hash_map_mt,236490752 +random,memory,7342416,absl::parallel_flat_hash_map_mt,240955392 +random,memory,7343877,absl::parallel_flat_hash_map_mt,245415936 +random,memory,7348892,absl::parallel_flat_hash_map_mt,245415936 +random,memory,7348911,absl::parallel_flat_hash_map_mt,240947200 +random,memory,7349331,absl::parallel_flat_hash_map_mt,240947200 +random,memory,7349332,absl::parallel_flat_hash_map_mt,249876480 +random,memory,7349765,absl::parallel_flat_hash_map_mt,254345216 +random,memory,7349943,absl::parallel_flat_hash_map_mt,258818048 +random,memory,7351616,absl::parallel_flat_hash_map_mt,263278592 +random,memory,7352328,absl::parallel_flat_hash_map_mt,267739136 +random,memory,7352954,absl::parallel_flat_hash_map_mt,272199680 +random,memory,7353831,absl::parallel_flat_hash_map_mt,276664320 +random,memory,7360307,absl::parallel_flat_hash_map_mt,281124864 +random,memory,7360322,absl::parallel_flat_hash_map_mt,281124864 +random,memory,7360340,absl::parallel_flat_hash_map_mt,276656128 +random,memory,7362083,absl::parallel_flat_hash_map_mt,276656128 +random,memory,7362084,absl::parallel_flat_hash_map_mt,285589504 +random,memory,7368696,absl::parallel_flat_hash_map_mt,290050048 +random,memory,7370511,absl::parallel_flat_hash_map_mt,294510592 +random,memory,7545581,absl::parallel_flat_hash_map_mt,294510592 +random,memory,7545600,absl::parallel_flat_hash_map_mt,290041856 +random,time,10000000,absl::parallel_flat_hash_map_mt,0.685000 +random,memory,10125610,absl::parallel_flat_hash_map_mt,290045952 +random,memory,14624490,absl::parallel_flat_hash_map_mt,290045952 +random,memory,14624491,absl::parallel_flat_hash_map_mt,307908608 +random,memory,14640456,absl::parallel_flat_hash_map_mt,316846080 +random,memory,14645771,absl::parallel_flat_hash_map_mt,325771264 +random,memory,14646996,absl::parallel_flat_hash_map_mt,334704640 +random,memory,14657141,absl::parallel_flat_hash_map_mt,334704640 +random,memory,14657247,absl::parallel_flat_hash_map_mt,325775360 +random,memory,14658963,absl::parallel_flat_hash_map_mt,325775360 +random,memory,14658964,absl::parallel_flat_hash_map_mt,343642112 +random,memory,14659931,absl::parallel_flat_hash_map_mt,352571392 +random,memory,14665267,absl::parallel_flat_hash_map_mt,352571392 +random,memory,14665268,absl::parallel_flat_hash_map_mt,379363328 +random,memory,14670387,absl::parallel_flat_hash_map_mt,379363328 +random,memory,14670388,absl::parallel_flat_hash_map_mt,397221888 +random,memory,14671763,absl::parallel_flat_hash_map_mt,397221888 +random,memory,14671764,absl::parallel_flat_hash_map_mt,424009728 +random,memory,14677622,absl::parallel_flat_hash_map_mt,432939008 +random,memory,14680084,absl::parallel_flat_hash_map_mt,441864192 +random,memory,14680689,absl::parallel_flat_hash_map_mt,450789376 +random,memory,14683195,absl::parallel_flat_hash_map_mt,459726848 +random,memory,14683950,absl::parallel_flat_hash_map_mt,468652032 +random,memory,14688089,absl::parallel_flat_hash_map_mt,477581312 +random,memory,14691193,absl::parallel_flat_hash_map_mt,486514688 +random,memory,14694936,absl::parallel_flat_hash_map_mt,495443968 +random,memory,14696388,absl::parallel_flat_hash_map_mt,504377344 +random,memory,14697737,absl::parallel_flat_hash_map_mt,513314816 +random,memory,14698140,absl::parallel_flat_hash_map_mt,522248192 +random,memory,14699618,absl::parallel_flat_hash_map_mt,531177472 +random,memory,14700009,absl::parallel_flat_hash_map_mt,540110848 +random,memory,14700466,absl::parallel_flat_hash_map_mt,540110848 +random,memory,14700467,absl::parallel_flat_hash_map_mt,566910976 +random,memory,14716491,absl::parallel_flat_hash_map_mt,575832064 +random,memory,14739622,absl::parallel_flat_hash_map_mt,584757248 +random,memory,14831157,absl::parallel_flat_hash_map_mt,584757248 +random,memory,14831255,absl::parallel_flat_hash_map_mt,575823872 +random,time,20000000,absl::parallel_flat_hash_map_mt,1.386000 +random,memory,20162525,absl::parallel_flat_hash_map_mt,575811584 +random,memory,29290166,absl::parallel_flat_hash_map_mt,575811584 +random,memory,29290167,absl::parallel_flat_hash_map_mt,611536896 +random,memory,29290166,absl::parallel_flat_hash_map_mt,611536896 +random,memory,29290167,absl::parallel_flat_hash_map_mt,647262208 +random,memory,29308217,absl::parallel_flat_hash_map_mt,665128960 +random,memory,29316853,absl::parallel_flat_hash_map_mt,682983424 +random,memory,29322818,absl::parallel_flat_hash_map_mt,682983424 +random,memory,29322819,absl::parallel_flat_hash_map_mt,736567296 +random,memory,29335771,absl::parallel_flat_hash_map_mt,754425856 +random,memory,29341930,absl::parallel_flat_hash_map_mt,772284416 +random,memory,29343145,absl::parallel_flat_hash_map_mt,790142976 +random,memory,29350232,absl::parallel_flat_hash_map_mt,808005632 +random,memory,29354162,absl::parallel_flat_hash_map_mt,825868288 +random,memory,29356843,absl::parallel_flat_hash_map_mt,843722752 +random,memory,29362327,absl::parallel_flat_hash_map_mt,843722752 +random,memory,29362363,absl::parallel_flat_hash_map_mt,825860096 +random,memory,29366343,absl::parallel_flat_hash_map_mt,825860096 +random,memory,29366344,absl::parallel_flat_hash_map_mt,861585408 +random,memory,29369094,absl::parallel_flat_hash_map_mt,879448064 +random,memory,29370268,absl::parallel_flat_hash_map_mt,897310720 +random,memory,29370522,absl::parallel_flat_hash_map_mt,897310720 +random,memory,29370585,absl::parallel_flat_hash_map_mt,879452160 +random,memory,29371240,absl::parallel_flat_hash_map_mt,879452160 +random,memory,29371241,absl::parallel_flat_hash_map_mt,915177472 +random,memory,29377637,absl::parallel_flat_hash_map_mt,933036032 +random,memory,29378552,absl::parallel_flat_hash_map_mt,950894592 +random,memory,29380612,absl::parallel_flat_hash_map_mt,968757248 +random,memory,29382146,absl::parallel_flat_hash_map_mt,986615808 +random,memory,29383649,absl::parallel_flat_hash_map_mt,1004474368 +random,memory,29386774,absl::parallel_flat_hash_map_mt,1022328832 +random,memory,29391253,absl::parallel_flat_hash_map_mt,1040187392 +random,memory,29392067,absl::parallel_flat_hash_map_mt,1058045952 +random,memory,29393223,absl::parallel_flat_hash_map_mt,1075908608 +random,memory,29397664,absl::parallel_flat_hash_map_mt,1093763072 +random,memory,29397820,absl::parallel_flat_hash_map_mt,1111621632 +random,memory,29402968,absl::parallel_flat_hash_map_mt,1129480192 +random,memory,29416940,absl::parallel_flat_hash_map_mt,1147346944 +random,memory,29425034,absl::parallel_flat_hash_map_mt,1165201408 +random,memory,29437495,absl::parallel_flat_hash_map_mt,1165201408 +random,memory,29437615,absl::parallel_flat_hash_map_mt,1147342848 +random,time,30000000,absl::parallel_flat_hash_map_mt,2.397000 +random,memory,30000064,absl::parallel_flat_hash_map_mt,1147179008 +random,time,40000000,absl::parallel_flat_hash_map_mt,2.894000 +random,memory,40092788,absl::parallel_flat_hash_map_mt,1147342848 +random,time,50000000,absl::parallel_flat_hash_map_mt,3.419000 +random,memory,50016621,absl::parallel_flat_hash_map_mt,1147351040 +random,memory,58617730,absl::parallel_flat_hash_map_mt,1147351040 +random,memory,58617731,absl::parallel_flat_hash_map_mt,1218797568 +random,memory,58624447,absl::parallel_flat_hash_map_mt,1254522880 +random,memory,58647163,absl::parallel_flat_hash_map_mt,1290244096 +random,memory,58652294,absl::parallel_flat_hash_map_mt,1290244096 +random,memory,58652331,absl::parallel_flat_hash_map_mt,1254518784 +random,memory,58657858,absl::parallel_flat_hash_map_mt,1254518784 +random,memory,58657859,absl::parallel_flat_hash_map_mt,1325965312 +random,memory,58672238,absl::parallel_flat_hash_map_mt,1361690624 +random,memory,58684143,absl::parallel_flat_hash_map_mt,1361690624 +random,memory,58684144,absl::parallel_flat_hash_map_mt,1468854272 +random,memory,58686216,absl::parallel_flat_hash_map_mt,1504571392 +random,memory,58705047,absl::parallel_flat_hash_map_mt,1540292608 +random,memory,58707030,absl::parallel_flat_hash_map_mt,1576017920 +random,memory,58713785,absl::parallel_flat_hash_map_mt,1611739136 +random,memory,58719051,absl::parallel_flat_hash_map_mt,1647460352 +random,memory,58719339,absl::parallel_flat_hash_map_mt,1683181568 +random,memory,58721442,absl::parallel_flat_hash_map_mt,1718906880 +random,memory,58722510,absl::parallel_flat_hash_map_mt,1754628096 +random,memory,58731866,absl::parallel_flat_hash_map_mt,1790353408 +random,memory,58732950,absl::parallel_flat_hash_map_mt,1826086912 +random,memory,58733354,absl::parallel_flat_hash_map_mt,1861804032 +random,memory,58734852,absl::parallel_flat_hash_map_mt,1897525248 +random,memory,58735358,absl::parallel_flat_hash_map_mt,1933242368 +random,memory,58739746,absl::parallel_flat_hash_map_mt,1968967680 +random,memory,58739993,absl::parallel_flat_hash_map_mt,2004692992 +random,memory,58745310,absl::parallel_flat_hash_map_mt,2040410112 +random,memory,58746926,absl::parallel_flat_hash_map_mt,2076135424 +random,memory,58747125,absl::parallel_flat_hash_map_mt,2111860736 +random,memory,58756624,absl::parallel_flat_hash_map_mt,2147586048 +random,memory,58769646,absl::parallel_flat_hash_map_mt,2183303168 +random,memory,58771866,absl::parallel_flat_hash_map_mt,2219024384 +random,memory,58789875,absl::parallel_flat_hash_map_mt,2254741504 +random,memory,58798355,absl::parallel_flat_hash_map_mt,2290466816 +random,memory,58824040,absl::parallel_flat_hash_map_mt,2326183936 +random,memory,59024387,absl::parallel_flat_hash_map_mt,2326183936 +random,memory,59024466,absl::parallel_flat_hash_map_mt,2290458624 +random,time,60000000,absl::parallel_flat_hash_map_mt,4.973000 +random,memory,60000000,absl::parallel_flat_hash_map_mt,2290229248 +random,time,70000000,absl::parallel_flat_hash_map_mt,5.544000 +random,memory,70133805,absl::parallel_flat_hash_map_mt,2290458624 +random,time,80000000,absl::parallel_flat_hash_map_mt,6.054000 +random,memory,80033533,absl::parallel_flat_hash_map_mt,2290458624 +random,time,90000000,absl::parallel_flat_hash_map_mt,6.624000 +random,memory,90023483,absl::parallel_flat_hash_map_mt,2290458624 +random,time,100000000,absl::parallel_flat_hash_map_mt,7.175000 diff --git a/extern/phmap/benchmark/results/output_mt_par_only b/extern/phmap/benchmark/results/output_mt_par_only new file mode 100644 index 0000000..30ed8e4 --- /dev/null +++ b/extern/phmap/benchmark/results/output_mt_par_only @@ -0,0 +1,104 @@ +random,memory,0,absl::parallel_flat_hash_map,41910272 +random,memory,924422,absl::parallel_flat_hash_map,41910272 +random,memory,924433,absl::parallel_flat_hash_map,44146688 +random,memory,952903,absl::parallel_flat_hash_map,44146688 +random,memory,953013,absl::parallel_flat_hash_map,40779776 +random,memory,1010078,absl::parallel_flat_hash_map,40779776 +random,memory,1010200,absl::parallel_flat_hash_map,38539264 +random,memory,1863512,absl::parallel_flat_hash_map,38539264 +random,memory,1863540,absl::parallel_flat_hash_map,85454848 +random,memory,2941624,absl::parallel_flat_hash_map,85454848 +random,memory,2941816,absl::parallel_flat_hash_map,74272768 +random,memory,3683917,absl::parallel_flat_hash_map,74272768 +random,memory,3683918,absl::parallel_flat_hash_map,154685440 +random,memory,3692980,absl::parallel_flat_hash_map,154685440 +random,memory,3693011,absl::parallel_flat_hash_map,168075264 +random,memory,4474443,absl::parallel_flat_hash_map,168075264 +random,memory,4474556,absl::parallel_flat_hash_map,145719296 +random,memory,6754095,absl::parallel_flat_hash_map,145707008 +random,memory,6754147,absl::parallel_flat_hash_map,226099200 +random,memory,7294556,absl::parallel_flat_hash_map,226099200 +random,memory,7294670,absl::parallel_flat_hash_map,235036672 +random,memory,7983489,absl::parallel_flat_hash_map,235036672 +random,memory,7983651,absl::parallel_flat_hash_map,261820416 +random,memory,8242552,absl::parallel_flat_hash_map,261820416 +random,memory,8242691,absl::parallel_flat_hash_map,252887040 +random,memory,8949833,absl::parallel_flat_hash_map,252887040 +random,memory,8949892,absl::parallel_flat_hash_map,305504256 +random,memory,8987991,absl::parallel_flat_hash_map,305475584 +random,memory,8988323,absl::parallel_flat_hash_map,296538112 +random,memory,9004502,absl::parallel_flat_hash_map,296538112 +random,memory,9004594,absl::parallel_flat_hash_map,287604736 +random,time,10000000,absl::parallel_flat_hash_map,0.471000 +random,memory,10862319,absl::parallel_flat_hash_map,287756288 +random,memory,14670115,absl::parallel_flat_hash_map,287756288 +random,memory,14670116,absl::parallel_flat_hash_map,573566976 +random,memory,14678079,absl::parallel_flat_hash_map,573566976 +random,memory,14678102,absl::parallel_flat_hash_map,627142656 +random,memory,14690163,absl::parallel_flat_hash_map,627142656 +random,memory,14690164,absl::parallel_flat_hash_map,716455936 +random,memory,15024573,absl::parallel_flat_hash_map,716455936 +random,memory,15024686,absl::parallel_flat_hash_map,591388672 +random,memory,15476837,absl::parallel_flat_hash_map,591388672 +random,memory,15476994,absl::parallel_flat_hash_map,573521920 +random,time,20000000,absl::parallel_flat_hash_map,0.956000 +random,memory,20410280,absl::parallel_flat_hash_map,573497344 +random,memory,29273379,absl::parallel_flat_hash_map,573497344 +random,memory,29273380,absl::parallel_flat_hash_map,1073627136 +random,memory,29353638,absl::parallel_flat_hash_map,1073627136 +random,memory,29353639,absl::parallel_flat_hash_map,1252241408 +random,memory,29686553,absl::parallel_flat_hash_map,1287847936 +random,memory,29688294,absl::parallel_flat_hash_map,1287847936 +random,memory,29688316,absl::parallel_flat_hash_map,1252122624 +random,memory,29707720,absl::parallel_flat_hash_map,1252122624 +random,memory,29707784,absl::parallel_flat_hash_map,1180663808 +random,memory,29924480,absl::parallel_flat_hash_map,1180577792 +random,memory,29924509,absl::parallel_flat_hash_map,1144856576 +random,time,30000000,absl::parallel_flat_hash_map,1.567000 +random,memory,30708549,absl::parallel_flat_hash_map,1145061376 +random,time,40000000,absl::parallel_flat_hash_map,1.993000 +random,memory,40790845,absl::parallel_flat_hash_map,1145049088 +random,time,50000000,absl::parallel_flat_hash_map,2.423000 +random,memory,50009479,absl::parallel_flat_hash_map,1145065472 +random,memory,58110357,absl::parallel_flat_hash_map,1145065472 +random,memory,58110423,absl::parallel_flat_hash_map,1716617216 +random,memory,58545607,absl::parallel_flat_hash_map,1716617216 +random,memory,58545651,absl::parallel_flat_hash_map,1859506176 +random,memory,58671713,absl::parallel_flat_hash_map,1859506176 +random,memory,58672142,absl::parallel_flat_hash_map,2002403328 +random,memory,58697955,absl::parallel_flat_hash_map,2002403328 +random,memory,58697956,absl::parallel_flat_hash_map,2288181248 +random,memory,58704727,absl::parallel_flat_hash_map,2288181248 +random,memory,58704728,absl::parallel_flat_hash_map,2359627776 +random,memory,58705597,absl::parallel_flat_hash_map,2359627776 +random,memory,58705598,absl::parallel_flat_hash_map,2288181248 +random,memory,58730957,absl::parallel_flat_hash_map,2288181248 +random,memory,58730958,absl::parallel_flat_hash_map,2573950976 +random,memory,58736077,absl::parallel_flat_hash_map,2645401600 +random,memory,58736169,absl::parallel_flat_hash_map,2716848128 +random,memory,58742702,absl::parallel_flat_hash_map,2716848128 +random,memory,58742703,absl::parallel_flat_hash_map,2859741184 +random,memory,58787870,absl::parallel_flat_hash_map,2859741184 +random,memory,58787918,absl::parallel_flat_hash_map,2716848128 +random,memory,58863920,absl::parallel_flat_hash_map,2716848128 +random,memory,58863994,absl::parallel_flat_hash_map,2645397504 +random,memory,59087411,absl::parallel_flat_hash_map,2645397504 +random,memory,59087521,absl::parallel_flat_hash_map,2573955072 +random,memory,59355340,absl::parallel_flat_hash_map,2573877248 +random,memory,59355391,absl::parallel_flat_hash_map,2502426624 +random,memory,59387965,absl::parallel_flat_hash_map,2502426624 +random,memory,59388025,absl::parallel_flat_hash_map,2430980096 +random,memory,59484220,absl::parallel_flat_hash_map,2430951424 +random,memory,59484283,absl::parallel_flat_hash_map,2359500800 +random,memory,59503076,absl::parallel_flat_hash_map,2359500800 +random,memory,59503156,absl::parallel_flat_hash_map,2288058368 +random,time,60000000,absl::parallel_flat_hash_map,3.220000 +random,memory,60745902,absl::parallel_flat_hash_map,2288160768 +random,time,70000000,absl::parallel_flat_hash_map,3.671000 +random,memory,70722318,absl::parallel_flat_hash_map,2288156672 +random,time,80000000,absl::parallel_flat_hash_map,4.159000 +random,memory,80002281,absl::parallel_flat_hash_map,2288119808 +random,time,90000000,absl::parallel_flat_hash_map,4.615000 +random,memory,90715643,absl::parallel_flat_hash_map,2288152576 +random,time,100000000,absl::parallel_flat_hash_map,5.128000 +random,memory,100000000,absl::parallel_flat_hash_map,2287927296 diff --git a/extern/phmap/benchmark/results/output_mt_stl_flat_par b/extern/phmap/benchmark/results/output_mt_stl_flat_par new file mode 100644 index 0000000..e6b94d5 --- /dev/null +++ b/extern/phmap/benchmark/results/output_mt_stl_flat_par @@ -0,0 +1,446 @@ +random,memory,0,std::unordered_map,6217728 +random,memory,81839,std::unordered_map,6217728 +random,memory,81866,std::unordered_map,7081984 +random,memory,96791,std::unordered_map,7081984 +random,memory,96811,std::unordered_map,7938048 +random,memory,108492,std::unordered_map,7938048 +random,memory,108510,std::unordered_map,8482816 +random,memory,119431,std::unordered_map,8482816 +random,memory,119443,std::unordered_map,9027584 +random,memory,127648,std::unordered_map,9027584 +random,memory,127666,std::unordered_map,9420800 +random,memory,131071,std::unordered_map,9420800 +random,memory,131072,std::unordered_map,11681792 +random,memory,140589,std::unordered_map,11681792 +random,memory,140596,std::unordered_map,12238848 +random,memory,152717,std::unordered_map,12238848 +random,memory,152732,std::unordered_map,12861440 +random,memory,164819,std::unordered_map,12861440 +random,memory,164832,std::unordered_map,13570048 +random,memory,176210,std::unordered_map,13570048 +random,memory,176219,std::unordered_map,14192640 +random,memory,185598,std::unordered_map,14581760 +random,memory,195438,std::unordered_map,14581760 +random,memory,195443,std::unordered_map,15126528 +random,memory,206045,std::unordered_map,15126528 +random,memory,206062,std::unordered_map,15675392 +random,memory,216715,std::unordered_map,15675392 +random,memory,216726,std::unordered_map,16220160 +random,memory,227698,std::unordered_map,16220160 +random,memory,227712,std::unordered_map,16764928 +random,memory,238365,std::unordered_map,16764928 +random,memory,238381,std::unordered_map,17309696 +random,memory,248089,std::unordered_map,17309696 +random,memory,248095,std::unordered_map,17858560 +random,memory,257442,std::unordered_map,18325504 +random,memory,262143,std::unordered_map,18325504 +random,memory,262144,std::unordered_map,26894336 +random,memory,262143,std::unordered_map,26894336 +random,memory,262144,std::unordered_map,22691840 +random,memory,273217,std::unordered_map,23314432 +random,memory,284202,std::unordered_map,23937024 +random,memory,294934,std::unordered_map,24403968 +random,memory,304770,std::unordered_map,24948736 +random,memory,314973,std::unordered_map,25497600 +random,memory,325228,std::unordered_map,26046464 +random,memory,335546,std::unordered_map,26591232 +random,memory,344776,std::unordered_map,26980352 +random,memory,353536,std::unordered_map,27525120 +random,memory,362203,std::unordered_map,27996160 +random,memory,371418,std::unordered_map,28385280 +random,memory,380977,std::unordered_map,28852224 +random,memory,390397,std::unordered_map,29396992 +random,memory,399764,std::unordered_map,29863936 +random,memory,409260,std::unordered_map,30334976 +random,memory,418252,std::unordered_map,30801920 +random,memory,426340,std::unordered_map,31191040 +random,memory,434549,std::unordered_map,31657984 +random,memory,443151,std::unordered_map,32129024 +random,memory,451873,std::unordered_map,32518144 +random,memory,460714,std::unordered_map,32985088 +random,memory,469657,std::unordered_map,33476608 +random,memory,478601,std::unordered_map,33865728 +random,memory,487440,std::unordered_map,34336768 +random,memory,494742,std::unordered_map,34725888 +random,memory,502423,std::unordered_map,35192832 +random,memory,518619,std::unordered_map,35971072 +random,memory,524287,std::unordered_map,35971072 +random,memory,524288,std::unordered_map,53104640 +random,memory,524287,std::unordered_map,53104640 +random,memory,524288,std::unordered_map,44699648 +random,memory,549272,std::unordered_map,45944832 +random,memory,558487,std::unordered_map,46411776 +random,memory,568160,std::unordered_map,46882816 +random,memory,577422,std::unordered_map,47427584 +random,memory,605424,std::unordered_map,48828416 +random,memory,640487,std::unordered_map,50622464 +random,memory,649784,std::unordered_map,51171328 +random,memory,684975,std::unordered_map,52965376 +random,memory,718904,std::unordered_map,54677504 +random,memory,753470,std::unordered_map,56393728 +random,memory,787320,std::unordered_map,58187776 +random,memory,828012,std::unordered_map,60215296 +random,memory,868058,std::unordered_map,62320640 +random,memory,906661,std::unordered_map,64348160 +random,memory,945911,std::unordered_map,66297856 +random,memory,990443,std::unordered_map,68644864 +random,memory,1036174,std::unordered_map,70983680 +random,memory,1048575,std::unordered_map,71294976 +random,memory,1048576,std::unordered_map,105234432 +random,memory,1048575,std::unordered_map,105234432 +random,memory,1048576,std::unordered_map,88424448 +random,memory,1100160,std::unordered_map,91078656 +random,memory,1160386,std::unordered_map,94117888 +random,memory,1221920,std::unordered_map,97316864 +random,memory,1282706,std::unordered_map,100433920 +random,memory,1342726,std::unordered_map,103477248 +random,memory,1401981,std::unordered_map,106594304 +random,memory,1464762,std::unordered_map,109793280 +random,memory,1530705,std::unordered_map,113143808 +random,memory,1603780,std::unordered_map,116887552 +random,memory,1674989,std::unordered_map,120631296 +random,memory,1752908,std::unordered_map,124608512 +random,memory,1826840,std::unordered_map,128352256 +random,memory,1901645,std::unordered_map,132247552 +random,memory,1981814,std::unordered_map,136306688 +random,memory,2068859,std::unordered_map,140754944 +random,memory,2097151,std::unordered_map,141922304 +random,memory,2097152,std::unordered_map,209481728 +random,memory,2097151,std::unordered_map,209481728 +random,memory,2097152,std::unordered_map,175861760 +random,memory,2207315,std::unordered_map,181477376 +random,memory,2312577,std::unordered_map,186937344 +random,memory,2423407,std::unordered_map,192659456 +random,memory,2540989,std::unordered_map,198664192 +random,memory,2659046,std::unordered_map,204750848 +random,memory,2780893,std::unordered_map,210989056 +random,memory,2908456,std::unordered_map,217616384 +random,memory,3037917,std::unordered_map,224169984 +random,memory,3170468,std::unordered_map,230952960 +random,memory,3306278,std::unordered_map,237973504 +random,memory,3450118,std::unordered_map,245383168 +random,memory,3598043,std::unordered_map,252985344 +random,memory,3747662,std::unordered_map,260706304 +random,memory,3904906,std::unordered_map,268820480 +random,memory,4066463,std::unordered_map,277086208 +random,memory,4194303,std::unordered_map,283484160 +random,memory,4194304,std::unordered_map,418127872 +random,memory,4194303,std::unordered_map,418127872 +random,memory,4194304,std::unordered_map,350887936 +random,memory,4406007,std::unordered_map,361725952 +random,memory,4618998,std::unordered_map,372645888 +random,memory,4841808,std::unordered_map,384188416 +random,memory,5068021,std::unordered_map,395784192 +random,memory,5303596,std::unordered_map,407875584 +random,memory,5541719,std::unordered_map,420122624 +random,memory,5791497,std::unordered_map,432910336 +random,memory,6050086,std::unordered_map,446242816 +random,memory,6317526,std::unordered_map,459972608 +random,memory,6591123,std::unordered_map,474009600 +random,memory,6871888,std::unordered_map,488439808 +random,memory,7157069,std::unordered_map,503103488 +random,memory,7455408,std::unordered_map,518389760 +random,memory,7759096,std::unordered_map,533991424 +random,memory,8071668,std::unordered_map,550060032 +random,memory,8388607,std::unordered_map,566202368 +random,memory,8388608,std::unordered_map,835330048 +random,memory,8388607,std::unordered_map,835330048 +random,memory,8388608,std::unordered_map,700846080 +random,memory,8800929,std::unordered_map,721985536 +random,memory,9229377,std::unordered_map,743981056 +random,memory,9669903,std::unordered_map,766681088 +random,time,10000000,std::unordered_map,4.058000 +random,memory,10006234,std::unordered_map,783917056 +random,memory,10471995,std::unordered_map,807780352 +random,memory,10944895,std::unordered_map,832118784 +random,memory,11437088,std::unordered_map,857387008 +random,memory,11942425,std::unordered_map,883281920 +random,memory,12462221,std::unordered_map,910032896 +random,memory,12997032,std::unordered_map,937488384 +random,memory,13549619,std::unordered_map,965877760 +random,memory,14116358,std::unordered_map,994889728 +random,memory,14695755,std::unordered_map,1024761856 +random,memory,15302036,std::unordered_map,1055805440 +random,memory,15922424,std::unordered_map,1087705088 +random,memory,16564203,std::unordered_map,1120698368 +random,memory,16777216,std::unordered_map,1131618304 +random,memory,16777217,std::unordered_map,1669545984 +random,memory,16777216,std::unordered_map,1669545984 +random,memory,16777217,std::unordered_map,1400582144 +random,memory,17598216,std::unordered_map,1442697216 +random,memory,18446165,std::unordered_map,1486299136 +random,memory,19317877,std::unordered_map,1531068416 +random,time,20000000,std::unordered_map,8.836000 +random,memory,20005214,std::unordered_map,1566400512 +random,memory,20925154,std::unordered_map,1613586432 +random,memory,21874581,std::unordered_map,1662332928 +random,memory,22851058,std::unordered_map,1712484352 +random,memory,23854188,std::unordered_map,1764044800 +random,memory,24889194,std::unordered_map,1817235456 +random,memory,25956856,std::unordered_map,1871986688 +random,memory,27052917,std::unordered_map,1928302592 +random,memory,28182525,std::unordered_map,1986330624 +random,memory,29343496,std::unordered_map,2045997056 +random,time,30000000,std::unordered_map,12.189000 +random,memory,30003110,std::unordered_map,2079850496 +random,memory,31219769,std::unordered_map,2142253056 +random,memory,32472749,std::unordered_map,2206601216 +random,memory,33554433,std::unordered_map,2262134784 +random,memory,33554434,std::unordered_map,3338063872 +random,memory,33554433,std::unordered_map,3338063872 +random,memory,33554434,std::unordered_map,2800144384 +random,memory,35192104,std::unordered_map,2884296704 +random,memory,36882738,std::unordered_map,2971029504 +random,memory,38624262,std::unordered_map,3060490240 +random,time,40000000,std::unordered_map,19.469000 +random,memory,40004148,std::unordered_map,3131314176 +random,memory,41836642,std::unordered_map,3225452544 +random,memory,43723699,std::unordered_map,3322322944 +random,memory,45664059,std::unordered_map,3422003200 +random,memory,47663952,std::unordered_map,3524804608 +random,memory,49729822,std::unordered_map,3630796800 +random,time,50000000,std::unordered_map,22.945000 +random,memory,50002422,std::unordered_map,3644837888 +random,memory,52133946,std::unordered_map,3754262528 +random,memory,54331297,std::unordered_map,3867045888 +random,memory,56594458,std::unordered_map,3983339520 +random,memory,58922279,std::unordered_map,4102909952 +random,time,60000000,std::unordered_map,26.724001 +random,memory,60000504,std::unordered_map,4158287872 +random,memory,62432538,std::unordered_map,4283162624 +random,memory,64938021,std::unordered_map,4411858944 +random,memory,67108867,std::unordered_map,4523159552 +random,memory,67108868,std::unordered_map,6675017728 +random,memory,67108867,std::unordered_map,6674984960 +random,memory,67108868,std::unordered_map,5599145984 +random,time,70000000,std::unordered_map,38.929001 +random,memory,70005239,std::unordered_map,5747884032 +random,memory,73363452,std::unordered_map,5920329728 +random,memory,76824572,std::unordered_map,6098083840 +random,time,80000000,std::unordered_map,42.421001 +random,memory,80004058,std::unordered_map,6261411840 +random,memory,83663065,std::unordered_map,6449299456 +random,memory,87431119,std::unordered_map,6642888704 +random,time,90000000,std::unordered_map,46.064999 +random,memory,90003941,std::unordered_map,6775009280 +random,memory,93967227,std::unordered_map,6978502656 +random,memory,98046859,std::unordered_map,7188000768 +random,time,100000000,std::unordered_map,49.808998 +random,memory,0,absl::flat_hash_map,15753216 +random,memory,246268,absl::flat_hash_map,15753216 +random,memory,246423,absl::flat_hash_map,11280384 +random,memory,458751,absl::flat_hash_map,11280384 +random,memory,458752,absl::flat_hash_map,29143040 +random,memory,494344,absl::flat_hash_map,29143040 +random,memory,494581,absl::flat_hash_map,20209664 +random,memory,587568,absl::flat_hash_map,20209664 +random,memory,587757,absl::flat_hash_map,19087360 +random,memory,917503,absl::flat_hash_map,19087360 +random,memory,917504,absl::flat_hash_map,54812672 +random,memory,933203,absl::flat_hash_map,54812672 +random,memory,933351,absl::flat_hash_map,36950016 +random,memory,1835007,absl::flat_hash_map,36950016 +random,memory,1835008,absl::flat_hash_map,108396544 +random,memory,1862555,absl::flat_hash_map,108396544 +random,memory,1862669,absl::flat_hash_map,72671232 +random,memory,3670015,absl::flat_hash_map,72671232 +random,memory,3670016,absl::flat_hash_map,215560192 +random,memory,3671239,absl::flat_hash_map,215560192 +random,memory,3671292,absl::flat_hash_map,144113664 +random,memory,7340031,absl::flat_hash_map,144113664 +random,memory,7340032,absl::flat_hash_map,429895680 +random,memory,7357262,absl::flat_hash_map,429895680 +random,memory,7357325,absl::flat_hash_map,287002624 +random,time,10000000,absl::flat_hash_map,0.917000 +random,memory,10004410,absl::flat_hash_map,287002624 +random,memory,14680063,absl::flat_hash_map,287002624 +random,memory,14680064,absl::flat_hash_map,858546176 +random,memory,14692106,absl::flat_hash_map,858546176 +random,memory,14692158,absl::flat_hash_map,572772352 +random,time,20000000,absl::flat_hash_map,2.219000 +random,memory,20000770,absl::flat_hash_map,572772352 +random,memory,29360127,absl::flat_hash_map,572772352 +random,memory,29360128,absl::flat_hash_map,1715863552 +random,memory,29364265,absl::flat_hash_map,1715863552 +random,memory,29364312,absl::flat_hash_map,1144311808 +random,time,30000000,absl::flat_hash_map,3.875000 +random,memory,30003827,absl::flat_hash_map,1144311808 +random,time,40000000,absl::flat_hash_map,5.254000 +random,memory,40009000,absl::flat_hash_map,1144311808 +random,time,50000000,absl::flat_hash_map,6.636000 +random,memory,50012195,absl::flat_hash_map,1144311808 +random,memory,58720255,absl::flat_hash_map,1144311808 +random,memory,58720256,absl::flat_hash_map,3430490112 +random,memory,58721997,absl::flat_hash_map,3430490112 +random,memory,58722035,absl::flat_hash_map,2287411200 +random,time,60000000,absl::flat_hash_map,9.076000 +random,memory,60006216,absl::flat_hash_map,2287411200 +random,time,70000000,absl::flat_hash_map,10.597000 +random,memory,70010624,absl::flat_hash_map,2287411200 +random,time,80000000,absl::flat_hash_map,12.121000 +random,memory,80009799,absl::flat_hash_map,2287411200 +random,time,90000000,absl::flat_hash_map,13.627000 +random,memory,90004802,absl::flat_hash_map,2287411200 +random,time,100000000,absl::flat_hash_map,15.121000 +random,memory,0,absl::parallel_flat_hash_map,10170368 +random,memory,411848,absl::parallel_flat_hash_map,10170368 +random,memory,411907,absl::parallel_flat_hash_map,16375808 +random,memory,434804,absl::parallel_flat_hash_map,16375808 +random,memory,434919,absl::parallel_flat_hash_map,19169280 +random,memory,499955,absl::parallel_flat_hash_map,19169280 +random,memory,500092,absl::parallel_flat_hash_map,18636800 +random,memory,767798,absl::parallel_flat_hash_map,18636800 +random,memory,767958,absl::parallel_flat_hash_map,20873216 +random,memory,810538,absl::parallel_flat_hash_map,20873216 +random,memory,810597,absl::parallel_flat_hash_map,30941184 +random,memory,819492,absl::parallel_flat_hash_map,30941184 +random,memory,819493,absl::parallel_flat_hash_map,39882752 +random,memory,835988,absl::parallel_flat_hash_map,39882752 +random,memory,836052,absl::parallel_flat_hash_map,36519936 +random,memory,894649,absl::parallel_flat_hash_map,36519936 +random,memory,894754,absl::parallel_flat_hash_map,34279424 +random,memory,1154846,absl::parallel_flat_hash_map,34242560 +random,memory,1154988,absl::parallel_flat_hash_map,35360768 +random,memory,1216254,absl::parallel_flat_hash_map,35360768 +random,memory,1216391,absl::parallel_flat_hash_map,36552704 +random,memory,1583771,absl::parallel_flat_hash_map,36552704 +random,memory,1583947,absl::parallel_flat_hash_map,39907328 +random,memory,1622124,absl::parallel_flat_hash_map,39907328 +random,memory,1622237,absl::parallel_flat_hash_map,52199424 +random,memory,1639638,absl::parallel_flat_hash_map,52199424 +random,memory,1639661,absl::parallel_flat_hash_map,65605632 +random,memory,1653514,absl::parallel_flat_hash_map,65605632 +random,memory,1653539,absl::parallel_flat_hash_map,72306688 +random,memory,1666888,absl::parallel_flat_hash_map,72306688 +random,memory,1666916,absl::parallel_flat_hash_map,79003648 +random,memory,1691750,absl::parallel_flat_hash_map,79003648 +random,memory,1691824,absl::parallel_flat_hash_map,72306688 +random,memory,1738807,absl::parallel_flat_hash_map,72306688 +random,memory,1738925,absl::parallel_flat_hash_map,65593344 +random,memory,2222488,absl::parallel_flat_hash_map,65593344 +random,memory,2222655,absl::parallel_flat_hash_map,70066176 +random,memory,2275719,absl::parallel_flat_hash_map,70066176 +random,memory,2275807,absl::parallel_flat_hash_map,72294400 +random,memory,2319482,absl::parallel_flat_hash_map,72294400 +random,memory,2319616,absl::parallel_flat_hash_map,76759040 +random,memory,2370330,absl::parallel_flat_hash_map,76759040 +random,memory,2370869,absl::parallel_flat_hash_map,74518528 +random,memory,2422380,absl::parallel_flat_hash_map,74518528 +random,memory,2422622,absl::parallel_flat_hash_map,76754944 +random,memory,2471942,absl::parallel_flat_hash_map,76754944 +random,memory,2472109,absl::parallel_flat_hash_map,74518528 +random,memory,3212727,absl::parallel_flat_hash_map,74518528 +random,memory,3212832,absl::parallel_flat_hash_map,92385280 +random,memory,3279060,absl::parallel_flat_hash_map,92385280 +random,memory,3279135,absl::parallel_flat_hash_map,110256128 +random,memory,3330438,absl::parallel_flat_hash_map,110256128 +random,memory,3330505,absl::parallel_flat_hash_map,119193600 +random,memory,3357017,absl::parallel_flat_hash_map,119193600 +random,memory,3357061,absl::parallel_flat_hash_map,123658240 +random,memory,3382717,absl::parallel_flat_hash_map,123658240 +random,memory,3382766,absl::parallel_flat_hash_map,128126976 +random,memory,3410216,absl::parallel_flat_hash_map,128126976 +random,memory,3410294,absl::parallel_flat_hash_map,119193600 +random,memory,3487891,absl::parallel_flat_hash_map,119193600 +random,memory,3487995,absl::parallel_flat_hash_map,114720768 +random,memory,3535204,absl::parallel_flat_hash_map,114720768 +random,memory,3535343,absl::parallel_flat_hash_map,110252032 +random,memory,3806272,absl::parallel_flat_hash_map,110252032 +random,memory,3806419,absl::parallel_flat_hash_map,119189504 +random,memory,3851844,absl::parallel_flat_hash_map,119189504 +random,memory,3851947,absl::parallel_flat_hash_map,137056256 +random,memory,3912789,absl::parallel_flat_hash_map,137056256 +random,memory,3912899,absl::parallel_flat_hash_map,141520896 +random,memory,3936842,absl::parallel_flat_hash_map,141520896 +random,memory,3936909,absl::parallel_flat_hash_map,150458368 +random,memory,3959815,absl::parallel_flat_hash_map,150458368 +random,memory,3959905,absl::parallel_flat_hash_map,159383552 +random,memory,4023374,absl::parallel_flat_hash_map,159383552 +random,memory,4023538,absl::parallel_flat_hash_map,150446080 +random,memory,4065053,absl::parallel_flat_hash_map,154906624 +random,memory,4204140,absl::parallel_flat_hash_map,154906624 +random,memory,4204297,absl::parallel_flat_hash_map,150437888 +random,memory,4301074,absl::parallel_flat_hash_map,150437888 +random,memory,4301249,absl::parallel_flat_hash_map,145965056 +random,memory,6549677,absl::parallel_flat_hash_map,145965056 +random,memory,6549825,absl::parallel_flat_hash_map,181694464 +random,memory,6997079,absl::parallel_flat_hash_map,181694464 +random,memory,6997211,absl::parallel_flat_hash_map,208494592 +random,memory,7230339,absl::parallel_flat_hash_map,208494592 +random,memory,7230465,absl::parallel_flat_hash_map,226361344 +random,memory,7291549,absl::parallel_flat_hash_map,226361344 +random,memory,7291670,absl::parallel_flat_hash_map,217427968 +random,memory,7657520,absl::parallel_flat_hash_map,217427968 +random,memory,7657607,absl::parallel_flat_hash_map,297807872 +random,memory,7804692,absl::parallel_flat_hash_map,297807872 +random,memory,7804756,absl::parallel_flat_hash_map,315654144 +random,memory,7862884,absl::parallel_flat_hash_map,324587520 +random,memory,8300446,absl::parallel_flat_hash_map,324587520 +random,memory,8300602,absl::parallel_flat_hash_map,288845824 +random,time,10000000,absl::parallel_flat_hash_map,0.424000 +random,memory,10549382,absl::parallel_flat_hash_map,287694848 +random,memory,14509630,absl::parallel_flat_hash_map,287694848 +random,memory,14509631,absl::parallel_flat_hash_map,537772032 +random,memory,14625205,absl::parallel_flat_hash_map,537772032 +random,memory,14625206,absl::parallel_flat_hash_map,662798336 +random,memory,14985538,absl::parallel_flat_hash_map,662798336 +random,memory,14985695,absl::parallel_flat_hash_map,573476864 +random,memory,15812726,absl::parallel_flat_hash_map,573476864 +random,memory,15812791,absl::parallel_flat_hash_map,591331328 +random,memory,16545857,absl::parallel_flat_hash_map,591331328 +random,memory,16545973,absl::parallel_flat_hash_map,573460480 +random,time,20000000,absl::parallel_flat_hash_map,0.954000 +random,memory,20807098,absl::parallel_flat_hash_map,573456384 +random,memory,29087356,absl::parallel_flat_hash_map,573456384 +random,memory,29087477,absl::parallel_flat_hash_map,644902912 +random,memory,29349303,absl::parallel_flat_hash_map,644902912 +random,memory,29349304,absl::parallel_flat_hash_map,1145028608 +random,memory,29350502,absl::parallel_flat_hash_map,1145028608 +random,memory,29350503,absl::parallel_flat_hash_map,1180753920 +random,memory,29353744,absl::parallel_flat_hash_map,1180753920 +random,memory,29353745,absl::parallel_flat_hash_map,1252196352 +random,memory,29356269,absl::parallel_flat_hash_map,1252196352 +random,memory,29356270,absl::parallel_flat_hash_map,1216475136 +random,memory,29371063,absl::parallel_flat_hash_map,1216475136 +random,memory,29371064,absl::parallel_flat_hash_map,1430810624 +random,memory,29406162,absl::parallel_flat_hash_map,1430810624 +random,memory,29406217,absl::parallel_flat_hash_map,1359364096 +random,memory,29624052,absl::parallel_flat_hash_map,1359364096 +random,memory,29624117,absl::parallel_flat_hash_map,1216425984 +random,memory,29711436,absl::parallel_flat_hash_map,1216397312 +random,memory,29711557,absl::parallel_flat_hash_map,1180667904 +random,memory,29779052,absl::parallel_flat_hash_map,1180643328 +random,memory,29779149,absl::parallel_flat_hash_map,1144913920 +random,time,30000000,absl::parallel_flat_hash_map,1.510000 +random,memory,30000000,absl::parallel_flat_hash_map,1144786944 +random,time,40000000,absl::parallel_flat_hash_map,1.977000 +random,memory,40000000,absl::parallel_flat_hash_map,1144782848 +random,time,50000000,absl::parallel_flat_hash_map,2.410000 +random,memory,50109244,absl::parallel_flat_hash_map,1144987648 +random,memory,58696456,absl::parallel_flat_hash_map,1144987648 +random,memory,58696478,absl::parallel_flat_hash_map,2145222656 +random,memory,58705957,absl::parallel_flat_hash_map,2145222656 +random,memory,58705958,absl::parallel_flat_hash_map,2288111616 +random,memory,58710284,absl::parallel_flat_hash_map,2288111616 +random,memory,58710285,absl::parallel_flat_hash_map,2502451200 +random,memory,58716154,absl::parallel_flat_hash_map,2502451200 +random,memory,58716155,absl::parallel_flat_hash_map,2645327872 +random,memory,58719191,absl::parallel_flat_hash_map,2645327872 +random,memory,58719214,absl::parallel_flat_hash_map,2573885440 +random,memory,58734799,absl::parallel_flat_hash_map,2573885440 +random,memory,58734800,absl::parallel_flat_hash_map,2859651072 +random,memory,58754516,absl::parallel_flat_hash_map,2859651072 +random,memory,58754559,absl::parallel_flat_hash_map,2716762112 +random,memory,59072502,absl::parallel_flat_hash_map,2716762112 +random,memory,59072581,absl::parallel_flat_hash_map,2359533568 +random,memory,59445636,absl::parallel_flat_hash_map,2359533568 +random,memory,59449345,absl::parallel_flat_hash_map,2288054272 +random,time,60000000,absl::parallel_flat_hash_map,3.184000 +random,memory,60659819,absl::parallel_flat_hash_map,2288070656 +random,time,70000000,absl::parallel_flat_hash_map,3.678000 +random,memory,70001013,absl::parallel_flat_hash_map,2288001024 +random,time,80000000,absl::parallel_flat_hash_map,4.120000 +random,memory,80008641,absl::parallel_flat_hash_map,2288046080 +random,time,90000000,absl::parallel_flat_hash_map,4.653000 +random,memory,90000000,absl::parallel_flat_hash_map,2287878144 +random,time,100000000,absl::parallel_flat_hash_map,5.111000 diff --git a/extern/phmap/benchmark/results/output_mt_stl_flat_par_run2 b/extern/phmap/benchmark/results/output_mt_stl_flat_par_run2 new file mode 100644 index 0000000..d01e475 --- /dev/null +++ b/extern/phmap/benchmark/results/output_mt_stl_flat_par_run2 @@ -0,0 +1,374 @@ +random,memory,0,std::unordered_map,6262784 +random,memory,66147,std::unordered_map,6340608 +random,memory,82637,std::unordered_map,6340608 +random,memory,82649,std::unordered_map,7204864 +random,memory,99619,std::unordered_map,7204864 +random,memory,99639,std::unordered_map,8060928 +random,memory,116159,std::unordered_map,8060928 +random,memory,116174,std::unordered_map,8916992 +random,memory,129704,std::unordered_map,8916992 +random,memory,129718,std::unordered_map,9621504 +random,memory,131071,std::unordered_map,9621504 +random,memory,131072,std::unordered_map,11804672 +random,memory,135283,std::unordered_map,12038144 +random,memory,147679,std::unordered_map,12038144 +random,memory,147680,std::unordered_map,12660736 +random,memory,159818,std::unordered_map,12660736 +random,memory,159834,std::unordered_map,13291520 +random,memory,170700,std::unordered_map,13291520 +random,memory,170717,std::unordered_map,13914112 +random,memory,179486,std::unordered_map,14303232 +random,memory,188398,std::unordered_map,14303232 +random,memory,188409,std::unordered_map,14770176 +random,memory,195927,std::unordered_map,14770176 +random,memory,195939,std::unordered_map,15237120 +random,memory,203959,std::unordered_map,15630336 +random,memory,211779,std::unordered_map,15941632 +random,memory,220483,std::unordered_map,15941632 +random,memory,220484,std::unordered_map,16486400 +random,memory,229922,std::unordered_map,16953344 +random,memory,239746,std::unordered_map,17424384 +random,memory,250042,std::unordered_map,17424384 +random,memory,250053,std::unordered_map,17969152 +random,memory,259821,std::unordered_map,18436096 +random,memory,262143,std::unordered_map,18436096 +random,memory,262144,std::unordered_map,26927104 +random,memory,262143,std::unordered_map,26927104 +random,memory,262144,std::unordered_map,22724608 +random,memory,273337,std::unordered_map,23347200 +random,memory,281584,std::unordered_map,23814144 +random,memory,291318,std::unordered_map,24293376 +random,memory,301478,std::unordered_map,24838144 +random,memory,311977,std::unordered_map,25382912 +random,memory,322715,std::unordered_map,25935872 +random,memory,333302,std::unordered_map,26558464 +random,memory,343264,std::unordered_map,27025408 +random,memory,352924,std::unordered_map,27492352 +random,memory,361958,std::unordered_map,27963392 +random,memory,369865,std::unordered_map,28352512 +random,memory,378535,std::unordered_map,28819456 +random,memory,387443,std::unordered_map,29286400 +random,memory,396689,std::unordered_map,29753344 +random,memory,405932,std::unordered_map,30224384 +random,memory,415263,std::unordered_map,30691328 +random,memory,424445,std::unordered_map,31158272 +random,memory,433724,std::unordered_map,31625216 +random,memory,442183,std::unordered_map,32096256 +random,memory,450170,std::unordered_map,32485376 +random,memory,458338,std::unordered_map,32874496 +random,memory,466025,std::unordered_map,33341440 +random,memory,474254,std::unordered_map,33730560 +random,memory,482593,std::unordered_map,34123776 +random,memory,491058,std::unordered_map,34590720 +random,memory,499360,std::unordered_map,35057664 +random,memory,514720,std::unordered_map,35758080 +random,memory,522349,std::unordered_map,36147200 +random,memory,524287,std::unordered_map,36147200 +random,memory,524288,std::unordered_map,53125120 +random,memory,524287,std::unordered_map,53125120 +random,memory,524288,std::unordered_map,44720128 +random,memory,543462,std::unordered_map,45654016 +random,memory,552986,std::unordered_map,46198784 +random,memory,572111,std::unordered_map,47136768 +random,memory,608007,std::unordered_map,49004544 +random,memory,626830,std::unordered_map,49938432 +random,memory,662501,std::unordered_map,51838976 +random,memory,697143,std::unordered_map,53633024 +random,memory,730779,std::unordered_map,55349248 +random,memory,763966,std::unordered_map,57061376 +random,memory,797419,std::unordered_map,58777600 +random,memory,838262,std::unordered_map,60805120 +random,memory,877693,std::unordered_map,62910464 +random,memory,919839,std::unordered_map,65015808 +random,memory,963409,std::unordered_map,67280896 +random,memory,1006880,std::unordered_map,69541888 +random,memory,1048575,std::unordered_map,71491584 +random,memory,1048576,std::unordered_map,105275392 +random,memory,1048575,std::unordered_map,105279488 +random,memory,1048576,std::unordered_map,88469504 +random,memory,1101898,std::unordered_map,91201536 +random,memory,1159041,std::unordered_map,94085120 +random,memory,1214581,std::unordered_map,96968704 +random,memory,1277500,std::unordered_map,100163584 +random,memory,1336144,std::unordered_map,103211008 +random,memory,1401705,std::unordered_map,106561536 +random,memory,1467192,std::unordered_map,109993984 +random,memory,1539228,std::unordered_map,113659904 +random,memory,1610540,std::unordered_map,117321728 +random,memory,1679692,std::unordered_map,120909824 +random,memory,1754775,std::unordered_map,124731392 +random,memory,1829692,std::unordered_map,128552960 +random,memory,1911333,std::unordered_map,132685824 +random,memory,1992045,std::unordered_map,136900608 +random,memory,2078160,std::unordered_map,141344768 +random,memory,2097151,std::unordered_map,141967360 +random,memory,2097152,std::unordered_map,209526784 +random,memory,2097151,std::unordered_map,209526784 +random,memory,2097152,std::unordered_map,175906816 +random,memory,2203649,std::unordered_map,181366784 +random,memory,2313060,std::unordered_map,187060224 +random,memory,2430763,std::unordered_map,193064960 +random,memory,2547134,std::unordered_map,199041024 +random,memory,2663349,std::unordered_map,205049856 +random,memory,2783850,std::unordered_map,211288064 +random,memory,2910198,std::unordered_map,217763840 +random,memory,3037927,std::unordered_map,224313344 +random,memory,3177861,std::unordered_map,231485440 +random,memory,3313832,std::unordered_map,238505984 +random,memory,3457523,std::unordered_map,245760000 +random,memory,3602506,std::unordered_map,253329408 +random,memory,3759506,std::unordered_map,261279744 +random,memory,3911955,std::unordered_map,269160448 +random,memory,4070796,std::unordered_map,277348352 +random,memory,4194303,std::unordered_map,283435008 +random,memory,4194304,std::unordered_map,418156544 +random,memory,4194303,std::unordered_map,418156544 +random,memory,4194304,std::unordered_map,350916608 +random,memory,4407009,std::unordered_map,361832448 +random,memory,4622523,std::unordered_map,372908032 +random,memory,4840785,std::unordered_map,384139264 +random,memory,5069285,std::unordered_map,395759616 +random,memory,5303878,std::unordered_map,407928832 +random,memory,5543266,std::unordered_map,420253696 +random,memory,5791025,std::unordered_map,432885760 +random,memory,6044095,std::unordered_map,445906944 +random,memory,6305319,std::unordered_map,459321344 +random,memory,6577545,std::unordered_map,473284608 +random,memory,6858697,std::unordered_map,487792640 +random,memory,7147317,std::unordered_map,502611968 +random,memory,7442937,std::unordered_map,517742592 +random,memory,7748304,std::unordered_map,533422080 +random,memory,8065615,std::unordered_map,549801984 +random,memory,8388607,std::unordered_map,566177792 +random,memory,8388608,std::unordered_map,835301376 +random,memory,8388607,std::unordered_map,835301376 +random,memory,8388608,std::unordered_map,700817408 +random,memory,8802366,std::unordered_map,722030592 +random,memory,9226003,std::unordered_map,743714816 +random,memory,9659613,std::unordered_map,766099456 +random,time,10000000,std::unordered_map,4.219000 +random,memory,10004203,std::unordered_map,783728640 +random,memory,10467953,std::unordered_map,807591936 +random,memory,10941688,std::unordered_map,831930368 +random,memory,11430458,std::unordered_map,856965120 +random,memory,11932272,std::unordered_map,882782208 +random,memory,12452228,std::unordered_map,909455360 +random,memory,12986599,std::unordered_map,936914944 +random,memory,13534295,std::unordered_map,965074944 +random,memory,14099120,std::unordered_map,994086912 +random,memory,14685277,std::unordered_map,1024192512 +random,memory,15284333,std::unordered_map,1055002624 +random,memory,15901280,std::unordered_map,1086668800 +random,memory,16540739,std::unordered_map,1119506432 +random,memory,16777216,std::unordered_map,1131593728 +random,memory,16777217,std::unordered_map,1669521408 +random,memory,16777216,std::unordered_map,1669521408 +random,memory,16777217,std::unordered_map,1400561664 +random,memory,17594843,std::unordered_map,1442594816 +random,memory,18441168,std::unordered_map,1486041088 +random,memory,19314823,std::unordered_map,1530888192 +random,time,20000000,std::unordered_map,9.237000 +random,memory,20001449,std::unordered_map,1566220288 +random,memory,20922961,std::unordered_map,1613488128 +random,memory,21867605,std::unordered_map,1661919232 +random,memory,22842566,std::unordered_map,1711992832 +random,memory,23846371,std::unordered_map,1763553280 +random,memory,24877882,std::unordered_map,1816588288 +random,memory,25939795,std::unordered_map,1871106048 +random,memory,27035961,std::unordered_map,1927417856 +random,memory,28166332,std::unordered_map,1985449984 +random,memory,29325566,std::unordered_map,2045038592 +random,time,30000000,std::unordered_map,12.731000 +random,memory,30005312,std::unordered_map,2079903744 +random,memory,31220485,std::unordered_map,2142306304 +random,memory,32473699,std::unordered_map,2206654464 +random,memory,33554433,std::unordered_map,2261954560 +random,memory,33554434,std::unordered_map,3338039296 +random,memory,33554433,std::unordered_map,3338039296 +random,memory,33554434,std::unordered_map,2800119808 +random,memory,35190517,std::unordered_map,2884198400 +random,memory,36881331,std::unordered_map,2971004928 +random,memory,38618963,std::unordered_map,3060154368 +random,time,40000000,std::unordered_map,20.341999 +random,memory,40000165,std::unordered_map,3131133952 +random,memory,41832534,std::unordered_map,3225194496 +random,memory,43716435,std::unordered_map,3321987072 +random,memory,45660968,std::unordered_map,3421900800 +random,memory,47664978,std::unordered_map,3524857856 +random,memory,49728995,std::unordered_map,3630772224 +random,time,50000000,std::unordered_map,23.892000 +random,memory,50003393,std::unordered_map,3644891136 +random,memory,52133603,std::unordered_map,3754237952 +random,memory,54328284,std::unordered_map,3866943488 +random,memory,56590586,std::unordered_map,3983159296 +random,memory,58922512,std::unordered_map,4102963200 +random,time,60000000,std::unordered_map,27.804001 +random,memory,60002789,std::unordered_map,4158418944 +random,memory,62434781,std::unordered_map,4283215872 +random,memory,64938804,std::unordered_map,4411912192 +random,memory,67108867,std::unordered_map,4523261952 +random,memory,67108868,std::unordered_map,6674964480 +random,memory,67108867,std::unordered_map,6674964480 +random,memory,67108868,std::unordered_map,5599125504 +random,time,70000000,std::unordered_map,40.429001 +random,memory,70000893,std::unordered_map,5747630080 +random,memory,73361782,std::unordered_map,5920231424 +random,memory,76823810,std::unordered_map,6098063360 +random,time,80000000,std::unordered_map,43.907001 +random,memory,80001253,std::unordered_map,6261313536 +random,memory,83662519,std::unordered_map,6449278976 +random,memory,87433081,std::unordered_map,6642946048 +random,time,90000000,std::unordered_map,47.674000 +random,memory,90000620,std::unordered_map,6774833152 +random,memory,93961521,std::unordered_map,6978170880 +random,memory,98041926,std::unordered_map,7187746816 +random,time,100000000,std::unordered_map,51.557999 +random,memory,100000000,std::unordered_map,7288283136 +random,memory,0,phmap::flat_hash_map,15810560 +random,memory,239818,phmap::flat_hash_map,15810560 +random,memory,240039,phmap::flat_hash_map,11341824 +random,memory,458751,phmap::flat_hash_map,11341824 +random,memory,458752,phmap::flat_hash_map,29208576 +random,memory,487182,phmap::flat_hash_map,29208576 +random,memory,487416,phmap::flat_hash_map,20275200 +random,memory,669554,phmap::flat_hash_map,20275200 +random,memory,669793,phmap::flat_hash_map,19144704 +random,memory,917503,phmap::flat_hash_map,19144704 +random,memory,917504,phmap::flat_hash_map,54870016 +random,memory,956900,phmap::flat_hash_map,54870016 +random,memory,957064,phmap::flat_hash_map,37003264 +random,memory,1835007,phmap::flat_hash_map,37003264 +random,memory,1835008,phmap::flat_hash_map,108449792 +random,memory,1849262,phmap::flat_hash_map,108449792 +random,memory,1849368,phmap::flat_hash_map,72724480 +random,memory,3670015,phmap::flat_hash_map,72724480 +random,memory,3670016,phmap::flat_hash_map,215613440 +random,memory,3671196,phmap::flat_hash_map,215613440 +random,memory,3671252,phmap::flat_hash_map,144166912 +random,memory,7340031,phmap::flat_hash_map,144166912 +random,memory,7340032,phmap::flat_hash_map,429944832 +random,memory,7345416,phmap::flat_hash_map,429944832 +random,memory,7345476,phmap::flat_hash_map,287055872 +random,time,10000000,phmap::flat_hash_map,0.952000 +random,memory,10005890,phmap::flat_hash_map,287055872 +random,memory,14680063,phmap::flat_hash_map,287055872 +random,memory,14680064,phmap::flat_hash_map,858599424 +random,memory,14681371,phmap::flat_hash_map,858599424 +random,memory,14681406,phmap::flat_hash_map,572825600 +random,time,20000000,phmap::flat_hash_map,2.315000 +random,memory,20016264,phmap::flat_hash_map,572825600 +random,memory,29360127,phmap::flat_hash_map,572825600 +random,memory,29360128,phmap::flat_hash_map,1715916800 +random,memory,29363718,phmap::flat_hash_map,1715916800 +random,memory,29363764,phmap::flat_hash_map,1144373248 +random,time,30000000,phmap::flat_hash_map,4.047000 +random,memory,30001212,phmap::flat_hash_map,1144373248 +random,time,40000000,phmap::flat_hash_map,5.437000 +random,memory,40013884,phmap::flat_hash_map,1144373248 +random,time,50000000,phmap::flat_hash_map,6.807000 +random,memory,50012642,phmap::flat_hash_map,1144373248 +random,memory,58720255,phmap::flat_hash_map,1144373248 +random,memory,58720256,phmap::flat_hash_map,3430551552 +random,memory,58726692,phmap::flat_hash_map,3430551552 +random,memory,58726725,phmap::flat_hash_map,2287464448 +random,time,60000000,phmap::flat_hash_map,9.232000 +random,memory,60005561,phmap::flat_hash_map,2287464448 +random,time,70000000,phmap::flat_hash_map,10.811000 +random,memory,70008847,phmap::flat_hash_map,2287464448 +random,time,80000000,phmap::flat_hash_map,12.387000 +random,memory,80000522,phmap::flat_hash_map,2287464448 +random,time,90000000,phmap::flat_hash_map,13.936000 +random,memory,90006732,phmap::flat_hash_map,2287464448 +random,time,100000000,phmap::flat_hash_map,15.467000 +random,memory,0,phmap::parallel_flat_hash_map,37785600 +random,memory,1921864,phmap::parallel_flat_hash_map,37785600 +random,memory,1921990,phmap::parallel_flat_hash_map,75739136 +random,memory,2969317,phmap::parallel_flat_hash_map,75739136 +random,memory,2969478,phmap::parallel_flat_hash_map,73498624 +random,memory,3714056,phmap::parallel_flat_hash_map,73498624 +random,memory,3714057,phmap::parallel_flat_hash_map,162828288 +random,memory,4501128,phmap::parallel_flat_hash_map,162828288 +random,memory,4501312,phmap::parallel_flat_hash_map,144936960 +random,memory,7228404,phmap::parallel_flat_hash_map,144936960 +random,memory,7228507,phmap::parallel_flat_hash_map,207466496 +random,memory,7275817,phmap::parallel_flat_hash_map,207466496 +random,memory,7275940,phmap::parallel_flat_hash_map,216391680 +random,memory,7498901,phmap::parallel_flat_hash_map,216391680 +random,memory,7499009,phmap::parallel_flat_hash_map,323563520 +random,memory,7543411,phmap::parallel_flat_hash_map,323563520 +random,memory,7543523,phmap::parallel_flat_hash_map,305696768 +random,memory,8354331,phmap::parallel_flat_hash_map,305696768 +random,memory,8354519,phmap::parallel_flat_hash_map,287825920 +random,time,10000000,phmap::parallel_flat_hash_map,0.406000 +random,memory,10849279,phmap::parallel_flat_hash_map,288239616 +random,memory,14474156,phmap::parallel_flat_hash_map,288239616 +random,memory,14474206,phmap::parallel_flat_hash_map,395419648 +random,memory,14565308,phmap::parallel_flat_hash_map,395419648 +random,memory,14565382,phmap::parallel_flat_hash_map,466870272 +random,memory,14678635,phmap::parallel_flat_hash_map,466870272 +random,memory,14678636,phmap::parallel_flat_hash_map,609767424 +random,memory,14683611,phmap::parallel_flat_hash_map,627630080 +random,memory,14800987,phmap::parallel_flat_hash_map,627630080 +random,memory,14801039,phmap::parallel_flat_hash_map,663339008 +random,memory,15290395,phmap::parallel_flat_hash_map,663339008 +random,memory,15290450,phmap::parallel_flat_hash_map,591884288 +random,memory,15480090,phmap::parallel_flat_hash_map,591884288 +random,memory,15480237,phmap::parallel_flat_hash_map,574021632 +random,time,20000000,phmap::parallel_flat_hash_map,0.912000 +random,memory,20838704,phmap::parallel_flat_hash_map,574017536 +random,memory,28900745,phmap::parallel_flat_hash_map,574017536 +random,memory,28900840,phmap::parallel_flat_hash_map,645464064 +random,memory,29185725,phmap::parallel_flat_hash_map,645464064 +random,memory,29185801,phmap::parallel_flat_hash_map,788357120 +random,memory,29330003,phmap::parallel_flat_hash_map,788357120 +random,memory,29330055,phmap::parallel_flat_hash_map,1002696704 +random,memory,29349427,phmap::parallel_flat_hash_map,1002696704 +random,memory,29349428,phmap::parallel_flat_hash_map,1145589760 +random,memory,29352020,phmap::parallel_flat_hash_map,1145589760 +random,memory,29352021,phmap::parallel_flat_hash_map,1181310976 +random,memory,29355250,phmap::parallel_flat_hash_map,1181310976 +random,memory,29355251,phmap::parallel_flat_hash_map,1252745216 +random,memory,29363721,phmap::parallel_flat_hash_map,1252745216 +random,memory,29363722,phmap::parallel_flat_hash_map,1324191744 +random,memory,29370810,phmap::parallel_flat_hash_map,1324191744 +random,memory,29370811,phmap::parallel_flat_hash_map,1431351296 +random,memory,29553925,phmap::parallel_flat_hash_map,1431351296 +random,memory,29553998,phmap::parallel_flat_hash_map,1252732928 +random,memory,29747915,phmap::parallel_flat_hash_map,1252732928 +random,memory,29748035,phmap::parallel_flat_hash_map,1181249536 +random,memory,29849570,phmap::parallel_flat_hash_map,1181167616 +random,memory,29849635,phmap::parallel_flat_hash_map,1145438208 +random,time,30000000,phmap::parallel_flat_hash_map,1.470000 +random,memory,30044703,phmap::parallel_flat_hash_map,1145556992 +random,time,40000000,phmap::parallel_flat_hash_map,1.935000 +random,memory,40000000,phmap::parallel_flat_hash_map,1145356288 +random,time,50000000,phmap::parallel_flat_hash_map,2.359000 +random,memory,50622111,phmap::parallel_flat_hash_map,1145556992 +random,memory,58670362,phmap::parallel_flat_hash_map,1145556992 +random,memory,58670384,phmap::parallel_flat_hash_map,2145792000 +random,memory,58698634,phmap::parallel_flat_hash_map,2145792000 +random,memory,58698635,phmap::parallel_flat_hash_map,2288680960 +random,memory,58715876,phmap::parallel_flat_hash_map,2288685056 +random,memory,58715877,phmap::parallel_flat_hash_map,2574458880 +random,memory,58720779,phmap::parallel_flat_hash_map,2574458880 +random,memory,58720802,phmap::parallel_flat_hash_map,2503016448 +random,memory,58723605,phmap::parallel_flat_hash_map,2503016448 +random,memory,58723606,phmap::parallel_flat_hash_map,2645905408 +random,memory,58729212,phmap::parallel_flat_hash_map,2645905408 +random,memory,58729213,phmap::parallel_flat_hash_map,2788790272 +random,memory,58741845,phmap::parallel_flat_hash_map,2860228608 +random,memory,58760201,phmap::parallel_flat_hash_map,2860228608 +random,memory,58760227,phmap::parallel_flat_hash_map,2788786176 +random,memory,58967162,phmap::parallel_flat_hash_map,2788786176 +random,memory,58967269,phmap::parallel_flat_hash_map,2360111104 +random,memory,59568547,phmap::parallel_flat_hash_map,2360111104 +random,memory,59568692,phmap::parallel_flat_hash_map,2288660480 +random,time,60000000,phmap::parallel_flat_hash_map,3.120000 +random,memory,60764467,phmap::parallel_flat_hash_map,2288656384 +random,time,70000000,phmap::parallel_flat_hash_map,3.567000 +random,memory,70747076,phmap::parallel_flat_hash_map,2288652288 +random,time,80000000,phmap::parallel_flat_hash_map,4.004000 +random,memory,80005300,phmap::parallel_flat_hash_map,2288590848 +random,time,90000000,phmap::parallel_flat_hash_map,4.527000 +random,memory,90699330,phmap::parallel_flat_hash_map,2288656384 +random,time,100000000,phmap::parallel_flat_hash_map,4.986000 diff --git a/extern/phmap/benchmark/results/output_stl_flat b/extern/phmap/benchmark/results/output_stl_flat new file mode 100644 index 0000000..aee5272 --- /dev/null +++ b/extern/phmap/benchmark/results/output_stl_flat @@ -0,0 +1,225 @@ +random,memory,0,std::unordered_map,6688768 +random,memory,94189,std::unordered_map,7778304 +random,memory,109769,std::unordered_map,8556544 +random,memory,122654,std::unordered_map,9261056 +random,memory,131072,std::unordered_map,13778944 +random,memory,131072,std::unordered_map,11677696 +random,memory,139313,std::unordered_map,12144640 +random,memory,153935,std::unordered_map,12943360 +random,memory,165753,std::unordered_map,13643776 +random,memory,177309,std::unordered_map,14266368 +random,memory,188501,std::unordered_map,14733312 +random,memory,198715,std::unordered_map,15282176 +random,memory,208082,std::unordered_map,15749120 +random,memory,217961,std::unordered_map,16293888 +random,memory,228367,std::unordered_map,16838656 +random,memory,248349,std::unordered_map,17854464 +random,memory,262144,std::unordered_map,26890240 +random,memory,262144,std::unordered_map,22683648 +random,memory,276980,std::unordered_map,23543808 +random,memory,296991,std::unordered_map,24477696 +random,memory,317107,std::unordered_map,25571328 +random,memory,336773,std::unordered_map,26660864 +random,memory,356852,std::unordered_map,27676672 +random,memory,374674,std::unordered_map,28532736 +random,memory,393524,std::unordered_map,29544448 +random,memory,412757,std::unordered_map,30482432 +random,memory,430634,std::unordered_map,31416320 +random,memory,456096,std::unordered_map,32743424 +random,memory,480998,std::unordered_map,34017280 +random,memory,506761,std::unordered_map,35340288 +random,memory,524288,std::unordered_map,53096448 +random,memory,524288,std::unordered_map,44687360 +random,memory,559809,std::unordered_map,46481408 +random,memory,586869,std::unordered_map,47882240 +random,memory,625664,std::unordered_map,49827840 +random,memory,661343,std::unordered_map,51781632 +random,memory,697780,std::unordered_map,53575680 +random,memory,732263,std::unordered_map,55369728 +random,memory,767346,std::unordered_map,57163776 +random,memory,801265,std::unordered_map,58880000 +random,memory,843401,std::unordered_map,61063168 +random,memory,883359,std::unordered_map,63008768 +random,memory,923703,std::unordered_map,65114112 +random,memory,962276,std::unordered_map,67145728 +random,memory,1000499,std::unordered_map,69173248 +random,memory,1046029,std::unordered_map,71438336 +random,memory,1048576,std::unordered_map,105222144 +random,memory,1048576,std::unordered_map,88412160 +random,memory,1103068,std::unordered_map,91217920 +random,memory,1166341,std::unordered_map,94412800 +random,memory,1227947,std::unordered_map,97611776 +random,memory,1288360,std::unordered_map,100732928 +random,memory,1348784,std::unordered_map,103849984 +random,memory,1415960,std::unordered_map,107282432 +random,memory,1483476,std::unordered_map,110710784 +random,memory,1551489,std::unordered_map,114221056 +random,memory,1622998,std::unordered_map,117964800 +random,memory,1698528,std::unordered_map,121786368 +random,memory,1774279,std::unordered_map,125607936 +random,memory,1852847,std::unordered_map,129658880 +random,memory,1935045,std::unordered_map,133955584 +random,memory,2016124,std::unordered_map,138084352 +random,memory,2097152,std::unordered_map,209465344 +random,memory,2097152,std::unordered_map,175845376 +random,memory,2202017,std::unordered_map,181227520 +random,memory,2308233,std::unordered_map,186687488 +random,memory,2421995,std::unordered_map,192569344 +random,memory,2540952,std::unordered_map,198647808 +random,memory,2664197,std::unordered_map,205049856 +random,memory,2786842,std::unordered_map,211288064 +random,memory,2914893,std::unordered_map,217915392 +random,memory,3042611,std::unordered_map,224464896 +random,memory,3177918,std::unordered_map,231325696 +random,memory,3316856,std::unordered_map,238583808 +random,memory,3463219,std::unordered_map,245989376 +random,memory,3606297,std::unordered_map,253440000 +random,memory,3758685,std::unordered_map,261234688 +random,memory,3918344,std::unordered_map,269426688 +random,memory,4082497,std::unordered_map,277848064 +random,memory,4194304,std::unordered_map,418111488 +random,memory,4194304,std::unordered_map,350871552 +random,memory,4405390,std::unordered_map,361631744 +random,memory,4622462,std::unordered_map,372862976 +random,memory,4843447,std::unordered_map,384253952 +random,memory,5077057,std::unordered_map,396234752 +random,memory,5310379,std::unordered_map,408170496 +random,memory,5553459,std::unordered_map,420728832 +random,memory,5801485,std::unordered_map,433438720 +random,memory,6061642,std::unordered_map,446771200 +random,memory,6321544,std::unordered_map,460189696 +random,memory,6597657,std::unordered_map,474308608 +random,memory,6874638,std::unordered_map,488579072 +random,memory,7165061,std::unordered_map,503480320 +random,memory,7464156,std::unordered_map,518844416 +random,memory,7769321,std::unordered_map,534519808 +random,memory,8083787,std::unordered_map,550666240 +random,memory,8388608,std::unordered_map,835313664 +random,memory,8388608,std::unordered_map,700833792 +random,memory,8799364,std::unordered_map,721883136 +random,memory,9228893,std::unordered_map,743878656 +random,memory,9664620,std::unordered_map,766345216 +random,time,10000000,std::unordered_map,4.373000 +random,memory,10005035,std::unordered_map,783814656 +random,memory,10114472,std::unordered_map,789352448 +random,memory,10581340,std::unordered_map,813371392 +random,memory,11060026,std::unordered_map,837943296 +random,memory,11554760,std::unordered_map,863367168 +random,memory,12063672,std::unordered_map,889499648 +random,memory,12588048,std::unordered_map,916488192 +random,memory,13128601,std::unordered_map,944173056 +random,memory,13682065,std::unordered_map,972640256 +random,memory,14255923,std::unordered_map,1002127360 +random,memory,14847433,std::unordered_map,1032548352 +random,memory,15456818,std::unordered_map,1063825408 +random,memory,16080459,std::unordered_map,1095798784 +random,memory,16726977,std::unordered_map,1128947712 +random,memory,16777217,std::unordered_map,1669529600 +random,memory,16777217,std::unordered_map,1400569856 +random,memory,17595085,std::unordered_map,1442603008 +random,memory,18438183,std::unordered_map,1485893632 +random,memory,19311311,std::unordered_map,1530658816 +random,time,20000000,std::unordered_map,8.842000 +random,memory,20000810,std::unordered_map,1566150656 +random,memory,20207250,std::unordered_map,1576677376 +random,memory,21131235,std::unordered_map,1624178688 +random,memory,22086647,std::unordered_map,1673158656 +random,memory,23064920,std::unordered_map,1723465728 +random,memory,24073299,std::unordered_map,1775177728 +random,memory,25110516,std::unordered_map,1828532224 +random,memory,26181575,std::unordered_map,1883516928 +random,memory,27282467,std::unordered_map,1940062208 +random,memory,28422030,std::unordered_map,1998561280 +random,memory,29593778,std::unordered_map,2058694656 +random,time,30000000,std::unordered_map,12.018000 +random,memory,30000114,std::unordered_map,2079678464 +random,memory,30796939,std::unordered_map,2120552448 +random,memory,32039135,std::unordered_map,2184355840 +random,memory,33320240,std::unordered_map,2250104832 +random,memory,33554434,std::unordered_map,3338047488 +random,memory,33554434,std::unordered_map,2800128000 +random,memory,35194605,std::unordered_map,2884362240 +random,memory,36886268,std::unordered_map,2971246592 +random,memory,38624437,std::unordered_map,3060473856 +random,time,40000000,std::unordered_map,18.924999 +random,memory,40003628,std::unordered_map,3131297792 +random,memory,40417618,std::unordered_map,3152588800 +random,memory,42264600,std::unordered_map,3247431680 +random,memory,44165274,std::unordered_map,3345006592 +random,memory,46122181,std::unordered_map,3445542912 +random,memory,48137986,std::unordered_map,3549040640 +random,time,50000000,std::unordered_map,22.261999 +random,memory,50001657,std::unordered_map,3644821504 +random,memory,50216354,std::unordered_map,3655737344 +random,memory,52356080,std::unordered_map,3765637120 +random,memory,54556920,std::unordered_map,3878731776 +random,memory,56823702,std::unordered_map,3995103232 +random,memory,59156726,std::unordered_map,4114980864 +random,time,60000000,std::unordered_map,25.919001 +random,memory,60002957,std::unordered_map,4158427136 +random,memory,61562985,std::unordered_map,4238528512 +random,memory,64040759,std::unordered_map,4365746176 +random,memory,66594964,std::unordered_map,4496855040 +random,memory,67108868,std::unordered_map,6675001344 +random,memory,67108868,std::unordered_map,5599162368 +random,time,70000000,std::unordered_map,37.734001 +random,memory,70005322,std::unordered_map,5747867648 +random,memory,70384719,std::unordered_map,5767364608 +random,memory,73758686,std::unordered_map,5940674560 +random,memory,77233925,std::unordered_map,6119124992 +random,time,80000000,std::unordered_map,41.104000 +random,memory,80002815,std::unordered_map,6261395456 +random,memory,80810186,std::unordered_map,6302810112 +random,memory,84496350,std::unordered_map,6492106752 +random,memory,88293603,std::unordered_map,6687174656 +random,time,90000000,std::unordered_map,44.681000 +random,memory,90004365,std::unordered_map,6774996992 +random,memory,92206220,std::unordered_map,6888091648 +random,memory,96235553,std::unordered_map,7095013376 +random,time,100000000,std::unordered_map,48.382000 +random,memory,0,absl::flat_hash_map,15740928 +random,memory,240967,absl::flat_hash_map,11272192 +random,memory,458751,absl::flat_hash_map,11272192 +random,memory,458752,absl::flat_hash_map,29138944 +random,memory,493930,absl::flat_hash_map,20205568 +random,memory,678845,absl::flat_hash_map,19087360 +random,memory,917503,absl::flat_hash_map,19087360 +random,memory,917504,absl::flat_hash_map,54812672 +random,memory,930488,absl::flat_hash_map,36945920 +random,memory,1835007,absl::flat_hash_map,36945920 +random,memory,1835008,absl::flat_hash_map,108392448 +random,memory,1860950,absl::flat_hash_map,72667136 +random,memory,3670015,absl::flat_hash_map,72667136 +random,memory,3670016,absl::flat_hash_map,215556096 +random,memory,3681610,absl::flat_hash_map,144109568 +random,memory,7340031,absl::flat_hash_map,144109568 +random,memory,7340032,absl::flat_hash_map,429883392 +random,memory,7348393,absl::flat_hash_map,286994432 +random,time,10000000,absl::flat_hash_map,0.917000 +random,memory,10000174,absl::flat_hash_map,286994432 +random,memory,14680063,absl::flat_hash_map,286994432 +random,memory,14680064,absl::flat_hash_map,858537984 +random,memory,14680512,absl::flat_hash_map,572764160 +random,time,20000000,absl::flat_hash_map,2.199000 +random,memory,20013320,absl::flat_hash_map,572764160 +random,memory,29360127,absl::flat_hash_map,572764160 +random,memory,29360128,absl::flat_hash_map,1715859456 +random,memory,29369210,absl::flat_hash_map,1144307712 +random,time,30000000,absl::flat_hash_map,3.818000 +random,memory,30002294,absl::flat_hash_map,1144307712 +random,time,40000000,absl::flat_hash_map,5.070000 +random,memory,40010797,absl::flat_hash_map,1144307712 +random,time,50000000,absl::flat_hash_map,6.323000 +random,memory,50009729,absl::flat_hash_map,1144307712 +random,memory,58720255,absl::flat_hash_map,1144307712 +random,memory,58720256,absl::flat_hash_map,3430486016 +random,memory,58721491,absl::flat_hash_map,2287403008 +random,time,60000000,absl::flat_hash_map,8.700000 +random,memory,60002661,absl::flat_hash_map,2287403008 +random,time,70000000,absl::flat_hash_map,10.155000 +random,memory,70010887,absl::flat_hash_map,2287403008 +random,time,80000000,absl::flat_hash_map,11.589000 +random,memory,80002681,absl::flat_hash_map,2287403008 +random,time,90000000,absl::flat_hash_map,13.020000 +random,memory,90012468,absl::flat_hash_map,2287403008 +random,time,100000000,absl::flat_hash_map,14.407000 diff --git a/extern/phmap/benchmark/results/output_stl_flat_par b/extern/phmap/benchmark/results/output_stl_flat_par new file mode 100644 index 0000000..8714815 --- /dev/null +++ b/extern/phmap/benchmark/results/output_stl_flat_par @@ -0,0 +1,499 @@ +random,memory,0,std::unordered_map,6688768 +random,memory,94189,std::unordered_map,7778304 +random,memory,109769,std::unordered_map,8556544 +random,memory,122654,std::unordered_map,9261056 +random,memory,131072,std::unordered_map,13778944 +random,memory,131072,std::unordered_map,11677696 +random,memory,139313,std::unordered_map,12144640 +random,memory,153935,std::unordered_map,12943360 +random,memory,165753,std::unordered_map,13643776 +random,memory,177309,std::unordered_map,14266368 +random,memory,188501,std::unordered_map,14733312 +random,memory,198715,std::unordered_map,15282176 +random,memory,208082,std::unordered_map,15749120 +random,memory,217961,std::unordered_map,16293888 +random,memory,228367,std::unordered_map,16838656 +random,memory,248349,std::unordered_map,17854464 +random,memory,262144,std::unordered_map,26890240 +random,memory,262144,std::unordered_map,22683648 +random,memory,276980,std::unordered_map,23543808 +random,memory,296991,std::unordered_map,24477696 +random,memory,317107,std::unordered_map,25571328 +random,memory,336773,std::unordered_map,26660864 +random,memory,356852,std::unordered_map,27676672 +random,memory,374674,std::unordered_map,28532736 +random,memory,393524,std::unordered_map,29544448 +random,memory,412757,std::unordered_map,30482432 +random,memory,430634,std::unordered_map,31416320 +random,memory,456096,std::unordered_map,32743424 +random,memory,480998,std::unordered_map,34017280 +random,memory,506761,std::unordered_map,35340288 +random,memory,524288,std::unordered_map,53096448 +random,memory,524288,std::unordered_map,44687360 +random,memory,559809,std::unordered_map,46481408 +random,memory,586869,std::unordered_map,47882240 +random,memory,625664,std::unordered_map,49827840 +random,memory,661343,std::unordered_map,51781632 +random,memory,697780,std::unordered_map,53575680 +random,memory,732263,std::unordered_map,55369728 +random,memory,767346,std::unordered_map,57163776 +random,memory,801265,std::unordered_map,58880000 +random,memory,843401,std::unordered_map,61063168 +random,memory,883359,std::unordered_map,63008768 +random,memory,923703,std::unordered_map,65114112 +random,memory,962276,std::unordered_map,67145728 +random,memory,1000499,std::unordered_map,69173248 +random,memory,1046029,std::unordered_map,71438336 +random,memory,1048576,std::unordered_map,105222144 +random,memory,1048576,std::unordered_map,88412160 +random,memory,1103068,std::unordered_map,91217920 +random,memory,1166341,std::unordered_map,94412800 +random,memory,1227947,std::unordered_map,97611776 +random,memory,1288360,std::unordered_map,100732928 +random,memory,1348784,std::unordered_map,103849984 +random,memory,1415960,std::unordered_map,107282432 +random,memory,1483476,std::unordered_map,110710784 +random,memory,1551489,std::unordered_map,114221056 +random,memory,1622998,std::unordered_map,117964800 +random,memory,1698528,std::unordered_map,121786368 +random,memory,1774279,std::unordered_map,125607936 +random,memory,1852847,std::unordered_map,129658880 +random,memory,1935045,std::unordered_map,133955584 +random,memory,2016124,std::unordered_map,138084352 +random,memory,2097152,std::unordered_map,209465344 +random,memory,2097152,std::unordered_map,175845376 +random,memory,2202017,std::unordered_map,181227520 +random,memory,2308233,std::unordered_map,186687488 +random,memory,2421995,std::unordered_map,192569344 +random,memory,2540952,std::unordered_map,198647808 +random,memory,2664197,std::unordered_map,205049856 +random,memory,2786842,std::unordered_map,211288064 +random,memory,2914893,std::unordered_map,217915392 +random,memory,3042611,std::unordered_map,224464896 +random,memory,3177918,std::unordered_map,231325696 +random,memory,3316856,std::unordered_map,238583808 +random,memory,3463219,std::unordered_map,245989376 +random,memory,3606297,std::unordered_map,253440000 +random,memory,3758685,std::unordered_map,261234688 +random,memory,3918344,std::unordered_map,269426688 +random,memory,4082497,std::unordered_map,277848064 +random,memory,4194304,std::unordered_map,418111488 +random,memory,4194304,std::unordered_map,350871552 +random,memory,4405390,std::unordered_map,361631744 +random,memory,4622462,std::unordered_map,372862976 +random,memory,4843447,std::unordered_map,384253952 +random,memory,5077057,std::unordered_map,396234752 +random,memory,5310379,std::unordered_map,408170496 +random,memory,5553459,std::unordered_map,420728832 +random,memory,5801485,std::unordered_map,433438720 +random,memory,6061642,std::unordered_map,446771200 +random,memory,6321544,std::unordered_map,460189696 +random,memory,6597657,std::unordered_map,474308608 +random,memory,6874638,std::unordered_map,488579072 +random,memory,7165061,std::unordered_map,503480320 +random,memory,7464156,std::unordered_map,518844416 +random,memory,7769321,std::unordered_map,534519808 +random,memory,8083787,std::unordered_map,550666240 +random,memory,8388608,std::unordered_map,835313664 +random,memory,8388608,std::unordered_map,700833792 +random,memory,8799364,std::unordered_map,721883136 +random,memory,9228893,std::unordered_map,743878656 +random,memory,9664620,std::unordered_map,766345216 +random,time,10000000,std::unordered_map,4.373000 +random,memory,10005035,std::unordered_map,783814656 +random,memory,10114472,std::unordered_map,789352448 +random,memory,10581340,std::unordered_map,813371392 +random,memory,11060026,std::unordered_map,837943296 +random,memory,11554760,std::unordered_map,863367168 +random,memory,12063672,std::unordered_map,889499648 +random,memory,12588048,std::unordered_map,916488192 +random,memory,13128601,std::unordered_map,944173056 +random,memory,13682065,std::unordered_map,972640256 +random,memory,14255923,std::unordered_map,1002127360 +random,memory,14847433,std::unordered_map,1032548352 +random,memory,15456818,std::unordered_map,1063825408 +random,memory,16080459,std::unordered_map,1095798784 +random,memory,16726977,std::unordered_map,1128947712 +random,memory,16777217,std::unordered_map,1669529600 +random,memory,16777217,std::unordered_map,1400569856 +random,memory,17595085,std::unordered_map,1442603008 +random,memory,18438183,std::unordered_map,1485893632 +random,memory,19311311,std::unordered_map,1530658816 +random,time,20000000,std::unordered_map,8.842000 +random,memory,20000810,std::unordered_map,1566150656 +random,memory,20207250,std::unordered_map,1576677376 +random,memory,21131235,std::unordered_map,1624178688 +random,memory,22086647,std::unordered_map,1673158656 +random,memory,23064920,std::unordered_map,1723465728 +random,memory,24073299,std::unordered_map,1775177728 +random,memory,25110516,std::unordered_map,1828532224 +random,memory,26181575,std::unordered_map,1883516928 +random,memory,27282467,std::unordered_map,1940062208 +random,memory,28422030,std::unordered_map,1998561280 +random,memory,29593778,std::unordered_map,2058694656 +random,time,30000000,std::unordered_map,12.018000 +random,memory,30000114,std::unordered_map,2079678464 +random,memory,30796939,std::unordered_map,2120552448 +random,memory,32039135,std::unordered_map,2184355840 +random,memory,33320240,std::unordered_map,2250104832 +random,memory,33554434,std::unordered_map,3338047488 +random,memory,33554434,std::unordered_map,2800128000 +random,memory,35194605,std::unordered_map,2884362240 +random,memory,36886268,std::unordered_map,2971246592 +random,memory,38624437,std::unordered_map,3060473856 +random,time,40000000,std::unordered_map,18.924999 +random,memory,40003628,std::unordered_map,3131297792 +random,memory,40417618,std::unordered_map,3152588800 +random,memory,42264600,std::unordered_map,3247431680 +random,memory,44165274,std::unordered_map,3345006592 +random,memory,46122181,std::unordered_map,3445542912 +random,memory,48137986,std::unordered_map,3549040640 +random,time,50000000,std::unordered_map,22.261999 +random,memory,50001657,std::unordered_map,3644821504 +random,memory,50216354,std::unordered_map,3655737344 +random,memory,52356080,std::unordered_map,3765637120 +random,memory,54556920,std::unordered_map,3878731776 +random,memory,56823702,std::unordered_map,3995103232 +random,memory,59156726,std::unordered_map,4114980864 +random,time,60000000,std::unordered_map,25.919001 +random,memory,60002957,std::unordered_map,4158427136 +random,memory,61562985,std::unordered_map,4238528512 +random,memory,64040759,std::unordered_map,4365746176 +random,memory,66594964,std::unordered_map,4496855040 +random,memory,67108868,std::unordered_map,6675001344 +random,memory,67108868,std::unordered_map,5599162368 +random,time,70000000,std::unordered_map,37.734001 +random,memory,70005322,std::unordered_map,5747867648 +random,memory,70384719,std::unordered_map,5767364608 +random,memory,73758686,std::unordered_map,5940674560 +random,memory,77233925,std::unordered_map,6119124992 +random,time,80000000,std::unordered_map,41.104000 +random,memory,80002815,std::unordered_map,6261395456 +random,memory,80810186,std::unordered_map,6302810112 +random,memory,84496350,std::unordered_map,6492106752 +random,memory,88293603,std::unordered_map,6687174656 +random,time,90000000,std::unordered_map,44.681000 +random,memory,90004365,std::unordered_map,6774996992 +random,memory,92206220,std::unordered_map,6888091648 +random,memory,96235553,std::unordered_map,7095013376 +random,time,100000000,std::unordered_map,48.382000 +random,memory,0,phmap::flat_hash_map,15740928 +random,memory,240967,phmap::flat_hash_map,11272192 +random,memory,458751,phmap::flat_hash_map,11272192 +random,memory,458752,phmap::flat_hash_map,29138944 +random,memory,493930,phmap::flat_hash_map,20205568 +random,memory,678845,phmap::flat_hash_map,19087360 +random,memory,917503,phmap::flat_hash_map,19087360 +random,memory,917504,phmap::flat_hash_map,54812672 +random,memory,930488,phmap::flat_hash_map,36945920 +random,memory,1835007,phmap::flat_hash_map,36945920 +random,memory,1835008,phmap::flat_hash_map,108392448 +random,memory,1860950,phmap::flat_hash_map,72667136 +random,memory,3670015,phmap::flat_hash_map,72667136 +random,memory,3670016,phmap::flat_hash_map,215556096 +random,memory,3681610,phmap::flat_hash_map,144109568 +random,memory,7340031,phmap::flat_hash_map,144109568 +random,memory,7340032,phmap::flat_hash_map,429883392 +random,memory,7348393,phmap::flat_hash_map,286994432 +random,time,10000000,phmap::flat_hash_map,0.917000 +random,memory,10000174,phmap::flat_hash_map,286994432 +random,memory,14680063,phmap::flat_hash_map,286994432 +random,memory,14680064,phmap::flat_hash_map,858537984 +random,memory,14680512,phmap::flat_hash_map,572764160 +random,time,20000000,phmap::flat_hash_map,2.199000 +random,memory,20013320,phmap::flat_hash_map,572764160 +random,memory,29360127,phmap::flat_hash_map,572764160 +random,memory,29360128,phmap::flat_hash_map,1715859456 +random,memory,29369210,phmap::flat_hash_map,1144307712 +random,time,30000000,phmap::flat_hash_map,3.818000 +random,memory,30002294,phmap::flat_hash_map,1144307712 +random,time,40000000,phmap::flat_hash_map,5.070000 +random,memory,40010797,phmap::flat_hash_map,1144307712 +random,time,50000000,phmap::flat_hash_map,6.323000 +random,memory,50009729,phmap::flat_hash_map,1144307712 +random,memory,58720255,phmap::flat_hash_map,1144307712 +random,memory,58720256,phmap::flat_hash_map,3430486016 +random,memory,58721491,phmap::flat_hash_map,2287403008 +random,time,60000000,phmap::flat_hash_map,8.700000 +random,memory,60002661,phmap::flat_hash_map,2287403008 +random,time,70000000,phmap::flat_hash_map,10.155000 +random,memory,70010887,phmap::flat_hash_map,2287403008 +random,time,80000000,phmap::flat_hash_map,11.589000 +random,memory,80002681,phmap::flat_hash_map,2287403008 +random,time,90000000,phmap::flat_hash_map,13.020000 +random,memory,90012468,phmap::flat_hash_map,2287403008 +random,time,100000000,phmap::flat_hash_map,14.407000 +random,memory,0,phmap::parallel_flat_hash_map,6688768 +random,memory,228584,phmap::parallel_flat_hash_map,6688768 +random,memory,228585,phmap::parallel_flat_hash_map,8372224 +random,memory,230683,phmap::parallel_flat_hash_map,8372224 +random,memory,230684,phmap::parallel_flat_hash_map,11190272 +random,memory,257042,phmap::parallel_flat_hash_map,11190272 +random,memory,257105,phmap::parallel_flat_hash_map,11751424 +random,memory,456008,phmap::parallel_flat_hash_map,11751424 +random,memory,456009,phmap::parallel_flat_hash_map,13996032 +random,memory,456819,phmap::parallel_flat_hash_map,13582336 +random,memory,458740,phmap::parallel_flat_hash_map,13582336 +random,memory,458741,phmap::parallel_flat_hash_map,15847424 +random,memory,459266,phmap::parallel_flat_hash_map,15847424 +random,memory,459267,phmap::parallel_flat_hash_map,17518592 +random,memory,465267,phmap::parallel_flat_hash_map,17518592 +random,memory,465268,phmap::parallel_flat_hash_map,21155840 +random,memory,494937,phmap::parallel_flat_hash_map,20598784 +random,memory,911236,phmap::parallel_flat_hash_map,20598784 +random,memory,911237,phmap::parallel_flat_hash_map,22835200 +random,memory,913145,phmap::parallel_flat_hash_map,22835200 +random,memory,913146,phmap::parallel_flat_hash_map,25067520 +random,memory,914338,phmap::parallel_flat_hash_map,25067520 +random,memory,914339,phmap::parallel_flat_hash_map,27303936 +random,memory,916480,phmap::parallel_flat_hash_map,27303936 +random,memory,916481,phmap::parallel_flat_hash_map,29536256 +random,memory,916523,phmap::parallel_flat_hash_map,29536256 +random,memory,916524,phmap::parallel_flat_hash_map,30650368 +random,memory,917790,phmap::parallel_flat_hash_map,30650368 +random,memory,917791,phmap::parallel_flat_hash_map,32882688 +random,memory,918474,phmap::parallel_flat_hash_map,32882688 +random,memory,918475,phmap::parallel_flat_hash_map,35115008 +random,memory,924420,phmap::parallel_flat_hash_map,35115008 +random,memory,924421,phmap::parallel_flat_hash_map,37355520 +random,memory,937279,phmap::parallel_flat_hash_map,37355520 +random,memory,937319,phmap::parallel_flat_hash_map,38465536 +random,memory,1826595,phmap::parallel_flat_hash_map,38465536 +random,memory,1826596,phmap::parallel_flat_hash_map,42934272 +random,memory,1827102,phmap::parallel_flat_hash_map,42934272 +random,memory,1827103,phmap::parallel_flat_hash_map,45170688 +random,memory,1828265,phmap::parallel_flat_hash_map,45170688 +random,memory,1828266,phmap::parallel_flat_hash_map,47398912 +random,memory,1831166,phmap::parallel_flat_hash_map,47398912 +random,memory,1831167,phmap::parallel_flat_hash_map,49631232 +random,memory,1831515,phmap::parallel_flat_hash_map,49631232 +random,memory,1831516,phmap::parallel_flat_hash_map,51867648 +random,memory,1833264,phmap::parallel_flat_hash_map,51867648 +random,memory,1833265,phmap::parallel_flat_hash_map,54099968 +random,memory,1833345,phmap::parallel_flat_hash_map,54099968 +random,memory,1833346,phmap::parallel_flat_hash_map,56332288 +random,memory,1835078,phmap::parallel_flat_hash_map,56332288 +random,memory,1835079,phmap::parallel_flat_hash_map,58572800 +random,memory,1836213,phmap::parallel_flat_hash_map,58572800 +random,memory,1836214,phmap::parallel_flat_hash_map,60801024 +random,memory,1836364,phmap::parallel_flat_hash_map,60801024 +random,memory,1836365,phmap::parallel_flat_hash_map,63033344 +random,memory,1836849,phmap::parallel_flat_hash_map,63033344 +random,memory,1836850,phmap::parallel_flat_hash_map,65265664 +random,memory,1838065,phmap::parallel_flat_hash_map,65265664 +random,memory,1838066,phmap::parallel_flat_hash_map,67502080 +random,memory,1839241,phmap::parallel_flat_hash_map,67502080 +random,memory,1839242,phmap::parallel_flat_hash_map,69734400 +random,memory,1839771,phmap::parallel_flat_hash_map,69734400 +random,memory,1839772,phmap::parallel_flat_hash_map,71962624 +random,memory,1844031,phmap::parallel_flat_hash_map,71962624 +random,memory,1844032,phmap::parallel_flat_hash_map,74194944 +random,memory,1844165,phmap::parallel_flat_hash_map,74194944 +random,memory,1844166,phmap::parallel_flat_hash_map,76423168 +random,memory,1849529,phmap::parallel_flat_hash_map,74186752 +random,memory,3656347,phmap::parallel_flat_hash_map,74186752 +random,memory,3656348,phmap::parallel_flat_hash_map,83120128 +random,memory,3658236,phmap::parallel_flat_hash_map,83120128 +random,memory,3658237,phmap::parallel_flat_hash_map,87592960 +random,memory,3660832,phmap::parallel_flat_hash_map,87592960 +random,memory,3660833,phmap::parallel_flat_hash_map,92061696 +random,memory,3663897,phmap::parallel_flat_hash_map,92061696 +random,memory,3663898,phmap::parallel_flat_hash_map,96526336 +random,memory,3668004,phmap::parallel_flat_hash_map,96526336 +random,memory,3668005,phmap::parallel_flat_hash_map,100990976 +random,memory,3668781,phmap::parallel_flat_hash_map,100990976 +random,memory,3668782,phmap::parallel_flat_hash_map,105459712 +random,memory,3669316,phmap::parallel_flat_hash_map,100990976 +random,memory,3669736,phmap::parallel_flat_hash_map,100990976 +random,memory,3669737,phmap::parallel_flat_hash_map,109928448 +random,memory,3670780,phmap::parallel_flat_hash_map,109928448 +random,memory,3670781,phmap::parallel_flat_hash_map,114388992 +random,memory,3671735,phmap::parallel_flat_hash_map,114388992 +random,memory,3671736,phmap::parallel_flat_hash_map,118853632 +random,memory,3672742,phmap::parallel_flat_hash_map,118853632 +random,memory,3672743,phmap::parallel_flat_hash_map,123322368 +random,memory,3672841,phmap::parallel_flat_hash_map,123322368 +random,memory,3672842,phmap::parallel_flat_hash_map,127787008 +random,memory,3674661,phmap::parallel_flat_hash_map,127787008 +random,memory,3674662,phmap::parallel_flat_hash_map,132259840 +random,memory,3675918,phmap::parallel_flat_hash_map,132259840 +random,memory,3675919,phmap::parallel_flat_hash_map,136724480 +random,memory,3676502,phmap::parallel_flat_hash_map,136724480 +random,memory,3676503,phmap::parallel_flat_hash_map,141180928 +random,memory,3676556,phmap::parallel_flat_hash_map,141180928 +random,memory,3676557,phmap::parallel_flat_hash_map,145645568 +random,memory,3679943,phmap::parallel_flat_hash_map,141176832 +random,memory,3682847,phmap::parallel_flat_hash_map,141176832 +random,memory,3682848,phmap::parallel_flat_hash_map,150106112 +random,memory,3701420,phmap::parallel_flat_hash_map,145637376 +random,memory,7323550,phmap::parallel_flat_hash_map,145637376 +random,memory,7323551,phmap::parallel_flat_hash_map,163500032 +random,memory,7325955,phmap::parallel_flat_hash_map,154566656 +random,memory,7326781,phmap::parallel_flat_hash_map,154566656 +random,memory,7326782,phmap::parallel_flat_hash_map,172433408 +random,memory,7327471,phmap::parallel_flat_hash_map,172433408 +random,memory,7327472,phmap::parallel_flat_hash_map,181362688 +random,memory,7328548,phmap::parallel_flat_hash_map,181362688 +random,memory,7328549,phmap::parallel_flat_hash_map,190300160 +random,memory,7331571,phmap::parallel_flat_hash_map,190300160 +random,memory,7331572,phmap::parallel_flat_hash_map,199229440 +random,memory,7333270,phmap::parallel_flat_hash_map,199229440 +random,memory,7333271,phmap::parallel_flat_hash_map,208154624 +random,memory,7336330,phmap::parallel_flat_hash_map,208154624 +random,memory,7336331,phmap::parallel_flat_hash_map,217083904 +random,memory,7338941,phmap::parallel_flat_hash_map,217083904 +random,memory,7338942,phmap::parallel_flat_hash_map,226021376 +random,memory,7339987,phmap::parallel_flat_hash_map,226021376 +random,memory,7339988,phmap::parallel_flat_hash_map,234950656 +random,memory,7340192,phmap::parallel_flat_hash_map,234950656 +random,memory,7340193,phmap::parallel_flat_hash_map,243879936 +random,memory,7340212,phmap::parallel_flat_hash_map,243879936 +random,memory,7340213,phmap::parallel_flat_hash_map,252805120 +random,memory,7340756,phmap::parallel_flat_hash_map,252805120 +random,memory,7340757,phmap::parallel_flat_hash_map,261734400 +random,memory,7353138,phmap::parallel_flat_hash_map,261734400 +random,memory,7353139,phmap::parallel_flat_hash_map,270659584 +random,memory,7355638,phmap::parallel_flat_hash_map,270659584 +random,memory,7355639,phmap::parallel_flat_hash_map,279592960 +random,memory,7358552,phmap::parallel_flat_hash_map,279592960 +random,memory,7358553,phmap::parallel_flat_hash_map,288522240 +random,memory,7363002,phmap::parallel_flat_hash_map,279584768 +random,memory,7364175,phmap::parallel_flat_hash_map,279584768 +random,memory,7364176,phmap::parallel_flat_hash_map,297451520 +random,memory,7379232,phmap::parallel_flat_hash_map,288518144 +random,time,10000000,phmap::parallel_flat_hash_map,1.115000 +random,memory,10001837,phmap::parallel_flat_hash_map,288518144 +random,memory,14641981,phmap::parallel_flat_hash_map,288518144 +random,memory,14641982,phmap::parallel_flat_hash_map,324243456 +random,memory,14649536,phmap::parallel_flat_hash_map,306380800 +random,memory,14658094,phmap::parallel_flat_hash_map,306380800 +random,memory,14658095,phmap::parallel_flat_hash_map,342106112 +random,memory,14663598,phmap::parallel_flat_hash_map,342106112 +random,memory,14663599,phmap::parallel_flat_hash_map,359968768 +random,memory,14667323,phmap::parallel_flat_hash_map,359968768 +random,memory,14667324,phmap::parallel_flat_hash_map,377835520 +random,memory,14668425,phmap::parallel_flat_hash_map,377835520 +random,memory,14668426,phmap::parallel_flat_hash_map,395694080 +random,memory,14669145,phmap::parallel_flat_hash_map,395694080 +random,memory,14669146,phmap::parallel_flat_hash_map,413560832 +random,memory,14669916,phmap::parallel_flat_hash_map,395698176 +random,memory,14673506,phmap::parallel_flat_hash_map,395698176 +random,memory,14673507,phmap::parallel_flat_hash_map,431423488 +random,memory,14676201,phmap::parallel_flat_hash_map,431423488 +random,memory,14676202,phmap::parallel_flat_hash_map,449286144 +random,memory,14681323,phmap::parallel_flat_hash_map,449286144 +random,memory,14681324,phmap::parallel_flat_hash_map,467152896 +random,memory,14684771,phmap::parallel_flat_hash_map,449286144 +random,memory,14686498,phmap::parallel_flat_hash_map,449286144 +random,memory,14686499,phmap::parallel_flat_hash_map,485011456 +random,memory,14691299,phmap::parallel_flat_hash_map,485011456 +random,memory,14691300,phmap::parallel_flat_hash_map,502865920 +random,memory,14694531,phmap::parallel_flat_hash_map,502865920 +random,memory,14694532,phmap::parallel_flat_hash_map,520728576 +random,memory,14696324,phmap::parallel_flat_hash_map,520728576 +random,memory,14696325,phmap::parallel_flat_hash_map,538587136 +random,memory,14701255,phmap::parallel_flat_hash_map,538587136 +random,memory,14701256,phmap::parallel_flat_hash_map,556445696 +random,memory,14702651,phmap::parallel_flat_hash_map,538578944 +random,memory,14704639,phmap::parallel_flat_hash_map,538578944 +random,memory,14704640,phmap::parallel_flat_hash_map,574300160 +random,memory,14707748,phmap::parallel_flat_hash_map,574300160 +random,memory,14707749,phmap::parallel_flat_hash_map,592158720 +random,memory,14711651,phmap::parallel_flat_hash_map,574296064 +random,time,20000000,phmap::parallel_flat_hash_map,2.484000 +random,memory,20006564,phmap::parallel_flat_hash_map,574296064 +random,memory,29321443,phmap::parallel_flat_hash_map,574296064 +random,memory,29321444,phmap::parallel_flat_hash_map,645742592 +random,memory,29322576,phmap::parallel_flat_hash_map,645742592 +random,memory,29322577,phmap::parallel_flat_hash_map,681463808 +random,memory,29331685,phmap::parallel_flat_hash_map,645742592 +random,memory,29333141,phmap::parallel_flat_hash_map,645742592 +random,memory,29333142,phmap::parallel_flat_hash_map,717189120 +random,memory,29336447,phmap::parallel_flat_hash_map,717189120 +random,memory,29336448,phmap::parallel_flat_hash_map,752910336 +random,memory,29345055,phmap::parallel_flat_hash_map,717185024 +random,memory,29352413,phmap::parallel_flat_hash_map,717185024 +random,memory,29352414,phmap::parallel_flat_hash_map,788627456 +random,memory,29357051,phmap::parallel_flat_hash_map,752902144 +random,memory,29357141,phmap::parallel_flat_hash_map,752902144 +random,memory,29357142,phmap::parallel_flat_hash_map,824348672 +random,memory,29359481,phmap::parallel_flat_hash_map,824348672 +random,memory,29359482,phmap::parallel_flat_hash_map,860069888 +random,memory,29362077,phmap::parallel_flat_hash_map,860069888 +random,memory,29362078,phmap::parallel_flat_hash_map,895795200 +random,memory,29366120,phmap::parallel_flat_hash_map,895795200 +random,memory,29366121,phmap::parallel_flat_hash_map,931512320 +random,memory,29368098,phmap::parallel_flat_hash_map,931512320 +random,memory,29368099,phmap::parallel_flat_hash_map,967229440 +random,memory,29368978,phmap::parallel_flat_hash_map,931508224 +random,memory,29373953,phmap::parallel_flat_hash_map,931508224 +random,memory,29373954,phmap::parallel_flat_hash_map,1002954752 +random,memory,29376083,phmap::parallel_flat_hash_map,1002954752 +random,memory,29376084,phmap::parallel_flat_hash_map,1038680064 +random,memory,29378406,phmap::parallel_flat_hash_map,1002950656 +random,memory,29378970,phmap::parallel_flat_hash_map,1002950656 +random,memory,29378971,phmap::parallel_flat_hash_map,1074397184 +random,memory,29380083,phmap::parallel_flat_hash_map,1074397184 +random,memory,29380084,phmap::parallel_flat_hash_map,1110122496 +random,memory,29381250,phmap::parallel_flat_hash_map,1110122496 +random,memory,29381251,phmap::parallel_flat_hash_map,1145839616 +random,memory,29384576,phmap::parallel_flat_hash_map,1110110208 +random,memory,29391514,phmap::parallel_flat_hash_map,1110110208 +random,memory,29391515,phmap::parallel_flat_hash_map,1181556736 +random,memory,29398827,phmap::parallel_flat_hash_map,1145835520 +random,time,30000000,phmap::parallel_flat_hash_map,4.197000 +random,memory,30003726,phmap::parallel_flat_hash_map,1145835520 +random,time,40000000,phmap::parallel_flat_hash_map,5.407000 +random,memory,40004260,phmap::parallel_flat_hash_map,1145835520 +random,time,50000000,phmap::parallel_flat_hash_map,6.651000 +random,memory,50008463,phmap::parallel_flat_hash_map,1145835520 +random,memory,58650774,phmap::parallel_flat_hash_map,1145835520 +random,memory,58650775,phmap::parallel_flat_hash_map,1288724480 +random,memory,58651341,phmap::parallel_flat_hash_map,1217282048 +random,memory,58670748,phmap::parallel_flat_hash_map,1217282048 +random,memory,58670749,phmap::parallel_flat_hash_map,1360171008 +random,memory,58672543,phmap::parallel_flat_hash_map,1288724480 +random,memory,58679343,phmap::parallel_flat_hash_map,1288724480 +random,memory,58679344,phmap::parallel_flat_hash_map,1431609344 +random,memory,58679621,phmap::parallel_flat_hash_map,1431609344 +random,memory,58679622,phmap::parallel_flat_hash_map,1503047680 +random,memory,58681449,phmap::parallel_flat_hash_map,1503047680 +random,memory,58681450,phmap::parallel_flat_hash_map,1574498304 +random,memory,58687442,phmap::parallel_flat_hash_map,1503055872 +random,memory,58716081,phmap::parallel_flat_hash_map,1503055872 +random,memory,58716082,phmap::parallel_flat_hash_map,1645944832 +random,memory,58719988,phmap::parallel_flat_hash_map,1574498304 +random,memory,58720496,phmap::parallel_flat_hash_map,1574498304 +random,memory,58720497,phmap::parallel_flat_hash_map,1717387264 +random,memory,58723911,phmap::parallel_flat_hash_map,1717387264 +random,memory,58723912,phmap::parallel_flat_hash_map,1788841984 +random,memory,58728095,phmap::parallel_flat_hash_map,1717395456 +random,memory,58731608,phmap::parallel_flat_hash_map,1717395456 +random,memory,58731609,phmap::parallel_flat_hash_map,1860280320 +random,memory,58737338,phmap::parallel_flat_hash_map,1860280320 +random,memory,58737339,phmap::parallel_flat_hash_map,1931718656 +random,memory,58737397,phmap::parallel_flat_hash_map,1860272128 +random,memory,58744726,phmap::parallel_flat_hash_map,1860272128 +random,memory,58744727,phmap::parallel_flat_hash_map,2003165184 +random,memory,58746205,phmap::parallel_flat_hash_map,1931718656 +random,memory,58752523,phmap::parallel_flat_hash_map,1931718656 +random,memory,58752524,phmap::parallel_flat_hash_map,2074607616 +random,memory,58753838,phmap::parallel_flat_hash_map,2074607616 +random,memory,58753839,phmap::parallel_flat_hash_map,2146054144 +random,memory,58756083,phmap::parallel_flat_hash_map,2146054144 +random,memory,58756084,phmap::parallel_flat_hash_map,2217496576 +random,memory,58758266,phmap::parallel_flat_hash_map,2217496576 +random,memory,58758267,phmap::parallel_flat_hash_map,2288943104 +random,memory,58760494,phmap::parallel_flat_hash_map,2217492480 +random,memory,58766191,phmap::parallel_flat_hash_map,2217492480 +random,memory,58766192,phmap::parallel_flat_hash_map,2360381440 +random,memory,58773720,phmap::parallel_flat_hash_map,2288934912 +random,time,60000000,phmap::parallel_flat_hash_map,9.067000 +random,memory,60002586,phmap::parallel_flat_hash_map,2288934912 +random,time,70000000,phmap::parallel_flat_hash_map,10.409000 +random,memory,70011900,phmap::parallel_flat_hash_map,2288934912 +random,time,80000000,phmap::parallel_flat_hash_map,11.747000 +random,memory,80002981,phmap::parallel_flat_hash_map,2288934912 +random,time,90000000,phmap::parallel_flat_hash_map,13.091000 +random,memory,90007030,phmap::parallel_flat_hash_map,2288934912 +random,time,100000000,phmap::parallel_flat_hash_map,14.467000 diff --git a/extern/phmap/benchmark/results/output_various_N b/extern/phmap/benchmark/results/output_various_N new file mode 100644 index 0000000..352a033 --- /dev/null +++ b/extern/phmap/benchmark/results/output_various_N @@ -0,0 +1,838 @@ +random,memory,0,phmap::flat_hash_map,15736832 +random,memory,262696,phmap::flat_hash_map,15736832 +random,memory,262879,phmap::flat_hash_map,11268096 +random,memory,458751,phmap::flat_hash_map,11268096 +random,memory,458752,phmap::flat_hash_map,29134848 +random,memory,493071,phmap::flat_hash_map,29134848 +random,memory,493277,phmap::flat_hash_map,20201472 +random,memory,680181,phmap::flat_hash_map,20201472 +random,memory,680399,phmap::flat_hash_map,19083264 +random,memory,917503,phmap::flat_hash_map,19083264 +random,memory,917504,phmap::flat_hash_map,54808576 +random,memory,927756,phmap::flat_hash_map,54808576 +random,memory,927844,phmap::flat_hash_map,36941824 +random,memory,1835007,phmap::flat_hash_map,36941824 +random,memory,1835008,phmap::flat_hash_map,108388352 +random,memory,1840514,phmap::flat_hash_map,108388352 +random,memory,1840562,phmap::flat_hash_map,72663040 +random,memory,3670015,phmap::flat_hash_map,72663040 +random,memory,3670016,phmap::flat_hash_map,215552000 +random,memory,3672773,phmap::flat_hash_map,215552000 +random,memory,3672818,phmap::flat_hash_map,144105472 +random,memory,7340031,phmap::flat_hash_map,144105472 +random,memory,7340032,phmap::flat_hash_map,429887488 +random,memory,7341507,phmap::flat_hash_map,429887488 +random,memory,7341551,phmap::flat_hash_map,286994432 +random,time,10000000,phmap::flat_hash_map,0.959000 +random,memory,10013489,phmap::flat_hash_map,286994432 +random,memory,14680063,phmap::flat_hash_map,286994432 +random,memory,14680064,phmap::flat_hash_map,858537984 +random,memory,14689336,phmap::flat_hash_map,858537984 +random,memory,14689395,phmap::flat_hash_map,572764160 +random,time,20000000,phmap::flat_hash_map,2.235000 +random,memory,20014360,phmap::flat_hash_map,572764160 +random,memory,29360127,phmap::flat_hash_map,572764160 +random,memory,29360128,phmap::flat_hash_map,1715855360 +random,memory,29362598,phmap::flat_hash_map,1715855360 +random,memory,29362641,phmap::flat_hash_map,1144303616 +random,time,30000000,phmap::flat_hash_map,3.893000 +random,memory,30002217,phmap::flat_hash_map,1144303616 +random,time,40000000,phmap::flat_hash_map,5.194000 +random,memory,40013295,phmap::flat_hash_map,1144303616 +random,time,50000000,phmap::flat_hash_map,6.478000 +random,memory,50004165,phmap::flat_hash_map,1144303616 +random,memory,58720255,phmap::flat_hash_map,1144303616 +random,memory,58720256,phmap::flat_hash_map,3430486016 +random,memory,58730855,phmap::flat_hash_map,3430486016 +random,memory,58730895,phmap::flat_hash_map,2287407104 +random,time,60000000,phmap::flat_hash_map,8.861000 +random,memory,60005803,phmap::flat_hash_map,2287407104 +random,time,70000000,phmap::flat_hash_map,10.361000 +random,memory,70008717,phmap::flat_hash_map,2287407104 +random,time,80000000,phmap::flat_hash_map,11.848000 +random,memory,80003058,phmap::flat_hash_map,2287407104 +random,time,90000000,phmap::flat_hash_map,13.318000 +random,memory,90012411,phmap::flat_hash_map,2287407104 +random,time,100000000,phmap::flat_hash_map,14.773000 +random,memory,0,phmap::parallel_flat_hash_map_4,8425472 +random,memory,230139,phmap::parallel_flat_hash_map_4,8503296 +random,memory,230140,phmap::parallel_flat_hash_map_4,10977280 +random,memory,253089,phmap::parallel_flat_hash_map_4,10977280 +random,memory,253158,phmap::parallel_flat_hash_map_4,13225984 +random,memory,454288,phmap::parallel_flat_hash_map_4,13225984 +random,memory,454289,phmap::parallel_flat_hash_map_4,14352384 +random,memory,456498,phmap::parallel_flat_hash_map_4,14352384 +random,memory,456499,phmap::parallel_flat_hash_map_4,14082048 +random,memory,457735,phmap::parallel_flat_hash_map_4,14082048 +random,memory,457736,phmap::parallel_flat_hash_map_4,15777792 +random,memory,459898,phmap::parallel_flat_hash_map_4,15777792 +random,memory,459899,phmap::parallel_flat_hash_map_4,18591744 +random,memory,461397,phmap::parallel_flat_hash_map_4,18591744 +random,memory,461398,phmap::parallel_flat_hash_map_4,20283392 +random,memory,471716,phmap::parallel_flat_hash_map_4,20283392 +random,memory,471760,phmap::parallel_flat_hash_map_4,21397504 +random,memory,911802,phmap::parallel_flat_hash_map_4,21397504 +random,memory,911803,phmap::parallel_flat_hash_map_4,23633920 +random,memory,911912,phmap::parallel_flat_hash_map_4,23633920 +random,memory,911963,phmap::parallel_flat_hash_map_4,22515712 +random,memory,912599,phmap::parallel_flat_hash_map_4,22515712 +random,memory,912600,phmap::parallel_flat_hash_map_4,25866240 +random,memory,915388,phmap::parallel_flat_hash_map_4,25866240 +random,memory,915389,phmap::parallel_flat_hash_map_4,28098560 +random,memory,916642,phmap::parallel_flat_hash_map_4,28098560 +random,memory,916643,phmap::parallel_flat_hash_map_4,30339072 +random,memory,917177,phmap::parallel_flat_hash_map_4,30339072 +random,memory,917178,phmap::parallel_flat_hash_map_4,32575488 +random,memory,917415,phmap::parallel_flat_hash_map_4,32575488 +random,memory,917416,phmap::parallel_flat_hash_map_4,33689600 +random,memory,920064,phmap::parallel_flat_hash_map_4,33689600 +random,memory,920065,phmap::parallel_flat_hash_map_4,35917824 +random,memory,921982,phmap::parallel_flat_hash_map_4,35917824 +random,memory,921983,phmap::parallel_flat_hash_map_4,38154240 +random,memory,922325,phmap::parallel_flat_hash_map_4,39272448 +random,memory,1826091,phmap::parallel_flat_hash_map_4,39268352 +random,memory,1826092,phmap::parallel_flat_hash_map_4,43737088 +random,memory,1827754,phmap::parallel_flat_hash_map_4,43737088 +random,memory,1827755,phmap::parallel_flat_hash_map_4,45973504 +random,memory,1830054,phmap::parallel_flat_hash_map_4,45973504 +random,memory,1830055,phmap::parallel_flat_hash_map_4,48209920 +random,memory,1830521,phmap::parallel_flat_hash_map_4,48209920 +random,memory,1830522,phmap::parallel_flat_hash_map_4,50438144 +random,memory,1831966,phmap::parallel_flat_hash_map_4,50438144 +random,memory,1831967,phmap::parallel_flat_hash_map_4,52666368 +random,memory,1832841,phmap::parallel_flat_hash_map_4,52666368 +random,memory,1832842,phmap::parallel_flat_hash_map_4,59375616 +random,memory,1836262,phmap::parallel_flat_hash_map_4,59367424 +random,memory,1836263,phmap::parallel_flat_hash_map_4,61603840 +random,memory,1836728,phmap::parallel_flat_hash_map_4,61603840 +random,memory,1836729,phmap::parallel_flat_hash_map_4,63836160 +random,memory,1836910,phmap::parallel_flat_hash_map_4,63836160 +random,memory,1836911,phmap::parallel_flat_hash_map_4,66064384 +random,memory,1838008,phmap::parallel_flat_hash_map_4,66064384 +random,memory,1838009,phmap::parallel_flat_hash_map_4,68300800 +random,memory,1839009,phmap::parallel_flat_hash_map_4,68300800 +random,memory,1839010,phmap::parallel_flat_hash_map_4,70529024 +random,memory,1842043,phmap::parallel_flat_hash_map_4,70529024 +random,memory,1842044,phmap::parallel_flat_hash_map_4,72761344 +random,memory,1842263,phmap::parallel_flat_hash_map_4,72761344 +random,memory,1842264,phmap::parallel_flat_hash_map_4,74993664 +random,memory,1843365,phmap::parallel_flat_hash_map_4,77230080 +random,memory,1902147,phmap::parallel_flat_hash_map_4,77230080 +random,memory,1902233,phmap::parallel_flat_hash_map_4,74997760 +random,memory,3656950,phmap::parallel_flat_hash_map_4,74997760 +random,memory,3656951,phmap::parallel_flat_hash_map_4,83935232 +random,memory,3658625,phmap::parallel_flat_hash_map_4,83939328 +random,memory,3658626,phmap::parallel_flat_hash_map_4,88403968 +random,memory,3660741,phmap::parallel_flat_hash_map_4,88403968 +random,memory,3660742,phmap::parallel_flat_hash_map_4,92872704 +random,memory,3663376,phmap::parallel_flat_hash_map_4,92872704 +random,memory,3663377,phmap::parallel_flat_hash_map_4,97341440 +random,memory,3665288,phmap::parallel_flat_hash_map_4,97341440 +random,memory,3665289,phmap::parallel_flat_hash_map_4,101801984 +random,memory,3668214,phmap::parallel_flat_hash_map_4,101801984 +random,memory,3668215,phmap::parallel_flat_hash_map_4,106270720 +random,memory,3669632,phmap::parallel_flat_hash_map_4,106270720 +random,memory,3669633,phmap::parallel_flat_hash_map_4,110731264 +random,memory,3670422,phmap::parallel_flat_hash_map_4,110731264 +random,memory,3670423,phmap::parallel_flat_hash_map_4,115195904 +random,memory,3671980,phmap::parallel_flat_hash_map_4,115195904 +random,memory,3671981,phmap::parallel_flat_hash_map_4,119656448 +random,memory,3673456,phmap::parallel_flat_hash_map_4,119656448 +random,memory,3673457,phmap::parallel_flat_hash_map_4,124116992 +random,memory,3675504,phmap::parallel_flat_hash_map_4,124116992 +random,memory,3675548,phmap::parallel_flat_hash_map_4,119644160 +random,memory,3675608,phmap::parallel_flat_hash_map_4,119644160 +random,memory,3675609,phmap::parallel_flat_hash_map_4,137519104 +random,memory,3676812,phmap::parallel_flat_hash_map_4,137515008 +random,memory,3676813,phmap::parallel_flat_hash_map_4,141983744 +random,memory,3677010,phmap::parallel_flat_hash_map_4,141983744 +random,memory,3677011,phmap::parallel_flat_hash_map_4,146444288 +random,memory,3682438,phmap::parallel_flat_hash_map_4,146444288 +random,memory,3682439,phmap::parallel_flat_hash_map_4,150904832 +random,memory,3705594,phmap::parallel_flat_hash_map_4,150904832 +random,memory,3705595,phmap::parallel_flat_hash_map_4,146440192 +random,memory,7320177,phmap::parallel_flat_hash_map_4,146440192 +random,memory,7320178,phmap::parallel_flat_hash_map_4,164302848 +random,memory,7321389,phmap::parallel_flat_hash_map_4,164302848 +random,memory,7321390,phmap::parallel_flat_hash_map_4,173240320 +random,memory,7332480,phmap::parallel_flat_hash_map_4,173240320 +random,memory,7332481,phmap::parallel_flat_hash_map_4,182169600 +random,memory,7334320,phmap::parallel_flat_hash_map_4,182169600 +random,memory,7334321,phmap::parallel_flat_hash_map_4,191094784 +random,memory,7338310,phmap::parallel_flat_hash_map_4,191094784 +random,memory,7338311,phmap::parallel_flat_hash_map_4,200028160 +random,memory,7338542,phmap::parallel_flat_hash_map_4,200028160 +random,memory,7338543,phmap::parallel_flat_hash_map_4,208961536 +random,memory,7339365,phmap::parallel_flat_hash_map_4,208961536 +random,memory,7339366,phmap::parallel_flat_hash_map_4,217899008 +random,memory,7339930,phmap::parallel_flat_hash_map_4,217899008 +random,memory,7339931,phmap::parallel_flat_hash_map_4,226828288 +random,memory,7341026,phmap::parallel_flat_hash_map_4,226828288 +random,memory,7341027,phmap::parallel_flat_hash_map_4,253620224 +random,memory,7345230,phmap::parallel_flat_hash_map_4,253616128 +random,memory,7345231,phmap::parallel_flat_hash_map_4,262545408 +random,memory,7347839,phmap::parallel_flat_hash_map_4,262545408 +random,memory,7347840,phmap::parallel_flat_hash_map_4,271470592 +random,memory,7349398,phmap::parallel_flat_hash_map_4,271470592 +random,memory,7349399,phmap::parallel_flat_hash_map_4,280399872 +random,memory,7350072,phmap::parallel_flat_hash_map_4,280399872 +random,memory,7350073,phmap::parallel_flat_hash_map_4,289329152 +random,memory,7358606,phmap::parallel_flat_hash_map_4,289329152 +random,memory,7358607,phmap::parallel_flat_hash_map_4,298262528 +random,memory,7418699,phmap::parallel_flat_hash_map_4,298262528 +random,memory,7418807,phmap::parallel_flat_hash_map_4,289329152 +random,time,10000000,phmap::parallel_flat_hash_map_4,0.775000 +random,memory,10143429,phmap::parallel_flat_hash_map_4,288841728 +random,memory,14656465,phmap::parallel_flat_hash_map_4,288841728 +random,memory,14656466,phmap::parallel_flat_hash_map_4,324567040 +random,memory,14666142,phmap::parallel_flat_hash_map_4,324567040 +random,memory,14666153,phmap::parallel_flat_hash_map_4,342429696 +random,memory,14668185,phmap::parallel_flat_hash_map_4,342429696 +random,memory,14668186,phmap::parallel_flat_hash_map_4,360292352 +random,memory,14669296,phmap::parallel_flat_hash_map_4,360292352 +random,memory,14669297,phmap::parallel_flat_hash_map_4,378155008 +random,memory,14669466,phmap::parallel_flat_hash_map_4,378155008 +random,memory,14669467,phmap::parallel_flat_hash_map_4,396017664 +random,memory,14673507,phmap::parallel_flat_hash_map_4,396017664 +random,memory,14673508,phmap::parallel_flat_hash_map_4,413876224 +random,memory,14677314,phmap::parallel_flat_hash_map_4,413876224 +random,memory,14677315,phmap::parallel_flat_hash_map_4,467460096 +random,memory,14677330,phmap::parallel_flat_hash_map_4,467460096 +random,memory,14677331,phmap::parallel_flat_hash_map_4,449593344 +random,memory,14681511,phmap::parallel_flat_hash_map_4,449593344 +random,memory,14681512,phmap::parallel_flat_hash_map_4,467456000 +random,memory,14681884,phmap::parallel_flat_hash_map_4,467456000 +random,memory,14681885,phmap::parallel_flat_hash_map_4,485318656 +random,memory,14685984,phmap::parallel_flat_hash_map_4,485318656 +random,memory,14685985,phmap::parallel_flat_hash_map_4,503173120 +random,memory,14692178,phmap::parallel_flat_hash_map_4,503173120 +random,memory,14692179,phmap::parallel_flat_hash_map_4,521035776 +random,memory,14693317,phmap::parallel_flat_hash_map_4,521035776 +random,memory,14693318,phmap::parallel_flat_hash_map_4,538902528 +random,memory,14695057,phmap::parallel_flat_hash_map_4,538902528 +random,memory,14695058,phmap::parallel_flat_hash_map_4,556769280 +random,memory,14696242,phmap::parallel_flat_hash_map_4,556769280 +random,memory,14696243,phmap::parallel_flat_hash_map_4,574623744 +random,memory,14699788,phmap::parallel_flat_hash_map_4,574623744 +random,memory,14699789,phmap::parallel_flat_hash_map_4,592478208 +random,memory,14724882,phmap::parallel_flat_hash_map_4,592478208 +random,memory,14724958,phmap::parallel_flat_hash_map_4,574607360 +random,time,20000000,phmap::parallel_flat_hash_map_4,1.624000 +random,memory,20059632,phmap::parallel_flat_hash_map_4,574607360 +random,memory,29320741,phmap::parallel_flat_hash_map_4,574607360 +random,memory,29320742,phmap::parallel_flat_hash_map_4,646053888 +random,memory,29324660,phmap::parallel_flat_hash_map_4,646053888 +random,memory,29324661,phmap::parallel_flat_hash_map_4,681779200 +random,memory,29337731,phmap::parallel_flat_hash_map_4,681779200 +random,memory,29337732,phmap::parallel_flat_hash_map_4,717500416 +random,memory,29344679,phmap::parallel_flat_hash_map_4,717500416 +random,memory,29344680,phmap::parallel_flat_hash_map_4,753221632 +random,memory,29345420,phmap::parallel_flat_hash_map_4,753221632 +random,memory,29345421,phmap::parallel_flat_hash_map_4,788938752 +random,memory,29346467,phmap::parallel_flat_hash_map_4,788938752 +random,memory,29346468,phmap::parallel_flat_hash_map_4,824659968 +random,memory,29350032,phmap::parallel_flat_hash_map_4,824659968 +random,memory,29350033,phmap::parallel_flat_hash_map_4,860385280 +random,memory,29363538,phmap::parallel_flat_hash_map_4,860385280 +random,memory,29363539,phmap::parallel_flat_hash_map_4,896106496 +random,memory,29368515,phmap::parallel_flat_hash_map_4,896106496 +random,memory,29368516,phmap::parallel_flat_hash_map_4,931831808 +random,memory,29377392,phmap::parallel_flat_hash_map_4,931831808 +random,memory,29377393,phmap::parallel_flat_hash_map_4,967553024 +random,memory,29378023,phmap::parallel_flat_hash_map_4,967553024 +random,memory,29378024,phmap::parallel_flat_hash_map_4,1003274240 +random,memory,29379201,phmap::parallel_flat_hash_map_4,1003274240 +random,memory,29379202,phmap::parallel_flat_hash_map_4,1038991360 +random,memory,29380427,phmap::parallel_flat_hash_map_4,1038991360 +random,memory,29380428,phmap::parallel_flat_hash_map_4,1074712576 +random,memory,29380936,phmap::parallel_flat_hash_map_4,1074712576 +random,memory,29380937,phmap::parallel_flat_hash_map_4,1110429696 +random,memory,29381222,phmap::parallel_flat_hash_map_4,1110429696 +random,memory,29381223,phmap::parallel_flat_hash_map_4,1146150912 +random,memory,29383327,phmap::parallel_flat_hash_map_4,1146150912 +random,memory,29383328,phmap::parallel_flat_hash_map_4,1181872128 +random,memory,29481786,phmap::parallel_flat_hash_map_4,1181872128 +random,memory,29482210,phmap::parallel_flat_hash_map_4,1146150912 +random,time,30000000,phmap::parallel_flat_hash_map_4,2.765000 +random,memory,30042200,phmap::parallel_flat_hash_map_4,1146150912 +random,time,40000000,phmap::parallel_flat_hash_map_4,3.366000 +random,memory,40007439,phmap::parallel_flat_hash_map_4,1146093568 +random,time,50000000,phmap::parallel_flat_hash_map_4,3.980000 +random,memory,50022406,phmap::parallel_flat_hash_map_4,1146150912 +random,memory,58667479,phmap::parallel_flat_hash_map_4,1146150912 +random,memory,58667498,phmap::parallel_flat_hash_map_4,1289039872 +random,memory,58667500,phmap::parallel_flat_hash_map_4,1289039872 +random,memory,58667517,phmap::parallel_flat_hash_map_4,1217597440 +random,memory,58679732,phmap::parallel_flat_hash_map_4,1217597440 +random,memory,58679733,phmap::parallel_flat_hash_map_4,1360486400 +random,memory,58694839,phmap::parallel_flat_hash_map_4,1360486400 +random,memory,58694840,phmap::parallel_flat_hash_map_4,1431928832 +random,memory,58698836,phmap::parallel_flat_hash_map_4,1431928832 +random,memory,58698837,phmap::parallel_flat_hash_map_4,1503367168 +random,memory,58699874,phmap::parallel_flat_hash_map_4,1503367168 +random,memory,58699875,phmap::parallel_flat_hash_map_4,1574809600 +random,memory,58709079,phmap::parallel_flat_hash_map_4,1574809600 +random,memory,58709080,phmap::parallel_flat_hash_map_4,1646252032 +random,memory,58719855,phmap::parallel_flat_hash_map_4,1646252032 +random,memory,58719863,phmap::parallel_flat_hash_map_4,1717694464 +random,memory,58722595,phmap::parallel_flat_hash_map_4,1717694464 +random,memory,58722596,phmap::parallel_flat_hash_map_4,1789149184 +random,memory,58724186,phmap::parallel_flat_hash_map_4,1789149184 +random,memory,58724187,phmap::parallel_flat_hash_map_4,1860595712 +random,memory,58728663,phmap::parallel_flat_hash_map_4,1860595712 +random,memory,58728664,phmap::parallel_flat_hash_map_4,1932034048 +random,memory,58734146,phmap::parallel_flat_hash_map_4,1932034048 +random,memory,58734147,phmap::parallel_flat_hash_map_4,2003476480 +random,memory,58739881,phmap::parallel_flat_hash_map_4,2003476480 +random,memory,58739882,phmap::parallel_flat_hash_map_4,2074923008 +random,memory,58743626,phmap::parallel_flat_hash_map_4,2074923008 +random,memory,58743627,phmap::parallel_flat_hash_map_4,2146361344 +random,memory,58748930,phmap::parallel_flat_hash_map_4,2146361344 +random,memory,58748931,phmap::parallel_flat_hash_map_4,2217803776 +random,memory,58752653,phmap::parallel_flat_hash_map_4,2217803776 +random,memory,58752654,phmap::parallel_flat_hash_map_4,2289242112 +random,memory,58761467,phmap::parallel_flat_hash_map_4,2289242112 +random,memory,58761468,phmap::parallel_flat_hash_map_4,2360680448 +random,memory,58767953,phmap::parallel_flat_hash_map_4,2360680448 +random,memory,58767993,phmap::parallel_flat_hash_map_4,2289233920 +random,time,60000000,phmap::parallel_flat_hash_map_4,5.747000 +random,memory,60013676,phmap::parallel_flat_hash_map_4,2289242112 +random,time,70000000,phmap::parallel_flat_hash_map_4,6.369000 +random,memory,70124243,phmap::parallel_flat_hash_map_4,2289233920 +random,time,80000000,phmap::parallel_flat_hash_map_4,7.042000 +random,memory,80028849,phmap::parallel_flat_hash_map_4,2289238016 +random,time,90000000,phmap::parallel_flat_hash_map_4,7.670000 +random,memory,90048047,phmap::parallel_flat_hash_map_4,2289238016 +random,time,100000000,phmap::parallel_flat_hash_map_4,8.369000 +random,memory,0,phmap::parallel_flat_hash_map_5,8171520 +random,memory,230048,phmap::parallel_flat_hash_map_5,8171520 +random,memory,230049,phmap::parallel_flat_hash_map_5,11292672 +random,memory,447941,phmap::parallel_flat_hash_map_5,11292672 +random,memory,447942,phmap::parallel_flat_hash_map_5,12705792 +random,memory,454330,phmap::parallel_flat_hash_map_5,12705792 +random,memory,454331,phmap::parallel_flat_hash_map_5,16080896 +random,memory,459541,phmap::parallel_flat_hash_map_5,16080896 +random,memory,459542,phmap::parallel_flat_hash_map_5,18911232 +random,memory,463883,phmap::parallel_flat_hash_map_5,18911232 +random,memory,463884,phmap::parallel_flat_hash_map_5,23703552 +random,memory,907467,phmap::parallel_flat_hash_map_5,23703552 +random,memory,907468,phmap::parallel_flat_hash_map_5,25948160 +random,memory,910634,phmap::parallel_flat_hash_map_5,25948160 +random,memory,910635,phmap::parallel_flat_hash_map_5,25681920 +random,memory,912368,phmap::parallel_flat_hash_map_5,25681920 +random,memory,912369,phmap::parallel_flat_hash_map_5,25169920 +random,memory,914982,phmap::parallel_flat_hash_map_5,25169920 +random,memory,914983,phmap::parallel_flat_hash_map_5,29949952 +random,memory,918814,phmap::parallel_flat_hash_map_5,29949952 +random,memory,918815,phmap::parallel_flat_hash_map_5,32497664 +random,memory,920383,phmap::parallel_flat_hash_map_5,32497664 +random,memory,920384,phmap::parallel_flat_hash_map_5,33644544 +random,memory,922282,phmap::parallel_flat_hash_map_5,33644544 +random,memory,922283,phmap::parallel_flat_hash_map_5,35336192 +random,memory,924207,phmap::parallel_flat_hash_map_5,35336192 +random,memory,924208,phmap::parallel_flat_hash_map_5,38166528 +random,memory,1045187,phmap::parallel_flat_hash_map_5,38166528 +random,memory,1045188,phmap::parallel_flat_hash_map_5,39317504 +random,memory,1821687,phmap::parallel_flat_hash_map_5,39317504 +random,memory,1821688,phmap::parallel_flat_hash_map_5,41553920 +random,memory,1825706,phmap::parallel_flat_hash_map_5,41553920 +random,memory,1825707,phmap::parallel_flat_hash_map_5,43786240 +random,memory,1827224,phmap::parallel_flat_hash_map_5,43786240 +random,memory,1827225,phmap::parallel_flat_hash_map_5,47144960 +random,memory,1828449,phmap::parallel_flat_hash_map_5,48259072 +random,memory,1831516,phmap::parallel_flat_hash_map_5,48259072 +random,memory,1831517,phmap::parallel_flat_hash_map_5,52727808 +random,memory,1832911,phmap::parallel_flat_hash_map_5,52727808 +random,memory,1832912,phmap::parallel_flat_hash_map_5,56082432 +random,memory,1835515,phmap::parallel_flat_hash_map_5,56078336 +random,memory,1835516,phmap::parallel_flat_hash_map_5,60547072 +random,memory,1836508,phmap::parallel_flat_hash_map_5,60547072 +random,memory,1836509,phmap::parallel_flat_hash_map_5,62779392 +random,memory,1837620,phmap::parallel_flat_hash_map_5,63893504 +random,memory,1838419,phmap::parallel_flat_hash_map_5,63893504 +random,memory,1838420,phmap::parallel_flat_hash_map_5,68362240 +random,memory,1844110,phmap::parallel_flat_hash_map_5,68358144 +random,memory,1844111,phmap::parallel_flat_hash_map_5,71704576 +random,memory,1845194,phmap::parallel_flat_hash_map_5,72822784 +random,memory,1848605,phmap::parallel_flat_hash_map_5,72822784 +random,memory,1848606,phmap::parallel_flat_hash_map_5,76173312 +random,memory,1903391,phmap::parallel_flat_hash_map_5,76173312 +random,memory,2062005,phmap::parallel_flat_hash_map_5,75051008 +random,memory,3647995,phmap::parallel_flat_hash_map_5,75051008 +random,memory,3647996,phmap::parallel_flat_hash_map_5,79519744 +random,memory,3653763,phmap::parallel_flat_hash_map_5,81756160 +random,memory,3654750,phmap::parallel_flat_hash_map_5,83988480 +random,memory,3655941,phmap::parallel_flat_hash_map_5,86216704 +random,memory,3658224,phmap::parallel_flat_hash_map_5,88457216 +random,memory,3658959,phmap::parallel_flat_hash_map_5,90689536 +random,memory,3659868,phmap::parallel_flat_hash_map_5,90689536 +random,memory,3659869,phmap::parallel_flat_hash_map_5,97394688 +random,memory,3665747,phmap::parallel_flat_hash_map_5,99618816 +random,memory,3666483,phmap::parallel_flat_hash_map_5,101855232 +random,memory,3666786,phmap::parallel_flat_hash_map_5,104083456 +random,memory,3668303,phmap::parallel_flat_hash_map_5,106319872 +random,memory,3669798,phmap::parallel_flat_hash_map_5,108560384 +random,memory,3670157,phmap::parallel_flat_hash_map_5,110800896 +random,memory,3670634,phmap::parallel_flat_hash_map_5,110800896 +random,memory,3670635,phmap::parallel_flat_hash_map_5,117501952 +random,memory,3671412,phmap::parallel_flat_hash_map_5,117497856 +random,memory,3671413,phmap::parallel_flat_hash_map_5,124194816 +random,memory,3676143,phmap::parallel_flat_hash_map_5,126423040 +random,memory,3676807,phmap::parallel_flat_hash_map_5,128655360 +random,memory,3677068,phmap::parallel_flat_hash_map_5,128655360 +random,memory,3677069,phmap::parallel_flat_hash_map_5,135356416 +random,memory,3677181,phmap::parallel_flat_hash_map_5,135356416 +random,memory,3677182,phmap::parallel_flat_hash_map_5,133115904 +random,memory,3680571,phmap::parallel_flat_hash_map_5,135348224 +random,memory,3683612,phmap::parallel_flat_hash_map_5,137580544 +random,memory,3684355,phmap::parallel_flat_hash_map_5,139808768 +random,memory,3684486,phmap::parallel_flat_hash_map_5,142045184 +random,memory,3684703,phmap::parallel_flat_hash_map_5,144277504 +random,memory,3687105,phmap::parallel_flat_hash_map_5,146505728 +random,memory,3690770,phmap::parallel_flat_hash_map_5,148733952 +random,memory,3715764,phmap::parallel_flat_hash_map_5,148733952 +random,memory,3715808,phmap::parallel_flat_hash_map_5,146497536 +random,memory,7297554,phmap::parallel_flat_hash_map_5,146497536 +random,memory,7297555,phmap::parallel_flat_hash_map_5,155435008 +random,memory,7311903,phmap::parallel_flat_hash_map_5,159903744 +random,memory,7322014,phmap::parallel_flat_hash_map_5,164372480 +random,memory,7324284,phmap::parallel_flat_hash_map_5,168845312 +random,memory,7325861,phmap::parallel_flat_hash_map_5,168845312 +random,memory,7325862,phmap::parallel_flat_hash_map_5,182243328 +random,memory,7327665,phmap::parallel_flat_hash_map_5,186707968 +random,memory,7328023,phmap::parallel_flat_hash_map_5,186707968 +random,memory,7328024,phmap::parallel_flat_hash_map_5,200101888 +random,memory,7329789,phmap::parallel_flat_hash_map_5,200110080 +random,memory,7329790,phmap::parallel_flat_hash_map_5,213512192 +random,memory,7334043,phmap::parallel_flat_hash_map_5,217964544 +random,memory,7334415,phmap::parallel_flat_hash_map_5,222425088 +random,memory,7339734,phmap::parallel_flat_hash_map_5,226893824 +random,memory,7341649,phmap::parallel_flat_hash_map_5,231358464 +random,memory,7344137,phmap::parallel_flat_hash_map_5,235819008 +random,memory,7344731,phmap::parallel_flat_hash_map_5,240279552 +random,memory,7345981,phmap::parallel_flat_hash_map_5,244748288 +random,memory,7347533,phmap::parallel_flat_hash_map_5,249208832 +random,memory,7348108,phmap::parallel_flat_hash_map_5,253677568 +random,memory,7348995,phmap::parallel_flat_hash_map_5,258142208 +random,memory,7352977,phmap::parallel_flat_hash_map_5,262598656 +random,memory,7355355,phmap::parallel_flat_hash_map_5,267063296 +random,memory,7356095,phmap::parallel_flat_hash_map_5,271536128 +random,memory,7357263,phmap::parallel_flat_hash_map_5,276004864 +random,memory,7365455,phmap::parallel_flat_hash_map_5,280465408 +random,memory,7367447,phmap::parallel_flat_hash_map_5,284930048 +random,memory,7371641,phmap::parallel_flat_hash_map_5,289386496 +random,memory,7378137,phmap::parallel_flat_hash_map_5,289386496 +random,memory,7378146,phmap::parallel_flat_hash_map_5,284917760 +random,memory,7389605,phmap::parallel_flat_hash_map_5,284917760 +random,memory,7389606,phmap::parallel_flat_hash_map_5,293851136 +random,memory,7544723,phmap::parallel_flat_hash_map_5,293851136 +random,memory,7544854,phmap::parallel_flat_hash_map_5,289382400 +random,time,10000000,phmap::parallel_flat_hash_map_5,0.706000 +random,memory,10026761,phmap::parallel_flat_hash_map_5,288780288 +random,memory,14626943,phmap::parallel_flat_hash_map_5,288780288 +random,memory,14626967,phmap::parallel_flat_hash_map_5,306647040 +random,memory,14639253,phmap::parallel_flat_hash_map_5,306647040 +random,memory,14639317,phmap::parallel_flat_hash_map_5,297713664 +random,memory,14649711,phmap::parallel_flat_hash_map_5,297713664 +random,memory,14649712,phmap::parallel_flat_hash_map_5,315576320 +random,memory,14652713,phmap::parallel_flat_hash_map_5,324509696 +random,memory,14654833,phmap::parallel_flat_hash_map_5,333443072 +random,memory,14662126,phmap::parallel_flat_hash_map_5,342380544 +random,memory,14663094,phmap::parallel_flat_hash_map_5,351309824 +random,memory,14666099,phmap::parallel_flat_hash_map_5,360239104 +random,memory,14670830,phmap::parallel_flat_hash_map_5,360239104 +random,memory,14670831,phmap::parallel_flat_hash_map_5,387043328 +random,memory,14672442,phmap::parallel_flat_hash_map_5,387043328 +random,memory,14672443,phmap::parallel_flat_hash_map_5,404893696 +random,memory,14672704,phmap::parallel_flat_hash_map_5,404893696 +random,memory,14672705,phmap::parallel_flat_hash_map_5,422756352 +random,memory,14676798,phmap::parallel_flat_hash_map_5,431681536 +random,memory,14677479,phmap::parallel_flat_hash_map_5,440610816 +random,memory,14677635,phmap::parallel_flat_hash_map_5,440610816 +random,memory,14677636,phmap::parallel_flat_hash_map_5,467410944 +random,memory,14677806,phmap::parallel_flat_hash_map_5,467410944 +random,memory,14677964,phmap::parallel_flat_hash_map_5,449540096 +random,memory,14679982,phmap::parallel_flat_hash_map_5,449540096 +random,memory,14679983,phmap::parallel_flat_hash_map_5,467406848 +random,memory,14681796,phmap::parallel_flat_hash_map_5,476340224 +random,memory,14683621,phmap::parallel_flat_hash_map_5,485265408 +random,memory,14685751,phmap::parallel_flat_hash_map_5,494202880 +random,memory,14686247,phmap::parallel_flat_hash_map_5,503128064 +random,memory,14689965,phmap::parallel_flat_hash_map_5,503128064 +random,memory,14689966,phmap::parallel_flat_hash_map_5,529915904 +random,memory,14701543,phmap::parallel_flat_hash_map_5,538849280 +random,memory,14702897,phmap::parallel_flat_hash_map_5,547774464 +random,memory,14706767,phmap::parallel_flat_hash_map_5,556707840 +random,memory,14718882,phmap::parallel_flat_hash_map_5,565637120 +random,memory,14723067,phmap::parallel_flat_hash_map_5,574562304 +random,memory,14725863,phmap::parallel_flat_hash_map_5,583491584 +random,memory,14830100,phmap::parallel_flat_hash_map_5,583491584 +random,memory,14830101,phmap::parallel_flat_hash_map_5,574558208 +random,time,20000000,phmap::parallel_flat_hash_map_5,1.394000 +random,memory,20032077,phmap::parallel_flat_hash_map_5,574541824 +random,memory,29275812,phmap::parallel_flat_hash_map_5,574541824 +random,memory,29275813,phmap::parallel_flat_hash_map_5,610267136 +random,memory,29289707,phmap::parallel_flat_hash_map_5,610267136 +random,memory,29289796,phmap::parallel_flat_hash_map_5,592404480 +random,memory,29315566,phmap::parallel_flat_hash_map_5,592404480 +random,memory,29315567,phmap::parallel_flat_hash_map_5,628129792 +random,memory,29323636,phmap::parallel_flat_hash_map_5,645992448 +random,memory,29330379,phmap::parallel_flat_hash_map_5,663855104 +random,memory,29331279,phmap::parallel_flat_hash_map_5,681713664 +random,memory,29336070,phmap::parallel_flat_hash_map_5,699576320 +random,memory,29339390,phmap::parallel_flat_hash_map_5,717447168 +random,memory,29341008,phmap::parallel_flat_hash_map_5,735305728 +random,memory,29341515,phmap::parallel_flat_hash_map_5,753164288 +random,memory,29344933,phmap::parallel_flat_hash_map_5,771031040 +random,memory,29349195,phmap::parallel_flat_hash_map_5,771031040 +random,memory,29349196,phmap::parallel_flat_hash_map_5,824614912 +random,memory,29352451,phmap::parallel_flat_hash_map_5,824614912 +random,memory,29352452,phmap::parallel_flat_hash_map_5,878198784 +random,memory,29355941,phmap::parallel_flat_hash_map_5,878198784 +random,memory,29355942,phmap::parallel_flat_hash_map_5,913915904 +random,memory,29356055,phmap::parallel_flat_hash_map_5,913915904 +random,memory,29356056,phmap::parallel_flat_hash_map_5,896053248 +random,memory,29359791,phmap::parallel_flat_hash_map_5,913915904 +random,memory,29363827,phmap::parallel_flat_hash_map_5,931774464 +random,memory,29366034,phmap::parallel_flat_hash_map_5,949637120 +random,memory,29367103,phmap::parallel_flat_hash_map_5,967495680 +random,memory,29368343,phmap::parallel_flat_hash_map_5,985354240 +random,memory,29375432,phmap::parallel_flat_hash_map_5,1003216896 +random,memory,29376205,phmap::parallel_flat_hash_map_5,1021071360 +random,memory,29378354,phmap::parallel_flat_hash_map_5,1038925824 +random,memory,29385594,phmap::parallel_flat_hash_map_5,1056784384 +random,memory,29388397,phmap::parallel_flat_hash_map_5,1074647040 +random,memory,29401214,phmap::parallel_flat_hash_map_5,1092509696 +random,memory,29403877,phmap::parallel_flat_hash_map_5,1110368256 +random,memory,29410744,phmap::parallel_flat_hash_map_5,1128235008 +random,memory,29417350,phmap::parallel_flat_hash_map_5,1146093568 +random,memory,29423045,phmap::parallel_flat_hash_map_5,1163956224 +random,memory,29554740,phmap::parallel_flat_hash_map_5,1163956224 +random,memory,29554741,phmap::parallel_flat_hash_map_5,1146097664 +random,time,30000000,phmap::parallel_flat_hash_map_5,2.388000 +random,memory,30058375,phmap::parallel_flat_hash_map_5,1146105856 +random,time,40000000,phmap::parallel_flat_hash_map_5,2.859000 +random,memory,40129005,phmap::parallel_flat_hash_map_5,1146118144 +random,time,50000000,phmap::parallel_flat_hash_map_5,3.398000 +random,memory,50130659,phmap::parallel_flat_hash_map_5,1146114048 +random,memory,58648505,phmap::parallel_flat_hash_map_5,1146114048 +random,memory,58648506,phmap::parallel_flat_hash_map_5,1217560576 +random,memory,58659099,phmap::parallel_flat_hash_map_5,1253285888 +random,memory,58664853,phmap::parallel_flat_hash_map_5,1289011200 +random,memory,58672884,phmap::parallel_flat_hash_map_5,1324728320 +random,memory,58677336,phmap::parallel_flat_hash_map_5,1360449536 +random,memory,58685517,phmap::parallel_flat_hash_map_5,1396174848 +random,memory,58694184,phmap::parallel_flat_hash_map_5,1431896064 +random,memory,58695854,phmap::parallel_flat_hash_map_5,1467617280 +random,memory,58697408,phmap::parallel_flat_hash_map_5,1503346688 +random,memory,58697642,phmap::parallel_flat_hash_map_5,1503346688 +random,memory,58697658,phmap::parallel_flat_hash_map_5,1467617280 +random,memory,58702073,phmap::parallel_flat_hash_map_5,1467617280 +random,memory,58702074,phmap::parallel_flat_hash_map_5,1539063808 +random,memory,58705027,phmap::parallel_flat_hash_map_5,1574785024 +random,memory,58706773,phmap::parallel_flat_hash_map_5,1610506240 +random,memory,58709256,phmap::parallel_flat_hash_map_5,1646227456 +random,memory,58713971,phmap::parallel_flat_hash_map_5,1681940480 +random,memory,58714578,phmap::parallel_flat_hash_map_5,1717657600 +random,memory,58714931,phmap::parallel_flat_hash_map_5,1753378816 +random,memory,58723299,phmap::parallel_flat_hash_map_5,1789095936 +random,memory,58724869,phmap::parallel_flat_hash_map_5,1824829440 +random,memory,58728103,phmap::parallel_flat_hash_map_5,1860554752 +random,memory,58728557,phmap::parallel_flat_hash_map_5,1896271872 +random,memory,58735188,phmap::parallel_flat_hash_map_5,1931988992 +random,memory,58736098,phmap::parallel_flat_hash_map_5,1967710208 +random,memory,58737751,phmap::parallel_flat_hash_map_5,2003435520 +random,memory,58738589,phmap::parallel_flat_hash_map_5,2039152640 +random,memory,58739865,phmap::parallel_flat_hash_map_5,2074877952 +random,memory,58742832,phmap::parallel_flat_hash_map_5,2110599168 +random,memory,58754529,phmap::parallel_flat_hash_map_5,2146316288 +random,memory,58762104,phmap::parallel_flat_hash_map_5,2182037504 +random,memory,58767879,phmap::parallel_flat_hash_map_5,2217758720 +random,memory,58778531,phmap::parallel_flat_hash_map_5,2253479936 +random,memory,58793956,phmap::parallel_flat_hash_map_5,2289197056 +random,memory,58800861,phmap::parallel_flat_hash_map_5,2324922368 +random,memory,58894435,phmap::parallel_flat_hash_map_5,2324922368 +random,memory,58894436,phmap::parallel_flat_hash_map_5,2289197056 +random,time,60000000,phmap::parallel_flat_hash_map_5,4.975000 +random,memory,60010883,phmap::parallel_flat_hash_map_5,2289197056 +random,time,70000000,phmap::parallel_flat_hash_map_5,5.534000 +random,memory,70176985,phmap::parallel_flat_hash_map_5,2289192960 +random,time,80000000,phmap::parallel_flat_hash_map_5,6.041000 +random,memory,80051145,phmap::parallel_flat_hash_map_5,2289180672 +random,time,90000000,phmap::parallel_flat_hash_map_5,6.613000 +random,memory,90041943,phmap::parallel_flat_hash_map_5,2289188864 +random,time,100000000,phmap::parallel_flat_hash_map_5,7.142000 +random,memory,0,phmap::parallel_flat_hash_map_6,9543680 +random,memory,240118,phmap::parallel_flat_hash_map_6,9543680 +random,memory,240274,phmap::parallel_flat_hash_map_6,13426688 +random,memory,447602,phmap::parallel_flat_hash_map_6,13713408 +random,memory,456883,phmap::parallel_flat_hash_map_6,13713408 +random,memory,456884,phmap::parallel_flat_hash_map_6,17674240 +random,memory,462632,phmap::parallel_flat_hash_map_6,17674240 +random,memory,462653,phmap::parallel_flat_hash_map_6,23060480 +random,memory,564425,phmap::parallel_flat_hash_map_6,23060480 +random,memory,564455,phmap::parallel_flat_hash_map_6,23908352 +random,memory,910490,phmap::parallel_flat_hash_map_6,23920640 +random,memory,910491,phmap::parallel_flat_hash_map_6,27856896 +random,memory,914643,phmap::parallel_flat_hash_map_6,27856896 +random,memory,914659,phmap::parallel_flat_hash_map_6,32354304 +random,memory,918680,phmap::parallel_flat_hash_map_6,32354304 +random,memory,918789,phmap::parallel_flat_hash_map_6,37982208 +random,memory,923341,phmap::parallel_flat_hash_map_6,37982208 +random,memory,923342,phmap::parallel_flat_hash_map_6,43044864 +random,memory,967301,phmap::parallel_flat_hash_map_6,43479040 +random,memory,1818677,phmap::parallel_flat_hash_map_6,43479040 +random,memory,1818678,phmap::parallel_flat_hash_map_6,46841856 +random,memory,1820853,phmap::parallel_flat_hash_map_6,46841856 +random,memory,1820854,phmap::parallel_flat_hash_map_6,42500096 +random,memory,1822952,phmap::parallel_flat_hash_map_6,42500096 +random,memory,1822953,phmap::parallel_flat_hash_map_6,45305856 +random,memory,1826229,phmap::parallel_flat_hash_map_6,45305856 +random,memory,1826230,phmap::parallel_flat_hash_map_6,48701440 +random,memory,1828846,phmap::parallel_flat_hash_map_6,48701440 +random,memory,1828847,phmap::parallel_flat_hash_map_6,52629504 +random,memory,1830697,phmap::parallel_flat_hash_map_6,53891072 +random,memory,1834838,phmap::parallel_flat_hash_map_6,53891072 +random,memory,1834839,phmap::parallel_flat_hash_map_6,57712640 +random,memory,1835801,phmap::parallel_flat_hash_map_6,57712640 +random,memory,1835802,phmap::parallel_flat_hash_map_6,60547072 +random,memory,1837939,phmap::parallel_flat_hash_map_6,61685760 +random,memory,1839861,phmap::parallel_flat_hash_map_6,61685760 +random,memory,1839862,phmap::parallel_flat_hash_map_6,65630208 +random,memory,1843172,phmap::parallel_flat_hash_map_6,65630208 +random,memory,1843173,phmap::parallel_flat_hash_map_6,67899392 +random,memory,1846075,phmap::parallel_flat_hash_map_6,67899392 +random,memory,1846076,phmap::parallel_flat_hash_map_6,71970816 +random,memory,1850890,phmap::parallel_flat_hash_map_6,73510912 +random,memory,1864735,phmap::parallel_flat_hash_map_6,73510912 +random,memory,1864741,phmap::parallel_flat_hash_map_6,75743232 +random,memory,3640764,phmap::parallel_flat_hash_map_6,77979648 +random,memory,3643691,phmap::parallel_flat_hash_map_6,77979648 +random,memory,3643692,phmap::parallel_flat_hash_map_6,82452480 +random,memory,3647471,phmap::parallel_flat_hash_map_6,84680704 +random,memory,3647865,phmap::parallel_flat_hash_map_6,84680704 +random,memory,3647866,phmap::parallel_flat_hash_map_6,88031232 +random,memory,3657171,phmap::parallel_flat_hash_map_6,90267648 +random,memory,3659273,phmap::parallel_flat_hash_map_6,90267648 +random,memory,3659274,phmap::parallel_flat_hash_map_6,94740480 +random,memory,3661956,phmap::parallel_flat_hash_map_6,94736384 +random,memory,3661971,phmap::parallel_flat_hash_map_6,98091008 +random,memory,3662467,phmap::parallel_flat_hash_map_6,98091008 +random,memory,3662468,phmap::parallel_flat_hash_map_6,101441536 +random,memory,3663439,phmap::parallel_flat_hash_map_6,102551552 +random,memory,3664226,phmap::parallel_flat_hash_map_6,103669760 +random,memory,3667885,phmap::parallel_flat_hash_map_6,103669760 +random,memory,3667897,phmap::parallel_flat_hash_map_6,109264896 +random,memory,3669813,phmap::parallel_flat_hash_map_6,109264896 +random,memory,3669814,phmap::parallel_flat_hash_map_6,113737728 +random,memory,3675800,phmap::parallel_flat_hash_map_6,114843648 +random,memory,3675801,phmap::parallel_flat_hash_map_6,119308288 +random,memory,3676890,phmap::parallel_flat_hash_map_6,121536512 +random,memory,3679398,phmap::parallel_flat_hash_map_6,124882944 +random,memory,3681013,phmap::parallel_flat_hash_map_6,129355776 +random,memory,3682289,phmap::parallel_flat_hash_map_6,129355776 +random,memory,3682290,phmap::parallel_flat_hash_map_6,133828608 +random,memory,3684318,phmap::parallel_flat_hash_map_6,137175040 +random,memory,3687517,phmap::parallel_flat_hash_map_6,138289152 +random,memory,3687518,phmap::parallel_flat_hash_map_6,142753792 +random,memory,3690464,phmap::parallel_flat_hash_map_6,144990208 +random,memory,3699225,phmap::parallel_flat_hash_map_6,147214336 +random,memory,7301764,phmap::parallel_flat_hash_map_6,147214336 +random,memory,7301801,phmap::parallel_flat_hash_map_6,151683072 +random,memory,7304266,phmap::parallel_flat_hash_map_6,151683072 +random,memory,7304267,phmap::parallel_flat_hash_map_6,158388224 +random,memory,7306423,phmap::parallel_flat_hash_map_6,158388224 +random,memory,7306424,phmap::parallel_flat_hash_map_6,167325696 +random,memory,7307845,phmap::parallel_flat_hash_map_6,167325696 +random,memory,7307846,phmap::parallel_flat_hash_map_6,165093376 +random,memory,7313817,phmap::parallel_flat_hash_map_6,167325696 +random,memory,7317898,phmap::parallel_flat_hash_map_6,167325696 +random,memory,7317899,phmap::parallel_flat_hash_map_6,174026752 +random,memory,7321356,phmap::parallel_flat_hash_map_6,178499584 +random,memory,7324610,phmap::parallel_flat_hash_map_6,178503680 +random,memory,7324611,phmap::parallel_flat_hash_map_6,185208832 +random,memory,7324981,phmap::parallel_flat_hash_map_6,189681664 +random,memory,7329399,phmap::parallel_flat_hash_map_6,191909888 +random,memory,7330096,phmap::parallel_flat_hash_map_6,194138112 +random,memory,7330493,phmap::parallel_flat_hash_map_6,194138112 +random,memory,7330494,phmap::parallel_flat_hash_map_6,200835072 +random,memory,7330662,phmap::parallel_flat_hash_map_6,203063296 +random,memory,7331146,phmap::parallel_flat_hash_map_6,203063296 +random,memory,7331147,phmap::parallel_flat_hash_map_6,200830976 +random,memory,7333567,phmap::parallel_flat_hash_map_6,200830976 +random,memory,7333568,phmap::parallel_flat_hash_map_6,207536128 +random,memory,7334082,phmap::parallel_flat_hash_map_6,212000768 +random,memory,7339042,phmap::parallel_flat_hash_map_6,214237184 +random,memory,7339605,phmap::parallel_flat_hash_map_6,216465408 +random,memory,7340722,phmap::parallel_flat_hash_map_6,218705920 +random,memory,7341125,phmap::parallel_flat_hash_map_6,220938240 +random,memory,7342276,phmap::parallel_flat_hash_map_6,223170560 +random,memory,7342941,phmap::parallel_flat_hash_map_6,223170560 +random,memory,7342942,phmap::parallel_flat_hash_map_6,229871616 +random,memory,7346101,phmap::parallel_flat_hash_map_6,238796800 +random,memory,7350910,phmap::parallel_flat_hash_map_6,252190720 +random,memory,7351597,phmap::parallel_flat_hash_map_6,256651264 +random,memory,7353724,phmap::parallel_flat_hash_map_6,263344128 +random,memory,7356932,phmap::parallel_flat_hash_map_6,267808768 +random,memory,7365358,phmap::parallel_flat_hash_map_6,278974464 +random,memory,7367048,phmap::parallel_flat_hash_map_6,285671424 +random,memory,7381268,phmap::parallel_flat_hash_map_6,292360192 +random,time,10000000,phmap::parallel_flat_hash_map_6,0.625000 +random,memory,10048265,phmap::parallel_flat_hash_map_6,290181120 +random,memory,14624411,phmap::parallel_flat_hash_map_6,290181120 +random,memory,14624412,phmap::parallel_flat_hash_map_6,299114496 +random,memory,14629443,phmap::parallel_flat_hash_map_6,303583232 +random,memory,14631641,phmap::parallel_flat_hash_map_6,308051968 +random,memory,14634044,phmap::parallel_flat_hash_map_6,312520704 +random,memory,14636495,phmap::parallel_flat_hash_map_6,312520704 +random,memory,14636496,phmap::parallel_flat_hash_map_6,325926912 +random,memory,14643433,phmap::parallel_flat_hash_map_6,325914624 +random,memory,14643434,phmap::parallel_flat_hash_map_6,339308544 +random,memory,14646091,phmap::parallel_flat_hash_map_6,348241920 +random,memory,14653553,phmap::parallel_flat_hash_map_6,352714752 +random,memory,14654529,phmap::parallel_flat_hash_map_6,357175296 +random,memory,14655407,phmap::parallel_flat_hash_map_6,361639936 +random,memory,14658190,phmap::parallel_flat_hash_map_6,366100480 +random,memory,14658689,phmap::parallel_flat_hash_map_6,366100480 +random,memory,14658907,phmap::parallel_flat_hash_map_6,361635840 +random,memory,14658907,phmap::parallel_flat_hash_map_6,370573312 +random,memory,14659991,phmap::parallel_flat_hash_map_6,375033856 +random,memory,14665883,phmap::parallel_flat_hash_map_6,379498496 +random,memory,14667814,phmap::parallel_flat_hash_map_6,383963136 +random,memory,14669160,phmap::parallel_flat_hash_map_6,388435968 +random,memory,14671676,phmap::parallel_flat_hash_map_6,392896512 +random,memory,14673074,phmap::parallel_flat_hash_map_6,397361152 +random,memory,14675455,phmap::parallel_flat_hash_map_6,401829888 +random,memory,14676709,phmap::parallel_flat_hash_map_6,406294528 +random,memory,14678913,phmap::parallel_flat_hash_map_6,410755072 +random,memory,14680761,phmap::parallel_flat_hash_map_6,415219712 +random,memory,14682022,phmap::parallel_flat_hash_map_6,415219712 +random,memory,14682023,phmap::parallel_flat_hash_map_6,428617728 +random,memory,14682463,phmap::parallel_flat_hash_map_6,437538816 +random,memory,14685126,phmap::parallel_flat_hash_map_6,437534720 +random,memory,14685127,phmap::parallel_flat_hash_map_6,450936832 +random,memory,14686842,phmap::parallel_flat_hash_map_6,455397376 +random,memory,14690779,phmap::parallel_flat_hash_map_6,473251840 +random,memory,14692933,phmap::parallel_flat_hash_map_6,491126784 +random,memory,14696606,phmap::parallel_flat_hash_map_6,508981248 +random,memory,14700141,phmap::parallel_flat_hash_map_6,526839808 +random,memory,14711382,phmap::parallel_flat_hash_map_6,544669696 +random,memory,14716503,phmap::parallel_flat_hash_map_6,562524160 +random,memory,14754604,phmap::parallel_flat_hash_map_6,580382720 +random,time,20000000,phmap::parallel_flat_hash_map_6,1.270000 +random,memory,20169331,phmap::parallel_flat_hash_map_6,575909888 +random,memory,29250365,phmap::parallel_flat_hash_map_6,575909888 +random,memory,29250366,phmap::parallel_flat_hash_map_6,593772544 +random,memory,29252297,phmap::parallel_flat_hash_map_6,593772544 +random,memory,29252377,phmap::parallel_flat_hash_map_6,584843264 +random,memory,29295606,phmap::parallel_flat_hash_map_6,584843264 +random,memory,29295607,phmap::parallel_flat_hash_map_6,620572672 +random,memory,29295923,phmap::parallel_flat_hash_map_6,620572672 +random,memory,29295924,phmap::parallel_flat_hash_map_6,611643392 +random,memory,29298230,phmap::parallel_flat_hash_map_6,611643392 +random,memory,29298231,phmap::parallel_flat_hash_map_6,638443520 +random,memory,29301877,phmap::parallel_flat_hash_map_6,647368704 +random,memory,29307581,phmap::parallel_flat_hash_map_6,656306176 +random,memory,29311094,phmap::parallel_flat_hash_map_6,656306176 +random,memory,29311198,phmap::parallel_flat_hash_map_6,647376896 +random,memory,29318505,phmap::parallel_flat_hash_map_6,647376896 +random,memory,29318506,phmap::parallel_flat_hash_map_6,683106304 +random,memory,29324837,phmap::parallel_flat_hash_map_6,692023296 +random,memory,29328401,phmap::parallel_flat_hash_map_6,700956672 +random,memory,29328874,phmap::parallel_flat_hash_map_6,709894144 +random,memory,29330147,phmap::parallel_flat_hash_map_6,709894144 +random,memory,29330451,phmap::parallel_flat_hash_map_6,700964864 +random,memory,29330597,phmap::parallel_flat_hash_map_6,718827520 +random,memory,29333160,phmap::parallel_flat_hash_map_6,727752704 +random,memory,29336160,phmap::parallel_flat_hash_map_6,727752704 +random,memory,29336161,phmap::parallel_flat_hash_map_6,754544640 +random,memory,29344925,phmap::parallel_flat_hash_map_6,763461632 +random,memory,29345974,phmap::parallel_flat_hash_map_6,772395008 +random,memory,29346343,phmap::parallel_flat_hash_map_6,781320192 +random,memory,29348045,phmap::parallel_flat_hash_map_6,790245376 +random,memory,29352980,phmap::parallel_flat_hash_map_6,790245376 +random,memory,29352981,phmap::parallel_flat_hash_map_6,817045504 +random,memory,29357735,phmap::parallel_flat_hash_map_6,825970688 +random,memory,29359312,phmap::parallel_flat_hash_map_6,834904064 +random,memory,29360390,phmap::parallel_flat_hash_map_6,843833344 +random,memory,29361898,phmap::parallel_flat_hash_map_6,852766720 +random,memory,29363938,phmap::parallel_flat_hash_map_6,852766720 +random,memory,29363939,phmap::parallel_flat_hash_map_6,879566848 +random,memory,29366353,phmap::parallel_flat_hash_map_6,888500224 +random,memory,29366942,phmap::parallel_flat_hash_map_6,888500224 +random,memory,29366943,phmap::parallel_flat_hash_map_6,915296256 +random,memory,29370042,phmap::parallel_flat_hash_map_6,951009280 +random,memory,29373396,phmap::parallel_flat_hash_map_6,977809408 +random,memory,29378157,phmap::parallel_flat_hash_map_6,986734592 +random,memory,29378158,phmap::parallel_flat_hash_map_6,1022464000 +random,memory,29382962,phmap::parallel_flat_hash_map_6,1022464000 +random,memory,29382991,phmap::parallel_flat_hash_map_6,1004597248 +random,memory,29383516,phmap::parallel_flat_hash_map_6,1022435328 +random,memory,29395727,phmap::parallel_flat_hash_map_6,1067077632 +random,memory,29400644,phmap::parallel_flat_hash_map_6,1076006912 +random,memory,29411954,phmap::parallel_flat_hash_map_6,1111728128 +random,memory,29443826,phmap::parallel_flat_hash_map_6,1138507776 +random,time,30000000,phmap::parallel_flat_hash_map_6,2.204000 +random,memory,30001149,phmap::parallel_flat_hash_map_6,1147379712 +random,time,40000000,phmap::parallel_flat_hash_map_6,2.689000 +random,memory,40030313,phmap::parallel_flat_hash_map_6,1147482112 +random,time,50000000,phmap::parallel_flat_hash_map_6,3.140000 +random,memory,50107035,phmap::parallel_flat_hash_map_6,1147482112 +random,memory,58567867,phmap::parallel_flat_hash_map_6,1147482112 +random,memory,58567868,phmap::parallel_flat_hash_map_6,1183207424 +random,memory,58618664,phmap::parallel_flat_hash_map_6,1183207424 +random,memory,58618684,phmap::parallel_flat_hash_map_6,1165344768 +random,memory,58633951,phmap::parallel_flat_hash_map_6,1165344768 +random,memory,58633952,phmap::parallel_flat_hash_map_6,1201070080 +random,memory,58638135,phmap::parallel_flat_hash_map_6,1218936832 +random,memory,58641806,phmap::parallel_flat_hash_map_6,1218936832 +random,memory,58641908,phmap::parallel_flat_hash_map_6,1201074176 +random,memory,58644567,phmap::parallel_flat_hash_map_6,1236799488 +random,memory,58654398,phmap::parallel_flat_hash_map_6,1254662144 +random,memory,58661628,phmap::parallel_flat_hash_map_6,1272520704 +random,memory,58663366,phmap::parallel_flat_hash_map_6,1290387456 +random,memory,58664512,phmap::parallel_flat_hash_map_6,1308254208 +random,memory,58666679,phmap::parallel_flat_hash_map_6,1308254208 +random,memory,58666680,phmap::parallel_flat_hash_map_6,1361838080 +random,memory,58673711,phmap::parallel_flat_hash_map_6,1379696640 +random,memory,58680789,phmap::parallel_flat_hash_map_6,1397563392 +random,memory,58684297,phmap::parallel_flat_hash_map_6,1415430144 +random,memory,58688420,phmap::parallel_flat_hash_map_6,1433292800 +random,memory,58688990,phmap::parallel_flat_hash_map_6,1451155456 +random,memory,58690080,phmap::parallel_flat_hash_map_6,1469009920 +random,memory,58692416,phmap::parallel_flat_hash_map_6,1469009920 +random,memory,58692417,phmap::parallel_flat_hash_map_6,1522601984 +random,memory,58696961,phmap::parallel_flat_hash_map_6,1522597888 +random,memory,58696962,phmap::parallel_flat_hash_map_6,1576189952 +random,memory,58701807,phmap::parallel_flat_hash_map_6,1611915264 +random,memory,58702134,phmap::parallel_flat_hash_map_6,1611915264 +random,memory,58702166,phmap::parallel_flat_hash_map_6,1594044416 +random,memory,58702606,phmap::parallel_flat_hash_map_6,1611902976 +random,memory,58705250,phmap::parallel_flat_hash_map_6,1629765632 +random,memory,58706394,phmap::parallel_flat_hash_map_6,1647628288 +random,memory,58709861,phmap::parallel_flat_hash_map_6,1665486848 +random,memory,58710992,phmap::parallel_flat_hash_map_6,1683341312 +random,memory,58718600,phmap::parallel_flat_hash_map_6,1683341312 +random,memory,58718601,phmap::parallel_flat_hash_map_6,1736929280 +random,memory,58718836,phmap::parallel_flat_hash_map_6,1736929280 +random,memory,58718837,phmap::parallel_flat_hash_map_6,1719058432 +random,memory,58719131,phmap::parallel_flat_hash_map_6,1736916992 +random,memory,58721235,phmap::parallel_flat_hash_map_6,1754771456 +random,memory,58722232,phmap::parallel_flat_hash_map_6,1772634112 +random,memory,58723234,phmap::parallel_flat_hash_map_6,1790488576 +random,memory,58726963,phmap::parallel_flat_hash_map_6,1861939200 +random,memory,58740972,phmap::parallel_flat_hash_map_6,1933361152 +random,memory,58745109,phmap::parallel_flat_hash_map_6,2022670336 +random,memory,58754148,phmap::parallel_flat_hash_map_6,2058383360 +random,memory,58765822,phmap::parallel_flat_hash_map_6,2147696640 +random,memory,58786363,phmap::parallel_flat_hash_map_6,2201272320 +random,memory,58826606,phmap::parallel_flat_hash_map_6,2272714752 +random,time,60000000,phmap::parallel_flat_hash_map_6,4.560000 +random,memory,60000411,phmap::parallel_flat_hash_map_6,2290417664 +random,time,70000000,phmap::parallel_flat_hash_map_6,5.082000 +random,memory,70138168,phmap::parallel_flat_hash_map_6,2290565120 +random,time,80000000,phmap::parallel_flat_hash_map_6,5.576000 +random,memory,80036567,phmap::parallel_flat_hash_map_6,2290556928 +random,time,90000000,phmap::parallel_flat_hash_map_6,6.062000 +random,memory,90013913,phmap::parallel_flat_hash_map_6,2290528256 +random,time,100000000,phmap::parallel_flat_hash_map_6,6.613000 diff --git a/extern/phmap/cmake/CMakeLists.txt.in b/extern/phmap/cmake/CMakeLists.txt.in new file mode 100644 index 0000000..3e01ff5 --- /dev/null +++ b/extern/phmap/cmake/CMakeLists.txt.in @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.8) + +project(googletest-download NONE) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG main + SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) \ No newline at end of file diff --git a/extern/phmap/cmake/DetectVersion.cmake b/extern/phmap/cmake/DetectVersion.cmake new file mode 100644 index 0000000..4bffa5e --- /dev/null +++ b/extern/phmap/cmake/DetectVersion.cmake @@ -0,0 +1,8 @@ + +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/parallel_hashmap/phmap_config.h" _PHMAP_H_CONTENTS) +string(REGEX REPLACE ".*#define PHMAP_VERSION_MAJOR ([0-9]+).*" "\\1" DETECTED_PHMAP_VERSION_MAJOR "${_PHMAP_H_CONTENTS}") +string(REGEX REPLACE ".*#define PHMAP_VERSION_MINOR ([0-9]+).*" "\\1" DETECTED_PHMAP_VERSION_MINOR "${_PHMAP_H_CONTENTS}") +string(REGEX REPLACE ".*#define PHMAP_VERSION_PATCH ([0-9]+).*" "\\1" DETECTED_PHMAP_VERSION_PATCH "${_PHMAP_H_CONTENTS}") +set(DETECTED_PHMAP_VERSION "${DETECTED_PHMAP_VERSION_MAJOR}.${DETECTED_PHMAP_VERSION_MINOR}.${DETECTED_PHMAP_VERSION_PATCH}") + +message(STATUS "Detected PHMAP Version - ${DETECTED_PHMAP_VERSION}") diff --git a/extern/phmap/cmake/DownloadGTest.cmake b/extern/phmap/cmake/DownloadGTest.cmake new file mode 100644 index 0000000..055270f --- /dev/null +++ b/extern/phmap/cmake/DownloadGTest.cmake @@ -0,0 +1,34 @@ +# Downloads and unpacks googletest at configure time. Based on the instructions +# at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project + +# Download the latest googletest from Github master +configure_file( + ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in + ${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt +) + +# Configure and build the downloaded googletest source +execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) + +if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") +endif() + +execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) + +if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") +endif() + +# Prevent overriding the parent project's compiler/linker settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Add googletest directly to our build. This defines the gtest and gtest_main +# targets. +add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src + ${CMAKE_BINARY_DIR}/googletest-build + EXCLUDE_FROM_ALL) diff --git a/extern/phmap/cmake/helpers.cmake b/extern/phmap/cmake/helpers.cmake new file mode 100644 index 0000000..b290066 --- /dev/null +++ b/extern/phmap/cmake/helpers.cmake @@ -0,0 +1,60 @@ +#set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set(PHMAP_IDE_FOLDER phmap) + +# ------------------------------------------------------------- +# phmap_cc_test(NAME awesome_test +# SRCS "awesome_test.cc" +# DEPS phmap::awesome gmock gtest_main) +# ------------------------------------------------------------- +function(phmap_cc_test) + cmake_parse_arguments(PHMAP_CC_TEST + "" + "NAME" + "SRCS;COPTS;CWOPTS;CLOPTS;DEFINES;LINKOPTS;DEPS" + ${ARGN} + ) + + set(_NAME "test_${PHMAP_CC_TEST_NAME}") + add_executable(${_NAME} "") + target_sources(${_NAME} PRIVATE ${PHMAP_CC_TEST_SRCS}) + target_include_directories(${_NAME} + PUBLIC ${PHMAP_COMMON_INCLUDE_DIRS} + PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} + ) + target_compile_definitions(${_NAME} + PUBLIC ${PHMAP_CC_TEST_DEFINES} + ) +if(MSVC) + target_compile_options(${_NAME} + PRIVATE ${PHMAP_CC_TEST_CWOPTS} /W4 /Zc:__cplusplus /std:c++latest + ) +else() + target_compile_options(${_NAME} + PRIVATE ${PHMAP_CC_TEST_CLOPTS} + ) +endif() + target_compile_options(${_NAME} + PRIVATE ${PHMAP_CC_TEST_COPTS} + ) + target_link_libraries(${_NAME} + PUBLIC ${PHMAP_CC_TEST_DEPS} + PRIVATE ${PHMAP_CC_TEST_LINKOPTS} + ) + # Add all Abseil targets to a a folder in the IDE for organization. + set_property(TARGET ${_NAME} PROPERTY FOLDER ${PHMAP_IDE_FOLDER}/test) + + set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${PHMAP_CXX_STANDARD}) + set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) + + add_test(NAME ${_NAME} COMMAND ${_NAME}) +endfunction() + +# ------------------------------------------------------------- +function(check_target my_target) + if(NOT TARGET ${my_target}) + message(FATAL_ERROR " PHMAP: compiling phmap tests requires a ${my_target} CMake target in your project, + see CMake/README.md for more details") + endif(NOT TARGET ${my_target}) +endfunction() + + diff --git a/extern/phmap/cmake/phmap.cmake b/extern/phmap/cmake/phmap.cmake new file mode 100644 index 0000000..931bef1 --- /dev/null +++ b/extern/phmap/cmake/phmap.cmake @@ -0,0 +1,42 @@ +# --------------------------------------------------------------------------- +# Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp) +# with modifications. +# +# Copyright 2017 The Abseil Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# --------------------------------------------------------------------------- + + +include(CMakeParseArguments) + +function(check_target my_target) + if(NOT TARGET ${my_target}) + message(FATAL_ERROR " ABSL: compiling absl requires a ${my_target} CMake target in your project, + see CMake/README.md for more details") + endif(NOT TARGET ${my_target}) +endfunction() diff --git a/extern/phmap/css/bootstrap-responsive.min.css b/extern/phmap/css/bootstrap-responsive.min.css new file mode 100644 index 0000000..ab59da3 --- /dev/null +++ b/extern/phmap/css/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.1.0 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:auto;margin-left:0}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade.in{top:auto}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#555;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/extern/phmap/css/bootstrap.min.css b/extern/phmap/css/bootstrap.min.css new file mode 100644 index 0000000..4a4440c --- /dev/null +++ b/extern/phmap/css/bootstrap.min.css @@ -0,0 +1,10 @@ +/*! + * Bootstrap v2.1.0 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + * Augmented by Eric Kryski @ekryski + */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map-canvas img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:20px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:1;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1{font-size:36px;line-height:40px}h2{font-size:30px;line-height:40px}h3{font-size:24px;line-height:40px}h4{font-size:18px;line-height:20px}h5{font-size:14px;line-height:20px}h6{font-size:12px;line-height:20px}h1 small{font-size:24px}h2 small{font-size:18px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal dt{float:left;width:120px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:130px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:9px;font-size:14px;line-height:20px;color:#555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}input,textarea{width:210px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal;cursor:pointer}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #bbb}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:18px;padding-left:18px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"]{float:left}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning .checkbox:focus,.control-group.warning .radio:focus,.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error .checkbox:focus,.control-group.error .radio:focus,.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success .checkbox:focus,.control-group.success .radio:focus,.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;font-size:14px;vertical-align:top;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn{margin-left:-1px;vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:160px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:160px}.form-horizontal .help-block{margin-top:10px;margin-bottom:0}.form-horizontal .form-actions{padding-left:160px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child,.table-bordered tfoot:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child,.table-bordered tfoot:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-right-topleft:4px}.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9}.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5}table [class*=span],.row-fluid table [class*=span]{display:table-cell;float:none;margin-left:0}table .span1{float:none;width:44px;margin-left:0}table .span2{float:none;width:124px;margin-left:0}table .span3{float:none;width:204px;margin-left:0}table .span4{float:none;width:284px;margin-left:0}table .span5{float:none;width:364px;margin-left:0}table .span6{float:none;width:444px;margin-left:0}table .span7{float:none;width:524px;margin-left:0}table .span8{float:none;width:604px;margin-left:0}table .span9{float:none;width:684px;margin-left:0}table .span10{float:none;width:764px;margin-left:0}table .span11{float:none;width:844px;margin-left:0}table .span12{float:none;width:924px;margin-left:0}table .span13{float:none;width:1004px;margin-left:0}table .span14{float:none;width:1084px;margin-left:0}table .span15{float:none;width:1164px;margin-left:0}table .span16{float:none;width:1244px;margin-left:0}table .span17{float:none;width:1324px;margin-left:0}table .span18{float:none;width:1404px;margin-left:0}table .span19{float:none;width:1484px;margin-left:0}table .span20{float:none;width:1564px;margin-left:0}table .span21{float:none;width:1644px;margin-left:0}table .span22{float:none;width:1724px;margin-left:0}table .span23{float:none;width:1804px;margin-left:0}table .span24{float:none;width:1884px;margin-left:0}.table tbody tr.success td{background-color:#dff0d8}.table tbody tr.error td{background-color:#f2dede}.table tbody tr.info td{background-color:#d9edf7}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:32px;height:32px;margin-top:1px;margin-right:.3em;line-height:32px;vertical-align:text-top;background-image:url("../img/glyphicons.png");background-position:32px 32px;background-repeat:no-repeat}.icon-white,.nav>.active>a>[class^="icon-"],.nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"]{background-image:url("../img/glyphicons-white.png")}.icon-glass{background-position:0 0}.icon-leaf{background-position:-56px 0}.icon-dog{background-position:-112px 0}.icon-user{background-position:-170px 0}.icon-girl{background-position:-225px 0}.icon-car{background-position:-279px 0}.icon-user-add{background-position:-337px 0}.icon-user-remove{background-position:-397px 0}.icon-film{background-position:-455px 0}.icon-magic{background-position:-509px 0}.icon-envelope{background-position:-565px 0}.icon-camera{background-position:-621px 0}.icon-heart{background-position:-679px 0}.icon-beach-umbrella{background-position:-735px 0}.icon-train{background-position:-792px 0}.icon-print{background-position:-844px 0}.icon-bin{background-position:-900px 0}.icon-music{background-position:-952px 0}.icon-note{background-position:-1005px 0}.icon-cogwheel{background-position:-1055px 0}.icon-home{background-position:-1111px 0}.icon-snowflake{background-position:-1170px 0}.icon-fire{background-position:-1230px 0}.icon-cogwheels{background-position:-1282px 0}.icon-parents{background-position:-1340px 0}.icon-binoculars{background-position:-1404px 0}.icon-road{background-position:-1460px 0}.icon-search{background-position:-1520px 0}.icon-cars{background-position:-1576px 0}.icon-notes-2{background-position:-1644px 0}.icon-pencil{background-position:-1696px 0}.icon-bus{background-position:-1753px 0}.icon-wifi-alt{background-position:-1817px 0}.icon-luggage{background-position:-1875px 0}.icon-old-man{background-position:-1927px 0}.icon-woman{background-position:0 -60px}.icon-file{background-position:-54px -60px}.icon-credit{background-position:-105px -60px}.icon-airplane{background-position:-163px -60px}.icon-notes{background-position:-219px -60px}.icon-stats{background-position:-271px -60px}.icon-charts{background-position:-329px -60px}.icon-pie-chart{background-position:-388px -60px}.icon-group{background-position:-446px -60px}.icon-keys{background-position:-513px -60px}.icon-calendar{background-position:-569px -60px}.icon-router{background-position:-624px -60px}.icon-camera-small{background-position:-683px -60px}.icon-dislikes{background-position:-737px -60px}.icon-star{background-position:-795px -60px}.icon-link{background-position:-852px -60px}.icon-eye-open{background-position:-905px -60px}.icon-eye-close{background-position:-968px -60px}.icon-alarm{background-position:-1031px -60px}.icon-clock{background-position:-1091px -60px}.icon-stopwatch{background-position:-1147px -60px}.icon-projector{background-position:-1202px -60px}.icon-history{background-position:-1262px -60px}.icon-truck{background-position:-1319px -60px}.icon-cargo{background-position:-1383px -60px}.icon-compass{background-position:-1440px -60px}.icon-keynote{background-position:-1496px -60px}.icon-attach{background-position:-1548px -60px}.icon-power{background-position:-1606px -60px}.icon-lightbulb{background-position:-1660px -60px}.icon-tag{background-position:-1712px -60px}.icon-tags{background-position:-1768px -60px}.icon-cleaning{background-position:-1830px -60px}.icon-ruler{background-position:-1886px -60px}.icon-gift{background-position:-1945px -60px}.icon-umbrella{background-position:0 -122px}.icon-book{background-position:-58px -122px}.icon-bookmark{background-position:-112px -122px}.icon-signal{background-position:-160px -122px}.icon-cup{background-position:-223px -122px}.icon-stroller{background-position:-277px -122px}.icon-headphones{background-position:-334px -122px}.icon-headset{background-position:-390px -122px}.icon-warning-sign{background-position:-446px -122px}.icon-signal{background-position:-507px -122px}.icon-retweet{background-position:-563px -122px}.icon-refresh{background-position:-625px -122px}.icon-roundabout{background-position:-682px -122px}.icon-random{background-position:-741px -122px}.icon-heat{background-position:-801px -122px}.icon-repeat{background-position:-862px -122px}.icon-display{background-position:-918px -122px}.icon-log-book{background-position:-978px -122px}.icon-adress-book{background-position:-1032px -122px}.icon-magnet{background-position:-1086px -122px}.icon-table{background-position:-1139px -122px}.icon-adjust{background-position:-1195px -122px}.icon-tint{background-position:-1253px -122px}.icon-crop{background-position:-1308px -122px}.icon-vector-path-square{background-position:-1366px -122px}.icon-vector-path-circle{background-position:-1422px -122px}.icon-vector-path-polygon{background-position:-1478px -122px}.icon-vector-path-line{background-position:-1536px -122px}.icon-vector-path-curve{background-position:-1592px -122px}.icon-vector-path-all{background-position:-1648px -122px}.icon-font{background-position:-1704px -122px}.icon-italic{background-position:-1763px -122px}.icon-bold{background-position:-1809px -122px}.icon-text-underline{background-position:-1860px -122px}.icon-text-strike{background-position:-1912px -122px}.icon-text-height{background-position:-1964px -122px}.icon-text-width{background-position:0 -184px}.icon-text-resize{background-position:-54px -184px}.icon-left-indent{background-position:-112px -184px}.icon-right-indent{background-position:-168px -184px}.icon-align-left{background-position:-224px -184px}.icon-align-center{background-position:-280px -184px}.icon-align-right{background-position:-336px -184px}.icon-justify{background-position:-392px -184px}.icon-list{background-position:-448px -184px}.icon-text-smaller{background-position:-504px -184px}.icon-text-bigger{background-position:-558px -184px}.icon-embed{background-position:-614px -184px}.icon-embed-close{background-position:-676px -184px}.icon-adjust{background-position:-738px -184px}.icon-message-full{background-position:-793px -184px}.icon-message-empty{background-position:-849px -184px}.icon-message-in{background-position:-905px -184px}.icon-message-out{background-position:-961px -184px}.icon-message-plus{background-position:-1017px -184px}.icon-message-minus{background-position:-1078px -184px}.icon-message-ban{background-position:-1139px -184px}.icon-message-flag{background-position:-1200px -184px}.icon-message-lock{background-position:-1259px -184px}.icon-message-new{background-position:-1319px -184px}.icon-inbox{background-position:-1379px -184px}.icon-inbox-plus{background-position:-1435px -184px}.icon-inbox-minus{background-position:-1494px -184px}.icon-inbox-lock{background-position:-1553px -184px}.icon-inbox-in{background-position:-1611px -184px}.icon-inbox-out{background-position:-1667px -184px}.icon-computer-locked{background-position:-1723px -184px}.icon-computer-service{background-position:-1783px -184px}.icon-computer-process{background-position:-1843px -184px}.icon-phone{background-position:-1903px -184px}.icon-database-lock{background-position:-1950px -184px}.icon-database-plus{background-position:0 -246px}.icon-database-minus{background-position:-59px -246px}.icon-database-ban{background-position:-118px -246px}.icon-folder-open{background-position:-176px -246px}.icon-folder-plus{background-position:-238px -246px}.icon-folder-minus{background-position:-299px -246px}.icon-folder-lock{background-position:-360px -246px}.icon-folder-flag{background-position:-420px -246px}.icon-folder-new{background-position:-479px -246px}.icon-check{background-position:-539px -246px}.icon-edit{background-position:-593px -246px}.icon-new-window{background-position:-649px -246px}.icon-more-windows{background-position:-707px -246px}.icon-show-big-thumbnails{background-position:-762px -246px}.icon-show-thumbnails{background-position:-816px -246px}.icon-show-thumbnails-with-lines{background-position:-870px -246px}.icon-show-lines{background-position:-926px -246px}.icon-playlist{background-position:-982px -246px}.icon-picture{background-position:-1043px -246px}.icon-imac{background-position:-1099px -246px}.icon-macbook{background-position:-1157px -246px}.icon-ipad{background-position:-1217px -246px}.icon-iphone{background-position:-1269px -246px}.icon-iphone-transfer{background-position:-1315px -246px}.icon-iphone-exchange{background-position:-1376px -246px}.icon-ipod{background-position:-1437px -246px}.icon-ipod-shuffle{background-position:-1483px -246px}.icon-ear-plugs{background-position:-1530px -246px}.icon-albums{background-position:-1582px -246px}.icon-step-backward{background-position:-1642px -246px}.icon-fast-backward{background-position:-1688px -246px}.icon-rewind{background-position:-1745px -246px}.icon-play{background-position:-1800px -246px}.icon-pause{background-position:-1848px -246px}.icon-stop{background-position:-1890px -246px}.icon-forward{background-position:-1936px -246px}.icon-fast-forward{background-position:0 -308px}.icon-step-forward{background-position:-57px -308px}.icon-eject{background-position:-103px -308px}.icon-facetime-video{background-position:-153px -308px}.icon-download-alt{background-position:-209px -308px}.icon-mute{background-position:-265px -308px}.icon-volume-down{background-position:-319px -308px}.icon-volume-up{background-position:-367px -308px}.icon-screenshot{background-position:-423px -308px}.icon-move{background-position:-482px -308px}.icon-more{background-position:-538px -308px}.icon-brightness-reduce{background-position:-592px -308px}.icon-brightness-increase{background-position:-644px -308px}.icon-circle-plus{background-position:-700px -308px}.icon-circle-minus{background-position:-758px -308px}.icon-circle-remove{background-position:-816px -308px}.icon-circle-ok{background-position:-874px -308px}.icon-circle-question-mark{background-position:-932px -308px}.icon-circle-info{background-position:-990px -308px}.icon-circle-exclamation-mark{background-position:-1048px -308px}.icon-remove{background-position:-1106px -308px}.icon-ok{background-position:-1164px -308px}.icon-ban{background-position:-1222px -308px}.icon-download{background-position:-1280px -308px}.icon-upload{background-position:-1338px -308px}.icon-shopping-cart{background-position:-1396px -308px}.icon-lock{background-position:-1454px -308px}.icon-unlock{background-position:-1507px -308px}.icon-electricity{background-position:-1560px -308px}.icon-ok-2{background-position:-1603px -308px}.icon-remove-2{background-position:-1660px -308px}.icon-cart-out{background-position:-1710px -308px}.icon-cart-in{background-position:-1768px -308px}.icon-left-arrow{background-position:-1826px -308px}.icon-right-arrow{background-position:-1878px -308px}.icon-down-arrow{background-position:-1930px -308px}.icon-up-arrow{background-position:0 -370px}.icon-resize-small{background-position:-50px -370px}.icon-resize-full{background-position:-106px -370px}.icon-circle-arrow-left{background-position:-162px -370px}.icon-circle-arrow-right{background-position:-220px -370px}.icon-circle-arrow-up{background-position:-278px -370px}.icon-circle-arrow-down{background-position:-336px -370px}.icon-play-button{background-position:-394px -370px}.icon-unshare{background-position:-452px -370px}.icon-share{background-position:-508px -370px}.icon-thin-arrow-right{background-position:-564px -370px}.icon-thin-arrow-left{background-position:-611px -370px}.icon-bluetooth{background-position:-658px -370px}.icon-euro{background-position:-704px -370px}.icon-usd{background-position:-758px -370px}.icon-bp{background-position:-807px -370px}.icon-retweet-2{background-position:-856px -370px}.icon-moon{background-position:-921px -370px}.icon-sun{background-position:-975px -370px}.icon-cloud{background-position:-1031px -370px}.icon-direction{background-position:-1090px -370px}.icon-brush{background-position:-1148px -370px}.icon-pen{background-position:-1205px -370px}.icon-zoom-in{background-position:-1261px -370px}.icon-zoom-out{background-position:-1318px -370px}.icon-pin{background-position:-1375px -370px}.icon-riflescope{background-position:-1417px -370px}.icon-rotation-lock{background-position:-1474px -370px}.icon-flash{background-position:-1533px -370px}.icon-google-maps{background-position:-1579px -370px}.icon-anchor{background-position:-1626px -370px}.icon-conversation{background-position:-1682px -370px}.icon-chat{background-position:-1739px -370px}.icon-male{background-position:-1795px -370px}.icon-female{background-position:-1849px -370px}.icon-asterisk{background-position:-1897px -370px}.icon-divide{background-position:-1949px -370px}.icon-snorkel-diving{background-position:0 -432px}.icon-scuba-diving{background-position:-59px -432px}.icon-oxygen-bottle{background-position:-118px -432px}.icon-fins{background-position:-172px -432px}.icon-fishes{background-position:-235px -432px}.icon-boat{background-position:-295px -432px}.icon-delete-point{background-position:-351px -432px}.icon-sheriffs-star{background-position:-409px -432px}.icon-qrcode{background-position:-465px -432px}.icon-barcode{background-position:-521px -432px}.icon-pool{background-position:-577px -432px}.icon-buoy{background-position:-633px -432px}.icon-spade{background-position:-689px -432px}.icon-bank{background-position:-745px -432px}.icon-vcard{background-position:-801px -432px}.icon-electrical-plug{background-position:-855px -432px}.icon-flag{background-position:-905px -432px}.icon-credit-card{background-position:-958px -432px}.icon-keyboard-wireless{background-position:-1016px -432px}.icon-keyboard-wired{background-position:-1075px -432px}.icon-shield{background-position:-1134px -432px}.icon-ring{background-position:-1188px -432px}.icon-cake{background-position:-1241px -432px}.icon-drink{background-position:-1295px -432px}.icon-beer{background-position:-1350px -432px}.icon-fast-food{background-position:-1405px -432px}.icon-cutlery{background-position:-1465px -432px}.icon-pizza{background-position:-1510px -432px}.icon-birthday-cake{background-position:-1568px -432px}.icon-tablet{background-position:-1626px -432px}.icon-settings{background-position:-1683px -432px}.icon-bullets{background-position:-1739px -432px}.icon-cardio{background-position:-1798px -432px}.icon-t-shirt{background-position:-1855px -432px}.icon-pants{background-position:-1915px -432px}.icon-sweater{background-position:-1966px -432px}.icon-fabric{background-position:0 -494px}.icon-leather{background-position:-59px -494px}.icon-scissors{background-position:-114px -494px}.icon-podium{background-position:-170px -494px}.icon-skull{background-position:-230px -494px}.icon-celebration{background-position:-284px -494px}.icon-tea-kettle{background-position:-340px -494px}.icon-french-press{background-position:-398px -494px}.icon-coffe-cup{background-position:-453px -494px}.icon-pot{background-position:-510px -494px}.icon-grater{background-position:-569px -494px}.icon-kettle{background-position:-619px -494px}.icon-hospital{background-position:-674px -494px}.icon-hospital-h{background-position:-730px -494px}.icon-microphone{background-position:-786px -494px}.icon-webcam{background-position:-835px -494px}.icon-temple-christianity-church{background-position:-886px -494px}.icon-temple-islam{background-position:-942px -494px}.icon-temple-hindu{background-position:-999px -494px}.icon-temple-buddhist{background-position:-1055px -494px}.icon-electrical-socket-eu{background-position:-1115px -494px}.icon-electrical-socket-us{background-position:-1170px -494px}.icon-bomb{background-position:-1225px -494px}.icon-comments{background-position:-1284px -494px}.icon-flower{background-position:-1340px -494px}.icon-baseball{background-position:-1391px -494px}.icon-rugby{background-position:-1448px -494px}.icon-ax{background-position:-1503px -494px}.icon-table-tennis{background-position:-1562px -494px}.icon-bowling{background-position:-1618px -494px}.icon-tree-conifer{background-position:-1674px -494px}.icon-tree-deciduous{background-position:-1727px -494px}.icon-more-items{background-position:-1779px -494px}.icon-sort{background-position:-1832px -494px}.icon-filter{background-position:-1889px -494px}.icon-gamepad{background-position:-1941px -494px}.icon-playing-dices{background-position:0 -556px}.icon-calculator{background-position:-59px -556px}.icon-tie{background-position:-112px -556px}.icon-wallet{background-position:-155px -556px}.icon-share{background-position:-212px -556px}.icon-sampler{background-position:-266px -556px}.icon-piano{background-position:-325px -556px}.icon-web-browser{background-position:-380px -556px}.icon-blog{background-position:-436px -556px}.icon-dashboard{background-position:-489px -556px}.icon-certificate{background-position:-545px -556px}.icon-bell{background-position:-594px -556px}.icon-candle{background-position:-650px -556px}.icon-pin-classic{background-position:-702px -556px}.icon-iphone-shake{background-position:-758px -556px}.icon-pin-flag{background-position:-814px -556px}.icon-turtle{background-position:-876px -556px}.icon-rabbit{background-position:-936px -556px}.icon-globe{background-position:-994px -556px}.icon-briefcase{background-position:-1050px -556px}.icon-hdd{background-position:-1106px -556px}.icon-thumbs-up{background-position:-1162px -556px}.icon-thumbs-down{background-position:-1218px -556px}.icon-hand-right{background-position:-1274px -556px}.icon-hand-left{background-position:-1332px -556px}.icon-hand-up{background-position:-1390px -556px}.icon-hand-down{background-position:-1441px -556px}.icon-fullscreen{background-position:-1492px -556px}.icon-shopping-bag{background-position:-1548px -556px}.icon-book-open{background-position:-1603px -556px}.icon-nameplate{background-position:-1660px -556px}.icon-nameplate-alt{background-position:-1716px -556px}.icon-vases{background-position:-1772px -556px}.icon-announcement{background-position:-1828px -556px}.icon-dumbbell{background-position:-1885px -556px}.icon-suitcase{background-position:-1943px -556px}.icon-file-import{background-position:0 -618px}.icon-file-export{background-position:-54px -618px}.icon-pinterest{background-position:-109px -618px}.icon-dropbox{background-position:-165px -618px}.icon-google-alt{background-position:-221px -618px}.icon-jolicloud{background-position:-277px -618px}.icon-yahoo{background-position:-333px -618px}.icon-blogger{background-position:-389px -618px}.icon-picasa{background-position:-445px -618px}.icon-amazon{background-position:-501px -618px}.icon-tumblr{background-position:-557px -618px}.icon-wordpress{background-position:-613px -618px}.icon-instapaper{background-position:-669px -618px}.icon-evernote{background-position:-725px -618px}.icon-xing{background-position:-781px -618px}.icon-zootool{background-position:-837px -618px}.icon-dribbble{background-position:-893px -618px}.icon-deviantart{background-position:-949px -618px}.icon-read-it-later{background-position:-1005px -618px}.icon-linked-in{background-position:-1061px -618px}.icon-forrst{background-position:-1117px -618px}.icon-pinboard{background-position:-1173px -618px}.icon-behance{background-position:-1229px -618px}.icon-github{background-position:-1285px -618px}.icon-youtube{background-position:-1341px -618px}.icon-skitch{background-position:-1397px -618px}.icon-4square{background-position:-1453px -618px}.icon-quora{background-position:-1509px -618px}.icon-google-plus{background-position:-1565px -618px}.icon-spotify{background-position:-1621px -618px}.icon-stumbleupon{background-position:-1677px -618px}.icon-readability{background-position:-1733px -618px}.icon-facebook{background-position:-1789px -618px}.icon-twitter-t{background-position:-1845px -618px}.icon-twitter{background-position:-1901px -618px}.icon-buzz{background-position:-1957px -618px}.icon-vimeo{background-position:0 -680px}.icon-flickr{background-position:-56px -680px}.icon-last-fm{background-position:-112px -680px}.icon-rss{background-position:-168px -680px}.icon-skype{background-position:-224px -680px}.icon-e-mail{background-position:-280px -680px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{color:#fff;text-decoration:none;background-color:#08c;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#08c;background-color:#0081c2;background-image:linear-gradient(to bottom,#08c,#0077b3);background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:"\2191"}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover .dropdown-menu{display:block}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;overflow:visible \9;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 14px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;*line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbb;*border:0;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:9px 14px;font-size:16px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.btn-large [class^="icon-"]{margin-top:2px}.btn-small{padding:3px 9px;font-size:12px;line-height:18px}.btn-small [class^="icon-"]{margin-top:0}.btn-mini{padding:2px 6px;font-size:11px;line-height:16px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#c5c5c5;border-color:rgba(0,0,0,0.15) rgba(0,0,0,0.15) rgba(0,0,0,0.25)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-image:-moz-linear-gradient(top,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-image:-moz-linear-gradient(top,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-image:-moz-linear-gradient(top,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-group{position:relative;*margin-left:.3em;font-size:0;white-space:nowrap}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1}.btn-toolbar .btn+.btn,.btn-toolbar .btn-group+.btn,.btn-toolbar .btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu{font-size:14px}.btn-group>.btn-mini{font-size:11px}.btn-group>.btn-small{font-size:12px}.btn-group>.btn-large{font-size:16px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-top:0;border-bottom:5px solid #000}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical .btn{display:block;float:none;width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical .btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical .btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical .btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical .btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical .btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;color:#c09853;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible;color:#555}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar .container{width:auto}.nav-collapse.collapse{height:auto}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#555;text-shadow:0 1px 0 #fff}.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px}.navbar-link{color:#555}.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:6px}.navbar .btn-group .btn{margin:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;width:100%;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner,.navbar-static-top .navbar-inner{border:0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1);box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#555;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse{color:#999}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-image:-moz-linear-gradient(top,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb .divider{padding:0 5px;color:#ccc}.breadcrumb .active{color:#999}.pagination{height:40px;margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination li{display:inline}.pagination a,.pagination span{float:left;padding:0 14px;line-height:38px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination a:hover,.pagination .active a,.pagination .active span{background-color:#f5f5f5}.pagination .active a,.pagination .active span{color:#999;cursor:default}.pagination .disabled span,.pagination .disabled a,.pagination .disabled a:hover{color:#999;cursor:default;background-color:transparent}.pagination li:first-child a,.pagination li:first-child span{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.pagination li:last-child a,.pagination li:last-child span{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next a{float:right}.pager .previous a{float:left}.pager .disabled a,.pager .disabled a:hover{color:#999;cursor:default;background-color:#fff}.modal-open .dropdown-menu{z-index:2050}.modal-open .dropdown.open{*z-index:2050}.modal-open .popover{z-index:2060}.modal-open .tooltip{z-index:2080}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:50%;left:50%;z-index:1050;width:560px;margin:-250px 0 0 -280px;overflow:auto;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:50%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px}.tooltip.right{margin-left:3px}.tooltip.bottom{margin-top:3px}.tooltip.left{margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-bottom:10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-right:10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0}.popover .arrow,.popover .arrow:after{position:absolute;display:inline-block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow:after{z-index:-1;content:""}.popover.top .arrow{bottom:-10px;left:50%;margin-left:-10px;border-top-color:#fff;border-width:10px 10px 0}.popover.top .arrow:after{bottom:-1px;left:-11px;border-top-color:rgba(0,0,0,0.25);border-width:11px 11px 0}.popover.right .arrow{top:50%;left:-10px;margin-top:-10px;border-right-color:#fff;border-width:10px 10px 10px 0}.popover.right .arrow:after{bottom:-11px;left:-1px;border-right-color:rgba(0,0,0,0.25);border-width:11px 11px 11px 0}.popover.bottom .arrow{top:-10px;left:50%;margin-left:-10px;border-bottom-color:#fff;border-width:0 10px 10px}.popover.bottom .arrow:after{top:-1px;left:-11px;border-bottom-color:rgba(0,0,0,0.25);border-width:0 11px 11px}.popover.left .arrow{top:50%;right:-10px;margin-top:-10px;border-left-color:#fff;border-width:10px 0 10px 10px}.popover.left .arrow:after{right:-1px;bottom:-11px;border-left-color:rgba(0,0,0,0.25);border-width:11px 0 11px 11px}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.label,.badge{font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{padding:1px 4px 2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding:1px 9px 2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel .item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel .item>img{display:block;line-height:1}.carousel .active,.carousel .next,.carousel .prev{display:block}.carousel .active{left:0}.carousel .next,.carousel .prev{position:absolute;top:0;width:100%}.carousel .next{left:100%}.carousel .prev{left:-100%}.carousel .next.left,.carousel .prev.right{left:0}.carousel .active.left{left:-100%}.carousel .active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit p{font-size:18px;font-weight:200;line-height:30px;color:inherit}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} \ No newline at end of file diff --git a/extern/phmap/css/colors.css b/extern/phmap/css/colors.css new file mode 100644 index 0000000..8774c02 --- /dev/null +++ b/extern/phmap/css/colors.css @@ -0,0 +1,302 @@ +/*** + + colors.css v2.0.0 + http://clrs.cc + @mrmrs + MIT License + +***/ +/* + + SKINS + - Backgrounds + - Colors + - Border colors + - SVG fills + - SVG Strokes + +*/ +/* Backgrounds */ +.bg-navy { + background-color: #001F3F; } + +.bg-blue { + background-color: #0074D9; } + +.bg-aqua { + background-color: #7FDBFF; } + +.bg-teal { + background-color: #39CCCC; } + +.bg-olive { + background-color: #3D9970; } + +.bg-green { + background-color: #2ECC40; } + +.bg-lime { + background-color: #01FF70; } + +.bg-yellow { + background-color: #FFDC00; } + +.bg-orange { + background-color: #FF851B; } + +.bg-red { + background-color: #FF4136; } + +.bg-fuchsia { + background-color: #F012BE; } + +.bg-purple { + background-color: #B10DC9; } + +.bg-maroon { + background-color: #85144B; } + +.bg-white { + background-color: #fff; } + +.bg-gray { + background-color: #aaa; } + +.bg-silver { + background-color: #ddd; } + +.bg-black { + background-color: #111; } + +/* Colors */ +.navy { + color: #001F3F; } + +.blue { + color: #0074D9; } + +.aqua { + color: #7FDBFF; } + +.teal { + color: #39CCCC; } + +.olive { + color: #3D9970; } + +.green { + color: #2ECC40; } + +.lime { + color: #01FF70; } + +.yellow { + color: #FFDC00; } + +.orange { + color: #FF851B; } + +.red { + color: #FF4136; } + +.fuchsia { + color: #F012BE; } + +.purple { + color: #B10DC9; } + +.maroon { + color: #85144B; } + +.white { + color: #fff; } + +.silver { + color: #ddd; } + +.gray { + color: #aaa; } + +.black { + color: #111; } + +/* Border colors + + Use with another border utility that sets border-width and style + i.e .border { border-width: 1px; border-style: solid; } +*/ +.border--navy { + border-color: #001F3F; } + +.border--blue { + border-color: #0074D9; } + +.border--aqua { + border-color: #7FDBFF; } + +.border--teal { + border-color: #39CCCC; } + +.border--olive { + border-color: #3D9970; } + +.border--green { + border-color: #2ECC40; } + +.border--lime { + border-color: #01FF70; } + +.border--yellow { + border-color: #FFDC00; } + +.border--orange { + border-color: #FF851B; } + +.border--red { + border-color: #FF4136; } + +.border--fuchsia { + border-color: #F012BE; } + +.border--purple { + border-color: #B10DC9; } + +.border--maroon { + border-color: #85144B; } + +.border--white { + border-color: #fff; } + +.border--gray { + border-color: #aaa; } + +.border--silver { + border-color: #ddd; } + +.border--black { + border-color: #111; } + +/* Fills for SVG */ +.fill-navy { + fill: #001F3F; } + +.fill-blue { + fill: #0074D9; } + +.fill-aqua { + fill: #7FDBFF; } + +.fill-teal { + fill: #39CCCC; } + +.fill-olive { + fill: #3D9970; } + +.fill-green { + fill: #2ECC40; } + +.fill-lime { + fill: #01FF70; } + +.fill-yellow { + fill: #FFDC00; } + +.fill-orange { + fill: #FF851B; } + +.fill-red { + fill: #FF4136; } + +.fill-fuchsia { + fill: #F012BE; } + +.fill-purple { + fill: #B10DC9; } + +.fill-maroon { + fill: #85144B; } + +.fill-white { + fill: #fff; } + +.fill-gray { + fill: #aaa; } + +.fill-silver { + fill: #ddd; } + +.fill-black { + fill: #111; } + +/* Strokes for SVG */ +.stroke-navy { + stroke: #001F3F; } + +.stroke-blue { + stroke: #0074D9; } + +.stroke-aqua { + stroke: #7FDBFF; } + +.stroke-teal { + stroke: #39CCCC; } + +.stroke-olive { + stroke: #3D9970; } + +.stroke-green { + stroke: #2ECC40; } + +.stroke-lime { + stroke: #01FF70; } + +.stroke-yellow { + stroke: #FFDC00; } + +.stroke-orange { + stroke: #FF851B; } + +.stroke-red { + stroke: #FF4136; } + +.stroke-fuchsia { + stroke: #F012BE; } + +.stroke-purple { + stroke: #B10DC9; } + +.stroke-maroon { + stroke: #85144B; } + +.stroke-white { + stroke: #fff; } + +.stroke-gray { + stroke: #aaa; } + +.stroke-silver { + stroke: #ddd; } + +.stroke-black { + stroke: #111; } + +/* PRETTIER LINKS */ +a { + text-decoration: none; + -webkit-transition: color .3s ease-in-out; + transition: color .3s ease-in-out; } + +a:link { + -webkit-transition: color .3s ease-in-out; + transition: color .3s ease-in-out; } + +a:visited { } + +a:hover { + color: #001F3F; + -webkit-transition: color .3s ease-in-out; + transition: color .3s ease-in-out; } + +a:active { + -webkit-transition: color .3s ease-in-out; + transition: color .3s ease-in-out; } diff --git a/extern/phmap/css/style.css b/extern/phmap/css/style.css new file mode 100644 index 0000000..ca7987f --- /dev/null +++ b/extern/phmap/css/style.css @@ -0,0 +1,271 @@ +/* main stylesheet */ + +@import url(http://fonts.googleapis.com/css?family=Signika); + +html { + overflow-y: scroll; +} + +body { + font-size: 15px; + font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, sans-serif; + color: #332; +} + +h1, h2, h3, h4, h5 { + color: #332; + font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-weight: 400; + font-size: 1.4em; + line-height: 1.1; + margin-top: 30px; +} + +pre code { + font: 14px/19px Inconsolata, Monaco,"Lucida Console",Terminal,"Courier New",Courier; +} + +.figure { + text-align: center; +} + +.small .figure img { + height: 200px; +} + +.pagetitle .figure { + text-align: left !important; +} + +.pagetitle .figure img { + height: 36px; +} + +table{ + background:#fff; + border:1px solid #ccc; + border-width:2px; + border-collapse:collapse; + margin:5px 0 10px; + + margin-top: 20px; + margin-bottom: 20px; +} + +th, td{ + border:1px solid #ccc; + padding:3px 10px; + text-align:left; + vertical-align:top; +} + +tr.even td{ + background:#f7f7f7; +} + +th{ + background:#edeff0; +} + +td code { + border: 0px; +} + +img { + max-width: 100%; + height: auto; +} + +hr { + border: 0px; + height: 0; + border-bottom: 1px solid #ccc; + margin-bottom: 100px; +} + +/* Logo */ + +.logo { + text-align: center; +} + +.tagline { + font-family: Georgia; + font-size: 18px; + font-style: italic; + line-height: 1.45; + color: #383838; +} + +.author { +} + +.halfbreak { + padding-bottom: 100px; +} + +.break { + padding-bottom: 200px; +} + +/* TOC Links */ + +a { + color: #111111; + text-decoration: none; +} + +.body li a { + text-decoration: underline; +} + +/* Math */ + +.MathJax_Display { + padding-top: 20px; + padding-bottom: 20px; +} + +/* Body Links */ + +p a { + text-decoration: underline; +} + +li code, p code { + font-size: 12px; + border: 1px solid #ccc; + margin-left: 3px; + margin-right: 3px; + padding-left: 2px; + padding-right: 2px; +} + +/* */ + +.center { + text-align: center; +} + +.bigger img { + width: 120%; + height: 120%; +} + +pre { + font-size: 0.9em; + + margin-bottom: 18px; + margin-top: 18px; + + border-left: 1px solid #ccc; + +} + +h1 { + margin-top: 0px; +} + +.annotation { + font-size: 10pt; +} + +.annotation pre { + display: block; + margin: 0; + padding: 7px 10px; + overflow-x: auto; +} + +.annotation.span2 { + /* Override bootstrap */ + margin-left: 0px !important; + margin-top: 18px !important; +} + +.annotation pre code { + border: 0; + padding: 0; + background: transparent; +} + +blockquote { + border-left: 1px solid #ccc; + font-family: Georgia, serif; + font-size: 14px; + font-style: italic; + margin: 0.25em 0; + padding-left: 10px; + line-height: 1.45; + color: #383838; + left: 20px; +} + + +blockquote cite { + color: #999999; + font-size: 14px; + display: block; + margin-top: 5px; +} + +ul.sections { + list-style: none; + padding:0 0 5px 0; + margin:0; +} + +code.sourceCode { + padding: 0; + background: inherit; +} + +pre.sourceCode { + padding: 10px; +} + +ul.sections > li > div { + -moz-box-sizing: border-box; /* firefox */ + -ms-box-sizing: border-box; /* ie */ + -webkit-box-sizing: border-box; /* webkit */ + -khtml-box-sizing: border-box; /* konqueror */ + box-sizing: border-box; /* css3 */ +} + + +/* Make the naviation centered and larger on small screens */ +/*---------------------- (> 481px) ---------------------*/ + +@media only screen and (max-width: 481px) { + +} + +@media only screen and (min-width: 1025px) { + body { + padding: 10px; + } + + .side { + position: fixed; + width: 120px !important; + margin-left: 0px; + z-index: 1000; + } + + .side ul ul { + display: none; + } + + .side ul ul.active { + display: block; + } + + .side .active { + font-weight: bold; + } + + .body { + margin-left: 120px !important; + } + +} diff --git a/extern/phmap/examples/allmaps.cc b/extern/phmap/examples/allmaps.cc new file mode 100644 index 0000000..89b1ac0 --- /dev/null +++ b/extern/phmap/examples/allmaps.cc @@ -0,0 +1,75 @@ +// Silly program just to test the natvis file for Visual Studio +// ------------------------------------------------------------ +#include +#include "parallel_hashmap/phmap.h" + +template +void test_set(const F &f) +{ + Set s; + typename Set::iterator it; + for (int i=0; i<100; ++i) + s.insert(f(i)); + + it = s.begin(); + ++it; + + it = s.end(); + it = s.begin(); + while(it != s.end()) + ++it; + it = s.begin(); +} + +int main(int, char **) +{ + using namespace std; + + auto make_int = [](int i) { return i; }; + auto make_string = [](int i) { return std::to_string(i); }; + + auto make_2int = [](int i) { return std::make_pair(i, i); }; + auto make_2string = [](int i) { return std::make_pair(std::to_string(i), std::to_string(i)); }; + + + test_set>(make_int); + test_set>(make_string); + + test_set>(make_int); + test_set>(make_string); + + test_set>(make_2int); + test_set>(make_2string); + + test_set>(make_2int); + test_set>(make_2string); + + test_set>(make_int); + test_set>(make_string); + + test_set>(make_int); + test_set>(make_string); + + test_set>(make_2int); + test_set>(make_2string); + + test_set>(make_2int); + test_set>(make_2string); + + // example of using default parameters in order to specify the mutex type. + // + // Please be aware that the iterators returned (by find for example) cannot + // be safely read in a multithreaded environment. Instead use if_contains(), + // which passes a reference value to the callback while holding the submap lock. + // Similarly, write access can be done safely using modify_if, try_emplace_l + // or lazy_emplace_l. + // ---------------------------------------------------------------------------- + using Map = phmap::parallel_flat_hash_map, + std::equal_to, + std::allocator>, + 4, + std::mutex>; + auto make_2size_t = [](size_t i) { return std::make_pair(i, i); }; + test_set(make_2size_t); +} diff --git a/extern/phmap/examples/basic.cc b/extern/phmap/examples/basic.cc new file mode 100644 index 0000000..f83d6fb --- /dev/null +++ b/extern/phmap/examples/basic.cc @@ -0,0 +1,23 @@ +#include +#include +#include + +using phmap::flat_hash_map; + +int main() +{ + // Create an unordered_map of three strings (that map to strings) + flat_hash_map email; + + // Iterate and print keys and values + for (const auto& n : email) + std::cout << n.first << "'s email is: " << n.second << "\n"; + + // Add a new entry + email["bill"] = "bg@whatever.com"; + + // and print it + std::cout << "bill's email is: " << email["bill"] << "\n"; + + return 0; +} diff --git a/extern/phmap/examples/bench.cc b/extern/phmap/examples/bench.cc new file mode 100644 index 0000000..3c81471 --- /dev/null +++ b/extern/phmap/examples/bench.cc @@ -0,0 +1,480 @@ +#include + +#ifdef STL_UNORDERED + #include + #define MAPNAME std::unordered_map + #define EXTRAARGS +#elif defined(PHMAP_FLAT) + #include "parallel_hashmap/phmap.h" + #define MAPNAME phmap::flat_hash_map + #define NMSP phmap + #define EXTRAARGS +#else + #if 1 + #include + #define MTX std::mutex + #elif 0 + // Abseil's mutexes are very efficient (at least on windows) + #include "absl/synchronization/mutex.h" + #define MTX absl::Mutex + #elif 1 + #include + #if 1 + #include + #define MTX boost::mutex // faster if all we do is exclusive locks like this bench + #else + #include + #define MTX boost::upgrade_mutex + #endif + #elif 1 + #include + class srwlock { + SRWLOCK _lock; + public: + srwlock() { InitializeSRWLock(&_lock); } + void lock() { AcquireSRWLockExclusive(&_lock); } + void unlock() { ReleaseSRWLockExclusive(&_lock); } + }; + #define MTX srwlock + #else + // spinlocks - slow! + #include + class spinlock { + std::atomic_flag flag = ATOMIC_FLAG_INIT; + public: + void lock() { while(flag.test_and_set(std::memory_order_acquire)); } + void unlock() { flag.clear(std::memory_order_release); } + }; + #define MTX spinlock + #endif + + #include "parallel_hashmap/phmap.h" + #define MAPNAME phmap::parallel_flat_hash_map + #define NMSP phmap + + #define MT_SUPPORT 1 + #if MT_SUPPORT == 1 + // create the parallel_flat_hash_map without internal mutexes, for when + // we programatically ensure that each thread uses different internal submaps + // -------------------------------------------------------------------------- + #define EXTRAARGS , NMSP::priv::hash_default_hash, \ + NMSP::priv::hash_default_eq, \ + std::allocator>, 4, NMSP::NullMutex + #elif MT_SUPPORT == 2 + // create the parallel_flat_hash_map with internal mutexes, for when + // we read/write the same parallel_flat_hash_map from multiple threads, + // without any special precautions. + // -------------------------------------------------------------------------- + #define EXTRAARGS , NMSP::priv::hash_default_hash, \ + NMSP::priv::hash_default_eq, \ + std::allocator>, 4, MTX + #else + #define EXTRAARGS + #endif +#endif + +#define xstr(s) str(s) +#define str(s) #s + +template +using HashT = MAPNAME; + +using hash_t = HashT; +using str_hash_t = HashT; + +const char *program_slug = xstr(MAPNAME); // "_4"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "parallel_hashmap/meminfo.h" +#include +using std::vector; + +int64_t _abs(int64_t x) { return (x < 0) ? -x : x; } + +#ifdef _MSC_VER + #pragma warning(disable : 4996) +#endif // _MSC_VER + +// -------------------------------------------------------------------------- +class Timer +{ + typedef std::chrono::high_resolution_clock high_resolution_clock; + typedef std::chrono::milliseconds milliseconds; + +public: + explicit Timer(bool run = false) { if (run) reset(); } + void reset() { _start = high_resolution_clock::now(); } + + milliseconds elapsed() const + { + return std::chrono::duration_cast(high_resolution_clock::now() - _start); + } + +private: + high_resolution_clock::time_point _start; +}; + + +// -------------------------------------------------------------------------- +// from: https://github.com/preshing/RandomSequence +// -------------------------------------------------------------------------- +class RSU +{ +private: + unsigned int m_index; + unsigned int m_intermediateOffset; + + static unsigned int permuteQPR(unsigned int x) + { + static const unsigned int prime = 4294967291u; + if (x >= prime) + return x; // The 5 integers out of range are mapped to themselves. + unsigned int residue = ((unsigned long long) x * x) % prime; + return (x <= prime / 2) ? residue : prime - residue; + } + +public: + RSU(unsigned int seedBase, unsigned int seedOffset) + { + m_index = permuteQPR(permuteQPR(seedBase) + 0x682f0161); + m_intermediateOffset = permuteQPR(permuteQPR(seedOffset) + 0x46790905); + } + + unsigned int next() + { + return permuteQPR((permuteQPR(m_index++) + m_intermediateOffset) ^ 0x5bf03635); + } +}; + +// -------------------------------------------------------------------------- +char * new_string_from_integer(uint64_t num) +{ + int ndigits = num == 0 ? 1 : (int)log10(num) + 1; + char * str = (char *)malloc(ndigits + 1); + sprintf(str, "%u", (unsigned int)num); + return str; +} + +// -------------------------------------------------------------------------- +template +void _fill(vector &v) +{ + srand(1); // for a fair/deterministic comparison + for (size_t i = 0, sz = v.size(); i < sz; ++i) + v[i] = (T)(i * 10 + rand() % 10); +} + +// -------------------------------------------------------------------------- +template +void _shuffle(vector &v) +{ + for (size_t n = v.size(); n >= 2; --n) + std::swap(v[n - 1], v[static_cast(rand()) % n]); +} + +// -------------------------------------------------------------------------- +template +Timer _fill_random(vector &v, HT &hash) +{ + _fill(v); + _shuffle(v); + + Timer timer(true); + + for (size_t i = 0, sz = v.size(); i < sz; ++i) + hash.insert(typename HT::value_type(v[i], 0)); + return timer; +} + +// -------------------------------------------------------------------------- +void out(const char* test, int64_t cnt, const Timer &t, bool = false) +{ + printf("%s,time,%u,%s,%f\n", test, (unsigned int)cnt, program_slug, + (float)((double)t.elapsed().count() / 1000)); +} + +// -------------------------------------------------------------------------- +void outmem(const char*, int64_t cnt, uint64_t mem, bool final = false) +{ + static uint64_t max_mem = 0; + static uint64_t max_keys = 0; + if (final) + printf("peak memory usage for %u values: %.2f GB\n", (unsigned int)max_keys, + max_mem / ((double)1000 * 1000 * 1000)); + else { + if (mem > max_mem) + max_mem = mem; + if ((uint64_t)cnt > max_keys) + max_keys = cnt; + } +} + +static bool all_done = false; +static int64_t s_num_keys[16] = { 0 }; +static int64_t loop_idx = 0; +static int64_t inner_cnt = 0; +static const char *test = "random"; + +// -------------------------------------------------------------------------- +template +void _fill_random_inner(int64_t cnt, HT &hash, RSU &rsu) +{ + for (int64_t i=0; i +void _fill_random_inner_mt(int64_t cnt, HT &hash, RSU &rsu) +{ + constexpr int64_t num_threads = 8; // has to be a power of two + std::unique_ptr threads[num_threads]; + + auto thread_fn = [&hash, cnt, num_threads](size_t thread_idx, RSU rsu_) { +#if MT_SUPPORT + size_t modulo = hash.subcnt() / num_threads; // subcnt() returns the number of submaps + + for (int64_t i=0; ijoin(); +} + +// -------------------------------------------------------------------------- +size_t total_num_keys() +{ + size_t n = 0; + for (int i=0; i<16; ++i) + n += s_num_keys[i]; + return n; +} + +// -------------------------------------------------------------------------- +template +Timer _fill_random2(int64_t cnt, HT &hash) +{ + test = "random"; + unsigned int seed = 76687; + RSU rsu(seed, seed + 1); + + Timer timer(true); + const int64_t num_loops = 10; + inner_cnt = cnt / num_loops; + + for (int i=0; i<16; ++i) + s_num_keys[i] = 0; + + for (loop_idx=0; loop_idx +Timer _lookup(vector &v, HT &hash, size_t &num_present) +{ + _fill_random(v, hash); + + num_present = 0; + size_t max_val = v.size() * 10; + Timer timer(true); + + for (size_t i = 0, sz = v.size(); i < sz; ++i) + { + num_present += (size_t)(hash.find(v[i]) != hash.end()); + num_present += (size_t)(hash.find((T)(rand() % max_val)) != hash.end()); + } + return timer; +} + +// -------------------------------------------------------------------------- +template +Timer _delete(vector &v, HT &hash) +{ + _fill_random(v, hash); + _shuffle(v); // don't delete in insertion order + + Timer timer(true); + + for(size_t i = 0, sz = v.size(); i < sz; ++i) + hash.erase(v[i]); + return timer; +} + +// -------------------------------------------------------------------------- +void memlog() +{ + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + uint64_t nbytes_old_out = spp::GetProcessMemoryUsed(); + uint64_t nbytes_old = spp::GetProcessMemoryUsed(); // last non outputted mem measurement + outmem(test, 0, nbytes_old); + int64_t last_loop = 0; + + while (!all_done) + { + uint64_t nbytes = spp::GetProcessMemoryUsed(); + + if ((double)_abs(nbytes - nbytes_old_out) / nbytes_old_out > 0.03 || + (double)_abs(nbytes - nbytes_old) / nbytes_old > 0.01) + { + if ((double)(nbytes - nbytes_old) / nbytes_old > 0.03) + outmem(test, total_num_keys() - 1, nbytes_old); + outmem(test, total_num_keys(), nbytes); + nbytes_old_out = nbytes; + last_loop = loop_idx; + } + else if (loop_idx > last_loop) + { + outmem(test, total_num_keys(), nbytes); + nbytes_old_out = nbytes; + last_loop = loop_idx; + } + nbytes_old = nbytes; + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } +} + + +// -------------------------------------------------------------------------- +int main(int argc, char ** argv) +{ + int64_t num_keys = 100000000; + const char *bench_name = "random"; + int64_t i, value = 0; + + if(argc > 2) + { + num_keys = atoi(argv[1]); + bench_name = argv[2]; + } + + hash_t hash; + str_hash_t str_hash; + + srand(1); // for a fair/deterministic comparison + Timer timer(true); + +#if MT_SUPPORT + if (!strcmp(program_slug,"absl::parallel_flat_hash_map") || + !strcmp(program_slug,"phmap::parallel_flat_hash_map")) + program_slug = xstr(MAPNAME) "_mt"; +#endif + + std::thread t1(memlog); + + try + { + if(!strcmp(bench_name, "sequential")) + { + for(i = 0; i < num_keys; i++) + hash.insert(hash_t::value_type(i, value)); + } +#if 0 + else if(!strcmp(bench_name, "random")) + { + vector v(num_keys); + timer = _fill_random(v, hash); + out("random", num_keys, timer); + } +#endif + else if(!strcmp(bench_name, "random")) + { + fprintf(stderr, "size = %zu\n", sizeof(hash)); + timer = _fill_random2(num_keys, hash); + } + else if(!strcmp(bench_name, "lookup")) + { + vector v(num_keys); + size_t num_present; + + timer = _lookup(v, hash, num_present); + //fprintf(stderr, "found %zu\n", num_present); + } + else if(!strcmp(bench_name, "delete")) + { + vector v(num_keys); + timer = _delete(v, hash); + } + else if(!strcmp(bench_name, "sequentialstring")) + { + for(i = 0; i < num_keys; i++) + str_hash.insert(str_hash_t::value_type(new_string_from_integer(i), value)); + } + else if(!strcmp(bench_name, "randomstring")) + { + for(i = 0; i < num_keys; i++) + str_hash.insert(str_hash_t::value_type(new_string_from_integer((int)rand()), value)); + } + else if(!strcmp(bench_name, "deletestring")) + { + for(i = 0; i < num_keys; i++) + str_hash.insert(str_hash_t::value_type(new_string_from_integer(i), value)); + timer.reset(); + for(i = 0; i < num_keys; i++) + str_hash.erase(new_string_from_integer(i)); + } + + + //printf("%f\n", (float)((double)timer.elapsed().count() / 1000)); + fflush(stdout); + //std::this_thread::sleep_for(std::chrono::seconds(1000)); + } + catch (...) + { + } + + all_done = true; + outmem(test, 0, 0, true); + t1.join(); + return 0; +} diff --git a/extern/phmap/examples/btree.cc b/extern/phmap/examples/btree.cc new file mode 100644 index 0000000..4ff8e23 --- /dev/null +++ b/extern/phmap/examples/btree.cc @@ -0,0 +1,49 @@ +#include +#include "btree_fwd.h" +#include + +int main() +{ + // initialise map with some values using an initializer_list + phmap::btree_map map = + { { "John", 35 }, + { "Jane", 32 }, + { "Joe", 30 }, + }; + + // add a couple more values using operator[]() + map["lucy"] = 18; + map["Andre"] = 20; + + auto it = map.find("Joe"); + map.erase(it); + + map.insert(std::make_pair("Alex", 16)); + map.emplace("Emily", 18); // emplace uses pair template constructor + + for (auto& p: map) + std::cout << p.first << ", " << p.second << '\n'; + + IntString map2; // IntString is declared in btree_fwd.h + + map2.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple(10, 'c')); + map2.try_emplace(1, 10, 'a'); // phmap::btree_map supports c++17 API + + for (auto& p: map2) + std::cout << p.first << ", " << p.second << '\n'; + + // create a btree_set of tuples + using X = std::tuple; + phmap::btree_set set; + + for (int i=0; i<10; ++i) + set.insert(X((float)i, std::to_string(i))); + set.emplace(15.0f, "15"); + + set.erase(X(1.0f, "1")); + + for (auto& e: set) + std::cout << std::get<0>(e) << ", \"" << std::get<1>(e) << "\" \n"; + + return 0; +} diff --git a/extern/phmap/examples/btree_fwd.h b/extern/phmap/examples/btree_fwd.h new file mode 100644 index 0000000..bd8c5e7 --- /dev/null +++ b/extern/phmap/examples/btree_fwd.h @@ -0,0 +1,6 @@ +#include + +#include + +using IntString = phmap::btree_map; + diff --git a/extern/phmap/examples/dump_load.cc b/extern/phmap/examples/dump_load.cc new file mode 100644 index 0000000..6b003e4 --- /dev/null +++ b/extern/phmap/examples/dump_load.cc @@ -0,0 +1,53 @@ +#include +#include + +void dump_load_uint64_uint32() { + phmap::flat_hash_map mp1 = { {100, 99}, {300, 299} }; + + for (const auto& n : mp1) + std::cout << n.first << "'s value is: " << n.second << "\n"; + + { + phmap::BinaryOutputArchive ar_out("./dump.data"); + mp1.phmap_dump(ar_out); + } + + phmap::flat_hash_map mp2; + { + phmap::BinaryInputArchive ar_in("./dump.data"); + mp2.phmap_load(ar_in); + } + + for (const auto& n : mp2) + std::cout << n.first << "'s value is: " << n.second << "\n"; +} + +void dump_load_parallel_flat_hash_map() { + phmap::parallel_flat_hash_map mp1 = { + {100, 99}, {300, 299}, {101, 992} }; + + for (const auto& n : mp1) + std::cout << "key: " << n.first << ", value: " << n.second << "\n"; + + { + phmap::BinaryOutputArchive ar_out("./dump.data"); + mp1.phmap_dump(ar_out); + } + + phmap::parallel_flat_hash_map mp2; + { + phmap::BinaryInputArchive ar_in("./dump.data"); + mp2.phmap_load(ar_in); + } + + for (const auto& n : mp2) + std::cout << "key: " << n.first << ", value: " << n.second << "\n"; +} + +int main() +{ + dump_load_uint64_uint32(); + dump_load_parallel_flat_hash_map(); + return 0; +} + diff --git a/extern/phmap/examples/dump_nested.cc b/extern/phmap/examples/dump_nested.cc new file mode 100644 index 0000000..c207ba3 --- /dev/null +++ b/extern/phmap/examples/dump_nested.cc @@ -0,0 +1,88 @@ +/* + * + * Example of dumping a map, containing values which are phmap maps or sets + * building this requires c++17 support + * + */ + +#include +#include + +template +class MyMap : public phmap::flat_hash_map> +{ +public: + using Set = phmap::flat_hash_set; + + void dump(const std::string &filename) + { + phmap::BinaryOutputArchive ar_out (filename.c_str()); + + ar_out.dump(this->size()); + for (auto& [k, v] : *this) + { + ar_out.dump(k); + v.dump(ar_out); + } + } + + void load(const std::string & filename) + { + phmap::BinaryInputArchive ar_in(filename.c_str()); + + size_t size; + ar_in.load(&size); + this->reserve(size); + + while (size--) + { + K k; + Set v; + + ar_in.load(&k); + v.load(ar_in); + + this->insert_or_assign(std::move(k), std::move(v)); + } + } + + void insert(K k, V v) + { + Set &set = (*this)[k]; + set.insert(v); + } + + friend std::ostream& operator<<(std::ostream& os, const MyMap& map) + { + for (const auto& [k, m] : map) + { + os << k << ": ["; + for (const auto& x : m) + os << x << ", "; + os << "]\n"; + } + return os; + } +}; + +int main() +{ + MyMap m; + m.insert(1, 5); + m.insert(1, 8); + m.insert(2, 3); + m.insert(1, 15); + m.insert(1, 27); + m.insert(2, 10); + m.insert(2, 13); + + std::cout << m << "\n"; + + m.dump("test_archive"); + m.clear(); + m.load("test_archive"); + + std::cout << m << "\n"; + + return 0; +} diff --git a/extern/phmap/examples/emplace.cc b/extern/phmap/examples/emplace.cc new file mode 100644 index 0000000..540318c --- /dev/null +++ b/extern/phmap/examples/emplace.cc @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +template +using milliseconds = std::chrono::duration; + +// type containing std::string. Seems to take a long time to construct (and maybe move) +// ------------------------------------------------------------------------------------ +class custom_type +{ + std::string one = "one"; + std::string two = "two"; + std::uint32_t three = 3; + std::uint64_t four = 4; + std::uint64_t five = 5; +public: + custom_type() = default; + + // Make object movable and non-copyable + custom_type(custom_type &&) = default; + custom_type& operator=(custom_type &&) = default; + + // should be automatically deleted per http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014 + //custom_type(custom_type const&) = delete; + //custom_type& operator=(custom_type const&) = delete; +}; + +// type containing only integrals. should be faster to create. +// ----------------------------------------------------------- +class custom_type_2 +{ + std::uint32_t three = 3; + std::uint64_t four = 4; + std::uint64_t five = 5; + std::uint64_t six = 6; +public: + custom_type_2() = default; + + // Make object movable and non-copyable + custom_type_2(custom_type_2 &&) = default; + custom_type_2& operator=(custom_type_2 &&) = default; + + // should be automatically deleted per http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014 + //custom_type_2(custom_type_2 const&) = delete; + //custom_type_2& operator=(custom_type_2 const&) = delete; +}; + +// convert std::size_t to appropriate key +// -------------------------------------- +template +struct GenKey +{ + K operator()(std::size_t j); +}; + +template <> +struct GenKey +{ + std::string operator()(std::size_t j) { + std::ostringstream stm; + stm << j; + return stm.str(); + } +}; + +template <> +struct GenKey +{ + int operator()(std::size_t j) { + return (int)j; + } +}; + +// emplace key + large struct +// -------------------------- +template struct _emplace +{ + void operator()(Map &m, std::size_t j); +}; + +// "void" template parameter -> use emplace +template struct _emplace +{ + void operator()(Map &m, std::size_t j) + { + m.emplace(GenKey()(j), V()); + } +}; + +// "int" template parameter -> use emplace_back for std::vector +template struct _emplace +{ + void operator()(Map &m, std::size_t j) + { + m.emplace_back(GenKey()(j), V()); + } +}; + +// The test itself +// --------------- +template class INSERT> +void _test(std::size_t iterations, std::size_t container_size, const char *map_name) +{ + std::size_t count = 0; + auto t1 = std::chrono::high_resolution_clock::now(); + INSERT insert; + for (std::size_t i=0; i(t2 - t1).count(); + if (count != iterations*container_size) + std::clog << " invalid count: " << count << "\n"; + std::clog << map_name << std::fixed << int(elapsed) << " ms\n"; +} + + +template class INSERT> +void test(std::size_t iterations, std::size_t container_size) +{ + std::clog << "bench: iterations: " << iterations << " / container_size: " << container_size << "\n"; + + _test, K, V, void, INSERT>(iterations, container_size, " std::map: "); + _test, K, V, void, INSERT>(iterations, container_size, " std::unordered_map: "); + _test, K, V, void, INSERT>(iterations, container_size, " phmap::flat_hash_map: "); + _test>, K, V, int, INSERT> (iterations, container_size, " std::vector: "); + std::clog << "\n"; + +} + +int main() +{ + std::size_t iterations = 100000; + + // test with custom_type_2 (int key + 32 byte value). This is representative + // of the hash table insertion speed. + // ------------------------------------------------------------------------- + std::clog << "\n\n" << "testing with " "\n"; + std::clog << "---------------------------------" "\n"; + test(iterations,10); + test(iterations,100); + test(iterations,500); + + // test with custom_type, which contains two std::string values, and use + // a generated string key. This is not very indicative of the speed of the + // hash itself, as a good chunk of the time is spent creating the keys and + // values (as shown by the long times even for std::vector). + // ----------------------------------------------------------------------- + std::clog << "\n" << "testing with " "\n"; + std::clog << "---------------------------------" "\n"; + test(iterations,1); + test(iterations,10); + test(iterations,50); + +} diff --git a/extern/phmap/examples/f1.cc b/extern/phmap/examples/f1.cc new file mode 100644 index 0000000..9cec278 --- /dev/null +++ b/extern/phmap/examples/f1.cc @@ -0,0 +1,25 @@ +/* + * Make sure that the phmap.h header builds fine when included in two separate + * source files + */ +#include +#include + +using phmap::flat_hash_map; + +int main() +{ + // Create an unordered_map of three strings (that map to strings) + using Map = flat_hash_map; + Map email = + { + { "tom", "tom@gmail.com"}, + { "jeff", "jk@gmail.com"}, + { "jim", "jimg@microsoft.com"} + }; + + extern void f2(Map&); + f2(email); + + return 0; +} diff --git a/extern/phmap/examples/f2.cc b/extern/phmap/examples/f2.cc new file mode 100644 index 0000000..eca567e --- /dev/null +++ b/extern/phmap/examples/f2.cc @@ -0,0 +1,23 @@ +/* + * Make sure that the phmap.h header builds fine when included in two separate + * source files + */ +#include +#include +#include + +using phmap::flat_hash_map; +using Map = flat_hash_map; + +void f2(Map& email) +{ + // Iterate and print keys and values + for (const auto& n : email) + std::cout << n.first << "'s email is: " << n.second << "\n"; + + // Add a new entry + email["bill"] = "bg@whatever.com"; + + // and print it + std::cout << "bill's email is: " << email["bill"] << "\n"; +} diff --git a/extern/phmap/examples/hash_std.cc b/extern/phmap/examples/hash_std.cc new file mode 100644 index 0000000..04551ff --- /dev/null +++ b/extern/phmap/examples/hash_std.cc @@ -0,0 +1,20 @@ +#include "hash_std.h" // defines Person with std::hash specialization + +#include +#include + +int main() +{ + // As we have defined a specialization of std::hash() for Person, + // we can now create sparse_hash_set or sparse_hash_map of Persons + // ---------------------------------------------------------------- + phmap::flat_hash_set persons = + { { "John", "Mitchell", 35 }, + { "Jane", "Smith", 32 }, + { "Jane", "Smith", 30 }, + }; + + for (auto& p: persons) + std::cout << p._first << ' ' << p._last << " (" << p._age << ")" << '\n'; + +} diff --git a/extern/phmap/examples/hash_std.h b/extern/phmap/examples/hash_std.h new file mode 100644 index 0000000..debf4a9 --- /dev/null +++ b/extern/phmap/examples/hash_std.h @@ -0,0 +1,34 @@ +#ifndef phmap_example_hash_std_ +#define phmap_example_hash_std_ + +#include // minimal header providing phmap::HashState() +#include +using std::string; + +struct Person +{ + bool operator==(const Person &o) const + { + return _first == o._first && _last == o._last && _age == o._age; + } + + string _first; + string _last; + int _age; +}; + +namespace std +{ + // inject specialization of std::hash for Person into namespace std + // An alternative is to provide a hash_value() friend function (see hash_value.h) + // ------------------------------------------------------------------------------ + template<> struct hash + { + std::size_t operator()(Person const &p) const + { + return phmap::HashState().combine(0, p._first, p._last, p._age); + } + }; +} + +#endif // phmap_example_hash_std_ diff --git a/extern/phmap/examples/hash_value.cc b/extern/phmap/examples/hash_value.cc new file mode 100644 index 0000000..43d2b05 --- /dev/null +++ b/extern/phmap/examples/hash_value.cc @@ -0,0 +1,20 @@ +#include "hash_value.h" // defines Person with std::hash specialization + +#include +#include + +int main() +{ + // As we have defined a specialization of std::hash() for Person, + // we can now create sparse_hash_set or sparse_hash_map of Persons + // ---------------------------------------------------------------- + phmap::flat_hash_set persons = + { { "John", "Mitchell", 35 }, + { "Jane", "Smith", 32 }, + { "Jane", "Smith", 30 }, + }; + + for (auto& p: persons) + std::cout << p._first << ' ' << p._last << " (" << p._age << ")" << '\n'; + +} diff --git a/extern/phmap/examples/hash_value.h b/extern/phmap/examples/hash_value.h new file mode 100644 index 0000000..ffcc3e0 --- /dev/null +++ b/extern/phmap/examples/hash_value.h @@ -0,0 +1,28 @@ +#ifndef phmap_example_hash_value_ +#define phmap_example_hash_value_ + +#include // minimal header providing phmap::HashState() +#include +using std::string; + +struct Person +{ + bool operator==(const Person &o) const + { + return _first == o._first && _last == o._last && _age == o._age; + } + + // Demonstrates how to provide the hash function as a friend member function of the class + // This can be used as an alternative to providing a std::hash specialization + // -------------------------------------------------------------------------------------- + friend size_t hash_value(const Person &p) + { + return phmap::HashState().combine(0, p._first, p._last, p._age); + } + + string _first; + string _last; + int _age; +}; + +#endif // phmap_example_hash_value_ diff --git a/extern/phmap/examples/insert_bench.cc b/extern/phmap/examples/insert_bench.cc new file mode 100644 index 0000000..b01b982 --- /dev/null +++ b/extern/phmap/examples/insert_bench.cc @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include +#define PHMAP_ALLOCATOR_NOTHROW 1 +#include + +// this is probably the fastest high quality 64bit random number generator that exists. +// Implements Small Fast Counting v4 RNG from PractRand. +class sfc64 { +public: + using result_type = uint64_t; + + // no copy ctors so we don't accidentally get the same random again + sfc64(sfc64 const&) = delete; + sfc64& operator=(sfc64 const&) = delete; + + sfc64(sfc64&&) = default; + sfc64& operator=(sfc64&&) = default; + + sfc64(std::array const& _state) + : m_a(_state[0]) + , m_b(_state[1]) + , m_c(_state[2]) + , m_counter(_state[3]) {} + + static constexpr uint64_t(min)() { + return (std::numeric_limits::min)(); + } + static constexpr uint64_t(max)() { + return (std::numeric_limits::max)(); + } + + sfc64() + : sfc64(UINT64_C(0x853c49e6748fea9b)) {} + + sfc64(uint64_t _seed) + : m_a(_seed) + , m_b(_seed) + , m_c(_seed) + , m_counter(1) { + for (int i = 0; i < 12; ++i) { + operator()(); + } + } + + void seed() { + *this = sfc64{std::random_device{}()}; + } + + uint64_t operator()() noexcept { + auto const tmp = m_a + m_b + m_counter++; + m_a = m_b ^ (m_b >> right_shift); + m_b = m_c + (m_c << left_shift); + m_c = rotl(m_c, rotation) + tmp; + return tmp; + } + + // this is a bit biased, but for our use case that's not important. + uint64_t operator()(uint64_t boundExcluded) noexcept { +#ifdef PHMAP_HAS_UMUL128 + uint64_t h; + (void)umul128(operator()(), boundExcluded, &h); + return h; +#else + return 0; +#endif + } + + std::array state() const { + return {{m_a, m_b, m_c, m_counter}}; + } + + void state(std::array const& s) { + m_a = s[0]; + m_b = s[1]; + m_c = s[2]; + m_counter = s[3]; + } + +private: + template + T rotl(T const x, int k) { + return (x << k) | (x >> (8 * sizeof(T) - k)); + } + + static constexpr int rotation = 24; + static constexpr int right_shift = 11; + static constexpr int left_shift = 3; + uint64_t m_a; + uint64_t m_b; + uint64_t m_c; + uint64_t m_counter; +}; + + +int main() +{ + // Create an unordered_map of three strings (that map to strings) + using Map = phmap::parallel_node_hash_map; + static size_t const n = 50000000; + sfc64 rng(123); + + size_t checksum = 0; + + if (0) + { + size_t const max_rng = n / 20; + Map map; + for (size_t i = 0; i < n; ++i) { + checksum += ++map[static_cast(rng(max_rng))]; + } + } + + if (0) + { + size_t const max_rng = n / 4; + Map map; + for (size_t i = 0; i < n; ++i) { + checksum += ++map[static_cast(rng(max_rng))]; + } + } + + if (1) + { + size_t const max_rng = n / 2; + Map map; + for (size_t i = 0; i < n; ++i) { + checksum += ++map[static_cast(rng(max_rng))]; + } + } + + if (0) + { + Map map; + for (size_t i = 0; i < n; ++i) { + checksum += ++map[static_cast(rng())]; + } + } + printf("%zu\n", checksum); +} diff --git a/extern/phmap/examples/knucleotide-input.txt b/extern/phmap/examples/knucleotide-input.txt new file mode 100644 index 0000000..f1caba0 --- /dev/null +++ b/extern/phmap/examples/knucleotide-input.txt @@ -0,0 +1,171 @@ +>ONE Homo sapiens alu +GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA +TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT +AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG +GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG +CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT +GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA +GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA +TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG +AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA +GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT +AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC +AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG +GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC +CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG +AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT +TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA +TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT +GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG +TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT +CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG +CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG +TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA +CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG +AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG +GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC +TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA +TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA +GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT +GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC +ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT +TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC +CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG +CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG +GGCGACAGAGCGAGACTCCG +>TWO IUB ambiguity codes +cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg +tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa +NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt +cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga +gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa +HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca +tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt +tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt +acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct +tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt +gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa +accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt +RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt +tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag +cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg +ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat +actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg +YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa +KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata +aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa +aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg +gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc +tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK +tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt +ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg +ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa +BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt +aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc +tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc +cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac +aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga +tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga +aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD +gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg +ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV +taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa +ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat +gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg +gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa +tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt +tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt +taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca +cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag +aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt +cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt +ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW +attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag +ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa +attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc +tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta +>THREE Homo sapiens frequency +aacacttcaccaggtatcgtgaaggctcaagattacccagagaacctttgcaatataaga +atatgtatgcagcattaccctaagtaattatattctttttctgactcaaagtgacaagcc +ctagtgtatattaaatcggtatatttgggaaattcctcaaactatcctaatcaggtagcc +atgaaagtgatcaaaaaagttcgtacttataccatacatgaattctggccaagtaaaaaa +tagattgcgcaaaattcgtaccttaagtctctcgccaagatattaggatcctattactca +tatcgtgtttttctttattgccgccatccccggagtatctcacccatccttctcttaaag +gcctaatattacctatgcaaataaacatatattgttgaaaattgagaacctgatcgtgat +tcttatgtgtaccatatgtatagtaatcacgcgactatatagtgctttagtatcgcccgt +gggtgagtgaatattctgggctagcgtgagatagtttcttgtcctaatatttttcagatc +gaatagcttctatttttgtgtttattgacatatgtcgaaactccttactcagtgaaagtc +atgaccagatccacgaacaatcttcggaatcagtctcgttttacggcggaatcttgagtc +taacttatatcccgtcgcttactttctaacaccccttatgtatttttaaaattacgttta +ttcgaacgtacttggcggaagcgttattttttgaagtaagttacattgggcagactcttg +acattttcgatacgactttctttcatccatcacaggactcgttcgtattgatatcagaag +ctcgtgatgattagttgtcttctttaccaatactttgaggcctattctgcgaaatttttg +ttgccctgcgaacttcacataccaaggaacacctcgcaacatgccttcatatccatcgtt +cattgtaattcttacacaatgaatcctaagtaattacatccctgcgtaaaagatggtagg +ggcactgaggatatattaccaagcatttagttatgagtaatcagcaatgtttcttgtatt +aagttctctaaaatagttacatcgtaatgttatctcgggttccgcgaataaacgagatag +attcattatatatggccctaagcaaaaacctcctcgtattctgttggtaattagaatcac +acaatacgggttgagatattaattatttgtagtacgaagagatataaaaagatgaacaat +tactcaagtcaagatgtatacgggatttataataaaaatcgggtagagatctgctttgca +attcagacgtgccactaaatcgtaatatgtcgcgttacatcagaaagggtaactattatt +aattaataaagggcttaatcactacatattagatcttatccgatagtcttatctattcgt +tgtatttttaagcggttctaattcagtcattatatcagtgctccgagttctttattattg +ttttaaggatgacaaaatgcctcttgttataacgctgggagaagcagactaagagtcgga +gcagttggtagaatgaggctgcaaaagacggtctcgacgaatggacagactttactaaac +caatgaaagacagaagtagagcaaagtctgaagtggtatcagcttaattatgacaaccct +taatacttccctttcgccgaatactggcgtggaaaggttttaaaagtcgaagtagttaga +ggcatctctcgctcataaataggtagactactcgcaatccaatgtgactatgtaatactg +ggaacatcagtccgcgatgcagcgtgtttatcaaccgtccccactcgcctggggagacat +gagaccacccccgtggggattattagtccgcagtaatcgactcttgacaatccttttcga +ttatgtcatagcaatttacgacagttcagcgaagtgactactcggcgaaatggtattact +aaagcattcgaacccacatgaatgtgattcttggcaatttctaatccactaaagcttttc +cgttgaatctggttgtagatatttatataagttcactaattaagatcacggtagtatatt +gatagtgatgtctttgcaagaggttggccgaggaatttacggattctctattgatacaat +ttgtctggcttataactcttaaggctgaaccaggcgtttttagacgacttgatcagctgt +tagaatggtttggactccctctttcatgtcagtaacatttcagccgttattgttacgata +tgcttgaacaatattgatctaccacacacccatagtatattttataggtcatgctgttac +ctacgagcatggtattccacttcccattcaatgagtattcaacatcactagcctcagaga +tgatgacccacctctaataacgtcacgttgcggccatgtgaaacctgaacttgagtagac +gatatcaagcgctttaaattgcatataacatttgagggtaaagctaagcggatgctttat +ataatcaatactcaataataagatttgattgcattttagagttatgacacgacatagttc +actaacgagttactattcccagatctagactgaagtactgatcgagacgatccttacgtc +gatgatcgttagttatcgacttaggtcgggtctctagcggtattggtacttaaccggaca +ctatactaataacccatgatcaaagcataacagaatacagacgataatttcgccaacata +tatgtacagaccccaagcatgagaagctcattgaaagctatcattgaagtcccgctcaca +atgtgtcttttccagacggtttaactggttcccgggagtcctggagtttcgacttacata +aatggaaacaatgtattttgctaatttatctatagcgtcatttggaccaatacagaatat +tatgttgcctagtaatccactataacccgcaagtgctgatagaaaatttttagacgattt +ataaatgccccaagtatccctcccgtgaatcctccgttatactaattagtattcgttcat +acgtataccgcgcatatatgaacatttggcgataaggcgcgtgaattgttacgtgacaga +gatagcagtttcttgtgatatggttaacagacgtacatgaagggaaactttatatctata +gtgatgcttccgtagaaataccgccactggtctgccaatgatgaagtatgtagctttagg +tttgtactatgaggctttcgtttgtttgcagagtataacagttgcgagtgaaaaaccgac +gaatttatactaatacgctttcactattggctacaaaatagggaagagtttcaatcatga +gagggagtatatggatgctttgtagctaaaggtagaacgtatgtatatgctgccgttcat +tcttgaaagatacataagcgataagttacgacaattataagcaacatccctaccttcgta +acgatttcactgttactgcgcttgaaatacactatggggctattggcggagagaagcaga +tcgcgccgagcatatacgagacctataatgttgatgatagagaaggcgtctgaattgata +catcgaagtacactttctttcgtagtatctctcgtcctctttctatctccggacacaaga +attaagttatatatatagagtcttaccaatcatgttgaatcctgattctcagagttcttt +ggcgggccttgtgatgactgagaaacaatgcaatattgctccaaatttcctaagcaaatt +ctcggttatgttatgttatcagcaaagcgttacgttatgttatttaaatctggaatgacg +gagcgaagttcttatgtcggtgtgggaataattcttttgaagacagcactccttaaataa +tatcgctccgtgtttgtatttatcgaatgggtctgtaaccttgcacaagcaaatcggtgg +tgtatatatcggataacaattaatacgatgttcatagtgacagtatactgatcgagtcct +ctaaagtcaattacctcacttaacaatctcattgatgttgtgtcattcccggtatcgccc +gtagtatgtgctctgattgaccgagtgtgaaccaaggaacatctactaatgcctttgtta +ggtaagatctctctgaattccttcgtgccaacttaaaacattatcaaaatttcttctact +tggattaactacttttacgagcatggcaaattcccctgtggaagacggttcattattatc +ggaaaccttatagaaattgcgtgttgactgaaattagatttttattgtaagagttgcatc +tttgcgattcctctggtctagcttccaatgaacagtcctcccttctattcgacatcgggt +ccttcgtacatgtctttgcgatgtaataattaggttcggagtgtggccttaatgggtgca +actaggaatacaacgcaaatttgctgacatgatagcaaatcggtatgccggcaccaaaac +gtgctccttgcttagcttgtgaatgagactcagtagttaaataaatccatatctgcaatc +gattccacaggtattgtccactatctttgaactactctaagagatacaagcttagctgag +accgaggtgtatatgactacgctgatatctgtaaggtaccaatgcaggcaaagtatgcga +gaagctaataccggctgtttccagctttataagattaaaatttggctgtcctggcggcct +cagaattgttctatcgtaatcagttggttcattaattagctaagtacgaggtacaactta +tctgtcccagaacagctccacaagtttttttacagccgaaacccctgtgtgaatcttaat +atccaagcgcgttatctgattagagtttacaactcagtattttatcagtacgttttgttt +ccaacattacccggtatgacaaaatgacgccacgtgtcgaataatggtctgaccaatgta +ggaagtgaaaagataaatat diff --git a/extern/phmap/examples/knucleotide-input0.txt b/extern/phmap/examples/knucleotide-input0.txt new file mode 100644 index 0000000..fd4414b --- /dev/null +++ b/extern/phmap/examples/knucleotide-input0.txt @@ -0,0 +1,4171 @@ +>ONE Homo sapiens alu +GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA +TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT +AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG +GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG +CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT +GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA +GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA +TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG +AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA +GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT +AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC +AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG +GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC +CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG +AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT +TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA +TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT +GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG +TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT +CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG +CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG +TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA +CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG +AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG +GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC +TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA +TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA +GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT +GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC +ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT +TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC +CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG +CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG +GGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCC +CAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCT +GGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGC +GCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGA +GGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGA +GACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGA +GGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTG +AAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT +CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCA +GTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAA +AAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGC +GGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCT +ACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGG +GAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATC +GCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGC +GGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGG +TCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAA +AAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAG +GAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACT +CCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCC +TGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAG +ACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGC +GTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGA +ACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGA +CAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCA +CTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCA +ACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCG +CCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG +AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTC +CGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCG +AGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACC +CCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAG +CTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAG +CCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGG +CCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATC +ACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAA +AAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGC +TGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCC +ACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGG +CTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGG +AGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATT +AGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAA +TCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGC +CTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAA +TCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAG +CCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGT +GGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCG +GGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAG +CGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG +GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATG +GTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGT +AATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTT +GCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCT +CAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCG +GGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTC +TCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACT +CGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAG +ATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGG +CGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTG +AGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATA +CAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGG +CAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGC +ACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCAC +GCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTC +GAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCG +GGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCT +TGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGG +CGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCA +GCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGG +CCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGC +GCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGG +CGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGA +CTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGG +CCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAA +ACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCC +CAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGT +GAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAA +AGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGG +ATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTAC +TAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGA +GGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGC +GCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGG +TGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC +AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAA +ATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGA +GAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC +AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTG +TAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGAC +CAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGT +GGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC +CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACA +GAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACT +TTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAAC +ATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCC +TGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAG +GTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCG +TCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAG +GCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCC +GTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCT +ACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCC +GAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCC +GGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCAC +CTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAA +ATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTG +AGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCAC +TGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCT +CACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAG +TTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAG +CCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATC +GCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCT +GGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATC +CCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCC +TGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGG +CGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG +AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCG +AGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGG +AGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGT +GAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAA +TCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGC +AGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCA +AAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGG +CGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTC +TACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCG +GGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGAT +CGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCG +CGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAG +GTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACA +AAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCA +GGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCAC +TCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGC +CTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA +GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGG +CGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTG +AACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCG +ACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGC +ACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCC +AACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGC +GCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCG +GAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACT +CCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCC +GAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAAC +CCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA +GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGA +GCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAG +GCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGAT +CACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTA +AAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGG +CTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGC +CACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTG +GCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAG +GAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAAT +TAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGA +ATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAG +CCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTA +ATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCA +GCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGG +TGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCC +GGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGA +GCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT +GGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT +GGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTG +TAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGT +TGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTC +TCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGC +GGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGT +CTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTAC +TCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGA +GATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGG +GCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCT +GAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT +ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAG +GCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG +CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCA +CGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTT +CGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCC +GGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGC +TTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGG +GCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCC +AGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTG +GCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCG +CGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAG +GCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAG +ACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAG +GCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGA +AACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATC +CCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAG +TGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAA +AAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCG +GATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTA +CTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGG +AGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCG +CGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCG +GTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGT +CAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAA +AATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGG +AGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTC +CAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCT +GTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA +CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG +TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAA +CCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGAC +AGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCAC +TTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAA +CATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGC +CTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGA +GGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCC +GTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGA +GGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCC +CGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGC +TACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGC +CGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGC +CGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCA +CCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA +AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCT +GAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCA +CTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGC +TCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGA +GTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTA +GCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAAT +CGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCC +TGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAAT +CCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGC +CTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTG +GCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGG +GAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGC +GAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG +GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGG +TGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTA +ATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTG +CAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTC +AAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGG +GCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCT +CTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTC +GGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGA +TCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGC +GCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGA +GGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATAC +AAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGC +AGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCA +CTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACG +CCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCG +AGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGG +GCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTT +GAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGC +GACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAG +CACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGC +CAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCG +CGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGC +GGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGAC +TCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGC +CGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAA +CCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCC +AGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTG +AGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA +GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA +TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT +AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG +GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG +CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT +GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA +GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA +TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG +AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA +GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT +AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC +AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG +GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC +CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG +AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT +TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA +TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT +GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG +TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT +CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG +CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG +TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA +CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG +AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG +GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC +TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA +TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA +GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT +GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC +ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT +TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC +CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG +CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG +GGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCC +CAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCT +GGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGC +GCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGA +GGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGA +GACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGA +GGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTG +AAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT +CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCA +GTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAA +AAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGC +GGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCT +ACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGG +GAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATC +GCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGC +GGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGG +TCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAA +AAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAG +GAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACT +CCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCC +TGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAG +ACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGC +GTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGA +ACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGA +CAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCA +CTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCA +ACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCG +CCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG +AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTC +CGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCG +AGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACC +CCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAG +CTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAG +CCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGG +CCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATC +ACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAA +AAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGC +TGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCC +ACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGG +CTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGG +AGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATT +AGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAA +TCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGC +CTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAA +TCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAG +CCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGT +GGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCG +GGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAG +CGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG +GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATG +GTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGT +AATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTT +GCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCT +CAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCG +GGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTC +TCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACT +CGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAG +ATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGG +CGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTG +AGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATA +CAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGG +CAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGC +ACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCAC +GCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTC +GAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCG +GGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCT +TGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGG +CGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCA +GCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGG +CCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGC +GCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGG +CGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGA +CTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGG +CCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAA +ACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCC +CAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGT +GAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAA +AGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGG +ATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTAC +TAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGA +GGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGC +GCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGG +TGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC +AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAA +ATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGA +GAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC +AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTG +TAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGAC +CAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGT +GGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC +CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACA +GAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACT +TTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAAC +ATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCC +TGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAG +GTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCG +TCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAG +GCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCC +GTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCT +ACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCC +GAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCC +GGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCAC +CTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAA +ATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTG +AGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCAC +TGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCT +CACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAG +TTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAG +CCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATC +GCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCT +GGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATC +CCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCC +TGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGG +CGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG +AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCG +AGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGG +AGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGT +GAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAA +TCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGC +AGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCA +AAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGG +CGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTC +TACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCG +GGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGAT +CGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCG +CGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAG +GTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACA +AAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCA +GGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCAC +TCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGC +CTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA +GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGG +CGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTG +AACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCG +ACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGC +ACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCC +AACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGC +GCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCG +GAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACT +CCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCC +GAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAAC +CCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA +GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGA +GCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAG +GCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGAT +CACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTA +AAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGG +CTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGC +CACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTG +GCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAG +GAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAAT +TAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGA +ATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAG +CCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTA +ATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCA +GCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGG +TGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCC +GGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGA +GCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT +GGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT +GGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTG +TAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGT +TGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTC +TCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGC +GGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGT +CTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTAC +TCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGA +GATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGG +GCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCT +GAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT +ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAG +GCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG +CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCA +CGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTT +CGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCC +GGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGC +TTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGG +GCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCC +AGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTG +GCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCG +CGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAG +GCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAG +ACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAG +GCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGA +AACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATC +CCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAG +TGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAA +AAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCG +GATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTA +CTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGG +AGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCG +CGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCG +GTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGT +CAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAA +AATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGG +AGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTC +CAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCT +GTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA +CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG +TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAA +CCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGAC +AGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCAC +TTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAA +CATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGC +CTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGA +GGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCC +GTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGA +GGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCC +CGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGC +TACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGC +CGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGC +CGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCA +CCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA +AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCT +GAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCA +CTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGC +TCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGA +GTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTA +GCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAAT +CGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCC +TGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAAT +CCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGC +CTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTG +GCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGG +GAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGC +GAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG +GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGG +TGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTA +ATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTG +CAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTC +AAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGG +GCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCT +CTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTC +GGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGA +TCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGC +GCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGA +GGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATAC +AAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGC +AGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCA +CTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACG +CCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCG +AGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGG +GCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTT +GAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGC +GACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAG +CACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGC +CAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCG +CGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGC +GGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGAC +TCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGC +CGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAA +CCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCC +AGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTG +AGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA +GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA +TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT +AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG +GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG +CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT +GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA +GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA +TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG +AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA +GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT +AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC +AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG +GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC +CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG +AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT +TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA +TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT +GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG +TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT +CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG +CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG +TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA +CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG +AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG +GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC +TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA +TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA +GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT +GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC +ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT +TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC +CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG +CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG +GGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCC +CAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCT +GGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGC +GCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGA +GGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGA +GACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGA +GGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTG +AAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT +CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCA +GTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAA +AAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGC +GGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCT +ACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGG +GAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATC +GCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGC +GGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGG +TCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAA +AAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAG +GAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACT +CCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCC +TGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAG +ACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGC +GTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGA +ACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGA +CAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCA +CTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCA +ACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCG +CCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG +AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTC +CGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCG +AGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACC +CCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAG +CTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAG +CCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGG +CCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATC +ACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAA +AAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGC +TGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCC +ACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGG +CTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGG +AGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATT +AGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAA +TCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGC +CTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAA +TCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAG +CCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGT +GGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCG +GGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAG +CGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG +GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATG +GTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGT +AATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTT +GCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCT +CAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCG +GGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTC +TCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACT +CGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAG +ATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGG +CGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTG +AGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATA +CAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGG +CAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGC +ACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCAC +GCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTC +GAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCG +GGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCT +TGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGG +CGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCA +GCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGG +CCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGC +GCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGG +CGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGA +CTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGG +CCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAA +ACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCC +CAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGT +GAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAA +AGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGG +ATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTAC +TAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGA +GGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGC +GCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGG +TGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC +AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAA +ATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGA +GAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC +AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTG +TAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGAC +CAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGT +GGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC +CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACA +GAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACT +TTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAAC +ATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCC +TGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAG +GTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCG +TCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAG +GCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCC +GTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCT +ACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCC +GAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCC +GGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCAC +CTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAA +ATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTG +AGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCAC +TGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCT +CACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAG +TTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAG +CCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATC +GCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCT +GGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATC +CCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCC +TGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGG +CGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG +AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCG +AGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGG +AGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGT +GAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAA +TCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGC +AGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCA +AAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGG +CGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTC +TACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCG +GGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGAT +CGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCG +CGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAG +GTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACA +AAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCA +GGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCAC +TCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGC +CTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA +GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGG +CGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTG +AACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCG +ACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGC +ACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCC +AACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGC +GCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCG +GAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACT +CCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCC +GAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAAC +CCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA +GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGA +GCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAG +GCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGAT +CACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTA +AAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGG +CTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGC +CACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTG +GCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAG +GAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAAT +TAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGA +ATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAG +CCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTA +ATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCA +GCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGG +TGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCC +GGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGA +GCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT +GGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT +GGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTG +TAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGT +TGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTC +TCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGC +GGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGT +CTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTAC +TCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGA +GATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGG +GCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCT +GAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT +ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAG +GCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG +CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCA +CGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTT +CGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCC +GGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGC +TTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGG +GCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCC +AGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTG +GCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCG +CGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAG +GCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAG +ACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAG +GCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGA +AACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATC +CCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAG +TGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAA +AAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCG +GATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTA +CTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGG +AGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCG +CGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCG +GTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGT +CAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAA +AATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGG +AGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTC +CAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCT +GTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA +CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG +TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAA +CCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGAC +AGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCAC +TTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAA +CATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGC +CTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGA +GGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCC +GTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGA +GGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCC +CGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGC +TACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGC +CGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGC +CGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCA +CCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA +AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCT +GAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCA +CTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGC +TCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGA +GTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTA +GCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAAT +CGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCC +TGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAAT +CCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGC +CTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTG +GCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGG +GAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGC +GAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG +GAGGCCGAGGCGGGCGGATC +>TWO IUB ambiguity codes +cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg +tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa +NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt +cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga +gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa +HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca +tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt +tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt +acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct +tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt +gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa +accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt +RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt +tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag +cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg +ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat +actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg +YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa +KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata +aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa +aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg +gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc +tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK +tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt +ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg +ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa +BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt +aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc +tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc +cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac +aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga +tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga +aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD +gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg +ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV +taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa +ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat +gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg +gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa +tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt +tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt +taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca +cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag +aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt +cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt +ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW +attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag +ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa +attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc +tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta +aagacYRcaggattHaYgtKtaatgcVcaataMYacccatatcacgWDBtgaatcBaata +cKcttRaRtgatgaBDacggtaattaaYtataStgVHDtDctgactcaaatKtacaatgc +gYatBtRaDatHaactgtttatatDttttaaaKVccYcaaccNcBcgHaaVcattHctcg +attaaatBtatgcaaaaatYMctSactHatacgaWacattacMBgHttcgaatVaaaaca +BatatVtctgaaaaWtctRacgBMaatSgRgtgtcgactatcRtattaScctaStagKga +DcWgtYtDDWKRgRtHatRtggtcgaHgggcgtattaMgtcagccaBggWVcWctVaaat +tcgNaatcKWagcNaHtgaaaSaaagctcYctttRVtaaaatNtataaccKtaRgtttaM +tgtKaBtRtNaggaSattHatatWactcagtgtactaKctatttgRYYatKatgtccgtR +tttttatttaatatVgKtttgtatgtNtataRatWYNgtRtHggtaaKaYtKSDcatcKg +taaYatcSRctaVtSMWtVtRWHatttagataDtVggacagVcgKWagBgatBtaaagNc +aRtagcataBggactaacacRctKgttaatcctHgDgttKHHagttgttaatgHBtatHc +DaagtVaBaRccctVgtgDtacRHSctaagagcggWYaBtSaKtHBtaaactYacgNKBa +VYgtaacttagtVttcttaatgtBtatMtMtttaattaatBWccatRtttcatagVgMMt +agctStKctaMactacDNYgKYHgaWcgaHgagattacVgtttgtRaSttaWaVgataat +gtgtYtaStattattMtNgWtgttKaccaatagNYttattcgtatHcWtctaaaNVYKKt +tWtggcDtcgaagtNcagatacgcattaagaccWctgcagcttggNSgaNcHggatgtVt +catNtRaaBNcHVagagaaBtaaSggDaatWaatRccaVgggStctDaacataKttKatt +tggacYtattcSatcttagcaatgaVBMcttDattctYaaRgatgcattttNgVHtKcYR +aatRKctgtaaacRatVSagctgtWacBtKVatctgttttKcgtctaaDcaagtatcSat +aWVgcKKataWaYttcccSaatgaaaacccWgcRctWatNcWtBRttYaattataaNgac +acaatagtttVNtataNaYtaatRaVWKtBatKagtaatataDaNaaaaataMtaagaaS +tccBcaatNgaataWtHaNactgtcDtRcYaaVaaaaaDgtttRatctatgHtgttKtga +aNSgatactttcgagWaaatctKaaDaRttgtggKKagcDgataaattgSaacWaVtaNM +acKtcaDaaatttctRaaVcagNacaScRBatatctRatcctaNatWgRtcDcSaWSgtt +RtKaRtMtKaatgttBHcYaaBtgatSgaSWaScMgatNtctcctatttctYtatMatMt +RRtSaattaMtagaaaaStcgVgRttSVaScagtgDtttatcatcatacRcatatDctta +tcatVRtttataaHtattcYtcaaaatactttgVctagtaaYttagatagtSYacKaaac +gaaKtaaatagataatSatatgaaatSgKtaatVtttatcctgKHaatHattagaaccgt +YaaHactRcggSBNgtgctaaBagBttgtRttaaattYtVRaaaattgtaatVatttctc +ttcatgBcVgtgKgaHaaatattYatagWacNctgaaMcgaattStagWaSgtaaKagtt +ttaagaDgatKcctgtaHtcatggKttVDatcaaggtYcgccagNgtgcVttttagagat +gctaccacggggtNttttaSHaNtatNcctcatSaaVgtactgBHtagcaYggYVKNgta +KBcRttgaWatgaatVtagtcgattYgatgtaatttacDacSctgctaaaStttaWMagD +aaatcaVYctccgggcgaVtaaWtStaKMgDtttcaaMtVgBaatccagNaaatcYRMBg +gttWtaaScKttMWtYataRaDBMaDataatHBcacDaaKDactaMgagttDattaHatH +taYatDtattDcRNStgaatattSDttggtattaaNSYacttcDMgYgBatWtaMagact +VWttctttgYMaYaacRgHWaattgRtaagcattctMKVStatactacHVtatgatcBtV +NataaBttYtSttacKgggWgYDtgaVtYgatDaacattYgatggtRDaVDttNactaSa +MtgNttaacaaSaBStcDctaccacagacgcaHatMataWKYtaYattMcaMtgSttDag +cHacgatcaHttYaKHggagttccgatYcaatgatRaVRcaagatcagtatggScctata +ttaNtagcgacgtgKaaWaactSgagtMYtcttccaKtStaacggMtaagNttattatcg +tctaRcactctctDtaacWYtgaYaSaagaWtNtatttRacatgNaatgttattgWDDcN +aHcctgaaHacSgaataaRaataMHttatMtgaSDSKatatHHaNtacagtccaYatWtc +actaactatKDacSaStcggataHgYatagKtaatKagStaNgtatactatggRHacttg +tattatgtDVagDVaRctacMYattDgtttYgtctatggtKaRSttRccRtaaccttaga +gRatagSaaMaacgcaNtatgaaatcaRaagataatagatactcHaaYKBctccaagaRa +BaStNagataggcgaatgaMtagaatgtcaKttaaatgtaWcaBttaatRcggtgNcaca +aKtttScRtWtgcatagtttWYaagBttDKgcctttatMggNttattBtctagVtacata +aaYttacacaaRttcYtWttgHcaYYtaMgBaBatctNgcDtNttacgacDcgataaSat +YaSttWtcctatKaatgcagHaVaacgctgcatDtgttaSataaaaYSNttatagtaNYt +aDaaaNtggggacttaBggcHgcgtNtaaMcctggtVtaKcgNacNtatVaSWctWtgaW +cggNaBagctctgaYataMgaagatBSttctatacttgtgtKtaattttRagtDtacata +tatatgatNHVgBMtKtaKaNttDHaagatactHaccHtcatttaaagttVaMcNgHata +tKtaNtgYMccttatcaaNagctggacStttcNtggcaVtattactHaSttatgNMVatt +MMDtMactattattgWMSgtHBttStStgatatRaDaagattttctatMtaaaaaggtac +taaVttaSacNaatactgMttgacHaHRttgMacaaaatagttaatatWKRgacDgaRta +tatttattatcYttaWtgtBRtWatgHaaattHataagtVaDtWaVaWtgStcgtMSgaS +RgMKtaaataVacataatgtaSaatttagtcgaaHtaKaatgcacatcggRaggSKctDc +agtcSttcccStYtccRtctctYtcaaKcgagtaMttttcRaYDttgttatctaatcata +NctctgctatcaMatactataggDaHaaSttMtaDtcNatataattctMcStaaBYtaNa +gatgtaatHagagSttgWHVcttatKaYgDctcttggtgttMcRaVgSgggtagacaata +aDtaattSaDaNaHaBctattgNtaccaaRgaVtKNtaaYggHtaKKgHcatctWtctDt +ttctttggSDtNtaStagttataaacaattgcaBaBWggHgcaaaBtYgctaatgaaatW +cDcttHtcMtWWattBHatcatcaaatctKMagtDNatttWaBtHaaaNgMttaaStagt +tctctaatDtcRVaYttgttMtRtgtcaSaaYVgSWDRtaatagctcagDgcWWaaaBaa +RaBctgVgggNgDWStNaNBKcBctaaKtttDcttBaaggBttgaccatgaaaNgttttt +tttatctatgttataccaaDRaaSagtaVtDtcaWatBtacattaWacttaSgtattggD +gKaaatScaattacgWcagKHaaccaYcRcaRttaDttRtttHgaHVggcttBaRgtccc +tDatKaVtKtcRgYtaKttacgtatBtStaagcaattaagaRgBagSaattccSWYttta +ttVaataNctgHgttaaNBgcVYgtRtcccagWNaaaacaDNaBcaaaaRVtcWMgBagM +tttattacgDacttBtactatcattggaaatVccggttRttcatagttVYcatYaSHaHc +ttaaagcNWaHataaaRWtctVtRYtagHtaaaYMataHYtNBctNtKaatattStgaMc +BtRgctaKtgcScSttDgYatcVtggaaKtaagatWccHccgKYctaNNctacaWctttt +gcRtgtVcgaKttcMRHgctaHtVaataaDtatgKDcttatBtDttggNtacttttMtga +acRattaaNagaactcaaaBBVtcDtcgaStaDctgaaaSgttMaDtcgttcaccaaaag +gWtcKcgSMtcDtatgtttStaaBtatagDcatYatWtaaaBacaKgcaDatgRggaaYc +taRtccagattDaWtttggacBaVcHtHtaacDacYgtaatataMagaatgHMatcttat +acgtatttttatattacHactgttataMgStYaattYaccaattgagtcaaattaYtgta +tcatgMcaDcgggtcttDtKgcatgWRtataatatRacacNRBttcHtBgcRttgtgcgt +catacMtttBctatctBaatcattMttMYgattaaVYatgDaatVagtattDacaacDMa +tcMtHcccataagatgBggaccattVWtRtSacatgctcaaggggYtttDtaaNgNtaaB +atggaatgtctRtaBgBtcNYatatNRtagaacMgagSaSDDSaDcctRagtVWSHtVSR +ggaacaBVaccgtttaStagaacaMtactccagtttVctaaRaaHttNcttagcaattta +ttaatRtaaaatctaacDaBttggSagagctacHtaaRWgattcaaBtctRtSHaNtgta +cattVcaHaNaagtataccacaWtaRtaaVKgMYaWgttaKggKMtKcgWatcaDatYtK +SttgtacgaccNctSaattcDcatcttcaaaDKttacHtggttHggRRaRcaWacaMtBW +VHSHgaaMcKattgtaRWttScNattBBatYtaNRgcggaagacHSaattRtttcYgacc +BRccMacccKgatgaacttcgDgHcaaaaaRtatatDtatYVtttttHgSHaSaatagct +NYtaHYaVYttattNtttgaaaYtaKttWtctaNtgagaaaNctNDctaaHgttagDcRt +tatagccBaacgcaRBtRctRtggtaMYYttWtgataatcgaataattattataVaaaaa +ttacNRVYcaaMacNatRttcKatMctgaagactaattataaYgcKcaSYaatMNctcaa +cgtgatttttBacNtgatDccaattattKWWcattttatatatgatBcDtaaaagttgaa +VtaHtaHHtBtataRBgtgDtaataMttRtDgDcttattNtggtctatctaaBcatctaR +atgNacWtaatgaagtcMNaacNgHttatactaWgcNtaStaRgttaaHacccgaYStac +aaaatWggaYaWgaattattcMaactcBKaaaRVNcaNRDcYcgaBctKaacaaaaaSgc +tccYBBHYaVagaatagaaaacagYtctVccaMtcgtttVatcaatttDRtgWctagtac +RttMctgtDctttcKtWttttataaatgVttgBKtgtKWDaWagMtaaagaaattDVtag +gttacatcatttatgtcgMHaVcttaBtVRtcgtaYgBRHatttHgaBcKaYWaatcNSc +tagtaaaaatttacaatcactSWacgtaatgKttWattagttttNaggtctcaagtcact +attcttctaagKggaataMgtttcataagataaaaatagattatDgcBVHWgaBKttDgc +atRHaagcaYcRaattattatgtMatatattgHDtcaDtcaaaHctStattaatHaccga +cNattgatatattttgtgtDtRatagSacaMtcRtcattcccgacacSattgttKaWatt +NHcaacttccgtttSRtgtctgDcgctcaaMagVtBctBMcMcWtgtaacgactctcttR +ggRKSttgYtYatDccagttDgaKccacgVatWcataVaaagaataMgtgataaKYaaat +cHDaacgataYctRtcYatcgcaMgtNttaBttttgatttaRtStgcaacaaaataccVg +aaDgtVgDcStctatatttattaaaaRKDatagaaagaKaaYYcaYSgKStctccSttac +agtcNactttDVttagaaagMHttRaNcSaRaMgBttattggtttaRMggatggcKDgWR +tNaataataWKKacttcKWaaagNaBttaBatMHtccattaacttccccYtcBcYRtaga +ttaagctaaYBDttaNtgaaaccHcaRMtKtaaHMcNBttaNaNcVcgVttWNtDaBatg +ataaVtcWKcttRggWatcattgaRagHgaattNtatttctctattaattaatgaDaaMa +tacgttgggcHaYVaaNaDDttHtcaaHtcVVDgBVagcMacgtgttaaBRNtatRtcag +taagaggtttaagacaVaaggttaWatctccgtVtaDtcDatttccVatgtacNtttccg +tHttatKgScBatgtVgHtYcWagcaKtaMYaaHgtaattaSaHcgcagtWNaatNccNN +YcacgVaagaRacttctcattcccRtgtgtaattagcSttaaStWaMtctNNcSMacatt +ataaactaDgtatWgtagtttaagaaaattgtagtNagtcaataaatttgatMMYactaa +tatcggBWDtVcYttcDHtVttatacYaRgaMaacaStaatcRttttVtagaDtcacWat +ttWtgaaaagaaagNRacDtttStVatBaDNtaactatatcBSMcccaSttccggaMatg +attaaWatKMaBaBatttgataNctgttKtVaagtcagScgaaaDggaWgtgttttKtWt +atttHaatgtagttcactaaKMagttSYBtKtaYgaactcagagRtatagtVtatcaaaW +YagcgNtaDagtacNSaaYDgatBgtcgataacYDtaaactacagWDcYKaagtttatta +gcatcgagttKcatDaattgattatDtcagRtWSKtcgNtMaaaaacaMttKcaWcaaSV +MaaaccagMVtaMaDtMaHaBgaacataBBVtaatVYaNSWcSgNtDNaaKacacBttta +tKtgtttcaaHaMctcagtaacgtcgYtactDcgcctaNgagagcYgatattttaaattt +ccattttacatttDaaRctattttWctttacgtDatYtttcagacgcaaVttagtaaKaa +aRtgVtccataBggacttatttgtttaWNtgttVWtaWNVDaattgtatttBaagcBtaa +BttaaVatcHcaVgacattccNggtcgacKttaaaRtagRtctWagaYggtgMtataatM +tgaaRttattttgWcttNtDRRgMDKacagaaaaggaaaRStcccagtYccVattaNaaK +StNWtgacaVtagaagcttSaaDtcacaacgDYacWDYtgtttKatcVtgcMaDaSKStV +cgtagaaWaKaagtttcHaHgMgMtctataagBtKaaaKKcactggagRRttaagaBaaN +atVVcgRcKSttDaactagtSttSattgttgaaRYatggttVttaataaHttccaagDtg +atNWtaagHtgcYtaactRgcaatgMgtgtRaatRaNaacHKtagactactggaatttcg +ccataacgMctRgatgttaccctaHgtgWaYcactcacYaattcttaBtgacttaaacct +gYgaWatgBttcttVttcgttWttMcNYgtaaaatctYgMgaaattacNgaHgaacDVVM +tttggtHtctaaRgtacagacgHtVtaBMNBgattagcttaRcttacaHcRctgttcaaD +BggttKaacatgKtttYataVaNattccgMcgcgtagtRaVVaattaKaatggttRgaMc +agtatcWBttNtHagctaatctagaaNaaacaYBctatcgcVctBtgcaaagDgttVtga +HtactSNYtaaNccatgtgDacgaVtDcgKaRtacDcttgctaagggcagMDagggtBWR +tttSgccttttttaacgtcHctaVtVDtagatcaNMaVtcVacatHctDWNaataRgcgt +aVHaggtaaaaSgtttMtattDgBtctgatSgtRagagYtctSaKWaataMgattRKtaa +catttYcgtaacacattRWtBtcggtaaatMtaaacBatttctKagtcDtttgcBtKYYB +aKttctVttgttaDtgattttcttccacttgSaaacggaaaNDaattcYNNaWcgaaYat +tttMgcBtcatRtgtaaagatgaWtgaccaYBHgaatagataVVtHtttVgYBtMctaMt +cctgaDcYttgtccaaaRNtacagcMctKaaaggatttacatgtttaaWSaYaKttBtag +DacactagctMtttNaKtctttcNcSattNacttggaacaatDagtattRtgSHaataat +gccVgacccgatactatccctgtRctttgagaSgatcatatcgDcagWaaHSgctYYWta +tHttggttctttatVattatcgactaagtgtagcatVgtgHMtttgtttcgttaKattcM +atttgtttWcaaStNatgtHcaaaDtaagBaKBtRgaBgDtSagtatMtaacYaatYtVc +KatgtgcaacVaaaatactKcRgtaYtgtNgBBNcKtcttaccttKgaRaYcaNKtactt +tgagSBtgtRagaNgcaaaNcacagtVtttHWatgttaNatBgtttaatNgVtctgaata +tcaRtattcttttttttRaaKcRStctcggDgKagattaMaaaKtcaHacttaataataK +taRgDtKVBttttcgtKaggHHcatgttagHggttNctcgtatKKagVagRaaaggaaBt +NatttVKcRttaHctaHtcaaatgtaggHccaBataNaNaggttgcWaatctgatYcaaa +HaatWtaVgaaBttagtaagaKKtaaaKtRHatMaDBtBctagcatWtatttgWttVaaa +ScMNattRactttgtYtttaaaagtaagtMtaMaSttMBtatgaBtttaKtgaatgagYg +tNNacMtcNRacMMHcttWtgtRtctttaacaacattattcYaMagBaacYttMatcttK +cRMtgMNccattaRttNatHaHNaSaaHMacacaVaatacaKaSttHatattMtVatWga +ttttttaYctttKttHgScWaacgHtttcaVaaMgaacagNatcgttaacaaaaagtaca +HBNaattgttKtcttVttaaBtctgctacgBgcWtttcaggacacatMgacatcccagcg +gMgaVKaBattgacttaatgacacacaaaaaatRKaaBctacgtRaDcgtagcVBaacDS +BHaaaaSacatatacagacRNatcttNaaVtaaaataHattagtaaaaSWccgtatWatg +gDttaactattgcccatcttHaSgYataBttBaactattBtcHtgatcaataSttaBtat +KSHYttWggtcYtttBttaataccRgVatStaHaKagaatNtagRMNgtcttYaaSaact +cagDSgagaaYtMttDtMRVgWKWtgMaKtKaDttttgactatacataatcNtatNaHat +tVagacgYgatatatttttgtStWaaatctWaMgagaRttRatacgStgattcttaagaD +taWccaaatRcagcagaaNKagtaaDggcgccBtYtagSBMtactaaataMataBSacRM +gDgattMMgtcHtcaYDtRaDaacggttDaggcMtttatgttaNctaattaVacgaaMMt +aatDccSgtattgaRtWWaccaccgagtactMcgVNgctDctaMScatagcgtcaactat +acRacgHRttgctatttaatgaattataYKttgtaagWgtYttgcHgMtaMattWaWVta +RgcttgYgttBHtYataSccStBtgtagMgtDtggcVaaSBaatagDttgBgtctttctc +attttaNagtHKtaMWcYactVcgcgtatMVtttRacVagDaatcttgctBBcRDgcaac +KttgatSKtYtagBMagaRtcgBattHcBWcaactgatttaatttWDccatttatcgagS +KaWttataHactaHMttaatHtggaHtHagaatgtKtaaRactgtttMatacgatcaagD +gatKaDctataMggtHDtggHacctttRtatcttYattttgacttgaaSaataaatYcgB +aaaaccgNatVBttMacHaKaataagtatKgtcaagactcttaHttcggaattgttDtct +aaccHttttWaaatgaaatataaaWattccYDtKtaaaacggtgaggWVtctattagtga +ctattaagtMgtttaagcatttgSgaaatatccHaaggMaaaattttcWtatKctagDtY +tMcctagagHcactttactatacaaacattaacttaHatcVMYattYgVgtMttaaRtga +aataaDatcaHgtHHatKcDYaatcttMtNcgatYatgSaMaNtcttKcWataScKggta +tcttacgcttWaaagNatgMgHtctttNtaacVtgttcMaaRatccggggactcMtttaY +MtcWRgNctgNccKatcttgYDcMgattNYaRagatHaaHgKctcataRDttacatBatc +cattgDWttatttaWgtcggagaaaaatacaatacSNtgggtttccttacSMaagBatta +caMaNcactMttatgaRBacYcYtcaaaWtagctSaacttWgDMHgaggatgBVgcHaDt +ggaactttggtcNatNgtaKaBcccaNtaagttBaacagtatacDYttcctNgWgcgSMc +acatStctHatgRcNcgtacacaatRttMggaNKKggataaaSaYcMVcMgtaMaHtgat +tYMatYcggtcttcctHtcDccgtgRatcattgcgccgatatMaaYaataaYSggatagc +gcBtNtaaaScaKgttBgagVagttaKagagtatVaactaSacWactSaKatWccaKaaa +atBKgaaKtDMattttgtaaatcRctMatcaaMagMttDgVatggMaaWgttcgaWatga +aatttgRtYtattaWHKcRgctacatKttctaccaaHttRatctaYattaaWatVNccat +NgagtcKttKataStRaatatattcctRWatDctVagttYDgSBaatYgttttgtVaatt +taatagcagMatRaacttBctattgtMagagattaaactaMatVtHtaaatctRgaaaaa +aaatttWacaacaYccYDSaattMatgaccKtaBKWBattgtcaagcHKaagttMMtaat +ttcKcMagNaaKagattggMagaggtaatttYacatcWaaDgatMgKHacMacgcVaaca +DtaDatatYggttBcgtatgWgaSatttgtagaHYRVacaRtctHaaRtatgaactaata +tctSSBgggaaHMWtcaagatKgagtDaSatagttgattVRatNtctMtcSaagaSHaat +aNataataRaaRgattctttaataaagWaRHcYgcatgtWRcttgaaggaMcaataBRaa +ccagStaaacNtttcaatataYtaatatgHaDgcStcWttaacctaRgtYaRtataKtgM +ttttatgactaaaatttacYatcccRWtttHRtattaaatgtttatatttgttYaatMca +RcSVaaDatcgtaYMcatgtagacatgaaattgRtcaaYaaYtRBatKacttataccaNa +aattVaBtctggacaagKaaYaaatatWtMtatcYaaVNtcgHaactBaagKcHgtctac +aatWtaDtSgtaHcataHtactgataNctRgttMtDcDttatHtcgtacatcccaggStt +aBgtcacacWtccNMcNatMVaVgtccDYStatMaccDatggYaRKaaagataRatttHK +tSaaatDgataaacttaHgttgVBtcttVttHgDacgaKatgtatatNYataactctSat +atatattgcHRRYttStggaactHgttttYtttaWtatMcttttctatctDtagVHYgMR +BgtHttcctaatYRttKtaagatggaVRataKDctaMtKBNtMtHNtWtttYcVtattMc +gRaacMcctNSctcatttaaagDcaHtYccSgatgcaatYaaaaDcttcgtaWtaattct +cgttttScttggtaatctttYgtctaactKataHacctMctcttacHtKataacacagcN +RatgKatttttSaaatRYcgDttaMRcgaaattactMtgcgtaagcgttatBtttttaat +taagtNacatHgttcRgacKcBBtVgatKttcgaBaatactDRgtRtgaNacWtcacYtt +aaKcgttctHaKttaNaMgWgWaggtctRgaKgWttSttBtDcNtgtttacaaatYcDRt +gVtgcctattcNtctaaaDMNttttNtggctgagaVctDaacVtWccaagtaacacaNct +gaScattccDHcVBatcgatgtMtaatBgHaatDctMYgagaatgYWKcctaatNaStHa +aaKccgHgcgtYaaYtattgtStgtgcaaRtattaKatattagaWVtcaMtBagttatta +gNaWHcVgcaattttDcMtgtaRHVYtHtctgtaaaaHVtMKacatcgNaatttMatatg +ttgttactagWYtaRacgataKagYNKcattataNaRtgaacKaYgcaaYYacaNccHat +MatDcNgtHttRaWttagaaDcaaaaaatagggtKDtStaDaRtaVtHWKNtgtattVct +SVgRgataDaRaWataBgaagaaKtaataaYgDcaStaNgtaDaaggtattHaRaWMYaY +aWtggttHYgagVtgtgcttttcaaDKcagVcgttagacNaaWtagtaataDttctggtt +VcatcataaagtgKaaaNaMtaBBaattaatWaattgctHaVKaSgDaaVKaHtatatat +HatcatSBagNgHtatcHYMHgttDgtaHtBttWatcgtttaRaattgStKgSKNWKatc +agDtctcagatttctRtYtBatBgHHtKaWtgYBgacVVWaKtacKcDttKMaKaVcggt +gttataagaataaHaatattagtataatMHgttYgaRttagtaRtcaaVatacggtcMcg +agtaaRttacWgactKRYataaaagSattYaWgagatYagKagatgSaagKgttaatMgg +tataatgttWYttatgagaaacctNVataatHcccKtDctcctaatactggctHggaSag +gRtKHaWaattcgSatMatttagaggcYtctaMcgctcataSatatgRagacNaaDagga +VBagaYttKtacNaKgtSYtagttggaWcatcWttaatctatgaVtcgtgtMtatcaYcg +tRccaaYgDctgcMgtgtWgacWtgataacacgcgctBtgttaKtYDtatDcatcagKaV +MctaatcttgVcaaRgcRMtDcgattaHttcaNatgaatMtactacVgtRgatggaWttt +actaaKatgagSaaKggtaNtactVaYtaaKRagaacccacaMtaaMtKtatBcttgtaa +WBtMctaataaVcDaaYtcRHBtcgttNtaaHatttBNgRStVDattBatVtaagttaYa +tVattaagaBcacggtSgtVtatttaRattgatgtaHDKgcaatattKtggcctatgaWD +KRYcggattgRctatNgatacaatMNttctgtcRBYRaaaHctNYattcHtaWcaattct +BtMKtVgYataatMgYtcagcttMDataVtggRtKtgaatgccNcRttcaMtRgattaac +attRcagcctHtWMtgtDRagaKaBtgDttYaaaaKatKgatctVaaYaacWcgcatagB +VtaNtRtYRaggBaaBtgKgttacataagagcatgtRattccacttaccatRaaatgWgD +aMHaYVgVtaSctatcgKaatatattaDgacccYagtgtaYNaaatKcagtBRgagtcca +tgKgaaaccBgaagBtgSttWtacgatWHaYatcgatttRaaNRgcaNaKVacaNtDgat +tgHVaatcDaagcgtatgcNttaDataatcSataaKcaataaHWataBtttatBtcaKtK +tatagttaDgSaYctacaRatNtaWctSaatatttYaKaKtaccWtatcRagacttaYtt +VcKgSDcgagaagatccHtaattctSttatggtKYgtMaHagVaBRatttctgtRgtcta +tgggtaHKgtHacHtSYacgtacacHatacKaaBaVaccaDtatcSaataaHaagagaat +ScagactataaRttagcaaVcaHataKgDacatWccccaagcaBgagWatctaYttgaaa +tctVNcYtttWagHcgcgcDcVaaatgttKcHtNtcaatagtgtNRaactttttcaatgg +WgBcgDtgVgtttctacMtaaataaaRggaaacWaHttaRtNtgctaaRRtVBctYtVta +tDcattDtgaccYatagatYRKatNYKttNgcctagtaWtgaactaMVaacctgaStttc +tgaKVtaaVaRKDttVtVctaDNtataaaDtccccaagtWtcgatcactDgYaBcatcct +MtVtacDaaBtYtMaKNatNtcaNacgDatYcatcgcaRatWBgaacWttKttagYtaat +tcggttgSWttttDWctttacYtatatWtcatDtMgtBttgRtVDggttaacYtacgtac +atgaattgaaWcttMStaDgtatattgaDtcRBcattSgaaVBRgagccaaKtttcDgcg +aSMtatgWattaKttWtgDBMaggBBttBaatWttRtgcNtHcgttttHtKtcWtagHSt +aacagttgatatBtaWSaWggtaataaMttaKacDaatactcBttcaatatHttcBaaSa +aatYggtaRtatNtHcaatcaHtagVtgtattataNggaMtcttHtNagctaaaggtaga +YctMattNaMVNtcKtactBKcaHHcBttaSagaKacataYgctaKaYgttYcgacWVtt +WtSagcaacatcccHaccKtcttaacgaKttcacKtNtacHtatatRtaaatacactaBt +ttgaHaRttggttWtatYagcatYDatcggagagcWBataagRtacctataRKgtBgatg +aDatataSttagBaHtaatNtaDWcWtgtaattacagKttcNtMagtattaNgtctcgtc +ctcttBaHaKcKccgtRcaaYagSattaagtKataDatatatagtcDtaacaWHcaKttD +gaaRcgtgYttgtcatatNtatttttatggccHtgDtYHtWgttatYaacaattcaWtat +NgctcaaaSttRgctaatcaaatNatcgtttaBtNNVtgttataagcaaagattBacgtD +atttNatttaaaDcBgtaSKgacgtagataatttcHMVNttgttBtDtgtaWKaaRMcKM +tHtaVtagataWctccNNaSWtVaHatctcMgggDgtNHtDaDttatatVWttgttattt +aacctttcacaaggaSaDcggttttttatatVtctgVtaacaStDVaKactaMtttaSNa +gtgaaattaNacttSKctattcctctaSagKcaVttaagNaVcttaVaaRNaHaaHttat +gtHttgtgatMccaggtaDcgaccgtWgtWMtttaHcRtattgScctatttKtaaccaag +tYagaHgtWcHaatgccKNRtttagtMYSgaDatctgtgaWDtccMNcgHgcaaacNDaa +aRaStDWtcaaaaHKtaNBctagBtgtattaactaattttVctagaatggcWSatMaccc +ttHttaSgSgtgMRcatRVKtatctgaaaccDNatYgaaVHNgatMgHRtacttaaaRta +tStRtDtatDttYatattHggaBcttHgcgattgaKcKtttcRataMtcgaVttWacatN +catacctRataDDatVaWNcggttgaHtgtMacVtttaBHtgagVttMaataattatgtt +cttagtttgtgcDtSatttgBtcaacHattaaBagVWcgcaSYttMgcttacYKtVtatc +aYaKctgBatgcgggcYcaaaaacgNtctagKBtattatctttKtaVttatagtaYtRag +NtaYataaVtgaatatcHgcaaRataHtacacatgtaNtgtcgYatWMatttgaactacR +ctaWtWtatacaatctBatatgYtaagtatgtgtatSttactVatcttYtaBcKgRaSgg +RaaaaatgcagtaaaWgtaRgcgataatcBaataccgtatttttccatcNHtatWYgatH +SaaaDHttgctgtccHtggggcctaataatttttctatattYWtcattBtgBRcVttaVM +RSgctaatMagtYtttaaaaatBRtcBttcaaVtaacagctccSaaSttKNtHtKYcagc +agaaaccccRtttttaaDcDtaStatccaagcgctHtatcttaDRYgatDHtWcaaaBcW +gKWHttHataagHacgMNKttMKHccaYcatMVaacgttaKgYcaVaaBtacgcaacttt +MctaaHaatgtBatgagaSatgtatgSRgHgWaVWgataaatatttccKagVgataattW +aHNcYggaaatgctHtKtaDtctaaagtMaatVDVactWtSaaWaaMtaHtaSKtcBRaN +cttStggtBttacNagcatagRgtKtgcgaacaacBcgKaatgataagatgaaaattgta +ctgcgggtccHHWHaaNacaBttNKtKtcaaBatatgctaHNgtKcDWgtttatNgVDHg +accaacWctKaaggHttgaRgYaatHcaBacaatgagcaaattactgtaVaaYaDtagat +tgagNKggtggtgKtWKaatacagDRtatRaMRtgattDggtcaaYRtatttNtagaDtc +acaaSDctDtataatcgtactaHttatacaatYaacaaHttHatHtgcgatRRttNgcat +SVtacWWgaaggagtatVMaVaaattScDDKNcaYBYaDatHgtctatBagcaacaagaa +tgagaaRcataaKNaRtBDatcaaacgcattttttaaBtcSgtacaRggatgtMNaattg +gatatWtgagtattaaaVctgcaYMtatgatttttYgaHtgtcttaagWBttHttgtctt +attDtcgtatWtataataSgctaHagcDVcNtaatcaagtaBDaWaDgtttagYctaNcc +DtaKtaHcttaataacccaRKtacaVaatNgcWRaMgaattatgaBaaagattVYaHMDc +aDHtcRcgYtcttaaaWaaaVKgatacRtttRRKYgaatacaWVacVcRtatMacaBtac +tggMataaattttHggNagSctacHgtBagcgtcgtgattNtttgatSaaggMttctttc +ttNtYNagBtaaacaaatttMgaccttacataattgYtcgacBtVMctgStgMDtagtaR +ctHtatgttcatatVRNWataDKatWcgaaaaagttaaaagcacgHNacgtaatctttMR +tgacttttDacctataaacgaaatatgattagaactccSYtaBctttaataacWgaaaYa +tagatgWttcatKtNgatttttcaagHtaYgaaRaDaagtaggagcttatVtagtctttc +attaaaatcgKtattaRttacagVaDatgcatVgattgggtctttHVtagKaaRBtaHta +aggccccaaaaKatggtttaMWgtBtaaacttcactttKHtcgatctccctaYaBacMgt +cttBaBaNgcgaaacaatctagtHccHtKttcRtRVttccVctttcatacYagMVtMcag +aMaaacaataBctgYtaatRaaagattaaccatVRatHtaRagcgcaBcgDttStttttc +VtttaDtKgcaaWaaaaatSccMcVatgtKgtaKgcgatatgtagtSaaaDttatacaaa +catYaRRcVRHctKtcgacKttaaVctaDaatgttMggRcWaacttttHaDaKaDaBctg +taggcgtttaHBccatccattcNHtDaYtaataMttacggctNVaacDattgatatttta +cVttSaattacaaRtataNDgacVtgaacataVRttttaDtcaaacataYDBtttaatBa +DtttYDaDaMccMttNBttatatgagaaMgaNtattHccNataattcaHagtgaaggDga +tgtatatatgYatgaStcataaBStWacgtcccataRMaaDattggttaaattcMKtctM +acaBSactcggaatDDgatDgcWctaacaccgggaVcacWKVacggtaNatatacctMta +tgatagtgcaKagggVaDtgtaacttggagtcKatatcgMcttRaMagcattaBRaStct +YSggaHYtacaactMBaagDcaBDRaaacMYacaHaattagcattaaaHgcgctaaggSc +cKtgaaKtNaBtatDDcKBSaVtgatVYaagVtctSgMctacgttaacWaaattctSgtD +actaaStaaattgcagBBRVctaatatacctNttMcRggctttMttagacRaHcaBaacV +KgaataHttttMgYgattcYaNRgttMgcVaaacaVVcDHaatttgKtMYgtatBtVVct +WgVtatHtacaaHttcacgatagcagtaaNattBatatatttcVgaDagcggttMaagtc +ScHagaaatgcYNggcgtttttMtStggtRatctacttaaatVVtBacttHNttttaRca +aatcacagHgagagtMgatcSWaNRacagDtatactaaDKaSRtgattctccatSaaRtt +aaYctacacNtaRtaactggatgaccYtacactttaattaattgattYgttcagDtNKtt +agDttaaaaaaaBtttaaNaYWKMBaaaacVcBMtatWtgBatatgaacVtattMtYatM +NYDKNcKgDttDaVtaaaatgggatttctgtaaatWtctcWgtVVagtcgRgacttcccc +taDcacagcRcagagtgtWSatgtacatgttaaSttgtaaHcgatgggMagtgaacttat +RtttaVcaccaWaMgtactaatSSaHtcMgaaYtatcgaaggYgggcgtgaNDtgttMNg +aNDMtaattcgVttttaacatgVatgtWVMatatcaKgaaattcaBcctccWcttgaaWH +tWgHtcgNWgaRgctcBgSgaattgcaaHtgattgtgNagtDttHHgBttaaWcaaWagc +aSaHHtaaaVctRaaMagtaDaatHtDMtcVaWMtagSagcttHSattaacaaagtRacM +tRtctgttagcMtcaBatVKtKtKacgagaSNatSactgtatatcBctgagVtYactgta +aattaaaggcYgDHgtaacatSRDatMMccHatKgttaacgactKtgKagtcttcaaHRV +tccttKgtSataatttacaactggatDNgaacttcaRtVaagDcaWatcBctctHYatHa +DaaatttagYatSatccaWtttagaaatVaacBatHcatcgtacaatatcgcNYRcaata +YaRaYtgattVttgaatgaVaactcRcaNStgtgtattMtgaggtNttBaDRcgaaaagc +tNgBcWaWgtSaDcVtgVaatMKBtttcgtttctaaHctaaagYactgMtatBDtcStga +ccgtSDattYaataHctgggaYYttcggttaWaatctggtRagWMaDagtaacBccacta +cgHWMKaatgatWatcctgHcaBaSctVtcMtgtDttacctaVgatYcWaDRaaaaRtag +atcgaMagtggaRaWctctgMgcWttaagKBRtaaDaaWtctgtaagYMttactaHtaat +cttcataacggcacBtSgcgttNHtgtHccatgttttaaagtatcgaKtMttVcataYBB +aKtaMVaVgtattNDSataHcagtWMtaggtaSaaKgttgBtVtttgttatcatKcgHac +acRtctHatNVagSBgatgHtgaRaSgttRcctaacaaattDNttgacctaaYtBgaaaa +tagttattactcttttgatgtNNtVtgtatMgtcttRttcatttgatgacacttcHSaaa +ccaWWDtWagtaRDDVNacVaRatgttBccttaatHtgtaaacStcVNtcacaSRttcYa +gacagaMMttttgMcNttBcgWBtactgVtaRttctccaaYHBtaaagaBattaYacgat +ttacatctgtaaMKaRYtttttactaaVatWgctBtttDVttctggcDaHaggDaagtcg +aWcaagtagtWttHtgKtVataStccaMcWcaagataagatcactctHatgtcYgaKcat +cagatactaagNSStHcctRRNtattgtccttagttagMVgtatagactaactctVcaat +MctgtttgtgttgccttatWgtaBVtttctggMcaaKgDWtcgtaaYStgSactatttHg +atctgKagtagBtVacRaagRtMctatgggcaaaKaaaatacttcHctaRtgtDcttDat +taggaaatttcYHaRaaBttaatggcacKtgctHVcaDcaaaVDaaaVcgMttgtNagcg +taDWgtcgttaatDgKgagcSatatcSHtagtagttggtgtHaWtaHKtatagctgtVga +ttaBVaatgaataagtaatVatSttaHctttKtttgtagttaccttaatcgtagtcctgB +cgactatttVcMacHaaaggaatgDatggKtaHtgStatattaaSagctWcctccRtata +BaDYcgttgcNaagaggatRaaaYtaWgNtSMcaatttactaacatttaaWttHtatBat +tgtcgacaatNgattgcNgtMaaaKaBDattHacttggtRtttaYaacgVactBtaBaKt +gBttatgVttgtVttcaatcWcNctDBaaBgaDHacBttattNtgtDtatttVSaaacag +gatgcRatSgtaSaNtgBatagttcHBgcBBaaattaHgtDattatDaKaatBaaYaaMa +ataaataKtttYtagtBgMatNcatgtttgaNagtgttgtgKaNaSagtttgaSMaYBca +aaacDStagttVacaaaaactaaWttBaagtctgtgcgtMgtaattctcctacctcaNtt +taaccaaaaVtBcacataacaccccBcWMtatVtggaatgaWtcaaWaaaaaaaaWtDta +atatRcctDWtcctaccMtVVatKttaWaaKaaatataaagScHBagaggBaSMtaWaVt +atattactSaaaKNaactatNatccttgaYctattcaaaVgatttYHcRagattttaSat +aggttattcVtaaagaKgtattattKtRttNcggcRgtgtgtWYtaacHgKatKgatYta +cYagDtWcHBDctctgRaYKaYagcactKcacSaRtBttttBHKcMtNtcBatttatttt +tgSatVgaaagaWtcDtagDatatgMacaacRgatatatgtttgtKtNRaatatNatgYc +aHtgHataacKtgagtagtaacYttaNccaaatHcacaacaVDtagtaYtccagcattNt +acKtBtactaaagaBatVtKaaHBctgStgtBgtatgaSNtgDataaccctgtagcaBgt +gatcttaDataStgaMaccaSBBgWagtacKcgattgaDgNNaaaacacagtSatBacKD +gcgtataBKcatacactaSaatYtYcDaactHttcatRtttaatcaattataRtttgtaa +gMcgNttcatcBtYBagtNWNMtSHcattcRctttttRWgaKacKttgggagBcgttcgc +MaWHtaatactgtctctatttataVgtttaBScttttaBMaNaatMacactYtBMggtHa +cMagtaRtctgcatttaHtcaaaatttgagKtgNtactBacaHtcgtatttctMaSRagc +agttaatgtNtaaattgagagWcKtaNttagVtacgatttgaatttcgRtgtWcVatcgt +taaDVctgtttBWgaccagaaagtcSgtVtatagaBccttttcctaaattgHtatcggRa +ttttcaaggcYSKaagWaWtRactaaaacccBatMtttBaatYtaagaactSttcgaaSc +aatagtattgaccaagtgttttctaacatgtttNVaatcaaagagaaaNattaaRtttta +VaaaccgcaggNMtatattVctcaagaggaacgBgtttaacaagttcKcYaatatactaa +ccBaaaSggttcNtattctagttRtBacgScVctcaatttaatYtaaaaaaatgSaatga +tagaMBRatgRcMcgttgaWHtcaVYgaatYtaatctttYttatRaWtctgBtDcgatNa +tcKaBaDgatgtaNatWKctccgatattaacattNaaacDatgBgttctgtDtaaaMggt +gaBaSHataacgccSctaBtttaRBtcNHcDatcDcctagagtcRtaBgWttDRVHagat +tYatgtatcWtaHtttYcattWtaaagtctNgtStggRNcgcggagSSaaagaaaatYcH +DtcgctttaatgYcKBVSgtattRaYBaDaaatBgtatgaHtaaRaRgcaSWNtagatHa +acttNctBtcaccatctMcatattccaSatttgcgaDagDgtatYtaaaVDtaagtttWV +aagtagYatRttaagDcNgacKBcScagHtattatcDaDactaaaaaYgHttBcgaDttg +gataaaKSRcBMaBcgaBSttcWtgNBatRaccgattcatttataacggHVtaattcaca +agagVttaaRaatVVRKcgWtVgacctgDgYaaHaWtctttcacMagggatVgactagMa +aataKaaNWagKatagNaaWtaaaatttgaattttatttgctaaVgaHatBatcaaBWcB +gttcMatcgBaaNgttcgSNaggSaRtttgHtRtattaNttcDcatSaVttttcgaaaaa +ttgHatctaRaggSaNatMDaaatDcacgattttagaHgHaWtYgattaatHNSttatMS +gggNtcKtYatRggtttgtMWVtttaYtagcagBagHaYagttatatggtBacYcattaR +SataBatMtttaaatctHcaaaSaaaagttNSaaWcWRccRtKaagtBWtcaaattSttM +tattggaaaccttaacgttBtWatttatatWcDaatagattcctScacctaagggRaaYt +aNaatgVtBcttaaBaacaMVaaattatStYgRcctgtactatcMcVKatttcgSgatRH +MaaaHtagtaaHtVgcaaataatatcgKKtgccaatBNgaaWcVttgagttaKatagttc +aggKDatDtattgaKaVcaKtaataDataataHSaHcattagttaatRVYcNaHtaRcaa +ggtNHcgtcaaccaBaaagYtHWaaaRcKgaYaaDttgcWYtataRgaatatgtYtgcKt +aNttWacatYHctRaDtYtattcBttttatcSataYaYgttWaRagcacHMgtttHtYtt +YaatcggtatStttcgtRSattaaDaKMaatatactaNBaWgctacacYtgaYVgtgHta +aaRaaRgHtagtWattataaaSDaaWtgMattatcgaaaagtaYRSaWtSgNtBgagcRY +aMDtactaacttaWgtatctagacaagNtattHggataatYttYatcataDcgHgttBtt +ctttVttgccgaaWtaaaacgKgtatctaaaaaNtccDtaDatBMaMggaatNKtatBaa +atVtccRaHtaSacataHattgtttKVYattcataVaattWtcgtgMttcttKtgtctaa +cVtatctatatBRataactcgKatStatattcatHHRttKtccaacgtgggtgRgtgaMt +attattggctatcgtgacMtRcBDtcttgtactaatRHttttaagatcgVMDStattatY +BtttDttgtBtNttgRcMtYtgBacHaWaBaatDKctaagtgaaactaatgRaaKgatcc +aagNaaaatattaggWNtaagtatacttttKcgtcggSYtcttgRctataYcttatataa +agtatattaatttataVaacacaDHatctatttttKYVatHRactttaBHccaWagtact +BtcacgaVgcgttRtttttttSVgtSagtBaaattctgaHgactcttgMcattttagVta +agaattHctHtcaDaaNtaacRggWatagttcgtSttgaDatcNgNagctagDgatcNtt +KgttgtaDtctttRaaYStRatDtgMggactSttaDtagSaVtBDttgtDgccatcacaM +attaaaMtNacaVcgSWcVaaDatcaHaatgaattaMtatccVtctBtaattgtWattat +BRcWcaatgNNtactWYtDaKttaaatcactcagtRaaRgatggtKgcgccaaHgaggat +StattYcaNMtcaBttacttatgagDaNtaMgaaWtgtttcttctaHtMNgttatctaWW +atMtBtaaatagDVatgtBYtatcggcttaagacMRtaHScgatatYgRDtcattatSDa +HggaaataNgaWSRRaaaBaatagBattaDctttgHWNttacaataaaaaaatacggttt +gHgVtaHtWMttNtBtctagtMcgKMgHgYtataHaNagWtcaacYattaataYRgtaWK +gaBctataaccgatttaHaNBRaRaMtccggtNgacMtctcatttgcaattcWgMactta +caaDaaNtactWatVtttagccttMaatcagVaagtctVaaDaBtattaattaYtNaYtg +gattaKtaKctYaMtattYgatattataatKtVgDcttatatNBtcgttgtStttttMag +aggttaHYSttcKgtcKtDNtataagttataagSgttatDtRttattgttttSNggRtca +aKMNatgaatattgtBWtaMacctgggYgaSgaagYataagattacgagaatBtggtRcV +HtgYggaDgaYaKagWagctatagacgaaHgtWaNgacttHRatVaWacKYtgRVNgVcS +gRWctacatcKSactctgWYtBggtataagcttNRttVtgRcaWaaatDMatYattaact +ttcgaagRatSctgccttgcRKaccHtttSNVagtagHagBagttagaccaRtataBcca +taatSHatRtcHagacBWatagcaMtacaRtgtgaaBatctKRtScttccaNaatcNgta +atatWtcaMgactctBtWtaaNactHaaaaRctcgcatggctMcaaNtcagaaaaacaca +gtggggWttRttagtaagaVctVMtcgaatcttcMaaaHcaHBttcgattatgtcaDagc +YRtBtYcgacMgtDcagcgaNgttaataatagcagKYYtcgtaBtYctMaRtaRtDagaa +aacacatgYaBttgattattcgaaNttBctSataaMataWRgaHtttccgtDgaYtatgg +tDgHKgMtatttVtMtVagttaRatMattRagataaccctKctMtSttgaHagtcStcta +tttccSagatgttccacgaggYNttHRacgattcDatatDcataaaatBBttatcgaHtN +HaaatatDNaggctgaNcaaggagttBttMgRagVatBcRtaWgatgBtSgaKtcgHttt +gaatcaaDaHttcSBgHcagtVaaSttDcagccgttNBtgttHagYtattctttRWaaVt +SttcatatKaaRaaaNacaVtVctMtSDtDtRHRcgtaatgctcttaaatSacacaatcg +HattcaWcttaaaatHaaatcNctWttaNMcMtaKctVtcctaagYgatgatcYaaaRac +tctaRDaYagtaacgtDgaggaaatctcaaacatcaScttcKttNtaccatNtaNataca +tttHaaDHgcaDatMWaaBttcRggctMaagctVYcacgatcaDttatYtaatcKatWat +caatVYtNagatttgattgaYttttYgacttVtcKaRagaaaHVgDtaMatKYagagttN +atWttaccNtYtcDWgSatgaRgtMatgKtcgacaagWtacttaagtcgKtgatccttNc +ttatagMatHVggtagcgHctatagccctYttggtaattKNaacgaaYatatVctaataM +aaaYtgVtcKaYtaataacagaatHcacVagatYWHttagaaSMaatWtYtgtaaagNaa +acaVgaWtcacNWgataNttcaSagctMDaRttgNactaccgataMaaatgtttattDtc +aagacgctDHYYatggttcaagccNctccttcMctttagacBtaaWtaWVHggaaaaNat +ttaDtDtgctaaHHtMtatNtMtagtcatttgcaaaRatacagRHtatDNtgtDgaatVg +tVNtcaaatYBMaaaagcaKgtgatgatMgWWMaHttttMgMagatDtataaattaacca +actMtacataaattgRataatacgBtKtaataattRgtatDagDtcRDacctatRcagag +cSHatNtcaScNtttggacNtaaggaccgtgKNttgttNcttgaaRgYgRtNtcagttBc +ttttcHtKtgcttYaaNgYagtaaatgaatggWaMattBHtatctatSgtcYtgcHtaat +tHgaaMtHcagaaSatggtatgccaHBtYtcNattWtgtNgctttaggtttgtWatNtgH +tgcDttactttttttgcNtactKtWRaVcttcatagtgSNKaNccgaataaBttataata +YtSagctttaaatSttggctaaKSaatRccgWHgagDttaaatcatgagMtcgagtVtaD +ggaBtatttgDacataaacgtagYRagBWtgDStKDgatgaagttcattatttaKWcata +aatWRgatataRgttRacaaNKttNtKagaaYaStaactScattattaacgatttaaatg +DtaattagatHgaYataaactatggggatVHtgccgtNgatNYcaStRtagaccacWcaM +tatRagHgVactYtWHtcttcatgatWgagaKggagtatgaWtDtVtNaNtcgYYgtaaa +ctttaDtBactagtaDctatagtaatatttatatataacgHaaaRagKattSagttYtSt +atatatagtcttaaaaMtcatgttcaaDactgRttctaagagDtatttttagcgacttgt +gRtgNctgSgRaaaaatgcaMtYtDcatcaaYKttHcatSWgaaaatDataggttatgBD +MtgttataacaaYSgagttacgttatgtDStttaaatctcgWKtcSacgagagaSgttat +BMDgtcggtgtgcgaNtaSHBatBtttVMgVcagaNatcaDDaKMtMYtatagaBccctc +tDtgtatttatatKNtgggtatgtRaacttgaWaaYgcaHatccctggtttStatMtcgc +MtaaaWKttMVtWctVtgttaKDWctgWaVttaDVatgKtagagtcatctaKWgtaaMtt +SacBaMattaKaaHDataattgWtgttttgtcatBacacgtStacaaagtNctNtgtgat +cHtWttcKaagagttttaaaaWacgRacatctNatVStgaatDHgttWcgtRKcatatat +ctcaNttaaBDcctgaaaaaDtaYaHaKttNtaYVaVtttaDtctacttctWttaactaa +ttttMagWcaatcccNKYtBaacatgttgaKgKcgcBHaatDMttatatcSWacatDatR +cWaMtDgatBctHgScttaaaHtSgKtDtttattgtRStWgttccatatttcacWttcat +attgtaHVgaBtacaMtgMaaagDaataactDatattagMaNBagcttcattcgtaaKtg +tatttcacMtgBaVtaattStcttagtYgtgtcgccttKatgggtgaWaataggaatacM +MagaSKRttBgatgacRtgMtagaSRataggtatcaccgaNaaaWSWacDgatacttgat +tagcttgtgVMttatYctaRgHVcDtVRRtSaMtcaVtVtatcaYaHatattaaVaatct +aBtgtacRatNtatttgaYatSaHctaNgNtYtYaYagattVgatcRtaacgYggtgtat +KttaatMagatgRtatatgHaKccHaaaaYtgaacgaWaNgtYHgacagaYtctaVtacc +cgatttttaaagcDttatNRgattKaaattttcatctaatgccgcaataataattgttat +YtagtRNtaagttggtHaKttWMtDKgatSagBYcgRggtWaVaattHtatgtaaaMgSa +aagataaKaaKgttDttttRaagaacaWRcaacDgtgttaatattaKtatcaWacacatt +tVtctgatHRcagtttNcaaatcNctNttttataactWacBBttgBttaaaRaWtBKaaa +cgtatcRcaMaatgYacaaaagtgBataStWYtggtatgacaKWtctSgcKHgtcNaMNc +ataSatattgactacMcataattNVtDaRccaaatcagttttYttagYaacgtaatMtMV +atNgKaaMaaBgattaKttatDaBcttKtccttttacDagaYtacHgttggacaaaVaat +agtYatcataSgatcaaWVttcgaatgaccctccttNtaSBWaatttDttttcaatatYg +gctatDcttatNctttagDcMttcaacWaaNattSYgctttcaHcRaattaataaaatcV +ccRaattactctaMaVRattacagtgRcDtcgtgctcttNtWVtacagtHtatHaBDtcW +ggtgctcaaRHtatgtDgacStgcaaaVKtagttataatactaatatgtagScaatRSac +aattgtattgcagatHHtgBcaatKKtaaMMcaRcgactatKBaMaYatgKatttDaaNt +RatattgtatWttagcaaaaacaWgcacaaHcataYtDaHgttataaSacgcagggggtY +atgcKctaaaHgcVgctBDaVttccStagNgcSgtatgVYaMatcaWRBtVtgYttgtgR +cYttcgctgaacNttgtgtctattWttttcctagMtagaWtaKgatStScatMaBtaSta +SactattYNatctgtacRatYDaatgatgatatgaatYaaaaSHttaaYMaWtDcaNHaB +caYtgVgcatVaacattMRatBtaatttaDacRtagtaaaNYVSMtcagaaDtttDHtRc +YatacSNKaaMcHgatBaaVttactggBYgaYatttttgcDacHctWatcgtagagtact +cattDggtcatKaSgctttatttagtDtRBacttaWYaaaattttgaccttaaWtaatgc +RgccacttMtaggKtcBtgacgaHctttatcgtcStatMHDNagattatNagVaaaWcgg +aaaYcaVactDYactaStattgBHtcYctgggtacatataaYcgaYagaggaggacaVat +acHRtYtctgtaVgaYcNgaaaNatacVgcNgtaatttDcatttttcaacttSNcaaDat +VYctSgcaccttagMgacgcttgaSttaaaatagttaggRHttaaacMatagcaWgMgag +tcgctagtgtKgactaaHttattaWgcaaaaaaSatatgcgttaBNggttaYVatgaact +ttttgccatataaataRatSaBctagttataBccgaaacaagatacttaattttgaHgHM +gtaaKctttaYtaaRacBMtBaYgaBaaacaYtVtagcRgWatHaWagattWSacStMHa +tttaDagacaatcgtgtKtttggaMtgtWtgtgcaaNaaaaWtKaaBcMWtcttctatga +cVgagcgaggHaYYtttWgSaaYYaWtRYHHaMDtctttacaatggaaMctataagcttB +cgHcNWaatttgtatatYtStatctagcactgtVttccagaaattaDtttaRtVataBtt +WagcatDMVactYtgcatWtttgaaMggKaatgaaaaHtataDtgYcMggVaaatSMHtt +tgVttaYaWaataRttgttaYttattttRtWtataaBgtDtttatatcVgaaBcaDtatg +tcaDagaWtgaYtWctcVagctcagctatatagcRVtcaKtaataatHgNaccgaaaatV +HBaatattcgttaVYttatttctBYaatKaagaccVStttcattgaMagSaaaaccccWK +caaNtMYacctaDStagaaatttatcatVgtcaatacccKattgtaaagtggWgtatatV +tagBcttDaBacaattWtDYKtatRKggStRtaaaWatBtaagtaattDaaaaBRacWta +agtacaSttaaatccgctaaccKaattgVWttDattatttattKaMtcYtMRWagMtcgK +gBagacgggVaaNaaatgctKcgtaataaKtaaagtccWcttHMatSYgataaatDttBa +HccattgBttSgaaHYtaataaaMtgaagatgtttBgRcattaRaDHcttBgaMaWaaVM +MattaatttgtgBRctattgKMagNcMtatttaaaWttgaaacatWgcScgYYDYgttYt +VtattgcKcWtagcggtgBaSctaKatacaaVtcaRDccccgtgttBgKgggtHagcgaa +ttaaagMMttScggtDttttaHcSaagaacactcacactBcVgaKNaDHacacttatSag +aattSKHtcagtataaatKaaHtgaaRagaaVcBtaHtaaatcgatcWcaRtaaaattta +WttaagtcaggRctgaWcttDttgactttaVSaaaatggtaWDaRMtBtaaaaaKatBga +tMtctatatcaVaMgatttgNagtDRttDatcttttaMtYaaatcggagttctctaYatN +tagaNcgMMactacHcaagtaaaatStaSaacaHcacSgggtNKatggaaagcggaaKgg +gtaYtacSgccgBaggcRacgtVgDtggaMcYaaaMatggacgYStKKatgaBcaaRtSt +ccSagcRccgccgcSDtgcggBDgaDtBtSSggacMttttaWcatcMatgtNMBWgataa +tcaaVtgaataataaNatgcaaNttNctgacDMcaHccgatgKgWVttccaStggattct +cDacttttttctttaaNcWaMWccWKWttgaaaMctDaaBactRtVattttBtcMaNttW +cKacagttKSttaYaWSactHSaBtHgatgttacatgcatatMtttgtaacScWHBatHa +ctggatatatctgagMgRSatctaaSttaVagcaRcttggaYaatKHtagBBactattcg +taaagaagttgtVcgatgaVatHMtcaggtcgKSgWattgaaaVctccVgtDcaaatgaa +HgMYactcaMatatatattNVttWtWaatttacRagKataaaNtttacaaWgMVactatt +aSgaggVaaagVtaccDRHaaataRaHaRgcattMttcaatcaKaaataDcaDKtctcga +ggBggacctDtttatHacWVaWgatDctaNaNcgKatcMtcMaatBtttggacgtgataa +tagaaacRactcBtattttaKtgSaaggKtaggRaVtatagcccaNRttaccttSMaaga +tcggDacNBatWcgaactacactaactNBtaStgVtNagcatctaVtaKatKgaBtcgtt +tWaagWMgagRaNatHaaaaDtacagacaBagtgcaHaNatctcBccNttaagttDgaat +aaNtcgctaacRBgtaatSttaatatgcataacccaSattKcccttDttggtcaatgggt +tWaacgatacattBtgMaYgaRttatgatKaKgtattDtKWgataacgNBtaccgaKWat +cttcttKtgtcttagcattcctWcaaHgagtatDMSgKtcagcttgVHaKcttDaataaa +VaatttDgtgaaataaRgtcaVaatacttagtVatatgggcatgtDDtMtgtatBggatt +HtgcVtgtgatcaaSattatKYVaacSNNttNWcgaHttKDaaMYHatcgttaattaStt +gctWaacHtaKBtaaaaKHttcRWgaaWcRtBtttggBcDtgtacNttaagcKtaHgtag +aaaaRttgaaacatagtWRaacYggtaaatcgctYaBtWDRtgttgSctaaKatNcattg +tgtMttatccatatagctSacgccSNaaactacgNtgtgcttMatSKtcaaBaNaaacat +aacagaaatagtagctcNcatcVgaagStaataVcDKKttcagDHDtattctaatgaggg +RgBMctatacaagYactctMaaagtcgctttctcgtgaattatNcgatMtttaggcBaaa +tctNtactaaRKtgKactattgtcatatgtacgagttMaaHSSgHgBatatcgcaSaata +aaWgaagtatagaHgcttctttatgaccWaatttaRtaDaatttaatcgaaattgattMc +atcaWaMtaWaKactttctBacactatNgtccttaWgtctgaccKatStaKtgagtacgg +gcgcgtYNtatttagacctctKcatgatKWStcaataactaWgMSgHtgatctttttgtc +gacgtSacttaYgcctWctcctctacaagVtttMaBactWVaccaYtgtSgcgttattcK +tatStgaaKaccgNaataaHtatWtYtRacggcaDaScagcagHaYWRtRNcDtHtcVWt +ggaataaaYttgVaNtgttagtYttgtagSaaatDgaggccDcgBRYStattatttaagg +ccgHgggYRaaccMaagttatSttctttagcMtgcgMtgaSagaNaDagttSatgattWa +tttagtDgcttgagtgMKaYWaYccagcaHatKctaKaDgctagacttattgattaaYtt +atcttattattStaattWaRaYBWagYaatatgttRgScttgBagDaWgcgtgcVDaggc +ttgtctaDRKacttgcaKBWRtaaVaSctKtacttMaaSVaWWcgSaNtttSWgtcggtc +acttggVVtgagaataaataaDttgaaccaaaaMttaaaagaaaaaaaatcNBtatMgcc +WagcaNgaVaNaaaaaaYaMgttaWtatHaagtNtacgacaBtMMattttWNaRtaaata +gYaScKattacagctVKBtWNSKgYtYgtWatHaVatDaaatWgDatcctggSRagagta +aaaMgatttRtaHacatggtaKagVcctgatgaMtaaYgatgtattattttHggBaccaD +ctctggNNtYaatctVttgVtRtVcRacttNctttataggHSRtaRacaaattaacHaHg +tgttgtttcBtBtatWtgtattttgcKagMcaaagaMtattagtStagcBacYaaHcagV +gWtgtttcgtgDHaVtagDatcRaRtggtWtaactgcacgaggaaaRttSDaaVaSttaa +aaacSMttactaNtcaacaattDtacttttYatVSacYtWtMttaattatcKtcttctat +caKDtctStSaaacggtYccatgtgagagtWtagWKgcaBaaaaKttgNactaatcgagg +cWtcDDaaaaaacactHattaattcactatYttaagacactaKaagRtRataaattttca +tHggtaataaatgataHtggctaacBacDgtaatattRtYgtDNDBgKtcaggcHatttt +gHNgWtaatttccgactactgacatVNttYYgactcgctctatttagaMcgggatHcgtt +tatBaDSagBaaaagRttBggttaaBactVHgatgaatttattcaaaattgcacttcDga +cttYcVttactVtttatBaKHagaWgtgaatggBtaaSggcagacNcttaDttVgMtWag +attggVatttacHtctNcMatacttSatMagcttgtNcYaaScaYactcKctKtagScSt +cagtttcatWaatggtgagaggHaggggcaacgcRKtaRcMaNtHaatRaRaaactVtBt +gttaatRtWWcaaagKttccaaKaaatacgVttcacaaacgcggtgagaRaatggtgDMW +atcWVScacaaaDaggaaHtgttSMaaaaaccYccDBtatYgtMagcSagaccaVcctcg +gtVWaaagttatcNaagataataSaataaaKccgtaDtYttatYcttHttaagKcMctaa +atggaatRgaaaVaaVtcKYaggatWcaBtDaggDatccttcYNtgcSMRgaRtNgaatc +gttRttatDVMtagctttacatDVtatatatcagctaDagMtataccYgaggYaaatgDa +aaatSgctctgatgtttVaaBcctgataKtagaaaccaKatatgttaDtgaDtatagata +atacagtaDtatcNtgtDMtYcattRVtctataNtWttggNaSgtMgaaYctctDggHtg +gHDccaccacKKaaacaaaatRatttccctttaagcRattMHctattHaRtataVattgg +atcSttaaHaHgaaHNDtacattSaaggDatttcaaaYgctBcatattaaaKagtgccca +tSctcgatRtaaaMtgWactttNMaWctYgRatDggaactcDcaattaKaactgagtatc +tataagYaaaSRctggtacWtttccWtaYRtKHattatagWtKttaNgcDtatHacccat +taatttataacgctMgaagtaacaacagMgtaYHYVtKMHtacMgKcaaatctgRYataN +tcgttcaatacggWtMcaatYcBWaagYtVaDNagtatagDaaNtaaaYtttcYWttttS +tgggataaMgatattagaaYtNctcttcBagactaYDcgtacHDWccKaHgttcttHgVg +gVDttatcatKaMttttacWaaSattctatagaHaggKaDagBtaaagtcYccattgtYc +atctaNgRgVtgaagtDKttatBKcggDtattRYgHccgtgcgBNMtttVRgacaYctSc +taRacgtagagccgtacRaagtaHKagStSttttgYSatattaaaWHaaWagttDKaaNa +NHaaHttaYcttMtcaaatgKttBtSgtccaaVaattSaacgttgNattgatatNctaWt +VcagtactKcWacgVagggHaaRgaDaatcMttattaataacaBMaaVtgYtKgRgHact +gtactatcBaMtVggtagKcYtHtBSaattagtaatgMcaVVagYYgWtactttccaaSt +tDgaaMaMttcacttYtRgacttcagcttWtttagtgataMaattaagVtagaatatKat +aagtagttaagHMRaDattaHaaVcctDtagtcVYcaataaYcNttNaaaHctcaRaatt +tcaNRgatSHgVatagctRtcatgaBttMaaagRtcgHVtgRgStgatttgtagaKagaR +WRctgNaHYgaaatBctgtttRttNWagaccgagKgtgcggHKVttaatattaatataat +aDtaNcctacaaRgcaNMctctgaaSHWWHcttagtNagtWgWaaKtYaNgcBattatcc +aaaSctRRHKaNtKcBgtgagaDRWBttactaaattSMctatatagaaYacDgatttccV +taagRtgRataatatagtctttttatgtMgtcaacaaNtaaaaactctWtagaVaaaDta +attatagtBStcgaatDtgattVaatMtcaDattVKWaagatagggttgtMRSgtcYgWM +aatgNtagtcBttagtttctctWaaMtVgctWgSgtHagaSagactagKtagWggcattt +HgttgacaaactcggggHggcWBgVgtatgggagVgagtcVcBtDctttagtctaagVWt +HtgtttaScatacMBtKgattatRtgtttgtctttDggcHaBtRtgtaataNataattta +taWctgaYWataStcHaatcRtaaVagDWaSatagtaccNDgaagtatacgttttacgac +gKRtattgDctatRRattVtStaaactagatgVatttagaMaSaaaattVtatYtgttgt +RMagtHaatttSttaaYNaggWagtgcacgaMcactgHgtgtgggHMgtKacttaaYgtc +gcatcSatattgBaagtttacMtYagSatttatttaVtaaDtaWaHcgNatactgactHt +ggWtataDcDScatactcStcDtgtcgtgtatgaggtHaaNKgDattgcBccaagKgtat +gacKSMtttttgttcaaatcaaYtagtaSatgDaaaMccKNaMaatagaataagcaatta +ttataaMgagtgaSgtctNYttattHaNaYYtcDDtaatNRgtatttaaYtaaatcactH +VaHcStccttcccaaVatcVggatKtatgRaaDBgaYtttacttYggactSDtaBcaaNg +gggtattatattBDcttagagYNMatBgttYaagactMatgttRgatacccgtaacacBH +tatKacWgatRcHttaattYtKtStccaaatVDcaNKHHaaataatagtagtatcttgct +NDggVaVVtaVaRaaagSaccgttctcMtVtgNBgtDtttctYgttactBctcRtStWtW +DScMtcWSaRatgaataRHctaNtcStctYtWacagatgtatYBtHaHWBtacggtDcaa +BtatcaggtcaVattaNctactgaaaatWaDgactNWtMtggagaattBaataYcMWYcg +atMYatWtgattSatgaRtDaRgccagtSttatatRaBtattRcWtagtVgaagttMcta +ttatatDttaggtctKtgtgtBagacgttatRKtgatctatttBtataactgataacKcg +gagtgHgtVttcttgtKDgcDtaYatBDatcaatattgttNtaBacatcgcNcaKcaWcR +ataWcVgtacgScaWgttcggHcMttcRccatgaRStYgNacagatacYacWWtggNaDc +WagttHatMaNaatNtcDMDcMaKgHNatScVgatKWatatgNRgtccgYgaagattDHg +tMtcHaSNaaattBatRagtaaatttacaagHWtKatcaagtccHtYcctgttKDMSgta +ctactVctgacaaaaHgatatacataatKtStHgctScSatNatacaYttaaWHtctgaa +tYtagtHtKaggccWBaStaDctaagagNtaatcaatcgttNgaYDaagtaaaaHataga +atcgcgBaYaBgaacSaaWaaaaactccgcMttHttYgtaagaMctKBtacSagattcBa +aWtaattttacRttatcgaRtacaRHgtgRagaaBcttaVgacVDgggaatVatagaact +RRtacgYttNattVHgaHttacaaaaaaaYtcRWtgtgattatgccaSDtttatKWgaat +atSNDgattttaacgtcSRtatggttcttcBtWtttMtBtMScttaHatBattHacYtaY +acattcgttKgtcStSctcKtatatttcaKSgagcttccaacaccRDtttDaccattata +tSgtcWtVaaagttgtagccattDtYaatattDaccatcVDaaRccagttttgtcHacMa +ttcHgaNcatgttKcVttcctgtgcSataaatattgaKtctaWctMRaKggtaYcaagtt +DttcgttacRtatgatggHNaWMtKttcatattaaDaSaBaaaMtMatBgKtttgHtHac +taatcatcgtWaatKaaWcaWtcctVttaaNaggaaaagtaaagaDctNttaDBaBgata +gMgaataacRcYggatcRaaaHaagatRDtVRactaYagttcaccaaWtctcSSaaatcS +KattctggDgaacagDtaDagacagtgtaattcaStYttNaStgtaHgccttaScatMRc +accWtcatttatRtaagatWtNataaWtMNtDVgWttgcWgtgaRttttRgWcttMtcta +HacaaYtKctgaBagtRagacttDatNttaaaDgRtatNcHatcSDgtBatcttacVcYa +cNgaattaacgagttgYgacttDattatacBattMgctagcctagatVcaactNttccta +atgtDaacgYaNatagMatSWtYBaaaRtgMtatSRgaataYaScaVgtaScMagatNNt +ttacaaHBaWtNtRtctaaacDaaaaWMcaNtcVaDNcagaDtgcWKYgagttaHtgcDY +ataaacataBaWWtcggtatgtgaaScaacctttRNatcgttaaagcaDctaatgcBatt +tacaattVaMgSMMtccYaaaBYtggattttcataWttgBtatDtBgactaatgtccWaa +HataaScHttWttDtcgtcaagMctMDtaaaatRtBaaaacaatgtcagcatBgNNBVtt +ttttcBacWtttWtSWWtgaaaaSacgBtaaataaagtcDStaagaactgttaatYatgD +ctattactgaHtaaatStHaagacaKtagDtaaHaDgttccaaDtaaggacactctDggc +gtDagtcWaHgRcHgDgaSctttattgtcttttccttRYaDgNactaaatcaWggcNSBa +gttttatatStKgtcRtgattaaggtcaSBttaacaaKatgggatcaaattgRgcBagtN +tcgDcatttWcctttgtNagDgctgcatttactttgtgtcaBgSatttNHaMcggcagSc +tcKDtWBaagSagWatggYtVatSRgKagattgaVatKttcgatYatKYSgDaacNtcVg +tttaWataWtgVctgcgSggMgatccatgagttgtWcatYWWcctVcNHagtNtgtKttt +gatcaacttaSttattgatNcatWaVgNHcagStVHcggHacaaDttgDttWcaaRaKga +aatKaattagtaWacattgaaatgtgaatgacagtgaRVtaaYagYtcggcatMttgaag +gDgagDRcaKgHtacacaaaMcaBtagHactgKaatRtNttcttcatcatNgYgStggac +tatgSMttgKtDaDgacRRgtWaVattgatttaagYctatatagactaagaggtatWtat +aaactaYaHRctStgKWcgtRtKtYtYtagacgattRaaYBtaStcttaWataatcHtta +taRcactgagtgggagccaattctcDtgDaggHcDRVaVVggaaBtRttaataaRRttgt +aagKNcaVWWgtatacctgatcttBtcttRgaWcaVRKcagttSacttagcgtKtgtYWa +tatcgNttcKaccacacVKctgattBtggacgtctgacaDtWKttattttgMBgKaacaD +ataattWtBtBRtVtacataaatatttgtWtttatagtDtgcctagctHYaatgcaNaaR +caatVtacctgggggKtagBgagaBgRaaNttttMtMagMtgtgattNctcNaKggWtMa +tcttagWgtaatatatNctaYBggKaataBattYtaattataVtggNtcgtgtctaatta +aacctHtacaaactDctDtctgatatgMtgataacWctgtgYSaaNScgDYaWtatDatM +KgcaatttctgNcgtHtaWtagatatcYBttaattactcaaaVattYRWtatttDtaNMY +MttgattataatgcgNggWaatYagttgBagNcaagaaaDtRgtaaaagctgcatctagc +ttaVgtBttatagcKMSaattYtHcMaBttcagtcttgKatgVSVttKgttttttagtgt +DHgNggtcaVtatttaacNtgaatatgctatMcatgaaaBtgBSaWctaataaattatYt +tagtaDtaccggaatgagtaattggatttaacBtctSMgWYtgKgattacgRctctccaa +tgtaggcctgaNaatScgYataaBBacaKtHtttcatgaaHtgBtagaKHVtacctVtca +accaDaaWNHNaatgataattgatgWcagggtcMBtgSgRataHctMctgMHHtKaBtaa +MtMgataaRWtagYtgaaMaSgctYtgcgaaHatDtatgtcWRatKatatYDcBgNtRaR +acattMcagaHgaaagRccgcgWttggSatBagagcHgYtatctVtcatYaaVRtcaSac +aMYDcgRtcaaWgaRgataMtaaaacaggtgtaaYcattgWgDHcWgttaVatttgcatc +taatccacaaagaagSatgcgtagRgagtHDgaVcgtgcttatggMttttcatKSctNac +HcctMaKRatttgatctaaatgHaaScataataatgtttgtgtHaVcaaaaNHaaaatcg +ctgSVtattVttagaaNWcacagtgKtatgattHcYcttgDaWVataBatBttttWtaac +tNaattttctttaaYHaMtttaaaccgStcHaVBaatcRacaaWactgtagVKtNRtcct +agcWaatNgctKccttctcDaBDcatYHatatgcaataaBaagaatgDMttaHcaaYYtc +actgttRtgacRaacctaWtBtBMagBctaaBaWtgatgVtttattataggttaattgta +atYcaRtVctcttgcacSaaMaatactRSgcataKcagcaVNKttcgSatcaaactaatt +DtaHtNaVtgttttttaWVtatNccagWttcgtatBcgttVctcBttaaaaMSaDattKR +cctttcataHaattaatWaaataKcaHVaggaatataBYKHVtgVcVgtcHcttccgcct +attDtMMgWaacttgWttYtttcMcgtcctaaVHtgWtggtgacKtcaWaYMttacttag +VWtacgSatatcgWcKaaatHKaaaYttgtagtcaacWtttggtcaagttgaaBBaSHac +VcgYgttWBSRWggtattttaYDtHatattcgatNttacaaaaVacaMccaaYStaataR +ttVtcttagaVKaacaWcgccgtRatcatctaaatccMcctttaMggccHgYcDgaKcta +tgMRYBagcaNDtgMtcRttgtgHaRttacatgaWcDtgctgtataggNggtgaatagBg +agYNtatcagKtHcatBatgVKgaHWagattRDatatcgYcHagRtaatgWtcStagcVa +tNaaaaKttgRaRBYNgtaaDtStaVRgcMccatMWaaattBDatttaatttataaHtag +tVVaDRMKBtaacaatttttttDaRSgaaKDtVaBatcagtaaMttaagcctRgaNVggg +ttcataatagNatcctacactacgcatgtcggaYgtaKcatggattgactttHtaattWN +RaaWYggttcaaaggaaNtaatgcHcaaaattBtagcttattcaagVtatttWgcctaKt +atBttDYcattagDacKVaYNccgYaYRaaMaattRaagaHtatgcttgcRagcgctSaa +tagaaRacaRacSccagcacVMataatHgRtagcgaKgYRaDcVWSDVgRaMgcDgtaat +tttaYttggtaaWcttKDaaYtatMRcgKccYcagtYcBgRccattcaKtgaSSRtactg +acgHtgtaaaaBatWgcaMcBcYcgccagactcttcSatYattgatgaNccaaaaWaKat +VgcaggtWtBcgttaRMagcaaagtgttcacatataaagaHWtKatctacttatatcacY +RaaVagataagtaattttgatgtBctaataggtaRtaaHaattgtaRcStYSYaWRgMta +caHcNSttVNScattNKaaKgBtagtgatYcaaaStactggttggggaBggtNtgtcaaW +BaYVSNgtaataBNtagtatatcacMcScccVcgtVRRtttNcKaSRNaNtHRttattta +ttgacaatggSaBagataaccgttcctaDNaattgctVtatNtHtatagSccaagctKtt +aaacaaattattgtSHgMWgStttNaccattBMYatRtccStNgttgaaBcctVagcaaa +atgatattcRaBccMWaagKtttttcMtgaRYNaataDttgttWRttattggHtNtataa +tggttgtStYgaMcYVtcattaggtaatVcaNggaRtNataMWcctcYgcgagagRgcHM +gcWtgaYtVSttgDaacgaaaatMttYWtWttcctgaKNttatttattRaattaagaccM +KtttcWgtcaBagKSaWaaacaNtaYaDtBNaaagWtHgacaaagtgVtcatKcgcaatV +aactatgcgaaactccNctatatMgactatttatSaaVttNttRttagHtccKtHtaaaN +atttYVctaatttaaaatHWaNtSacgaaaHggaaatcacagVYcctaattcMNtgtYtg +agttatttaBtcRgBHNacBtactctagaacgcKaaDWYYgcattactVagaYtgaVVcg +caNctttBagKRcSgaaatttgtatccattgtggHcaatRtaVtaSaBtcYYcatcgtgt +cHaVttaHattctgtcaBSNYaKBBattaatggctgtHatattgtBacDcBgatttaaaN +tggaaaaYtNcaKagRRtRgttRtMtWgggatcNtacacctgtWKagatataaYVMtaaD +taaacctctgtgtgccttScacWaggaYacttttKacgtttgtgataKYagaYaVatcWc +SattaMcatBYttYaaatgStKagWattKtttaWgtagaaSgtRattcSaDagVaMatta +ttYaagccSgcNaaDgaaSaggtaNgtWactaWcgHctgaNatttttcaatgtaMHSWaR +tggtaNtaHBtttWWaaatattcVtBtctStWtaWMaBcatttcDagttDtttatatgtt +WBtNaYatcccSgtgagcgaRYtBtagaDacBtaagaataWactaaaagKtaKaWaataa +cKcccgDtagccaaagcggaatcgctSRtacKgcactacccHaactMgtgccaBaRaaaB +VtcgSacRKtttStgatcaaHgKtaaKaccHaccacccKttgagcttcSttttKKcgacB +gggtYMaatcBStcgDBtMcataWtaWaMtgaataagaaDatccSYDtgBatgactBaVt +aagatctcNMgtcaWKtgcWggcgatacgtgtttatttWaDaNWBNaaNtNttcaaatag +taatScgHtMWttgttgaBaDtgNatSaagtttHttaNaNKaattKatttgatcgtVcat +gaatatBtttctaacKaNttVttSagccatRtatatcactcHHatctWSKttaMacaaDa +ttccaRaYttttagttaatattcctYaacVactgctMcgagcaMYtttgaagctagtKgN +WttgaaaMatcaMcttcSVatcaatgtNactaaBagatagagtDMgtNtNWatttSaHac +tagaaaDggtaaaaNctMaatagtaHgacgMaaacMtacatHtaSagaHatYDccagtBt +gaWatcYtVaagataattgatcgacctgcaacgttttattacNMWNcattataDVDacta +tattatYattttgcgaagtgagYVtagYaWaHaatctgWttttatgcHaacgttaccDaK +tatagaccaDDttaacgtHBaacatccgtYaBtVtNccaaataaaatVactDttSKtcMt +DSgaagctaMtatattgattactgtNaagNBcagHaDattaaaWttacacaaatactcaa +tSDatagctcaDttWactttgaStaaDtagatSaaDtgtaatKtgVataggaagWSaaaa +KatttaaagtttgcgtaaagcccggNWaacatacatgttctaRcaHttVtcattatctag +ttttNcataaacDttWaagVtNYtaggctttggtatgagaWgtactNaVatcactVttBK +cttaaccttcMtatcggtaataYaMaYggttgtcaaagSWHctaRMSatVcggactMata +tccgaatcttttttcgagtccagtttgaMtcgcatcaaKagtattRMaaaKDBttDNcca +tttttaaBNtVtccgtaatgaKgtcagMVSattatttaWaattttaHNcaaMaHttgtgg +ctattctacDtgaagattatcgacaaVRHttcSaSaatactNHWaaNcgtWaWgaccgRS +ttNtHtcttcKatYatatBaagtcgctBtgagccatatScctKaagaaKDaWactWagBg +ctgattBagKtgaaataBaaaaagSacScaaagagtagcgaDaYtaMcaYcKtaataMat +ttttaactttgYgtcgaaggacgcHctBcgYgaaVacRYagagBaaYgtagattgcgagt +caagtStDagatBgtgaccctaSWtctDgactaSHttctWatWttctaWtatctYacact +gBWatKKctgtatYgacaaHSatYSaNgSagtatagatgagtatttatgaccMaatgtaH +tStaWttgYagccaWattcagtBaYtaaNaBtaNatactggcttWcaagatDctacggaN +ctatcacatSgKgattgacgacccccgagtNDtattgagaaatattaatcVttNKtaaWt +YacgSNcBHgttgWtatgtttcgccaactKaattaRgacgNataatctacaacKgttBat +YatNMSaaaNtctKgacttatgcttatKtcaVtVcagDaataattYgNtRtHaagcaata +HcacaVgtaNNHtHDatgttaMNtggWagSVaRttcMVDtcttWgtRttctacKaaVttc +VcgcatcctHRKtattSgttSacgaagtcccRDVaacBWagtgYtKtgattgSgaBtgcc +BtcaKacaDatacttHatcattNatttacgtcagtgaggcBtaRNaRcaSgcatattatS +tatgctYcacgtattcattaaRtgStcttWgtattKtSYttNaHaRtNYcRaYtVtggtD +cKcttctactaMcacggcMtacgcttctatatHtaatggcattMDtaaMaKattgaagtB +aaKMVMNacKaDtttKNcgagctaaagtccMMtgagaagVaataatggcaWaaaaVaBgt +aSaVgaaaSaaaataDttVtBccaNagcSBgaMaDaVaVYYRVBgttYMtagtaactDta +agWaattBtattttMDYHtSaStScRaKatattacacctMttgNBKtcRtRggNagtYMa +ttaaatMctYgaatgcKHagSggaaaaBcaggtHtatWcatcgtStagMcctcatgatta +WRcStcgWtgRgttttcctaacatcgctcgDDtRaatatMgtcMtHtMaDYatgDattta +tagctKDtYHaaaaattaSatatctggtctttattttatMtgtYttgtcatactcaaVcY +BgatgSctKtYcctWaRaataWcMgNgcgggagtcttRMgactataHaHtgctNtVaatc +aaccacgSRaDtgKtaaMSKgtaaaaWaKtttVagSDtaaaaaatgttYattttNagMHa +aRtNgBttWattatatgcttatatcatttatKtKaaaagctRaaatcgcYgacgNtacNt +ccVtSaaatttcDVctaatacWgcaMtcttSaaWaaaWagtagtaattaactagRttaVc +SaaatataacHgHatWaattggaagtgcgSSgaaVtgYgSttccatWVataatcgaatat +gHtRcgtBttcttaaggatatgttgtBcNtaatgtcacVatactgaaatMBttRRcRatc +catagagggacatcgccWttagttgWttatKagtaaaagHtttccttSatVatKtgagca +atttattaaYVattcaaattctgSattRaMtgaatMgttattattacaNcggVagcctta +aKgccYcaaDattWtggMcttMacWttccMVgtgaattctDaBYgacttKYtBacatgct +DcRaaKaaRaatatctttagKcKtaactttaatNaaggctgScacctYgcgcaaaccaHt +tVHcBaDgtaatHaHVaaatMgttggtSatHtNNaaVagtgtacaataaagacgKttcaa +aWVacagctcacWHaatcctgtBNWtaNMKcVcVSWtSgcaattctgKtVVaaacaRaat +tgatRcgBacaKacVccVMactagcgMNaaactgataDaSgagaatVHaatVSVtccgga +tgRgtagRatttgtaactaBataVaggcaagHgaaSMSaKgctRagcStNcatttVgcta +tacttcNDtcaKBDcaHtDcaatagttHttattMBgagctgtaaagtMgatStStcagat +atYcBtataacRcaggRaaaggtaWSatKgatatgagcgtgMYatcagcatVttSgaaaa +aatatatgttYttcattatacataatVcacgattataDggttBtRaagtHMtatagaDgN +ttggDaKctBcaaRcgattcgtgccttacaaaWattYWVcaaWagDattgaaagggaaga +HattBtatVggtaHtWtaMagtccagaKttSatatcaStDtgWaagtKWaggtatttaWa +aRcattaatStgaaVtacggaacatKctacatHtaaaBtcNWatttBBaNatRcDattcg +aactataaattataactcagtSgatataagRaYaKHctggtaaNtttaaNgaRHtttatt +atacNttttaDccttYgtaaacaggaagtgataaacatBgaSgtaaaaaaVcBgtWNtRM +ttBttaaBgtaaaatatcHNStaBtaggtaVatYaccNtBaWagRctNSacRtMatDact +StVctaaDtaYSRgttaRNttttKggccagaaBcatagtYcaYNtDatcgtatVcaatWR +taggaattMcatRtgggatgtcMggMtttataagtaBgtggacNaaKYtgctWgagYtWc +ctWtVcttaaactaRacatggtRcatctSDcHcMgcaactttttagttaccttattHRgt +acggcactDBggtMHcVaaRatKctSHacctacaccactaaHaacgSttagKtKttttgN +HVgagtaYaMtVYNVcggttaSBaBtaatttSRcgtBgaWaatctttttKggacaWKaat +tKSaccttgDRgtcatatDatVMtMaVcgaattaNaagMWccctaaHgataatatgtatt +WataaaatBaaMtgRttcHctaagctaagatatattMcggactaRttttKaSttactWYt +gBcaMMacRRgNtactttaaaSKtttcaYBaBttaVagtRtHcWaggaVccttNgtgagt +catataWttYScMtWgVRgattWtaSggacggWWctBHatattataaKaagttactaMRa +aataSRaDttDaaatataVHaatggaaBDgWgHtcKStVcatHtaatcatggBWaagHta +gtMtgHcHtcatggggWcatacaHNHagcDatRcaaattcgcttgDggDNVcaacgSgtg +gcaccttMttaatattVYtVgaagRttaBcagVaYaHcaRDBagatgaVHtNMtcttact +DaggMgMaattRWDcctVtgagaaaaSKatHHttVDgtctgtcacatHNttgaatSaagt +KBatatagacaaRVctcWtgtacKtaacHtgHataSgVtactaggtttatggBgtcaaaY +aDgaaaaaatcgMtagaKaYatgaattatYcttKtacaatttgWttMaatBgaatSttMt +NaVgVtScgcttctBHKgtaRcNBaatcDtacgattgacgtgctatNaaBtMgagNgKct +tWcWKacactYgttVgNcgaattttcttgaaaaactacccctcgcNtgMctatcccacMc +actcMatttatttagtagaacMNtttcttgYKaWtaaBtttcWttagHtgtttctcttgt +ggctatgDgctaatWDataatttagaNcgcRRNataKtctaataHgaaMYctNaKWtact +aacDtgaVcgagaactggtaccaactHgaggctagagHHagtMgKtaaactacaggMatg +tYgSBaKaaaattMgatRtggggtHBVgttaattgKttaaRDacgMactcaaacStaaag +ctctgtgccttcgtSagtSaRctacaataKatattctaVgtgtaattRacKagttattga +MtaatgaNatacDataaggactttccNtStatatKaagaataKtatggtcctctatgagg +ttaaDtgtattgataaaactggatcactKBtttggcgtcaaagaaaNtagtWKatctaaW +BactDaBaYtacaWtaSgcaattattWgaaBgactgaKctatBRgtagttaBaRRgattt +aagBHctStgtVYRtaaataaagtMWtcHgcattcacaaMWtcMccWttgVgcHaWttca +NtgtVaggNgcVatKttataaWDcccctatgatVttttattacagRBBWttcttRaWgaa +tBVgcgtHgWgaccagtYacaattgSttaaMcVtDatttaVttRgttKtcaYWatKtaaD +tttWaYtaatYctSctatagtcctBtccMaMMtaMYHaSSgKaaacttctcBtMtgDtgt +ttttagRcgtacttataHgKtNtMtKcBtaNKaHStgSagYHtataDtcKtagRtNWaac +VgctVtRtttStNtgaaccttaVatgagaaggtcaKSttaDataagcYaSatNStcaatD +NgttcgacaatttaSgaRaBNNacattRatNtgSttHVtgWHgtSHccaactKttYtatH +YttVtgHcNgactMcaacttBatatgSgattttacgtatttgtggtScaacggYtHtgca +tctatttttWtaSatcagaYatcgcagtgtgtMgtattctttcattaRatttStcaatat +gcttDtStaaagaccDcVtaWNcHYtWMaMcgaacKcaNcttacctaBtgcDacatcaHK +tRcDaaacataaRacNNtccDataNactttatBSDYatDtctBtaBatctDatKaMcatt +MatatcDHctaagRgYVcatgttcgtgataHDYaagttSgHYctaaatgtaaaactNgta +gaaactaattRaatcttttBKcgaatSctMaggVaVaaatgagataaataSgttKgtcat +KaKatDYtaaaRttYaMtgctcSatRtagttttagcaaNtaKgatcgWYcacDgaatcaa +tactgBgaNtaactaaWatatacaatacactaNatcaVaKaaMaaaaaatcaccBtgttg +NctaacaBattttaaKWcaggataWMtaattgtaaHtgVtcgaHtScaHtctcHacVata +gtaMcaaKtcccSagMYtWcaaatHHtaagRttDagtMtcYtttaaWWaaaVaRtcHNtc +tcSttagcacaKttgtagtNgWYtatKDtcatttgaacctcKHtatccttattcttNggt +BgtgtKaggWtYgtStgtVaRtaRaaagtagtgtcgcKtKagatgagYtttaatKcScct +gaaaaaRaaHtttttaaaVgtatagKctaNtKaSVgttcgagacattttRSatagttSac +ataMtaYHccacttttctatactagtatgaBaagctttaMtgaatgtcaKYtaaatatgg +attataNcgBHatcctaRaaactgttgacttYaHtStcatcctDaMBttgtaWgagtaat +WKataaaBgBattcttttctttaatWStaatacgNaagtWaMaaNgactMtgaaDaggaa +aSctaSSgatatDttattatcatagBcaataVcHcRgcStaHaaatWagatHttMHacta +RacttaYaaaaNtataHKVaataKtatgatcgtcVaaWgttYtVcaaYggctRWttaaKt +RttDaKtgtatcaattWKaatBHaaaaNgaatggStHgVVgatMgBYtaRNgBDttMcNt +ggaNgtcaHtgttDcNaggBtatYtacVaNttctcWtactHYcSctgtYtDtgWaatcHg +atDatatcHtcttatattaaKaRYaDgaatgSYcgactgcRgaagttagtStYatYtttc +cgacactacagKcaaagDttaatVatcttaaacRaDatRcBatKNtNtaaaHtcBgatKH +cWStSRaKaSMgtaKaBacWgDDttgYaaYttaNtDgHtatSaSataaaaMBaaDtaMat +DaagWtggaMtRcacttatggctNataaaaatatWNMtacctatgtcaYKaRacagttHD +agccgtaaYcaatataatcatagggaaSatgMYBcKBBtaaRVRatRtccVtgtgaagVN +ttcttagtgtcWataVggtaaNaatVgVaKctttNgtttagtaaagBatBtgaYSagHtt +SYaacaStcgcagaSttcDBtKtttggtctacNttgNgKNNtcaaaaKWactgaaYgaYa +ctatHtaWcaactgttSatNVtgtctSttYctgattVaatKgtaYcaaattSgttaStat +ggtccaatgSWccaaactattgccgttacgcNatcHctctcaKatgtagtctattttaag +gHRatcDaagSaVgaVNccaBKtacgtttStagKgtctaHtcattaYcctaVKtttaYaa +atYtccgataaaVttcDgatWcgBtcctaatttNaattgctDYgtgatcaatttaagggc +tctcatcKattgBtaBagcaYcKctctttNtaacHacNStggRtMatHHgtacatgcaMa +gtgtccatRWttRKctaaaDtcMctttaNVgaNtcMatcacHcctgWtaaStcacgtctN +aagRNNaagMaDtactDgctttttcatcYacttaKttatgcStDaStNaMgDtaacKtMt +acctaaWattggtttNaaVHatgaaattaattacgVNaaWtggaWatctgVatcacYctc +VHMtVaNacNtcccaWtttgcaacctcWctHaatcttWcaaaYaBaattSctYatctaag +DgBttagtaSgaWtBcRcKtccYatatcKBgtctttatgaaHDcgNaMatggatgtWagR +ctStagagaagaacagctWtNtataaaataRatHatKgctNactHgttRgRgVcRacatg +HYaNttaHtattaNStaagatgtagaHcVctcYgggccYcaaaatgatcttctagctctH +MaMMgcaVtgHgtaagaWHHtggtaactBcaMNNctagaacggWtctttgaggHcYNaaM +HtaYcttKaagtSccgttgggNMStatacDttataaaVaYcKtcgcattttcgacctctc +acVttNtttattgtcttctaVcatagaattMttgtHtMgacataaatagttctMtgtWgW +ctttcaagYgcgtNaagcaaDaVHaaStMtaaagccccgtgVgtcacatcHVaDtgttBt +BacBtcggYttDagaDYtccMttagcttacNcgaagatRtDataRtgctaatatatgRtW +VttatWKtgcBgactcgagaSgtaaaaagttaaWaaagtatttctcWtatcBtcataacN +cgctcRKaaDKactRaNtagtatBtgaaatttcgcDactttaNtYgagagaNttgaatta +ataaaSMattRHNtYtgttgaDBRBttgWttagSatgacDggNVagRWcggctacDaYSg +aaattHgtYaaagctccVtatacattaMctttgSgacatBKaattRgtaBRtttaactat +tctagcMKMtttctgtgtgVgtctttcDcgtaaMtaggtaaaDtcaYtatccgattcYtg +aaRttctKaNctaYgYaattYgRttWctWttaaaccaatcactVatgcgYttgaaatgat +KBcNRgctcatgaccHagcgaaaatgtVgccatcaBSatKccRStSattaaatttggtaa +gcVattctgVcattMtacatMgaaaaaataYNDtDaatcatWattcaggNcaccctcBtg +cKcHagYtatBatgBttgtVttaYBgBgataaHNtacRtcaaBaKcagNtcagaatYgtt +WgggaNDagtatagRtctcDtDaHScagttcYcatcSYacHcagagNgtgcHagtacagc +tgRtatatMtaatRaWMHgaaKacaBRtagHtaaaNcVHcatWBgWaaacWccggtaaRc +attgMgttaNgttVMVttgcaagagaatcaaaaaagYScKVtgccgacHgacgttcaMcc +tcattatgcBttttaagtKatDactccgBatHYgttcatcgaaatctSaKaagaatWVtc +gttgtcttaMaaYaSDtaaaataccgcKMtatgKtgScaaDMaaaactgtgagcVtttaR +cttgtaNMatatatttggtMgYVatDaatttgctttaaRtaBgttaYaaagKtataMtWS +tcHaaaaNacgctacMttDDgactacaNaatBcagtcattatatSttaVgRtWgSggcaa +tSataVgSYgctBttataaYRRgaactgtgHtgacHWSactYNgtttBactatWStaNtc +StcMttgattStacctgaattctWatNaaHgMatattcaaaKWaBaataatHKgaWgata +YcaWMBtgtacKagaaaaagaattttWttDaMtggttgtgaNMtVtDcaacNttactatt +acggKctatttaaaaBKatagttHaatggaatatYWgtaVtNaaYgataatMaccWagag +atRttMtgKaMcgatattaacaagatgttBBcNaYattcNgtRttgaBcctaagaSMttc +MtcctcYattcaNaRBttaatgVcMNgaacKagatcgNctaWVgttaaYRtgctSctaaa +aNtttgctaaScttcVattaHtaaMacNgttNtKHMcctattttaRtttVtSgtacatBg +tVaaSSaMVaRBcaSaRHtaWtWHttMtattVcaMtWaaaNaccccgHYtcatagaaRta +aBaatttaBccaatcRctcatagWgcBHRtacaaDttcBgaHggcgctaHtgacagcSNa +ttcctcgagaccBggtcaagWctgVcRDgVtaagtttaattatcMtgatNagYttHtYta +gccRatagDtaatcNtaKtacaMSgDaaaatttgHaHtRDgtaattKtaMHgaBcaWtBN +YaWgtttStttaSttgataatgactMKatHBtttaVcYatgggttttaDKcSatttMata +tcagtYaBtgVacaatHcaDMcccgtaataatagDataatVaaagaagaVtctccgaRgt +RtaatcgagtcacttgttSatgNDHaSNRcggtaSaagcSaBgWSgcatcaaWatgttac +atgattcWacMtagtgNcacgatgatttttRcWttSgtaatMRRBaacNWRHaaBaattD +aagStgatccttcaDacccctKaagScSSHaaYHWcHcaWcaaaMBataattgDtagccW +tcRHataMNKtMgHaBcatcgaagtgtaRgtgggaVMatgttaWRtStBHactaaRaact +NctcHaaaggcatgcVHKHgaatcSccttggSaWatWtNcaaBctaRagaaacacgcttc +KatRattcWtgYDaaaaaaNatWtKgaacgtNttactgWHBaccaWacggttcaaVgaga +aacVtMttatagaagtatWtaaaNHYaMacagWagtaatttgcatcttcgaatacggaHt +aatVattctaDaHtRKRaNHcttacatcDKttMDKaWggDtaatcttYctcWtRaaaaKt +aatcctgccccatgcgDtctaaVMtWRKKDctaatatDgactagWtaaaBcKcacMactM +HHttgDataKHDaDttHttatttagtcaaVatccKWtacWtSVcaggtaatatDSatgcc +tKtatDtttagacKaaaagcgtttaaSaaaYtgattgtKtgBMcKttgDaaaagttBRat +HgcaKgDgtgcWataatMWgcVaVatcYgWttaDatcatNaVgtttgggcttgaHRDaWg +atttctgMHgtVtgccttBtWtaatcgttcgKgRcaBaRMtaattWgctaatMaVBccaH +tDagaBNaataRcacYcYcHcatBgaNtgaNgKHttctYaacaaaYgBttRNtNggaagc +WtDggattgagtHaWttVacaaaBtgttaNctaatactKaMaaaaaDtaRatttDaaagN +ttcYcaaactcMgaYgtacaaatMaaatYtcacVaacgaaDagatWgBgaataggtWtKa +aMtgDttHtgagttaatttgVaaDagttNMataatttaSVattNaDtKVccaaatcgaYV +taaaacKRaataatgaBDtctRtgVcttatttYtgaHgttBWatgaatatacSaacctSa +tNNRccagtactKagaRtgSKMcgaaDattttagtHcKcaaagtggtataaaggctccta +SatHtaMtRKattaNRcWtccgctataKggatWttaggtaatHDRatttattRWgcgatc +ttagSgtcttactatgYgttYaVBtgcaYaaRtDaatacHHtDcttHgBgNcccataDta +aaaatctNtacatatWaRMBgaattaaaacgctctctcaagtKcacNacgVRVcttttta +acttgctcStatRScaRaMataNaKagtatcattRttNaVatcKgtacNatttttgaNcg +acaaKctHWtgaKStacMaBatgWttNSacaaKcaDaatcWaKaccgYBggMScgaMcct +agcaDatgtttcVatgtRBtKNWHtcctWDtatttttNNSaatattcMttgatKgNgaNB +atcSggtctRcttttttatatggtNttDYNYgaaaKctcacacYHRgttacatacttYac +aataNaagaaaagttataNaataSatacagttScacVaScaccSWtccagKHtaatcaaa +tVacatWacgBctccaataHaaYtMtacKacHttttKtcataWWtgtgaatWaataaaaa +catttcaccttaHtttgttccaatcccgRBaWgatKgagtttBaVgaNtaNVBgcaataa +gaatagcaKRttgtatcaattaMtaacatataDBgtaaNttcaNcgagatYactggttat +gtNVtaBNtDaaDtDttaSaWtactaVtHactttNttcttcatWttcDatKaacgtttgg +VDaDtVagttatgtcagactKaatcaYtSgttttataaataDttKttKagacWgHgatat +aaatcttagatNKtttWtWaaatattacSHaRgtttScttaatWttacgRRaaMactcat +BacaccatRtttgaacctacttcDMggcVaSBagaatcttaKMagcaVtctDVataWtSg +atagacttBctDtBNWgtgKatWctYgaaStccgVaaaDattYatagtatcaacBaWYct +gaaatttaKVgYtStNtcaVggtggaNYgaRtMaacataSttcagacVactcaVaagtgg +tattaaDBNDaagtatatMtactatatgatRSgtttgccaacgcacRMtacRYNataaga +tcMgttgatcataaacttVcatatgWtacaaaWttggaaactttaScataactRattMtD +acVYataaaagMaattttKtgaBttKcaacatattVtagtcatgactcgDaacDtaWcta +tRttSSYNtgWaScaaataagaaatKtagacataatggNaatttcSKtVWtgacagKWat +tcgVatttcKWgagcaWgNKaaaatatgtaaacgttcactaaWgacaccBNaacagaaSt +ctgctaHcVtttMtcYttStagYcgtttBcRtaYacttgNaacMtDRtagcatgtgcgag +cScaMgtaatBaKataactMttttattaRcattattatacgtaagSNatVRgcttcgaVa +acHNtctaHBKYgKaccYcttagagcccaVgatttgttagactaaacgtgcaBgccaWga +VataggattDBWaattttgtBacWtttttaatDtMgaactaagcVtctcagBMKatgatt +gaNaVttggatDaSaBatttcgccatatgctaattgYacatgatccacaaMHtttcKYKa +WtYcgDtNaaDccgNaNcacacHKttDtttaggctagRVtYgtaactagctttcacaaat +YtHaattYacaattaMSagMactcctcatgtScttcaaYtataaaaScHYaKcaYacact +VcacataNtaBcaRatgYagVBatttgtaactttgRggacaagcVacctattacRcaaMa +cHRagagtaVNctacagtgagacgaaaggKttacattgggacaataKNtattcaagWKtt +gatNagNtgctaNgagatNacSatctNatttatctatRgaaaatKatNKSBcKactatac +StcagtaggtVtcaaaBYYgctattKtWNttcRacaaaNatgaacttaRtaaDSttVBYt +aatccagtNaaacRttagaaccRBatataWaatKctcattcSacWaacaacactDttVtt +gacYaagagtaSgcMttBttaVNgRVagKDcttcttcNtaggttgcgacYacttaaggVH +caagDagaagataaVaatctgtatRatDtKaaSDgattcaattYtcatgYgtgaVMtMaa +ctaagaatgRgDtHttaaccaatStaaaaMctVDDtgttatcttaBBgccNacKMaHggc +BMttctgNctHggagaataYMgtaMccaataattHttYttKggtKaccaactcccHtMSa +atNactcRtttcatgcKcatgcacttcatSaatatactttVtaYttDattgWcctcactc +YccattaDDaHaaKcaatSttagKtWtcatRcaactattaattYaDggKtagtNcgSgtt +tKRgtDWtVHtDNcHWNtKtccgtctagtatSctaBcacgcaBtaacatgagatVtttaa +ggcaVttBttaStWtattgYaggtSatBMBDactVtggttDagacataaactactBgcac +aacMaagaStccaWNaaSYMYtgtaKaMcYSaHaaaatatttMgtcaaDScaKtcaBVta +MVMRRDMtcttRBgWctaacttgaacNaatgttWgtggBtRttHVKgKcHVtatattSaa +aatBttcBtttcDgHccBagtRBRttaVagBctRcaagcattacKccaWVWtaVcggtta +tNaSgccgKtYcBaagcWgcatgaNHaKtagNgcHcgtgtcataaaatagagacttgHYa +tattctaBgtttatRatctatttagacattttNtWaaSagtaHatRtctcggatttatgt +gatBtctRggggcatWctaSVMaRtcatgKattgRcatMaHaataNcBcDcaggcactat +tHBgaatStatattcatBgMVataaSacVacKHatggttaaBKtgtaSaWMattttMacK +tgaaWaaWgctgRatgtgDacBtSaHtDgtgtMVttagatgattagagaSttgattgtSa +aacagHaaatacaRcaccBtaaDtcaMtKaaStttatKagaataaNcaaBtattKaVNaW +aNactagtYattaaagWgHttaMcKaSagatSactctatMSagtggaYctcacKKgaSMg +cRgKtgccagNMataatccaVgatcttHagttttcttaaccataggggcttaDtYatcga +aaMataagcaaatBttgHHcHagacagagaggcacWtacccMttacgtgNttattYctVa +aactgttaagtKatMagttcacaaagggatgaVNMatgcaSattatcKagtHaBtgaagB +cggagtWttVaaDaccMScactgVatccaRaSatattNtgcBatgBaaNgtcaBMgggaa +tgagtatRgaatgtNttacaggcttaHaataaHSagatagtgVctattaaagggaagDWV +ccatcKaaaatRccccaSVaaatttMtatStgtWagtStMaaatBctgcctKWgttDDaS +KactctaaVRtaSWcVactggaaaaNMaaaccgcacNtaVgaagcttDNgaDBtaMaMKN +tKccaVtgctcttMMYaaaaHaattcWgHcgtacatWaMaaKtaataccgBDaYRaggat +atSKcScYagMtaatKHMtaaccatgHgtagDaggtgtaaatatagaKVgccRYctcRaK +BKWtgatHYcaHgBaYtttMcatataatgaDttcatttaStgtcVSgacggtggVgtBtg +acatgtaaSgtBgatKtKtaYcatVtNattataaaHaSccHaaagctSMKattcatagca +cagtgBRataacaatMttKcWaaaaatagStcggRttaattatWaataatMaYagatgVt +atccttttHaScgtBgagWcatgBtgcctatcgtaaWHacagtactgaattaaaaaNatt +RNMaSSNSctattcaaagccVVcatattttagMcgtattNtVBactacScattgKVtata +aKtttgNaWcttNacctagtgaNaaDcagtaWgKggaaKtacgcaaaYttatacSttgYa +YttcDNagggttVDagHatSgtacYVatataVattataSataacgKgatVtVacHYRWtt +atcctaaDtgtaaDgRDttttattWtaaDttggatcattNgtVaaaVggaaggcYgSWaa +attcWHcgaSaVWaMatctMDtHBgttttaatctaWaagatatDKtVttaccgaMatRaa +aBttaNagHatDHWcDtBVttaatKtMataYttSRHHcgtaHDtggttccaaagRRtaWt +VctRcaNDttatacgatMcaatNHtacgaattBaatHtcccatctctccBtgtataYcta +tgtcgaaDYWtNggatNcacRtMaatNtKcttSYSctaDaaaggctDaStatKtataBgc +VaatttggYcttaaatgatgtHctaaccaactttgggttcMaaDattatKtVacgVcSca +actSataSccHttYctttgtggcDtMcactaNSBtMRBMaggttWKtattaatgtKHact +tcaMVatctgttgtccaaYNtaagttKaacttctHcgcWtYttatMBgBaMacaattaDa +actNaaatSatcVtSSgatctatgNatSYaattRatgcDgtctataagagaagRgatatt +tcccaataHgttttWKtgaagNRtctaaBtWcHHcDgaattgaaaKtgttaaRtatgtaM +aggDttcMaccaMaattDctgYctaWtStaNtgRKaBtNcMHcSttMtaKccYacgNNct +ttatStgVtaYtaagttaagaBHaaStVKHatgttRVWtataMtSatgcaattcMcttat +KgMcagtgaatcYtcctNaYcttactttctcttcatggcgNcatScStBtagctWtHaaW +attaccgtctcgtBMcaaacKctcccaacttBgtWStVttMRgKcVagHttVtaagMaNa +tcaHttacatcYKttDBtatgSattVcgBcBVYttHNtcatKgcYgaaSaKtatttttMt +ctatctaSaattDttcWagHSacgttagYgacWaSaDKatcNgctaatgVSctgctYgaK +gKtaataggtggagcgtcgaaaaRYtgYWYSaatacBgacWtaNStcaattWtRctttta +aSYgttcNgtBWWgtgaatHttttBaMcMtKccagtattttcgaHaDtSVgatgaacatg +cacgtcagagDYattBcagDctcttNcNtaaaatRctgMcDacaagtttagtcaaSSaag +aaacatacaDtctctYgcaaacBcaagaBatgtattgacgagYacBDgttcgtgRtaMga +attttcNtgVcttctgtctagtgtccatatctgatYatNtatVWgttacaDacaHDDagW +tgataWtatcaaBRatDRtMgVcgaaattcSMagYgWacgggtaacaaattcagcatagS +gttactBctgSVWatYcYgcBWgggRcHtataSaattBcagHgcgcctttKcttWaggct +ttaaDtRacBactaaVaaKtaaacctcgcgccattactKactKSDcgacaVtatatagga +taKctcgSatgHSatVcgtagtgaBtSYtgaBataatStaaccaagttcaDtHtatatta +acYatattatcctacgagatcaccgtVSttctYgtcataaVactcgWtaVatttgttgga +ctaaaVcaSaDtYcgNtYtctVaMtaattatWRtWcaNtaKcaaYggatgNgaatcaatc +RtcgagtHcgVgttataHDcatttaagttctHtcgMRHtaaagaVactBMtatgaagtaa +aaaBNtataaNttcKcctaNttaaDtcgMacgDcaMatttgYtaaNtcaccgatgagMtg +ttaggWcacHttNgtcttHYMcaattKcagttcNcaaaacgNaaSattgKttaaBaKtta +tttaMggHcttttaaRNVgttaYttttMVRtYVgRatKcgVtacgaatttccBatBgYBR +tSKKctaaaatgatatgBtcttcgtttgacHagtaattatatctgDtBttatgaDtatKt +cKRcRttagattattagHgDNaaaKgcgMtHtttKtDtgaaaagtaMatcagaaccgaat +KgtatatVaccRaKYtDHtcSagtBgtgccWaaaggtYKcaHatDDaaattDStDtcKgg +tMgcMtgtHtcaaVcgtttNtagtNtgKgctaDcScgBcWSatgtatagcKgWgttgaac +gagtgcgcgtKaaaacgRtttccatatatttttMgaKagcVcVRataccWctctcgBcga +ggcgttaatgaHYtttHtaSWtagcagtttKtYaacaaataMtaNDatRgMBaBacSaat +aSDctgaactattgataaRtaVtttHatWaacWtVaHaaBDtactYtaDactttSgtKtR +attgatttatatattattataattBatagattctaacDcRMaaggttcgtcatattRVYc +ttKgtRcgWaatcgaaWWatDctacaaaagaattHaatctgttttacYatKatBaccMaM +aaVtcacStaaYgYKgtttctcattatattNgSaaHtgRaBtcataKYtHtacttgtaca +aaDtYtgatagNRcYatgaStaaagactgtcWDtYaatVaNStagaaaWtaaaataDYtc +aMatSVBVaaaYagaaaattgtgcDagWSaStattttaatNcacgataNBtaattggaat +gcMgacattHaattctctaaMatactaBaaattacaHWgBNtNaaSattttaacHtgtag +tBtcRtttSaNNaYaMaDtatDtagaKggYgcaaSttgctactDcNRtWgtttaVtggca +aactattgSgaagtattatgDgcgtgtcttagcNtRctKggtMaHgaDaaagtactgtcg +atttagatcagNggtaattaKaatgaaYaaHaattggttVaaMggatactctaBgtYHMc +ttccVcaaWtgttHHRgagttKaaagaBtaRtaaWaggttctatRatSgtatcYtaWcat +gtaBtcaatctaatRgaYYtWtccattataBacttWtcctaHaaaaggttgacgtRattK +gaagcattSBtttctaNcSctSStNtYtWaWtgtagtcttgtctttaagNKgaagacgDa +RgtNaBaVDgaattggaYtaccSVYKctSKKcatagttgSttatcStactcaatSMataH +caKgatWVYtNacagtttBtRagYHaagtaNaaVVDgatattMaagattagcatcctaMa +aMctgNtMcSaRcgctHMttaattDtttYttcgataaagtMtaagttaWaaDcaatccKg +tgMMcatBgtRtaHBcttgtBaBggcaDcgaWttgggtaDaggtgatRtYaMWDttatcN +tVcttRaKagctRgtgcNaatctgattatagattagtatatgaataDNatcYaggKRaca +atcaHcaagttagtKgRatRgttaagaaaatacVctaaaagtgtaagKVgcttSWaaHat +agHctagtDgDtSaVtgatcatttaNKgKHataKBctatatWaNgtttgcRaVNttaDgt +cttagHYKatYaVaBtaatgaBattaYcNtgcaBtHaacttVtccatDagVaaaYgWtND +BgacagVgctcaRtaHaaacttttacaaggaSRaaatagaagaatacccVaHatcBRtct +tttaaDMHWtHgacMtctcaagKDttctgYctctcNagaMgcgaaDWatMcMatatttDc +tttactaVSctagttcaRKWgtttKRaVaaKtacaacaKttatttttggcctataaDgtc +BctBDgcYYaatNactcaaRgaRWcgattgVNcWaatctgKagDMgctatKttRatcatt +MaagtctaRaVaattKctgaKtatccgaaRatcHMaaaaaagattccacgtacgaDStat +atctcataggtacgcgatgtgaaggtHYtatWagKVKgaMDcaatttWccttgKgagtct +agatgaatgVRcctaMttgtaRaaYtRtaacWgaaaMttatcatNcgttactaaggtDaa +ggcagtRctcatcaatggYagccagcgaatatagtgttWtaccaRctagatttDtaaatR +cDKtccHtBWgttctWaagccYBSgtggaaagHNttHtctaaattaBatggaDMgaBgat +atcaatactcMtaaKtcYccgatDaYgHDBaagBattWattgatttttaagaRaaggatg +gYggaKttaKtBVBcttaWcttBtacctYaNYttgctgtBaaMtWtcWaagtaaggWcgM +DaaNtccWMWtatcMVgaSaRctaKtBgKWDacDgaaaaNgttcaaaaataMcttaWtat +gNaVaaRataWtgKctRatataagtgttgacgaKgaNgtaHattaaRagSgattctatgt +YtcaattagBYBatccYtgtNacHagHtacVcVacaacaccgNgBtataYaatWHSttat +tgctDacttgtgHgHcMcHacagctRSDtgattaggaDHtYagatggagWtaMatcRccc +acRaaaYagcagatgatacatatttVBBcaaMtctctaWgaNtttcctaVcttaYBDBct +RgSaagcNgatttcacgtcRDaVBttaRaggtaaggHcacttccgDBKgagaatttataa +aMaRattagcVgtttacaaagagaaaMtgDtttYttggcttataKaStacaVttBttctt +gBcVaataaagagtgagBgcgNcNattgaaacRcactDaaccaatWMtaaHtBgaaacaa +ccctcMctcaaatctMWttggttttacttagcRtttacatRtccBttVcatgaaBacaYg +agHttatWDtcctSatRtYggHtNMttRgNtgcatcacgacagaHgtYaSaactgaaNWV +agtagttagaNgatctgcatWYaDacataHtaWttaatHaDgactYgttcaSVtttacct +aatttaDgRcagacaDtgcYVttaagaSSKBYtgHtDtNtcgtcWttDtgtcNtgacKag +cactccDMacDNcccctWataRKcaaatttctRVaacagcaMtataaattWBctttgKgV +catttaVgtDgtatHtgtaSctagtatagcBtBtgtatgtcgcMcgagttctacgaaBgW +ccgaWatgcaRtWtaagYttaNtcWaHtgattYDatWRgRWagtRcHggNatNttWaaac +aSgcaatMatgacNgggaSatgatttcBHcctaaggWactacagaaaagctMcaaagaYt +HVgtaaHKgKattVaWtttcctaWgaKattatgMaattBgaaagtgaSaaaWtSNBtttY +ataVgNatgaSgcBaaccatattcctctagRtattatctttctMtgaRtctcYgaatDtR +cHgcRVtWtaacDtcacYatRcttNgcgaDtVctWtacHtatatgtatKaaggtaNcata +KRaataacacDctcctWgtSaWcatcDgatatBtaatHSNBtcaataaStHtacttaYaD +aMtaagMtgNaaaaNccccgYWHaatgcBcttaBcgtMBKggccaVgacaWgaaaaaVYc +RKctMgcaccWctcSacttcVtacgaagtYtcctttttaYgttattaataactSttRggt +cVgagWRStatKataYcaatNMtacttcgcttVBaYRaKttaaYatacagctBgagcttc +HcaatBaaaVcgctcacaMgttaHaggctaDtSgatattggggBgRMagtaattggattg +YYHtVtcttSRYaacttataBtNKgatVaWSDWacatVcttgttgaagScaDaSttcact +aattagatKttaMcHtMgKccaYatKataMcKNgattgtYtaaRHHcaWagctgtgcYat +MHaatRDgtgttYctatNKtSDtaKgcBttgagtKtacatgaaggcgMatDaWtcBatag +taaaatNYtSVgVatttcaNgRtaRaaNBttggaatVgaaaaagaaggtgNtttVBgcct +tgtgaBtgMgtaaacBgtactWgtaacctatatggaSYattYtVgtttaagccaRtatRM +cgWMgDVSNgataatBRccNagagStHttBgctaBagatattaacaagaggttttcDaRa +gtcDgtHttcataagaacaKBttaBgactaRatgaaDYHttgVagcMcBDgYactWgSga +cBataMMcttSaRHgcagKcgaaYaDgttcataYKcttcMWttattaaBacDcttDtttB +catVggttVHtgtMgKcgaaVgtcgMaaHHYBMaHtaaKaDttaNgNtttttaggMcWtt +NaaaDaaaaactRgaatagSVHtaataagttStccaatcHataatacMcattHtacaatt +tctgatggacatatgcaaacaKBatgcagacagVcctccgcaacNatcMaHtcMtaSctg +taYgtStcBtcatDacRggttRgagaaHatVcttYWgaDtatgYcaBKgtSWVYtttctW +ttHtctaYttttaBtcataaNgtBRaNcgttKgtgVKgggVtWatcWagttSttttttaM +aRWtccgttttattaHatttBVtataSctRWtgcMacaattaStBcacggaatRatactV +gaagMaaagWacaMgctaacaHctHtaatacacgaYagtcttKagcDttaKBHccgtaHa +acaKVtcMKcaataaaNaggttSaatcatgaNaaBtacggBcaagatcRgttttHaNgtK +ctYatBHHtaaaDNHtaVtVagttVacKtcYgcattcatacaaagtaacKaKKtaaNtNa +taaNaaSaBtagaattctgacacNtaHtataBDttBctataatagYSctgtaHcgccgaM +BaggttaMHtKgttactaaHaacgDatataaagcaWtgaMtttgVatcKaattcgHVNat +NgDaaYtataHacaaacaagagtatatDStgcNgcRtaaWVVaDStNgtcaaacgDttaa +ggNttWcaVNaccctgaaaMcagVYVaMtBgtatacSacgSgNtaaaDtRaBSaWcNacg +YaggtcaYtattagVStaccgatgSStMattctWtattHtHaDtatgYaatattgtttta +NggttVatcttRcgaNtHaVaStgaagactcacaaatcactgataaKBtNHtttctWWta +ttgactacNtaWatataaaBaatBttgggtatYtttYtgttttVttgagtcVaMVgaatN +taaNgKMaacgtaatattKWggcagtgRttgtgacactaaYacactggaaKaWYRgcatg +cgttctBcttggtVaaWgtttHagtcaatctcggaNWtaatBNcaMVKStaNcMtgatat +aatDYMctttcgcatgcYtHtVNgStggagcBtggMgccctgtgNtVatactgcctcHca +taDBtaStgNcagaYttaMtcaYtgtagatDaagaHaaaRcRataattcaDtcaDgttgt +atRaaaaYaRgtttDBgDcgaagcNttgcVttcacttaMgtMWaYaattcggaDcgaVtY +attaBYaaaattaHVttttWaacDttaRaSWactcBgaRctacaVStBaaatRgaacMSa +agaatagYtNctcaatagctNttaVtgctgtttgYcttaatgtgMaStactgDBagVSgg +tSKMYttDatgtMaaSaVtccSRMgaaaactHaatWWtcatttctDgcMcggVtgtRtca +tctttNatcaatatYaKaaaatKWtDDDaaactaagtacRHtcKttacaataggttWctt +ataSaYctgctVtaaVggatcctaHVttgWtgHtWttaDHaNgaccctatatgcWtNtta +cctaYtttDWtttaggHNgccatattacKggattVatatcRcggRWMtgcaVRaaHgtaa +taattttaggtctcDccaatatgSaaaagatDtaaVtYgNaHBtcaYttaaaaacagata +taaagttaaaDWccMHMattggtaaagtccgaKtatDKaVHaBagaBatactataVttDt +tDaMagctctaaDSggtttgaDacacVatcttNtgatKtVaBStatgNtgDKYcaatcat +aWtcNatYccgRtcgBHacaBaatagaVtagcttgaKagcgHtttDNtgaagMttStttt +gDDKRWtagtaBgtgagtgBcaDtWtaHcctatHatttgttWgagcggDtgtRDRcaaat +agcacacRtDgtgVaWtaattRacVataBWacSYWVctgYtWDaVtaKataaacttKaaa +MVHaaaaKNtaaacttgVataaaatMaaatMaagtatcaaRtatSYRtBtaataattgtt +tgaWtaNNtctcaatNaataaaaaaattgaaaattattgtgttaaYatccccHtaNcatt +cacttttaMgVDtaDMtcaWSgYWcSYtSgaatHtgctagaVattaBtaaaYgatattcg +aaBtgaaDacacatRaagcgggagggDMtatDttaatttggaKSNtactRMttactgtBg +gcgtcatNttctattaVacgttccKtVttMacttWtctaYcacgtaVtaaRgKcttggat +SYatattttgttacaaMgtgagagaSatattWcagDttggNtNaaYtaggaaKtYHcttg +KattWagNgtaagHHVatYatcattaaaaaYtHgttcaaaataattatBgcaKWKtagaa +tagtatBagaaMtattMagaMtHcWgYcacgttagtgtDNggctatNatRcYYHtaacMa +SStattRagRcgataaaatWNNatgaaatttVtKcRtKtDtaaMcctccaDRcaHtBSWc +YtaKttcacaaMaataaMaactccgSgtYattDtaWctagatBtaatSgatgatHKgttg +caaaaagaScHtgaaHRDatSagatcBcggcatcatYVaatgMaatStgNgWaaaaMttg +cYaaagttSHaYgaaatHattBgtaaMRagSaSacBaagtttttcatgttaaYcagYtgK +tYctaStcaagcgtaVattaNatWtHgtHKNDtcNaKaVaStSacaaStttagaaataat +gcDSatgtaKtgMMtcaaagtNattacMYgtgctNgVcaaNcDtaaaVtYggtaaaactg +caagaWNcaaacctDSaaSgVaKtctcatataMtggBtaRttKtagRcctgttaHgWRaa +ttgDaaatttHtaccagctcagaccKaaBctaagtatWtaVagBgtttatgaHaaggatt +StaactWacKDVtMHccgtacaMWYctDtagatttRctaccRagtWcWgaaaaMcagttc +tgacSctaaaactgaatcacaNcaMWtWccYgtttNaatttggttaaNtggttSattttc +aacgYVccMtcgaactBtatcYttcYDVMttcgattaKWtatttagcaatatcagWatgc +RVaatgRtacWaVVBttggatRtaNgRagttDYataacDVBcaaactttgtttgaccata +gHMtRctaWcgacagtgcVcaaVgRgtaagtRaaaattSBKacBaatcagaatgtHattc +aVRtatVSSaKatNataWRVaaagMaacataDgataWHatcNYcMtatttggaSatttcH +cgacaYcaKaaatattacHcSaBVatHacactaMDataaaggcacaacaSacctgtaaRg +tcccaaaatWtDtagtcaagNtttgatDacDgcagaDcWgatDaaKagctDWtttatatW +gDcaaaWttStDtKtatSagVgaaKtaacgaccgMgaSaatRRcagYtgttNDggcHSca +aYDWtcaacgtaHgaStKtgMtRtaatccagtDaaacHgtacaaccHtagataNaattat +cVtgaKaaNaaaaaaaagttgMgtcRaNaacagtaKcaBgtttgaMDgDMacttattatg +aDgagcgtcacaaRaagtYaggMtaaactagaacagVaMWataggtatHagtttaaHtca +gtaaatgRgcatgRctgaMttBaaataagWVtcHctgtgtYaaaaVtKtaSaaBatMttt +gttatattattcaaBYctBWtggatBtgaggDagtgcacVataRBctaBaaaataatttt +tNggtccgtVaaaaataaattBHaatBaagaHgttaagcctaatcaaatgaYtKaatYta +aggtMgaRggtWgggNactaacgaRaaattSttWtaataaVtHgtacttNtaagHaSacg +WggaYggNStcctgacgDcgHggtttHggtNtMtttDatNDgtgacgtatacgatKatat +aaacaattSaaagcagatKtttSagcaaMttttgaKtMtagtcRacctKSttBttaatMt +gcgttacaaagaVaataattcaSaaWcBVacYKtacaNBaaKRtRtcgWtWBaRKVtYWW +WgattgBctaaatKaattaYtMtSBMBHDtBtaggDtcNctWYagtgSaaBaVtcttNgt +cgttHtgtMtctatKtatVggKaSaagtttattttatgtactactHtHttSMactatHca +agaattVataaaMKNtaMccgtgatDaHcaacttRataacaNgaatcSBtatgacBcctc +gggtaatWaaWtacacaattctRVgattctatgtgtatHagatagggacVaattttDtNa +WKagtatatHtagacgaggtatgtcagtgagHccccaatNataKMBaHtcWgctagtgHa +atBatSataDatatcacccaagattttcSatKgatWtgaagtcBMataaHaaMaattatg +cttWWtttcgVKYNBattggtacttcaaMaVNcctcHatcgctVcttKatgtctctBMgg +acatcaggacSgaKttgagtctKVYaaagtaaSgaaaHaWactgRattaaBttVaHtgga +ttagRWtaaDaaatgatttSMBWMaDactScgRYtgaVagNctgtSBataKacStHRatc +tVgBKaggccaRctaacttcYKtcaDcttgaaacBBataatacYMgWgctgtacttttat +gaSaaatYcccgattattRStccaaaBagaacaaaVtttgcttatagaaacacScccSaN +taaaaBgtaaggcDgtSttRatMYSWatcgtaacgtStBagttaVaaaScccSggaMDBS +gcaaKaggatatacgtatgcWactccgVctNttMaYtaaatKaaatgKStaaaHaKatat +gBtcctatgtVaBggaatBcgcaatgagtatHcYagctDgtWaaccagtatWWtaRtKag +atagtgKatatgaaaggcaWgtNKaaagataWaatHaaaaaKMaaatttBtatHtctNac +tKtBVVagtatcacgtMgtgttaKtaatcgaaMHtYKNcMaatgcaSaaDBaaaaagaWa +DtWMgaacatttDcatttaBaBtDttaaSMtcagcttttRWWaataattcNctactWaat +NaBaattaagaaacttYRHaccatatKtaKcNVgttYagttBtaaaaVtctcgVctagct +cgSVatatagVtMcaaHRctaHStttNtcattRaatgtaRtgttaatYtaagcattgaat +ttaKtctaKKgaaggtcgMctttcWaagcgWaKcttcYttgtgaRaagMtDatgWgYaat +aKaatSWScatKBtYgtaagagaVcacgctHStaacaSgBtgtaNRYaaWtWcKgaccDt +gaWtgagMaYgVVgBaRacYtcKgatcagttgtaKcgttgagNaStctggaatVtactaS +NtaaagtaatcaattaaVaaDattHDBaHKDHctVggcaaacccKMaatVtgttacBcct +StgBgMtScgaaHcatgctMtStaVttttcDaNagtDVaatYcggaDaYtaactaNgtcc +aattSacaaaaRgtagaaKgtcRSNtgatBacccttMtactatKgtaaRMagataMatgV +tVKagaRagtcagMgMaatRHNttagaagaatgggaatcHtttttSgtNgYatgtgcYta +atgDctMaaaMccVScgcRgKNaaagtaMtacaKaMNaBatagBttttcttttYatataN +aWcagatttgMtgaaacaBYtHaaatgtaDactatttNatttKttSattgBatSRtgKHt +tacgattgcggtaaaaacHHtaNgMcgHaVDtgtagaagatBaaagDttaacSatttaat +ttaccagatataattggVgaRctRtcgccVatRNtDgcagBcVaHtBaatDttatgKRKa +gataaRgcagtaKgagttatatcaMSagttccRcttaaatgatcttataaacaaatttcc +cttaBaWtagtagttMaacMaKaaaagHatYKactttRatgtctcgattBcSagaDKttt +HtBaccttNttVttVVtggttacgtaaBMRgatcgtctacaaNBtaVggttYaaggattc +caNgRgtagBtgtaBacaagtataaatBaaatKRtaMtKHgatcgYggDSgKRaSttHSt +catgtatatWacacRacHcatYtttaacYatatgtgttNtgcSagDHgataYttNattat +cVattcaaYttggtaRHtWtcgaBacgtttaBaccaBaatgtcgcNagaNtKtaDtgDta +tgDaBtcKgtBgatacNaccDDatttYtKggMtYNtaactgVacattaaHgMttatcgtH +MNtataBtKSgccaVttaBcttattcBaagtgaWtaRtcctDVRatgaattgatatgaWg +ccacDaatKaHtttacatNttaWNWgtacaggctacttBaYaaatatacaaaatttcgNH +gMgttHctcKYcttgMtaacBaDVtaatttacagaRttttttagcKagtKactatMRtgt +DtaattccRcaaKSttagttttBtctatagaKaVttttgcNagtKVccttagRgWaNaKW +ttataDgcgaatgMKatgatRcYtctgVagaccgcgVgactagaWaaHNtcRNRKaatac +tcYaNtSDKtcVVggNgDagtttaaKRgttaDcgtNNgtcaYttggtttYtatgtaaagg +attttagatattKMcatgYaaatcaVactcagagtRYtgtaactatagtBaDtVaWatDa +tctataaaSgggtactaYaKKWagaaaaataaattatagRcaaaVataVagatatgtagg +cWagacRWattctgacgcDtaBcYattgtaDggMatgagcgagaggctaaatVtctcagR +agDtSgKNcgtVcStacatttagNtgatSNgatcYVtHattHtBgMacRaattaHBacRc +NaaccctVaaYaattcVccatacKcttSagtctgKMNagRaNcatNgcgHattStSKYRg +gtcagtcaccattttagtMaccctggVattHaatVagaaMaattaVacatacacaaatta +attacgtKtagaaaMgatWgWccatYtagacKatctKatMcggYcgcatgHRtcStVtaa +tHgSaaaVagtgaatgtgYtattaYcRagatgatcataacacSgaYaactMKttatRcga +ataaMSatacNgaMatttcggccacgaYYMcaKattRagDtRtatMVBtaattWtMHgNa +WDgStaaSNggStcBcVYtaYagaHtacagttccMcgtYtYttcattgSWcttagttcgt +HtgVRYgaMacttBtatcaactaaaaVtDgataaDgtatcatYDttaStgccBacctaaB +agttgRtaSBtaaaagWgcacBggttagcMaYatttBgtaggtRBaSagttcacgtaDaY +aaaacDSaKattctgtSatatgtatggVBcctctgtgaaHDKgttaRttttBMHgRMgHa +gtagMgacgaagttaatattgRtHtHttatYaaagcagatgtgattagtggcactactVa +ttagatctctgtttatcattYttgatHcHttagStgatgactctDaaatcagtgttgttt +ttcYaaagtatatcYcaSaacaVttcgWtatKaaaHWtRgtttaKacttctgaaNaYacc +tNtcStatttaaagttKgtgatcctBcaBtctttaaaKagttgDtWctDtgtgctataKa +gtaNHatctagYgatcMgtggYaagactgacacttaRaaccHgttcaYtagWtggtgBcS +tacaMcMHataaaNagatactccaggagttaatcatRttttgaKNgSgcaggtgttRaYc +aaataBtaDtatHgBtatacKaataKtaggaaatatgcataaHgaKttttatMaaaNgMa +tYattgaatNtatVaggtKctttHattcatttatYtattagtataYtttagYcattagaa +ataHtaaccttactcatYttHMRagttctDagNSVgcgVaNNattctVcaaVagaattta +agaggttttacRagtagtaaaBaBaaMtaScKgVaRcNtctgtataagtatVgtDgHaYt +tcHYttaagatRgtgaattctYaaaattRtcWtacDDaRatcaKtaSacaagctaNttRY +agMSDKtWgWaYNgaaaatatNtaatatHMtMWRaRacaaaatgctgctacNKaKtagtt +gVatDaVccatSDtgaSggcgWatccBgaaVtgtaWttagatVaBWtacgWtaYattaaa +tMctDgDaaKatttgaaatgctWctttaHtggHaBBSRVBWtgattgagatccNcaaaHt +>THREE Homo sapiens frequency +gcactagtattgtcgggatcccattaacaggctcaaccacgagctcacgcgaggacatgt +agtccgtatctttaacgaagcgacagcgacagaactcccatggataaccaattataaggc +ccgtaatcctctagacatcgtttaccaataaatccgctttctccgtaatcatgttgaata +ccccagagtagtccagatgataaccgatgaaacacaagtctttctcaatgcacttacggt +gaacttattaccgccaacgtagctcatcaaggttgcgacatctagttgtgtgtttgcgac +gagcccagcgaacttcatcaactttcgtatattcaacgccttgtaattttactttaagac +gcctggtgatgtagattcttagataatcagtttgttatcggctgtactttaccataattt +cacaggtttcaggtcaagaagattatagctgtatatacagttccatgctcggtgcacaga +aacgtgatcggataataatcaatcgcttatgtcgtctttaggcgtatccaatacatgccc +cgataccgcagtgtatttcgacatgtaggtataccgtcgcatttgagctcgagtcaggac +gtcagctagattagattccttaatagaatataccgacctctagtccgaactaaactatag +ataacgccaacttcaggttaattgtctagtcgtctgtttgcagatgggattcttagatga +gtgagtatcggccatattggttcgagcactttagtttttgatgcataggatatgcaatgt +atagctgaaagtactttatctgtttcaaactcacattgattaaaccggtaaacctttaaa +gactacaagaaaatattcagtgagggcaattttgtcaatcacaatcttccagctagagat +acttcacaatttgtcttgaggctacgcaacattagacggattttcgcgttttattgaaat +aatcgaggggcccaagagtatccatagttcattttgtaagatttctttacaggcttatta +cagcttcttcagactcctacatgcttacgagttatatgctagcatgtgaacaatagatta +atatacaggaaaacgtacattgagagagatgaccctacacagcgcaaccgttgagtactt +tcattaaagggtaacgctctcgagacagcatccttaagatggccttattgtcaaatcatt +tgcagaagtacgcaagatccctaaccaacgtagaagaatccctacaaacacatgagacgc +ggtgaaaatagacagggtgttagtattcaatcttcggagtatcaatttcgccaatcttgg +tgagaaagcataccctttcttcagagaaagaagatcaatcataacactatctttaacgag +gtacgcacgcgcatcattacctgcctccatggatctttaggatagcggaaagtattggca +gcgtattgtgatttcgttcctactttatcaatttcacattcatatacatgtcttttatca +aaatcgccaataagataggatgagctatattagatgctagtagagttcgcgccaacatca +tcgataggaatactcaggacagcgtgataggacttttcaatccctaatactctctataat +tataactctctcttaagtttggaggcagtaacgcgctctatataatcagtttgctgcacc +attcttcagcctctgatacatacaaataaattccacagcagtaagagggtttaattgaga +catcttgggaacttaggattttactctaacatcaccgaaacgattattggataccgtacc +taaacgaactttctcaaggcagtaatataggacatccgcaataacacaaatgctgcctcc +ccaggagttatgtcttcctggaggctatatcttacacccactcactataggcaaactaaa +gtttaaatgttgattgtctaaaaaaaagatagataagagttggccggcgtagcacatgcg +aaagtgaatcgtaagctataattctctggacttgaagttctgtcctgttcctctgcaaga +aacaaacttcctttaaagctatttacgacgcacatctcagcaagttataaacatgttgga +agtttctagtcggaattcccaaagaacggatctatctaatgcattcctacatttttcctg +tctgccgatggtgccatcctattcaaagaatttcttaaaagtagattaaatgggactttt +aacaatgagtaaccttacgcctctaagggttcctcgagtgccatacaccagtcaggtccg +agccacatacacggagaacattctaacatagcattctcaactcgatcatttgcaggttac +ttctttcctatcctagtgctaaaaatcatacttgcaatcccatagcacggattaagaacc +taagaaacaattcagtaaaacatgttcgaattcttggtatgggaacatcattgcagctat +ggtctaacgcattaatgtttgggtacatcttccatcatataaacaggaagagtctgacga +cagggagtgcttgcgatcatgtctatcattgtgaaatcaaattgtagctcacatgtcgtc +tatgagagcgtgtatccgataagatttagaaaaatagaagtcgtataagatctcactgaa +cttttgaatgaatgtgaagcatatatgatctgctttaataaaactttatccataggatac +gtttccaaatcaattcaataattattagtcaaaatagataaggatgaacaacctgaaggc +cgatcggacgtagaaagtggtcccatcactttgagttgatattgttgaaccacacgttat +tatggttttcaaacagtctcaggatattgtatatacagataatccgataccagttgtctg +acgcccctcttacgtaccccaccctttgtgacgtttaaagcagttgttcagtattttaaa +ctaggcggcaactaatttggaaagaagcacagtggatatgtctaaattcttgttattcag +gcctgaatttaatacaccgcatagttaacttcgcggtagagttgttcatcatgcctcctc +taagctaccacttctatgatacaccaatagttgttctacggaatctgataattggccaag +tcataaacttccgctgcgttcaacccccttgctcgaatatccaactcgaaaagacagcct +tttggtgtccggaacaaatcagttacttcttttctgatgttaattctctgtggtcagata +cagaccaaaaactccgcggatttaccatcctccaagaacaaatttgcatcaacatagcat +tttggctacatattctaagtctcaatagtttaggttttcaactacattatcccaacatta +ggattggaggaataatagctgggtaagtccccttgcgtctacaatcgactattttttatg +aatatgcttctgccgcacctatggttattaaaaaagtcatgactttgaagaaccctgaaa +agatagatgaatcaggtgtaatggcagcagccaaagagcatataattagcaacactctaa +gaacattatagatatgatgatagcgatcgtcatgatgttatccggtcacaatagtagctt +catcagctaattcgttttgccagtggtgacttgcgctggaagaatcgttatacggtccct +tccctcttgatacggtgggggcttattcaaccgcgtggattgggttgtcatacttgcatt +aaacgatgtaaaccatctagtagtcaactatactaaatcacaaaatagtgatcaatacat +acccgcttcatggttttaaccatttaattgattaaagatattccgctaagaaccattatc +tacctaaactgatcgccgtatcctagtagtttgaaatttgatgtaccgtaatgatcaacg +aagtaaaacgttatattgtatgtagaataataggtcttggagctaaatgatgtgattggt +agtgaagacttacccttacaactttaccggtttctcggaagaatatactagagaatcaat +gcatgggctacataagcactttagtctaatgagataaaaaatacacgagtcttccatcat +gaattttttgtcgaaaaactcgaacctggtaatttaaaccatatatctttatgtcgtcaa +taactctcatatgttttatataacttcccaatcacgacttgtaactgcttgttcgactga +gctgtttgagctatgaggccgggatccggttgagctacatctatttgctacaagaaaaat +gaaagcacatttgttgggagttctggctacactcatagagaaataagtggcccgagtggg +tgcggcctgcctccatattcaagtgtatcttaaaccaagtggttccaacgctcgcgctaa +agaattaaagcctttatttcctccacggagtagcccgtaatccggttcgaaagagaccat +tgaagttaattttcatatccagtgaagtttaggcacaagcatgtgttctgccacatgcct +caaagcgctcttcaaccaagatatgattcatcctaacttcgatgaatgcgtctgtaacat +aaatatagaaggaatgattcggcgagttaattttcgccttctccaacatggcatccctac +gttcgttataaggaccatacatgtaggttttaaaggtttgcggttaatcgatatttacat +catagaaattctatagtcaaatttacaagactctagatactcactcgttgcagccggcta +ggaagcgctttgtaccttacttcccttttcgttgcgtaatatgaatttcatatagtaagt +tcaaggcactcatacctccgtgaagagggtagatagactattaaagttgtttaatagtac +gtattgatggaaatgacccgtaggagatttaccactcaatccacaagattcgctgctgtg +cattatcaaaacagtgcatgtcgaaacatgggttgggtccttcaaacacgaatccaggta +gagatacctttgcaatttttcgatgaaggcgaccgagataaatgagctataacactgtat +gtcttttgattgctataaaacacagaaacggatattaatttaggccgtaaccaacatctg +ttatttgacatagaacagatggtcctttacagcgtattccggccttaatattgaggtcca +gtgtattgtcctcctttaaagaagttgattgtaactgacttaaataagacatgtcaccca +ttcactgggttgcaactgctggccctttttgtccatcgcacgctaatgtgataacagtac +cgccctcacacctgcgtttaaaagacataaatgtcgctatgaaggttattcattaatttt +agctgttttcttagaaaaggtaaatttaaaattgaaaaggctagaaaactaaagttacga +caaatgtgtttgtcaagtaggcgggcatcattgagattgtaagaaataaagccataacca +gccccggaatagaaaatgttaaggaaaggcgatcttctttgaattcttattgtcaagtgc +agtcatacgttcttatcagaggacattgcaataaaatctaacaccctcccttgtgtggtt +gggccatttgtacttcgaagcgtccaccatgtgcagaggataacggaatgtggttccgtc +ccataaacgatcattctcgcccacttagtggcgcggtaaatcgctctcatagaggtaact +ggcctgtaatgtccaatgttaggctaccttctccaactttagtacaacgaataatgtccg +attaacaaggagtcaatttgtcatgaccagttcattcaggtacttgtatctatacggacg +cgttccagagtagtatttgaaattttgaggttctactgataagtttagctatcgctgtat +gtctgaataagaatttaatgtttatcttcgataaataacaattaacaactcctaggtgat +acactgtgaagtctgctgttccccaaattacatatgctattttgttcacataccatgaag +ttaagctaagtgctctataatggcataaacggttatcaaactagctcgaatttcttttat +tacgccggaagcggattaactgctgtagatcaaacacgttaggatagtgtcgttttcata +tatatctaaattcggtctaacatgcattacccatgcttgataacgtagcacttcgcagtc +taattatgtaatgtccgtttaaccaaactttaaaaaagtttatctatcaccagtgatgcc +tcatcgtgactacccggatctttagcctttagggtctaaacagaactaatattactacgt +gtcatactccggagcttaaccaggtgaaacttatttgttaaccaaatttagtgacagggt +agaaatacgtatcaaattaacccagcaatacaataagcatgaaaataattgtaatcgggt +ttgggccggaatcccgcttggcgaaaacttaatgacatagtgtgatgcattttgcactgg +attgagccacaaactcaactagcattatgctcaatatttggccagtgttctacggtttga +aatttataaaggccgcgcaaaagtcttgtagttacaaacgcataaatctcgaacgtaata +ggtttaattagaacatccgtaggatttctgtttatagtagatttatactaaatgttctga +ttagattctgacggccttacccatacaattaataaagacgaatatattagttatagttta +ctatccaaataaattaagcgaatcgaaataaactgtcacgatactgggcagttatcaact +tatcacttatacagttcggacactctatattggtctgtgagtactctatcaaactaactc +ataagttaactgcgcttccattaaatttcaatacgttcttgtgctgtgtacaaacctata +atcgaataaatgacacatatggagatgcataataaaaaaaacggctccatatttctcgtt +aatcgggcattcttaaggaggagcatctcaccaaaaataacgttcctgataagtcttaac +tattagaccgtcttcgggaatgaacgaaacctcaagctagcatggtatagttcttgatag +cgcgtaaattctgataatactgggcggacagctggaaattagttgccagtgcacctacgc +aaatagtttacataaatcaacgggctccgaacgtaaatacaaagggttagttacatcgca +acaagatgaaaagcatgtatgtctaccgtcatccgtccctaacaaacataaaggtggtga +agaatctcgtaggtcaactataactccatccttgaagcaactactccgcgtccgtgtgcg +tagttcgcaacgagaacactactgaaaaaagctaaacaactctcggtacaaatgcggctt +gtgtcgataaagttggtggtagtgcacggaataacataacaaggaatattatttattcaa +attttttgtgactgttatttgttttctgcctagaatgtaaggatgtgttttttgtgacct +gatagttacgcttatttcaggtccacggtgcgtgagagtgtgtcctataacggcagggga +gcgaagtagtgtcctttagactattcaaggtagaattttgataacgctctataaaaggta +gaaaatcatgattgagcaataagaccccaacttatcaaaaaaggagttctcgacagcgcg +tgtacagtccctataacggctgtatttcctgtgtcacaacaccctcccatcgcactcaaa +atgtagatttatgatcagacgctaacttgttcttagagaaaaatacacgggatactctgt +gcaacgatttcattaataaggtgcagcttgggacttttttggccgtaggctttattaaca +ttcacagtaggtagcgagacttcctatgaaccaatcatgccacgcgttttaacgtttcaa +atataagctaggaagcgtttgccaggacttctataatgcaccgttttttttagtacttcc +ttactagccttagtttatgttagagtctttccaattacaaaggattgaatagccaaaatt +tctacaattctcagcgaacgccagcttaatctaaacacgagcttcaaatattctacatat +cggcaggagtcaatatataaatatgaaaatcgtaccatcctcgtacttttagaccaaacg +tcttcggataattaaatcctttttcaattaccacagtacgtgcattagaactactgctat +gaaagtaaaccttgaaatatagtcctcaagagcgtatccaagtacattgcacgtgtatac +agtcgtataaacgagttgatgttctgacgctagagcttaccattcgttaaacagataact +aaaatttaatggctgagtgacttagtgttttcgacaaacgtcgcggatgtagactattgt +ttataagcaatttttaaaaacatatgttcaaaacggtatgggatatgtcgaattccacag +gggtttatgtaccatagaagtatgtataaggtactaaaggtttaaatctgtgatattcgg +ttcggtgaaaatcagactagtcacacttagtgtctgtaaattagattgggtgaaggtaag +cgatcccgaactctacaaggcatgggatgagattctaccgactccggataacactttacg +atcgcgcataactctagctcttagataagtttaacttgtcgatctcataaacagttcaaa +atctgcgatttattgtatcaaatccatcctctatcttctataatcatctgaaccgcgata +cggcactatgagccaagtgaagattgaatccaagaaagctataattggtttattttagtc +catttaaattaagtccggtataagtgctctgtacaatatgcagtctcatgggcatatacg +ttaactaccttttgatacttcgaattggtaaaatatcgactatcgatttgcagtaaaagg +tgtagagtccaattactctttcctgttacatacgatctcttagtttggacaactagccca +tgatggcgctcctctagcgcatgaacctactttataattacatctttatcgatgaatttt +tttagactgcggaggccttgagttttaacagggctgctaaatttcttaagcgattagacg +gtagcgtcgtacgctacttgcttggaacaggcaccgaaaatattgatctactattgcgtc +aactctattctgctaatagcgatggcaaatcacagaagccctcttagtgacaatagttgt +caactatatctaagtcgacctttactgtatcaacgatcacggagagaattaccgaatacg +aaacctcaggactaaaaaacggaaaggatttgtcgacggtaaatataatacttgttaagg +gtagcgacacaggtatactttgggtgtaaacgtggtgcttcccggaacgattttcagacc +agaaaattgttccggtaaccaggaaatctcgtctgcgttaattcgtgttagtaaacttga +tcttcagactccttcttttcgttgcagcgagacttaaattatatctgcgaaatagtgccc +cgtgcatacttcagatggtaggagataccatttggcccattgtgactttacgcgattaat +taaccgacatacatctgttcctgagctatgatcgtctgaataaattacggtctcctcttg +atacctaatggtttctggagacgtttctcatgttcaaatggatagcaggagatcgcttca +tcaagtttagctacgcagagcatcaaaatatgtatgggaaagtcgatttccaaaccagaa +gggataaagagaaataacggacttctccgtagattagcctgatattttgatgggaatcat +ggcggcacatacgtaagagttgcgtgaacgaatattttggacggcgggagacacatatcg +gccattcgttaaggtctctatattggacatcacaagcttagcagtatgagctactaacac +tcaagacattattgattttttcaagatatgtttcattcctctaccgctattcccatacgt +tcgattcgccgggtgagcgaaaccacgggactgaggttaagctaatcaataacaactcgt +tgcgatagagacctatgtatactagagagaattccccaacatttttacaaaaacaaagca +gactaaaatagatacagtccctccatacaattaggaccaacatgttattgccgatcctag +cacacacaccacaaactcagaacttctgtcttacctatgaaagggtctgcacttctgatt +gtacgtgtctaattagcattaatattaaaactaattaggataaactataggtacgagctt +tactataagtcactaggtgttttccgatcgaaaaacgggaccttcaagccttggtaagta +catttaggataaagaaaaaaaggaaggtacgtgactaatctgtctaaactgacaatagag +tagtacctacatgcttcatgtcaagtcttaatacgcaagcgctctcgttatactgctcaa +caaaactcataaagttggactccatcatttagaatcatagggaccaaaacatttatttgc +tactgtcactttgtaggtgttctattctgaattcctcatattgatacatgaatcggaata +cctgtggatcccttaggacgcacgtgctttctttacgtcagaatacatattgtcagaatc +gagaagttccatgcaattaagaattcgcctctttgaaaactcatatccccacatataggg +tccaccgttattcggaaacgatataataattattccagcgttgagcgtcccttaagagcg +cattttcgcttggcctttcttctacgactctacaacgcaagtggctgtgtggagtttacc +acagcgcagcaccccatagaactacctctgagagcgcgagatggtggcagtatgctctgc +agctagcgtttagaacgcgcccgcgcattaaccagtcatattaaaatggactgtcttaat +tgtcggcattaggagcaatattaactgatgagggtatcggtcgcagaagtaatgacggaa +atacgcctctagtccgcagagatacgattacagactcagatcccctaacaagcaaaacga +ttaaatcggaatcactccccctatgacatatttgaaatacacaagaaaccacgcaacatg +tcccgcattctcaaccgcgctttataagatgttgagtctgagaattagatgacctaactg +caagaatcatggcgagtttatctagtaggcaagtctgtaccctagggttcgaacgctgtg +acgtcgtgatcggtctaaggacttagatgataaccaagaactggtttaccgagtactttc +actattaggagtaattacatgcgttcaccgcggaatacgacgaaattttttcatatcttt +atgagcgagatcgtgtcgtctttgcattgcaacagtcgctaccagtaattgctgatcaat +tatagattcattatacagatgcttacttttctctattcaatactgtcatgagttgttttt +aaataagcaccagaattatgtcgcctagtataatcttgcttccacttgaatcaatgcgat +ggacagtattctactgattgcaaagtagtctatttcggcttagcagtacgcatgcctatt +tttttgcaggcacagaataatatgcaactaggattctcggcatccaattaacaggctaaa +acaccaccgaaagacaggtaatctacgaagttgatgtttactacagaaagcgaatgatat +cacttggagaacattttagatgcccccttttaatctagactgagtgtaccaatatatcac +cggtctaccgaatcagcttgaataaaccactctagtactcatgataaccgagcatacaca +tgtatttctcaatgcactgaaggtgaactgtttacaccataccttgcgaatcaacgtggc +gacttatacttctgtctttgagtacagcacaccctaatgaatctaagttagttgttgata +cgaattgtaatttgactggatctcgcctcctcatctagattcttagagaagatgtttctt +atagccggtactgtaactttattgatctggtttatggtaatcaacattttacctctattt +aaacgtccttgcgccgtgcactcaatcctgatcggtttagattcaagcgattatcgagtc +tggaggccgagaaaagaaatgcacagagtaagctctctattgcgacatctacgtagaaac +tcgcatttcagatcgagtaagcaactctcattgtgttgattcagtaatacaagattacct +acgcttctacgaaatatactatagatttagcctacgtcacctttagtgtcgagtcggagc +tttgaagatcggatgcggtgtggactgtgtataggcaattttgctgcgagctcgtgactt +ttggttgatgtcgatatcaatgggatacctcaaacgtctttatctctggataactcacat +tgagtataccggtaaaaatttattctattcatctaaatagtcagtgagggctagggtcgc +aatcacattaggccacatacacatacttaacatgttctattgacccgacccaactttagt +agcattgtagccgtttatgcaaatatgccaggcgccaaacactagccagagggcattttg +ttacatttatttaatcgattattacacagtcggaacacgcctacatgcgttcgacttatt +tgcgacatggtcaacaattcagtaatttaatccaaaacctaaagtcagagacatgacact +aaaatcacattaaggtcagttagtgaaggaatggctaaccagctagagaatgcatcatta +acaggcacttattgtcaaatattttccagatctaagcaacatcacgttaaaaagtacaac +aatcacttaaaacacatcagtccaggtgtaattagaaagccgcttagtaggcaagcgtag +gagtataaatgtagacaatagtcgggacttagcagacactggatgcagtcatagaagatc +ttgcataacacgttagggttagagctacgaacgcccatcattaactgcctaaagcgtgcg +tgagcttagcgctaacttttccaacacgtttgtgatttcgttcataatgtatcaatttca +cagtcatatacagggagtgtagaaaaatcgcaattaacatacgttgacctatttttgttc +agagttcagttagagcctaatgattcgagagcaataatcaggacagcctcataggaagtg +tcaatcacttagaagctatattattataaatcgctctttactgtcgtcgaaggaacgagc +gagagagaatcagttgcctgcaactggcttaacaatatgatacataaaaatattttcatc +accactaagacggtggaattcagacttattggcaacttaggatgggactattaaataacc +cataagatgttgggataaagttacgaaacgaaagggatatagcctgttagataggaaatc +cccaataaaacatagccggcctccacagcagtgatctattccgccacgcgatatctttat +accacgcaatataccaataataaaggttaaatgtggttgcgatttaaaaaagatacatat +cagttgcaccgcgtagcaaatccgtatgtgaagcgtaacctagaattatagcgtctgcaa +gttctctaagcttcctctgcaagatacaatatgactttttagcttttttactaccaaatc +tcagaatcttagaaacaggttggtacgtgctactcggaattcccaaagtaccctgctata +tatgccattccttcattggtccgggctcaccatggggccatcatagtaatagaaggtagt +aaaactagttgatttccgacttttaacaatcactatcctgacccagatatgggttccgac +tggcccttactccagtaagggcagacacacagacaacgagaacttgataactttgaattc +tcaaatcgatcattgcaacgtgacttatttactagcctactcctataattcatacgtcaa +atacatttcaacggaggaagataataagtaaatattcactaaataatggtcgaaggagtc +ctttgccaacataagtccacatatgcgctatagattttttcttggggttcatattcaata +agataaacagcaagagtatcacgtcagcgagtcattgagatcttggctagcattgtgata +gcatattctacctaaatggtagtctagcacagagtggataagatatcagttagatataga +caagtactataacagatctcgcttcgttggattgtatggctagctttgatgatatgattt +tataaaaattgatccagacctgacctggccaattatattcattttttatgagtaaaaata +gataaccatgaaaatactcaagccccttaggacgtacaaagtggtaacataaatttcagg +tgttattctgcaaccacacctgttttgggttttcaaaaaggctaagcagattggttttac +agataatccctgaacactggtatctcccaacgatgtcgttcccaacccttgctgaccttt +taagctctgctgaagttttgtaaactaggcggaaaatatgttcgatagatccactcgcct +gaggtagaaattcgtcttagtaacgcctctttggattacacagaatagtgtactgacacg +tacactgctgcagcagccatacgctaacattaaaattcgttgagtctacatttgttgtta +ttcggattatgttattgggaatagtatttttattcccctgcgtgaaaccacatggataga +ttagcctactcctaaagactcccttttggtctacggttcaattctcttactgagtttatg +ttcgtaattatatcggcgcagtgaatctcctaattatcaccggagttaccagacgccatg +aacttatggccagaaacattgcatgtggcctacataggattagtatcaagagtttacgtt +tgcaacgacatttgaccaacttgaccattcctgcttgtagaccgcgggaactcccctgca +cgcgactatagaagttggtggtggatgtggcttatgccgcaaatatggttttgaaaaaag +taatctattgcttgatacctgaattgagacatgtataagggctattgccagatgaaaaac +tgcatataaggtcaaacaatataagaacattatacataggatcttagcgttcctcaggat +ggtatacgctataaagtctagcttcagcagctaaggagttttgccagtgcggacttccgc +tggaagattaggtttaaccgccctgacatcttcataaggtcgggcctgattcaaacccct +ggagtgccgtctcatacttgaattaatcgatggaaaacttcttctagtctaatattatta +ttaacaaatgacggttcaataaataacaccgtaagggtgggaaactgttaagtgatgaat +cattttaacctatcatccattagctacagataatgataccccgatccgactagggggtaa +gtggttgttccgttaggataaaccatgtaaaacgttagagggtttgtagattaattggta +ttccagataaatgaggtcagggcgagtgatcaattacactgaaaaattgtcagcttgcgc +ggtagttgttaagacagtataaatgaaggggattcagaagcaagtttctcgattgactga +atttataaaccagtcgtcaatcatgatttttgtgtcgattaaagcctaaatggtaattta +aaccattgatatttatcgagtctataaatatctttggttgtatattacttcacaatcacc +aattctaaatgattcttccactgtgcgggtggagatatcaggacgggttaaggttgacct +acatcgttttgatacaacaaaaatcaaagcacatggctggggacttctcgatactatctt +tgagatagtacgggcaagagtgggtgacgcctccctacattttcaagtctatcggataac +ttctcggtaaaacgctcgcgatatagttttaaagcattgatttaatccacgcaggagcaa +gttttaccggtcgaatgagaaaattcaacgtaagtgtcatatccagtcatggttagccaa +aagcatgggttatccaaaaggaataaaacagctcttcaacaaagagatgaggcttcataa +cttcgatgaatgcgtatggttctgatatatagatcgatgcatgaggacactttattttag +ccggcgaattaatggaatccatacgttacttatttggacatgacttctaggtgtttttgc +tgtcccgtttagcgatatttacagattagtatttcgtttctcatagttaattgtatctag +atactaactcgttgaagacgcataccttgccatttgtacaggacttaactgttccgtgcg +taatttgaatttcttataggttcttcaaggcacgaatacctcactcatgaccgttcatac +tctagttaaggtcgggaatactacgtatgcagggaattgtaacctaggagatttacaact +ctttaaacaagagtcgctgaggtccaggatcaaaacactgaatctcctaacttcgggtgc +ctccgtaaatcacctagaaacctactcatacatttgcaattttgagatgtaggcgaaaga +gagaaatctgctttttaacggtatctcttgggattccttttaaaaacacataacgatagt +aatgtaccaagtaaccaaaagctgggatgtgtctgtgtactgatccgccgtgtcagagta +gtccgccatgaatattgacgtcaaggctagtgtcatcaggtattgatgttcattgtaaat +gaaggaatgaactaatgtcaccaagtaaagggggtgaaaatgctccccagggttctacag +acatagagatggtcagaacacgacccccctctcaacgcagtgtatttgaaatatatggac +atatctaccttattctgtaattttagatgtgttctgtgtataccgatattgataagtcaa +taggcttgattacgtatcttaagacaaatctgtttcgcaagtaggaccgcatctttcaga +ttgtttctttttatgccataacctgcccaggaattcaaaaggttatcgatacccgatatg +ctgtgaattattattctaatggccactcattcctgcttatatctggaattggcatgaata +tcttacaacctaaagtctggcgttgcgccagttctacttcgtaccggacaccatctccag +tcgttaaccgaaggtgggtacgtcacataaaagttcattagaccacactttgtgccgacg +tatatagatatattacacgtatagggaatgttttctcctaggtgacccgaccttctacta +aggttgtacatcgtataatggcccattaactacgaggaaagtggtattgacctggtaatg +cacgttcttcgatatataccgacgaggtaaagtctactattgcaaagtttgacgttatac +tgataagtttagatttccctggatcgcgcatgaacaatgtatgcgttatctgccatatat +aacatgttacaaatccttggggatactatcgctactatcatcggaccaaaattaaatagg +ctagtgtcttatcagaacatcatgtttaccgaactgatctattttccaatttaagctgat +attacgtccgcgtatttattttagttccccggatgacgattatctgagctacatcataca +agttagcatactcgccggtgcattgatttcttatttcgctatatcttcaagttcacaggc +ttcatatagttccaattagcagtataattaggttttgtaactttaaccatactttataaa +aggttatattgcacaactgatcaagcatccgctataacccgagctttaccagttagcggc +taataacaaataagatgacttcgtgtcatacgaccgtcatgatcatgctctaacttaggt +gggaaccaaatttaggcaatgggtagtaataagtataaaatgataccacatatactataa +caatgaaattatttgtaatccggtttgccaacgtatcccccttcgcgataaattaatgac +atagggtcatccatgtgccaatcgtgtgtgccaaaatctcaaattcaattatcatcaata +ttggccaagtgttataagcgttgaaagtgatataggccgccaaaaagtagtctacttaaa +aaccaatatttatcgttcgttattgctggtagtacaacatcacgagcatttctcttttga +gttgatttatactatatctgctgatgtgattatgtcccacttacccagaatattaagaaa +gtcctagattgtaggtatacttgactataaatataatttaagactatacaaataatctgg +ctacattatgccatcgtagaaactgataacgtagtaacgtcggacactagattttggtcg +gggagtaatctagcatactaacgaatttgttaaatccgctgaaagtatatgtcattacct +gcttggcctgtcttcaatacgtttagactattaaggactcatttcgagatccagtattaa +ttatacgcatccatatttatactgaagacggattgagttaggacgacaagctaaacaaat +attaagttaaggattagtattatattgtagaaactcgtcgggttggaacgattcatcatc +atagaatgcgttacttattcagagagacttaattcggttatgactggcagctcacctgga +aagtaggtgaaaggcaacagaagaatattgttgactgaattctacgggctacgaacgtaa +ttacaaagcggttcgtaaagagcataaagatcaatacaatggatctctacagtattacgt +aaataacatacataaacctggtgttgattcgactagctcatagattaatcattaattgaa +gctacgaagacgcggaagtctgcggagtgagcaaacagtaatcgactgataaatgcttat +aatatcgcgcttaaatgccgcatggtgtacattaacgtgggggtagtcaaaggaatatat +ttactaggaatattagttatgcaaatgttgtgtcaatgtgatgtgttttatccagacatt +ggatgcatggctgtgggggcacaggatacttaccattagttcacctacaagcggcgtgag +agggtctcagttttagccagcgcagagaagtacgggcctttagacgattaatgctagaat +tgtcataaacctcgtgaaaagctagttaataatcatggtgctagaagaacacaacttttc +tataaaccagttctcgactgacagtcgtaactcactatatcgccgctttgtactgtcgca +aaaaaacctcacatagaaagaaaaatctactgggtgcatcagtagagatcgtgttctgag +agataaatacaccggatacgatctgcatcgagttcatgtattaggtcaagcttgggactg +ttgtgccagtagcattttttaacagtcaaagtagggtgagacacgtcatatcataatata +tgccatcgaggtttaaagtttatatgataagctagcatgcgttgcaatcgtattcttgaa +tgctccgtggtttgtactaattcctttatagactgagtgtatcgtacactcggtacaatt +acaaaggatggaagagcaaataggtcttcaattataacagtaccccaccttaatctaaaa +accagcttcaattagtattaatttcgccaggagtatatatataaatatctaaagactaaa +agactcgtacttttacaacttacgtcgtagcataattaaatcatgggtaaatgtcatcag +taagtgcattagaaatactcctttgtaaggatacagtgaatgtgtctcagcaagtcagta +gaaatggaaattcatactcgattaaggcctataaaactgttgttggtatctacagagtga +ttaaaattagtgaatcagattacgaaaatgttttcccgctcgcacttacgcgtttagaca +aaagtacaggtggtacaattggctgtagtagaattttggtataaaataggtgataaaccg +gatgggtgtgggcgaattcaaaagcggtttttgttccatagaactatgtagttggttata +aaggttgtaatctcggagattaggttagggcttaatcagaatagtaacaatttctctatg +taaagtacagtgggtgatcgtatgagttcacgaactcttaatgccatgcctggacaggat +aaacaatacgcatataacttgacgatcgagcttatatcgacctatttgagaagtttaacg +ggtcgatataatatacaggtcttaatagccgattttttctagaaaagcaatcctatatct +tagttaatcagatcaaccccgtgaacgatatatcagcaaactgaacattgtatacaacat +tcctttttgtccgggtggggactccatttaaagtatctcacctagaactcagcggtaata +gatgcagtctcttgcccagttacggtaactaaatgttgatacttagaattgctaaatttt +agtctagacatttccaggtaaaccggtagacgacaatttctctgtcatctgtcataagat +cgcttagtgtgctcaaattgcaattgagggccctactatagacaatcatcagacttttta +attaaatagttttccatgaatgtgttgtcaaggcggaccccttcacttttatcacggctc +ataaatgtcgtatgactgtagtcggtagcggccttcgagtcttcaggggaaatggaaaag +aaattaggcttctaagatggactataatcgattaggctaattccgttcgcaaatcacaga +agcaatcttactcaaaattgttggaatcgatagcgaacgcgaccgtgaatgtttaaaagt +gctcgcacagaattacccaatacctatcatcacgacttaaatacccaaagcagttgtagt +cgcgtaatagattaagtctgaagcctagagacaaagggatactgggcggggaaacctgct +ccttcacggtaacatggtaacaacagaatttggttaaggttaaaacgaaatatactcgga +gtgaattactgttaggtttcgtcatcggatcaataagtagtttccgtgaagacactctta +tattagatctccgaaattctgacccgtgcattaggcacttggtaggagattccatttgga +acttgctcaatgtaagccagtaatgttccgaaataattcgctgcaggagcgaggagccgc +tgaataaaggaccctcgcatcttgttaccttatggttgagggtcaccgttctctgcgtca +attccagagctggagatacattcatcaacgttacctacgcacagaataaaaagatcgagc +gctaactcgttttcctaaacacaacggatttagacaaattaccgaatgcgccggagagta +gcatcttagtgtcatgcctatcatggcggctcagtacgaagagttcaggcatcgaatatt +gtggtagcccgcactcaaagttccgccattaggtaagctatatattgtggtcagaacttg +aggacaactatgagctactaaaaataaacaattttgtcatttgttctagatatgtggcat +tcatcgaacgcttgtaccagaagttacattcgcagcgtgagcgaataaacccgaatgagc +gtaacattatcaataacatatagttcagatagagaacgaggtattcgacagagaattacc +caacattggttattaatctatgcagaataatttagataatgtcactacataatattagga +ccaaaaggtgattccccagaagacaaaacaataaacaatctcacatattcgctagtacct +atgtatgggtatgatcttctgattggacggggataatttccaggtatattaaaacttatt +accataatctagacctaagagaggttatataagtaaagagctgtgttccgatagaaaaac +ccgaccttaaagacttgcgaagtaaattttgctttaacaaaaaaacctacgtaagggaat +attctgtataaactgaaaagtcaggtgtaactacatgagtcatgtcttcgattaattaca +atgcgatctcgttattctgatcaactaatatcataaactgccactacatcttgtacaatc +attcgcaacaatacttttatgtgctaaggtcacgtgcttcctctgctatgctgatttaat +cagattcataaaggaatacgaataactctggatccattaccacgcaagggatttatttac +ggctgattactttttggctgttgacagaactgccatgaaagtaagatgtcgcatcttgca +taaataatagcacctaatatagccgacaaagtgattccgataacagattttaagttgtcc +agccttgagactccatgaagaccgcttgggagcttccccgtgattagaagaatctaaatc +ccaagtggatggggggagtttaaatctcagcaccaacaaatagtacttcctctcagagcg +cgtcatggtcgaaggagcctatcctgatagaggtttgaaagcgcacgcgcatttaactgt +catattaaattggaatctcgtaagtgtcggcagtacgacaaattttaactgatgtcggta +tacggagaagaaggaagcacgcattgaagcagctacgcagaactgagaagatgacactct +aagatacaattaatacaaaaacgttttaagcccaatctatcaacagatgtaagatgtcta +atacacaagaataaaaccttcatgtcccgatgtataataacagctttatttctgctggtc +gaggtgaagtagtggaaattactccatcttgctgcgcgtctttatagtgttggctactct +gtaaccgacgcgtccatccctctctcctagtgatccgtatatccaattagaggataacca +acatctgcgttaccgacgaatttaaatttttcgactatttaattccgttcaaacccgtat +tcgtagtaagtgtttcatagatttatgaccgacatcgtgtacgagttgcagtgcatatgt +agataccactaattgctgatctaggatacatgctttataaacatgcttacttggctattt +tatttactgtcatgtgggggtttttattttcaacaagtatgtgctaccattggataatct +ggcttcaaattgaagatatgcgttccaaacttgtctactgtttgctaagtaggagttgtc +ccattagaactacgcagcacgtggtttgtgatcgaaaagaataattggcaaatacgaggc +tagccttcaaatttaatgcagattactcctcagaaacacacgtaagcgacgaacgtgatg +tttactacacaatgcgtatcatagaaattcgtgataatttttgttccaacctttgaatct +agactgagtggaaaaagatttcaccgggataccgtttatgctggttttaaaaactcgtcg +aatcatcttataactgcattcaaatggatttctcaatcatctgtacgtcaactgttttaa +caataacgtcagaataaaccggcacaatgagacggcggtctttcactacaccacaccctt +aggattataagtgacgtgtggattcgaattctaaggtgacgggatctacaagcctcagct +acattaggtctgaagatctttcgtatagccgcgtatgttactgtttggatatgggttatg +ctaatcaacagttgacagcgagtgaaacggccttgcgacctgaaatctttacggttacct +tttgattcaagacaggatcgacgatggaccacgtgaaatgaattcaaaactgtaacatcg +cttgtgcctcagcgaccgagtaacgacaagttcacatcctctatgcaactatcattgtgg +tcattaaggtattcaagattaactaagagtcgaccatatattctagagttttacaattag +gaaccgttagtctagactaggagcgtgcaacatcgcaggaggtgtggactgtcttgaccc +aagttgcctgacacatagtgtcttttgcttcatgtccttagcaatgcgatacctcaatcg +tagttttatcgggataaataacatggtgtttaaccctattaatggtttctattaatctaa +attgtaaggcagcccttgggtcgaaagcacattaggccacatacacagtatgaaattgtt +cgagtgtccagaccataattgactaccatggtacacggtgttgctattatgactcccgca +aaactcttgacagagggaattttggtacattgatgtaatcgatgatttaacagtaggaac +tagacgtcatccgttagactgagttccgacatgctcaaattgtcaggatttttatccaat +aactaatggctctcacatgtaaataaaatcacattaacgtcacttagtgatggattcgct +aaacagatagactatcattcatgaactggcactgtttcgattatatttgcaacatcgaac +atacttaaagttaaatacgacatcattcaattaaaaaaattcagtacacctctaatgagt +atcccgctttggaggaaagagtagcactttaaatggacaatttaggccggactttcctgt +aaatggatgaagtcattgtacagcttgaataaatcgttagggttagtccttacatccacc +atatgttaatgaataaagcctgagggaccttagagctaacttgtccaacacgttgctcat +ttacttaataaggttgaaatgtatcagtaagtgacagcgagtgtagattttgaccattta +actgaccttcacagttttgtcttcagacgtcacttacaccataatgatgacagagcttgt +agatgcacacactcattcctagtgtaaatcaagtagtagctagattattataaagagata +ttttctggcgtcgaacgtaacacagagagagtataaggggcatgataatggcttatcaat +atgtgtaagaaaaagtttttaatatcatctaactcggtggaatgcacacttatggccaac +tgaccttgggacgagttaagataccataagaggttgcctgtaagttaagataacaaaggg +atattccatctttgtgtgctaagaacctatttatatttgcagccataaaaacctctgtgc +tatgcagccaccagagttatttatacaaagaaagagaccatttagatacgttaattctgc +ttgcgatttattaaacagacatttcacgtccaaccactacaaaagccctatcgcaagacg +atcattgtattatagcctatgcaacgtagctaagcggccgaggaatcataaaatatgaat +tgttacattgtttactacatatgatcacaatctttgtaaaaggttcgttcgtgatactac +catgtacctaactaacctgagatatatgcaatgacttatggggtcagcgcgcaacatccg +caaagcatagtaatacaaggtaggaaaacttctggatttcccaaggttataatgctctat +actgaccaagagatccgttacgactcgcaatgaatactctaagggcactcacaaagaaaa +ccactaattgataaatttcaatgataatatcctgaattgcatcgtgtatgagttacgaga +agtcgcatttaatgaattagtcatagaaatgtcatagcaggaacataattactatatttt +aacgatttaatcgtagttggagtcctttcccaaattatgtcatcagttccgatttagatg +ttttcgggcccttcttagtaaagaagttaatatccaagactagctcctcacccacgcatg +cacatattcgcgagaagtctgatagaatattcgacagaaatgcgactctagctcacactc +gttaactgatcaggtacttatagacaagtacgttatcagatatcgcttcggggcattgtt +gcgctacctttgtgcatagcagttttgaaaaattgttcaagacctgaacgggaaaatgat +attatttttttaggaggaataatacagtaccatgtaaatactcaaccaccttacgtactt +cttacgccgaacatatatggcacgtgttattcggctaacaaaactgttgtgccttttcta +taaggataagcagattcgttttaaacatatgacctgtaaactgggatctacaaaagaggt +acttaaaataaattgcgcaacggtttagatctgcggatctttggttaaagagcaccatta +gatgtgccatacttcctatcgcctgagcgagaatttagtctgaggaaccactcttgggat +ttaaaacaattcggttaggacacctactcggcggatgaagcaatacgataacattaaaag +tcgttcagtctaattttggtcgtagtacgatgagctgatggccaattgtatttttattaa +cagcactgaaacaaaatggagactttagactaatactaaagtctcaatgttcgtcgaacc +ttaaatgctcggaatgaggggatcttcggaagtatagcgccgaagtgtatctcattatta +taacaccagtgtacagacgacatctaattatggccagaaactgtcattgtgccattaaga +ggattagtagatagtctggaccgtggaatagaattttgaccaaattgaccagtcctgctt +gtagacagcgcgatctaaactgcacgagaatatacaagttggtggtgcttgtggctgagc +acgctaagatgcgtttgtttttacgattctagtgcttcttaacgcaattcagtcttctag +atccgctattccaacatcaatatctcaatttaaggtcaatatatataacaaaattagaca +gagcagctgacacttacgaagcatcgtagaaccgatatagtcgaccttatgatgatatgg +acgtgtccaagtccgcacttccgatgcatcttgacggtgaaccgaaatgaaatcttcatt +agggcccccatgtgtcaaaccactcgagtcccgtctctgaagtcaagtattactgcgaaa +aattcgtctactattagtttattatgaacttatgacgcttaaataaattaaacagtaagc +ctgggaaaatgttaaggcaggaatctttgtaacagttcataatgttgctaaagattatca +gaccccgtgaagacttcgggctttgggcttcgtaccgtagcataatacatctatatagtt +agaggcttgcgtgttgttgtgctattccacatatagcagctctgggcgactcttcaatga +aaatgaaaaatggtaacctggcgacctacttgttaagtcagtttaattcaaggggattaa +gtaccaagggtcgagtttctctgtatttattatactgtaggcaagaagcttttttggcga +gatttaagacttaagcctatggtaaaaatttgatagtgagcgactatagtaagagatttg +ggtggttagtaattaaaattctcctatgctaaatcaggcgtacaatctgagggtgcacat +ttctcgacgcgtgaaccttcaccgaaagcgtgtggattatacaaatttcaaacatattgg +cggggcacttatccataatagatttctgtttgtacgccaaactctgcctcacccctccat +aaattgtattggctagaggttaaattctccgtaaatagagacacatatagttttatacaa +ttgtttgaatcaaagcacgagaaacttttaaccgtacattgacaaatgtcttcggatggg +gcagagcatctcttcgtgacccaaatcaatcgctgagcaataagcaagaaaacacagatt +atacaaagagatctggatgaagatattcgtgcaatcactatcgttatgttagagagttcc +atgcatgaggactcgttttttgaccaggagaattaagccaagaaataactgacgtatttc +caaatgaattctacgtgtttttcctgtcacctttagccagtgttaaagatgactatggag +tttcgaataggttattctatagacattataacgagtggaacacccataccttcacagtgc +taaaggtaggaacgggtacgtcaggtagttcaagggattttaggttcttaatccaacgaa +gaaataacgcatcacccgtcattctattgttttcgtcgggattacttagtaggcagggta +ttctaacctacctgagttacaaatctttaaaaaactggccatgaggtcatggtgataaaa +tctgaatcgcctaaattcgcgtccctaaggaaatatactagaatccgtctcagaaagtgc +aaaggttgacttcttcccctaacacagaattctcagttttatagctatctagtggcattc +ctttttataaaactttacgtttgtaagggtccaactttacaaaagctcggatgtgtatgt +gtaatcttccgccgtgtaagacttggaacccatgtatattgacggcatggcgtggctaag +caggtattgatcttcagtgtaaagcaaggtatgttctaatctaacaatgtaaagccgggg +attagccgccaaaggggtctaatgacatagagatgctctgaaatcgtaccaactataaaa +gcacgggatttgaaatatagcgacagatcttccgtattctgttagttgacatctgtgctg +tctttaccgattgtgatttggctttagcagtcatttagtttcgttactcattgctcgtgc +gatagttccaccgaatatggcacattcgttctttttttccattttactgcaaaccttttc +aaaagctgatcgataccactgatgatggcattgattagtcgattggcaactatgtcctgc +ttatatctccaattgcattgaatatagtaaaaaataaaggctcgccttcccaatgggcta +cggagtacacgaaaaaatcgcaactcgtttaaccaagcgccgtacctaacatataagtga +ttgagacaaatagttctccagacgtattgagatatatgtctcctataggcaagcgtttct +aattgctgaccagaaattagaattaggttgttaatactatattcgaccattttattccac +gaatgtgctattctactggtattgctccgtatgcgatatataaccaacacggaaagtcgt +cgattgcaaagtggctccgtagaatcatttctggtcatttaccgggagcgcgcttgaaca +atggatgcggtatctgccatattgttattgttaaaaagacttccgcttactatcgcttcg +atcatcggaaaaatattaatgaggattgggtcgtataagaaaatcatcttttcagttcgc +agatttttgccaatttaaccggttatttcgtcagacttggtagtgtagttacaagcatca +cgattatatcagctacagaattaaactgtcctgactcgacggggcagtgtgtgagtattg +cgctatatattcaaggtaacaggaggcatataggtcatagtacaaggataatgaggtttg +ctaactttaaaaattattgatttaacggttgattgaaaatctctgcaagatgacgctaga +acacctgatgttcaagtttgccgataataacatataagatgaattactgtctttagaccc +tcatgttaatccgctaacttagggcggaaacaatgttaggctatgcggagtaagtactat +attatgataccacatagaatttaacattcatatgatgtctaatacccgttcccaaccttg +caaccgtcccgattaattaagcaattacggtcatcaatgggccaatcctgtctcaaaaat +tatcatattcaaggttcagctattttggcaatgggtgagtaccgttcttagtgatttacg +aacccataatctaggcgacttaatatacaagatttagagttacgttttccgggtagtaca +tattaacgaccatggatcgggtgaggtgttgtattagttatctgatcttgtcagtagctc +ccaatgtcccagaatattatgtttctactagagtgttcgtatactggaatttaaatatta +tgtaagactagacaaattttatggatacattaggccatcgtagaatatgatatagttgta +acgtccctctatagattttcggagggcaggtatattgcttaataaagatgttcggaaatc +agcggaaaggatttgtaattaactgatgcgcagcgcttaaataagtttagactattaagc +tatatgttcgacagcatgtagttttttttaccagaaagtgttatactgatgacccatgga +ggtagctcctcatgataaaaatattgttacttaagcattactattatagtgttcaaacta +gtaccgttgcatactttaagaatcagacatggcgtttcttatgcagacacacttttttag +ctgttgacgcccacctcacatccatagtaggtcaatcgcataagaacaatattctggact +gttttattacccagaagaaagttttttctttccggttcgttaagacaataaagatcattt +cattcgttctcttaacgatgaactaaagtacttaaagtatccgcctcttgtttcgactag +cgcatagtgtaataattaaggcaagataagaagaacaggaacgcgcacgtcggagataac +tctaatagtctctttattccgtttaatatagcccgtaattgcaccatgcgctacagtaac +ggccgccttcgcaaacctatttatgtaattccaagtttaggtatgcaatggttggggcaa +tgtgaggggttttatcaagactttcgttgcttcgcggggggcgcaaagcagactttacag +tagttaaccgaaaaccgcagggagtcgctctaagtgttaccaacccctcactactacgcg +aaggtactcgattattccttgaatgggctgaaacatcgtgattagcgtcttatgattcag +gctgatagaagaaaacttattttctatattccacgtatacaatcacactcgtaactaaat +agttcccagcgttgtaatgtcgctataataaataaaatacaaagaaaattcgtctgggtg +cataagtacagttagtcgtctgtcacataaataatccgcagtcgatctcattacaggtat +tgttgttggtcaaccttcgcaaggtggtccaagtagcattgttgaacagtaaaactaccg +tcacacaaggaatatcataatagatgccatacacggttttacttgatatgtttacagtcc +ttgagttgcaatcgtagtattgtttcatccggggtgtgtacgaagtaatttagacaaggt +gtgtagcggtcactaggtaaaatgacttaggatggatgagcatttaggtattctatgata +acactaaccatcatgtttctaaaatcctcaggaaatttgtattattttaccaacctgtat +ttatagaaagtgcttttgacttaaagaagccgaagtgttcaaattaaggagtacctgatt +gaaagaatggggaattgtaatctgtaactcaattacaaataagccgttctaaggattaag +gctttgtgtctaagcaactcacgtgaattcgaaattcatactcgattaacgactttaata +ctcttctgcgtatctacagactcatttaaattacggaatatgttttcgtttttggtttcc +agctcgcacgtacgcgtttacaaataaggacacctggtacaattggctggagtacaatgt +tggtttttatttgctgattatcccgatccctgtgggcgttggcataaccgggttttcttc +aagactactttcgtgttgcttatatacctggtaatatcggtgagtagcttagggcttaat +cacaatactaacaagttctctatggattggacagggcggcatccgttgactgaacgatct +attaatccattccctgcactggataaacaagacccatttaaattgaccatagagatgtta +gcgtcatatttctgttcgtgatagggtacatatattataaacggattatgagcagtggtt +ttctagaaaagcattcatagttaggagtgtatcagatcataccactgaaccatagagcac +aattctctactggctatacttcattcctttttgtccgggtggggacgaaatttaaaggtt +ctaacctagaacgcagagcgaattgatcaaggcgctggccaagtgaacggttctaaatgt +tcttaatgagaattgcgtattttgactattgacagggcatcgtaaaccgctactcgactt +ggtatctgtaatctgtatgtagatagagtacgggcctataattcaaattcagccaccgaa +gattcacaatcttcagacgtttgaaggaaagaggtttactggtatgtggtgtcaagcccc +acccattctctgttatatccgagcattaatgtagtttcactgtactacggtcacgccgta +gagtcggcagggcaaatccaaaacaatttaggctgagaagtggcactataatagtttagc +ctaagtcccttcgctaataactcaacaaagatgacgcaaaagtcggcgaatagattgcgt +tcgcgtaagggtatcttgaatactgatagctctcatggtaccaagaactttcataacctc +tttatttaccaaacctgttctactagcgttagtgttttagtctgtagccgacacaaaaac +cgagaatggccggcgtaaccggcgcctgcaagctaacatgggatcaaaactattggctta +acgtttaatcgaatgagactagcactgtattactctttcgtttcggcagcggatcaataa +ggaggtgacggcatcactctcttatagtagatatcacttattctcacaacggaagtagga +tcttccgtcctcattaaatttgcaactggctcaatgtaacactgtaatgttaacaaagta +tgagctgaaggtcagagcagacgatgtagtaaggtccctcgaagctgcttacagtatcct +tgaggctcaacgggctatgcggaaattccagacctcgagttacattatgaaacgtgtcat +tccatctcattaaatagttcgtgccctatcgccttgtaatataaacaaccgtttttgtct +attttcccaaggagaaggagagtagcagcttagtggcttgcctatatggccccctaagta +cgtactcggcacgcttagaagattgggctaccccgcactatatgttcccaaagtaggtaa +cctagatagtgtcgtatgaaattcaggtcatcgatgagagtataaaaatatacaattttg +gcaggggttatacattgcgggcatgaagagtaacattggacatgaacggacattcgaacc +ctgtgagtttaataccctatctccggatcattataaagtaaatatacgtcacttactcta +cgtgcgtttagacagtctttgaaactaaattggttatttttctttcatctagatttgtct +gtatctaactaaattatagttccacataaagctgattcaactgaagacataaatataaac +tttctaacatagtagcgaggaaagagctatgcctagcatcggatcatgcgtccgcgagta +gttcctggtagagttaaaagtttttccagaatctagaccgaacacagggtagtgaacgaa +agtgcgcggtgaacatacataataccgaacgtaaacaattccgttcgtattgttgctgta +tctatatttcctacgtaaggctatttgatctataatatgaaaagtcacgtcgaaataaat +caggaagcgcttcgagtatgtacattcagatctccttagtatcatcaaattatagatttt +acggccacgaattattggtctagatgtcccaaaaataatttgatgtcagtagcgatcgtg +cttcctcggagttgaggttggaagaagagtcattatgctataccaagaactctccatcca +gtacctagaaaggcaggtatgtaccgctcattaattttgcgatcttgacagatctgcatg +caaagtaacttgtaccagatggcttttataatagaaactaagtttcccgaataacggtgt +acgataacagatttttaggtgtacagacgtctgactcaatgaacacacattgggacctgc +cccgggaggagtagtagataattaccttctccagcgcgggtcttttaatatcacaacata +aaaatactaattaatatcacacaccctcatcctcgatggagcctagcatcatacacgttt +gatagacaacgccaattttactgtaatatgatattcgaatctagtatgtggacgctgtac +cacattgtttaaaggagctccctttaccgacatgaacgaagcaagctttgtacaagatac +gaagaactcagtactggtaactataagagacaatttatacataaaagtgttaagaccatt +atataaaaagaggtatgaggtctttgtaactacaataatacattcatcgaacgatggaga +ataacagagttatttctgctgctcgagctctagttctgctaatttctcaatcttgatgcc +actcgtttgagtcttccattcgctcttaacgacgcgtacatccctctctcctactcttac +ctatatcctattactggttaacctacatctccgggaaagacgtaggtaaagtggtccacg +attgtattcacttataacacctagtagtactatgtgttgctgagagtgaggacacactta +ctctacgagttcaagtccatatggacattacactttttcagcatctaggtgtcatgatgt +attaacagccgttaggggctatttgattttatcgattgtcggcgtgtgtattttcaacaa +ctaggtgctacaattcgtgaataggcatgaaaattcaagattgcagttcctatcttgtat +aatctttcctttggacgagttgtaccatttcaactaacctgcaagtggggggtcatccat +atgaagatttgccaaatacctggagaccctgaaaagtttatccagattaataataacaaa +caaacctaagcgaagaacgtcagctttaataaactatcactatcatagaaattcctgtta +attgttcttccaaacgttgaatagactatcacgggtaatagattgaacacggagaacgtt +tatccggcttgtaaaatatcgtcgaatctgctgataactcaattatattcgatggagaat +tcatatctaccgcttagcttttaaaaattaagtcagattattccgccacaatgagaaggc +gcgagtgcactaatcaaatcacttaggattattacggacgtctgcattacaatgctttgg +ggtagggttatacaagcatatgattctttaggtctcttgatcgggcgtttaccaccgtag +cttaatgttggcatatccgtgatcctaatattctgttgtcagcgtgtgtataggaatgca +caacgcaaatctttaagctgacctgttcatgaaagacaggagacacgaggcaccacctca +attctatgcaaaactctaacatagcgtggcactatgagtacgtgtaacgacaaggtctca +tactcgatcctaagataattctcgtctggaaggttttaatctttaactaagagtagaact +tagtttattgacttttacaattaggatacggttcgcgactctaccacagggcatcatacc +tggagctctgctatctcgtgaccaaagtggcagcacacatagggtcgggtcctgcatcta +ctgagcaatccctttaagcattcctagtttgagagccatttagatattgctgtttaaacc +gattaatggtttctattattataaagtgtaacgctcccattcgggacattgaaaattagc +aataagacaatgtatgatattcggcgagtctcaacaacattatggtctaccatgggacaa +ggggttgatatgatgaatccacaaaaaatagtcaaacacccatggttcgttaagtgaggg +tatccaggtgttataaggacgatctagaagtattcaggtacacggtgttcagacatgctc +taattgtcaggttgtttataatttaacgtatcgctctctattctaaataatataaaatta +accgctcgtagggatgctttccagtaaaagatacactatcattaaggttatgcaaatgtg +gcgatttgatttgaatcttagtacattcttaaacttaaatacgtattatttaaagtaaat +atattatctaaaccgcttttgtctatccacatttcgtcgaatcacgacctcgttaatgcg +acaatttacgaccctctttcatctaaagcgatcatctatttcttctgattgatgtaatac +tgacccttactccgtacatacaaatgatggtaagcaagaatgactgacgctcctgtcacc +tttcgtggcaatcaactggcgctggtactgaagtagcttgaaagggatatggatgtgtat +gccaggcttcattttgacaatttttctgtcctgctcagtgttgtctgaagtcgtatcgta +cacaataatgatgactctcattgtagatccaatcacgctttcctacgctaatgaaagttc +tagatagtgtaggtgttagacagaggttagcgcctacatccttacacacacagtgttgaa +cggcaagcataatcgagtatcaatagctgtatgtatttgtttggaatatcatatttctcc +cgcctttgaacaatgatgccaaaatgtcctgccctagagttatgataaaataactgctgc +cctgtaacttaagtttacaaaccgatattcaatcgttgtgtcctatgaaaatatttatat +ttgcaccaagaaaatcatctgtgcgatgaacaaaacacagtgatttataaatacaaagag +tacatttagttaccggattgcggcttgacatttattttacagaattttatcggcaaaaca +cttcatatgaactatcgcttcacgataagtctatgatagactagcattcgtagagaacag +gaagagcaatcattatatatgaagtgttacagtgggtactacatatgagatcattaggtc +tatatccggccttcctcataagaccttggaaatatcttacatcagagatatcaaaggaag +tatgggcgaacccagaaaaagccccaaagaatagtaattcatcggacgtaatagtctggt +tttaactaggggttattgatatttaagctaaaagagttccctgaacactcgaaatgtata +atctatcccaactaaaaaagtatacctctaattcagaaatgtcattgagattagactgat +gtcaatacgctaggaggtaagacaagtagaagtttttgatttaggaattgaaatgtaata +cctccatcttaagttctatattttaaagttttatgcggacttcgagtaagtgcacaaatg +atggcataagtgcccagttacatgtttgcggccccgtatgagtaatgatctgtttatcaa +tctctagctactatcccacgaatgcactgatgccagtcatggcgcttacattagtcgaca +gaaatccgacgatacctatcacgcgtgaactgttctggttcttattcaattcgaagtgat +ctcagatacattacggccatgcttgcccttcatgtctgctgagcagttttgttataggct +gaatctcctctaagcgaaattgataggatttttggtggtcgatttagtctgtacctgctt +attaagattcaaaatgacctacttcttacgccgaaatgatagggatcggctgaggaggat +aaatatacgctggtgcctggtatttatccagaacaagttgcctgtgtatcagatgaactc +taatctccgagataaaaaacaggtacgtaaaataaaggccgcaaagggttacatctcagg +atcgtggcgtatagtccaccattagttctgacttacttaatatagactgaccgagattgt +agtatgtggatccaagcttgccatgtaaaacatgtcggttagcaaaacgtataggagcat +gatcaaagaagagttaattaatagtactgcactataattgtcggcggagtaccatgagct +gttgcccaattcgatgtttattaacagcacgcataaaaaatccagacttttcaattagaa +ttaactataaatggtccgcgaaccttaaatgatcggaaggacgggatctgccgttgtata +gaccccaactctatctaatttttataacacctctgtaatcaacaaatcttattatgccat +cattatgtcattcgccaagtaagtccagttcgagattctctggaccgtgcaatagtattg +tcaaattatggtaatggaatccttcttctaacacccttagaaaagccacgagaattgaca +agttgggcgtgcttgtccaggagcaacataagtgccgtttctttttacgatgatagggat +tcttaaagcttttctctattctagatcccagttgccatcatcaatatctcaattgatgct +cattatatagttcttatttagtatgtccagatgtcactgaagatcctgcctagaaccgat +attctcgacaggatcatcagttcgacggggcaaacgcacctatgcacatccatcttgacc +gtgaaacgaaaggaaagagtcagtaccgacccaatgtggaaaaaaactcctgtccacgat +atgtaggcaagttttactgcctttaattagtagtcgattagtgtagtttgatattatcta +ccttatagaatgtaaacagtaacccggccttaatggtttggcaggattctttgtaaaagt +taataatgttcataaactttatcagaaaacctgaagtagtccgcctttcgcctgcgtaac +gttgcagattaattcgttttacggagtggcttgcgtcttgttgtccgagtacacatattg +ctcctctcccccactcttctaggaaaatcaattatgctaacctgcagaccttcttcttta +ctatctttaatgcatgcccagtatgttcatagggtagacttgctatctattttgtataat +ctacgaatgatgcttggggcgcgacttttaacaattaagccgttgggtataatttgagag +ggtgccacgatagtaagagatttccggcgtgagtaaggaaaatgataataggattaagca +ggcgtaatagctcaccctcctcagttctccaaccctgaaccggctaagtatgactgtgca +gtattaattttgaatacatattgcagcccctaggatacattatagatgtctctttcttac +ccaaactcgcccgcaccaagaaagaatgtggattcgattgaggttaaattagccggaatt +acagacacagattcttgtttacaattgtgggaagaaaaccacctcaaacgttgaaaccta +cattcacaaatggattacgttggggatgagaatcgattccggtcaaaaatcatgcccgga +gcaataaccaagaattcacagaggattaatacacttctccatgaagataggactgcttgc +actatccttatctttgtgtcttccttcaagcaccaatcgtttggggacaaccacaattat +gccaagaaataacggaaggtgttccaaatctatgagtccgcggtttcatcgcaacgtttc +actgtgggtatcatgactttggactttagatttgggtattctagagactgtagaaagact +gcaacaacaagacattcacagggcgaaacctaggaaaggggaccgcacgttgtgctaggg +atgtttccttaggaatccatacatgtaagaaagaatcaaccgtaattatagtgttttcgg +ccccttgaattacgtgcatgcctttgctaaaagacctctgggaaatagattgaatattct +ggacagcagcgaatcctgattatatctcaagcgaatatatgacccgcaagaaggatttat +actagaataagtctaagaaagggcattgggtcacttcttccactaacacacttttatcag +ttttataccttgagagtcccatgcatttttatatatatttaactttcgttgcgtaaaact +ttaaatatgatccgtgctctatctctaatctgaacaacggtatcacgtcgaacaaatcta +gtggctacgaatcgcgtcgctaagaacggtttcttctgctggcgttagctacgtatcttc +tatgctaaaaatgtatagccccgcattagcagcaaaaccgggagaatcaaatacacatcc +gatgaaatcgtaacaaagataaaacaacgcgatttctatgtttgccaaagtgattaagtt +gtatcgtaggggtcagcgctgatgtcttttcagtttgggttttggatttaccagtctttt +agtttcggtactatttgatcgggacattcgtccaaacatgatggctcattcgttcttttt +ttcaattttaatcaaaaccttgtatttacctgatacattaaactgagcatcgcatggagg +tggagattcccatatatgtaatcatttgatatcctattccattctttttagttataaata +aacgctccactgcacaatgggagtaggacttcaccaataattagcatctactgtaaacaa +gcgccgtaacgaaatgattactgattgagaaaaataggtctcaacaacttttgacagata +tgtatccgatacccaagcgttgctaattgcgcaaaagtaagtagaattacggtcgtatta +cttgttgccaaatggttattactccaatgggctattctaatccgatggatacgtaggaga +gagtgtacctacaccgaaactcgtagtgggcttagtggctacgtagaagctgttcgggtc +agttacagcgtgcgaccttgtaaaatcgatcacggtgatgaattattgttattgtttaaa +agaagtcccctgaatagcccttagataatacgaaaatttgttatgtccagtcgctcgtat +atcaaaagattcggttaagttcgcagagttttgccaagtttacaggtgatttactaacac +ttgggagggtacgtacaaccatcacctggttagcagagaatgaattatacggtcatgtcg +cgaagggcaagtgtgtgagtattgaccgagttattaaacgtaaatgcaggcatttacgtc +ataggacatcgagtttgtcctttgcgaaatgttaaatttatggttttttccgttgagtga +taatagctgcaacatgaagatagtaaaactgaggttaaactttcaccatattaaattata +tgttcaattacgcgatgtacaaactaatgttaatcagatttaggagcgcgcttaatatgg +gtccctatcccgactttgtacgagattttgataaaaaatagtattgtaaattcatttgat +ggcgtagaaccgggcaaaaccttgaaaaaggacacatttaggatgctatttccctaagaa +agcggaaaatcctggctcaatatttataatagtaatggttaagattgtggcccaatcgct +gagtacccgtcttacgctttttccaacacataatcgacgagaatgtatttaaatgtttga +gacttacgttttccgcgtacttattattaaagtcattggagagggtgtcgtctgggtgta +gttttctcatctgctcaggagctaaaaatgtaaatctattggttgtttctaattctgtcg +tccgtgtaggctatttaatttttatggtacacttgaatatgtttagccataatgtagcca +atactacaatatcagatacttgtatacgacctatagacttttgccgaccgctcgtagagt +gatttagaaagatgttcggatagcacagcaatcgtttgcgaatgtaagcatgcgaagcga +gtatttaactgttgactattttgctatatgttactctgaatgttgttttttttaccagaa +tgtgttataatgatcaaccatgcacgttcctactaatcatataaattttgttacgtaagc +ttttctatgatagtggtctaaagactacccttgcatactttaagattaagacatgcactt +taggaggaactcacacgttttgagctgttctagcccacctataagccattcgtccgcaat +cccataactacaatagtcggcaatcttttattacccagaactaacgtttttatttcccgg +tacgtatcacattaatcttaatttaatgcgtgagagtaacgatgaacgaaagttatttat +gtttaagccgcttcttgagaatacagattactgttagaatgaaggcatcataactagaac +accaacgcgcacctcgcacattactctaatagtagctttattcagtttaatatagacagt +atttgaaccaggcgctaatgttaaggcccccttcgaaaaccttgttatgttattccatgt +ggtcggaggatttgcggggcgatagcgctgggcggggatcaacaatttcgttcatgcgag +cgcccccataaccagtaggtacagttcggaaaagaaaaccccacgcactcgctagaagtg +ttacaatcacatcacttcgtaccgaagggactactgtattccgtcttggggatgtaacag +actgattacagtcttatgatgaagcctcattcatctaaaattagttgatttattccacgg +atactatcacactcctatagaaagagttaccaccgtgggaagctagatataataaataaa +agacatacaatattagtatggctcatgatctacacttactcggatctctctttttttata +accagtagatcgcattacacgtattgttgttccgcatcaggccctaggggctcaaacttc +catggtggataactaaaacgtccgtcactaaacgaagatattaatagatgaaatacacgg +gtttacttgatttctgttcagtcattcacgggaaatcctaggagtctttcataacggcgg +tcttagtaggaatgtagtcaagctctgtagaggtctcgacggaattggtatttcctggca +tcacaatttacctagtattggagatcacttaaaataatgttgagataataatcaggatat +ttctagtatgtgacaaacctctatttagtgattgtgattttcaattaaacaagacgtagg +ggtcaaattaacgactacatgttggaaagaaggccgaattgtaatatctaactcatgtac +taagaagaagtgctttcgtttaaggctttctgtctaacattctaacgtcaattcctatgt +aatactactgtaaccaagttattactcggctgcgtagataaagtctcatgtaaatgacgg +tttatctgttacttttgggtttcaacctagctaggacgccggtactaattacgacacctg +cgtatagtgcagggtgttcaatgtgcctttttatgtccggattataaccatccctctccc +acttggaatatcaccgggttcttaatgacttagttcgtcttccttattttccgggtaaga +tcgctgtggaccggacccattttgatctagtctaaaaaggtatatagcgtttcgtctggc +ccgcttacgttcactgaaacttagattaatcaatgcactgcactggattaacaagaacat +gttatagtgtactgacacatgttagactaagaggtctgttcgggttagccgacttatatg +tttaaccgattttgacaactgggttgagagataacaatgaagagtgaggactgtagaaga +tcttaaaactgtaccatagtgctcaattcgctaatggcttgaattatttaattgttctaa +ccctggcgtcgaatttttttggttcgaaaatacttagcacagcgtattgttcaacgagat +gcacaactgtaccgttagaaagcggcttaatgacaaggcagtattgtgactattgacagg +gaatcctaaaaagctactcgaattggtatatggaagaggtatgtactgagaggtcgcgcc +tattagtcaaattctgccaaagaagagtcaaaagcttaactagtttgatggtatgaggtt +taatgctaggtggtctataccaccaaaaagtatatgggatatcccagaatttatcgactt +tcaatcgtctaccgtcacgacgtacactaggcagccctaatccaaaacttttgaggatga +gtactgccactattatactgtaccatttgtaacttacattttatatcttcaaagaggtag +atattgtcggccattactgtcacttacactaagggtagcttgattactgatacctctcat +ggtaaaaagtaatttaagaacctatttttttacataacctctgctactaccgttagtgtt +ttagtcggttcaagtcacaaaatccctgtagcgcacccctataagcagaaggaaacctta +atgcggataaaaacttttgccggaaccgttaatcctatgagaataccactcttggaatcg +gtcctttaggctgaggatatagaacgaggggaacgcatcaatctaggttaggtgagagaa +ctttgtatcaaaacgcaagtaccatatgccgtcctcagtaaattgccaaatgcagaaatc +ttacactcttttcttaactaagtatgagagcaacctcactcctgaacagcttgttaccta +acgagaagaggctttaagtagcctggagcctcaaccggatatccggatttgactctcatc +cacttacatgatgattacggtcattacatctcatgattttctgagtgccctatagactgg +gaatttaatctaccctgtttctatttgttaacaaggagaaccactggtcaagatgacgcg +cttccatttatgccaccataagtaagttctcggaacccttacatgattggcctaccaacc +tatatatgtgaccaatgtacggtacatagagtgtggcctatcatattcaggtcatcgagc +tcagtatttaaagattatatggtcgctgggggtattcagtgcgcgatggaagactaacat +tggaaatcaacggaattgacaacacgctcactttaataacctatctcaggataagtttaa +tgtaattagacggaactttctctaactccgtgtactaactctttgaaaataatgtgggta +tttttatttcatctagatttgtctgtatcgaaagaaagtattggtccaaataatcctcag +taaaatcaagtcataaatataaaatttagatcttaggacagaggaaagtgctttcccgag +cataggatctggcctacgccagtagttcatgcttgtgttaaaagttgttactgtttatag +tccgtactcagggtagtgttcgatactcagcggggaactgacatattacactaaggaatc +aaggcccttcgtatgggtcatgtttatatatttaattacttacgctatttgatcgagaat +agctatagtaacgtcgtaagaatgcaggatgcgattcgagtttgtaaattcacagatact +gtgtatcatattattatagatgttaaggcatagaattattggtattgatgtacaaaaaat +tatgggtgggcagtaccgataggcattacgagcagtgcagcttggaagaactggatgtat +cctataactagtaagagccttaaaggtactacatacccagggatgttaccatcattaatt +tggccatcttcaatcttcgcaatgcatactttcttctacaagatgccttttagaagacaa +aataagtgtcaacaataacgctgtaacttaactctgttgtacgtggaatcaagtctcact +aaagcaactaacattccgacatgcaaacgcaggactactagattattaaattcgccagcc +cgcctcgtttaatataacatcataaaaattctaagtaatatctcacacactaatccgcca +tcgtccatagcatcagtcacctgtcttacacaaacacatgtttaatcgatgttgttatgc +caagctagtttcgcgaccatgtaactaattgtggaaagctgctaccttgaacgacatcaa +ccatcctacctttgtacaacagaccaacatctctgtactggtaaatagatctgaaaagtt +ataaatataactgttttcacattgatagaaaaacagctatgtgctatttgtatatactat +aataaattaagcgaaacatggagattaaaacagtgttttctcatcctccacctcttgttc +tgctaatttataattcttgatgccactcgtgtgagtcgtccattcgatcgtaaagaaccc +gacataaatagatacgacgctgaacgagatcctatttctcctgaaaattattagcacggt +aactcctagggatagtggtactagttggtatgaacgtataaaaacttgtactactttctc +gggatgtgagggagcaaactattactcgaccagtgcaacgcattatcgacagtaaaagtt +ttcagctgatacctgtctggatggattatatgcaggtaggcgagagtggattgtagcgat +gctcggcgggggtattttaaaaatctaggtgataaaagtcctgtttagccaggaaaagtc +atcattgcactgcatatcgtcgattagctgtcatttcgtccactggtaccagttcaacgt +acatcaaagtccgggcgcatccatatcaagttttgcaatagtactccagaccatgaaatg +gttatccagattaataataacttaatatactttcactacatactcagcgggtattaaatt +tcactttatgtcaaaggactcttatgtggtcttcaaaaaggtctagagtctatcacgcct +aattgtgtgaaaaccgagtaacttgatcagccttgtaaaatatagtagaatatgatgtta +aatcatttatattccagggagattgaatagcttacgattagctggtataatttaactcac +atgattaagcaaatatctgtaggaccgagggaaagaataaaataaagtaccatgagttcg +gaacgctgcattacatggcgttgggctagcctgatacaagaagatgagtatggagctctc +ttcatcgggacgtgacaaccctagcgtaatcttggcagatcccggagcagatgattatcg +tctaacactgtctttaccaatgcacaacgcatagatttaacctgaactgttctggattca +ctcctgactacagcctacaactcatttctatgcataactcttaaagacagtcgcaatatc +agtacctctatacacatcggatcagactagatcataagataagtctcctctggatccttg +tattctgttaagtacactacaaatttgtttagtgtctgggacaattacgataagggtcgc +gactagaccacagggcatatgacctccaccgctcctagcgagtctccaatctgcaagcac +tcatacgctaggggcatgaatcgactgtcaatgcactgtaagatttacgagggtgagacc +catttagatatgcctcgtttaaccgttttaggcttgataggatgagtttgtcgatccatc +aaattcccgacattcatattgtccaataagtatatctagcttattcggactcgctaaact +aaattatggtataaatgccgtcaaccggtgcatttgttcaatcaacaaattatagtcaat +ctcccatggggccttatggcagcgtatacagctggtataacgaccatatacaactatgaa +cggactagctgtgaactaagcagattattggatccttgtgtataattttaagtttcgatc +tatatgctatagtatagaaaatgttccgatcgtacgcttcctttacagttaaacagtcta +tatcatgaagcttatccaaagctggacatttgatggcaatcttacttaattatgaaactt +aattacctattattgaaagtatttatatgatcgaataagatttgctctataaacaggtcg +tccattcacgacctagtgattgcgtaaattgaccaacctaggtaatctaaagcctgcatc +tatttcttatcattcatgttatactgacccgttctcagtacttaaaaatgatcgtaagca +agaatcactcacgctcatgtcacatttagtcgaaataaactgccgatgggaaggaagttc +cgtcattgcgatatcgatgtctatcccacgcgtcattttcaaattggttatctacggata +actgtgcgatgaactactataggtcaaaattatcttcaatctcattctagatcatataaa +gatgtccttcgcgattgatacgtctacagtgtgttggtgttacacagagggtagcgacta +cttacttactaactctctcttgatccgcaagcataagccaggttaaagtgctctatcttt +ttctgtggattataatagttataccgccttgcatctaggtgcccattaggtaatgcccta +gtgttttcataaatttactcctgccatctaacgttactttaatttcccagattcaatagg +tctctcatttgaaaattgttatatgtcaacaaagaatataatagctgagtggaacaatac +actgtgagggagtaatacatactctaaattttctttacggtttgcgcctgcacagttttt +tttatctatgtgatccgcataaaaagtaatttcaacgttccattcaagttaagtcttggt +gacactagcattaggagagatcaccaagaccattatttatttagctagggtttaagtcgg +ttagaaatatcagataatgaggtctttatccggccttacgcagtagaaattggaaatttc +gtaaagcactgagttcaatggaagtatggccgaacccacataatgcacaaatcaagtcga +tttcttccgtccttttagtctcctgggaactacgggttattcatagttaagctaaatcag +ttaacggaactagacaaatgtataatagttcccaaatatatatctataaatcttatgcag +ttagggaatgcagatttgaatcatggcaatacgctagctcggaactcaactacaagtgtt +ggatgtacgaattcaaaggtattacatccttatgatgttcttttttggatacttttatga +cgacttccacgaagtgaaattatgttcgaatatctgaacagttacttggttgagcccaag +gatgacgaatgttctgtttataattctcgtcataatataaatacaagcatatgaggccag +tcatggagctttcatttggactaacatttccgtagagtcatatcacgcctgtaatctgat +ccgtctttttctattcgaagtgttatcagatacatgacgcccttgcgtgacattcatggc +tcctgacatcgggtcttttaggctgaatctaatctaacccaatttgtttggattgtgggt +cctccattttgtctgttaatgcttattaagattaaaaatgtactacgtatttagacctaa +tgattgcgatacgctgtggaccattaatataagctgcgccaggggatttttccagatcat +ctggcctgtgtatatgttcaaatctaatagccgagagaaattactccgacggaaaataaa +ggcagataagcgtttcagagcaccatcgtggcgtttagtcaacctttagttcggaattta +ttaatatacaatctcactctttggacgagctccttaaaagatgcccttgtatatcatgtc +ccgtacctaaaagtataccagcatcatcaaagaacagttaaggaatacgactgctctata +attgtccgaggagtaccttctcatctgccaatagtcgttgggttggaaaacaacgcatta +atatgccacacttgtcaattagaagtttctataaaggggacgagtaactgatttgagacc +tagcacggcagaggacgttcgtgtgacaacatctctttataagtttgagataaaatcgct +aatctacaatgattatttgccaatcattatcgaatgcgcaaagtatctcctgttcgtgat +tctagcctaaggccattactatggtcaaattatgctaatcgaagcagtcttctaacaccc +ttagaaaagcaaacactattgaatactgccgccgcattcgccagcaccaacataactgca +cgtgcttttttccatgattggcattatgaaagatttgatctatgattcttaccagttgca +atattcaatttagcatgtgttcctaattattgtgttattatggtctatctcatcatgtaa +atgaagatcatgacgtcaacacagattctagtcaggatcatcagttcctcggggaaatcg +cacctaggaacagccttatgcaaccgctaaacaaagcaatgaggatgtaccgacaaaagc +tcgatttaaaagcctcgaaacgagatgtacgaatcgtttactgccttttatgaggagtcg +agtactgttggttcatatttgctacatgattgtatgtaataacgatcccgccctttatcg +gttcgatcctttatggcgataagttatgaatcgtcagtatctttagatcaaaaactcaac +tagtacccagttccccggaggaacggtcatgattaatgcgttttacggtctcccgtccct +cttcttgtcagaggaatcagtttcatccgatcccactcgatgattggtatagctatttgc +cgaaaagccacaacgtattcggtactatcttgtttgattcccctgtatcttaattcgcga +cacttgatatcttttgtgtttaatcgacgaatcatcctgggggcgacacttgttacaatt +atccagttgcgtttaatggctgtgggtcacaagattgttagacaggtcccgcgtgtcgta +ggaaattgataattggagtttgcaggacgaatagctcacccgcctaagtgatccaaccct +catcaggataactatcactgggcagtattatttttgatttcatatgccaccccctaggag +actgtagtcatgtatctttcttacccaatctagcccgaaacaagaaagaatgtcgattcc +agtcaccttttattagaccgatttacacacaaagtgtcttggtttaaaggctggcatgaa +tacatactcaaaagttgaaaacgacttgctctattcgattaccttcgcgatctcaatcga +ttacgctaaattttaatgcccgctgaaatatccaacatttaaaacaggattaattctctg +atccatgaacttaggactcattgcacgtgacttatctttctctcttaattcatgctccaa +tacggtgggctaaaccacttttatcacatgaatgtacgcaacgtgttaataagctatgag +tacgcgggggcagcgaaacgggtcaatctgggtatcttctattgggacggtacatttcgg +ttttatagactatgtagttacacggcatcaacatgtaattaaaacggcgtaacctaggaa +agccgaacgcaccttgggattgccatgtgtccggaggattacatacatctaagaaacatt +ctaaactatgtatagtcgtttacgacccttgtagtacgtgcatcccttggcgaaaagtac +tctgggtattagagtgtatattatcgacagcaccgaatcctcattttatagcttgacaat +ttatgacccgaaagaaccttttataagtctataagtatatctaacgcaattgcggcactg +agtccactaactatctttgagcagtgttatacagtgagacgccatggaaggggtttatat +attttactgtcgttccctaaaaagttaattatcagacctgcgcgatctcgtagatgaaca +acgcgatctagtcgaaaaatgcttgtggctaccattccagtcgagatcaaccgtttctgc +ggatcgcgttacattccttgcttatttgcgataaatcgatacaaccccattaccagaaaa +acccggagaatcaattactctgcagatcttatactaaaaaagagattacaacccctgttc +tatgtgtcccaaagtgagtaacgtggagcgttggggtaagagcggagcgattttaacttt +cgcttttccattttccagtattgtactttacgttatatttgagcggcacattcgtcaaaa +catgatccatatggactgaggtgtttaaatgttaatcaaataattgtattttcagctgac +tttaaaatctgcagccattggaggtggagattccaatagatgtaagcaggtgatatcata +tgcaattcttgtgacttattaagataccagacacggcacaatcgcagtagcacgtaaaca +ataatgacaatcgacggttaaattccgaacgtaagatatgtttacggatgcactaaaata +ggtagcaacaacgtttctctgagatgtataagttaccaaacactggagaattccgctaaa +ctaaggacaatttccgtcgtattaattgttgacaaatggttagtaatacattcgcagtgg +ataatccgttgcatacctagcactgagtgtaaataaaaccaatcgactactggcatttcg +ggctaacgactagatgttagcctatgtgaaagcctcacacatgcttattgccttcacggt +gagcaatgtttcttattcgttattagaagtcacctgtagagacagtagagatgacctaaa +tttggtttgtccagtcccgaggtgatctaatgattaggttaacttagaacagtggtcaat +tggttaaagctgatttacgaacacttccgaggggtcgtaaaacattaaactggtgagaac +agtatgatgtattcggtcatctagacaaccccatcgctgggagtttggacagtgttatga +ttcgtaaatccaccatgtgtccgaattcgaaatcctgttgctccggggagatagggttaa +tttaggcttttttacggtgtggcatattagctcaaacatcaacattcttaaaatcagcgt +aaacggtcaccagttgatatttgttctgctaggaagcgatgtacaaaataagcttaataa +gatttaggtccgaccttaatttcggtccatagcacctctttctaagtgttttgcttaaat +aattgtattgttattgattttctgcgagttgaacacggaaaataagtcaaaaaggacact +tttaggttcatatgtaccgatgaatgcgcaatagaatcgagaaatttttagattagtaat +cgtgatgattgtggccaaatcccgcactaaacggctttcgctgtttccaaaaaattttag +tccactaggtatttaaatgttggacactgaacgtggaagccgtcgtattatgaaactaat +ggcagaggggctcctctgcgtgtactttgagcagatgctatcgtcagaaaaaggtaaatc +ttttggttctttataattctggcgtccgtgtagcctagtgaatgtgtttggttcaagtga +atttgtttagccagaatggaccaattacgtcattagctgttacgtctatacgaaatatag +actgtggacgacccatcgtagagtcatgtagttacatgtgaccttagaacaccaatcgtg +tgcgattgtaagcaggacaacacagtattgtactggtcaattggttcatagatctgacta +tgaatcttcgtttttgtacaacaatctcggtgaagcttcaaaaagcctccttcctaataa +tcagttaatttttcgtaaggttcctgttcgaggttagtcgtataaagacgaaacggcctt +aatgtaacattaactattccactgtaggtggatctaacaaggttggacatgtgctaccaa +taagataagaatttcgtccgcaatacaatatctacttttgtagcctatcttggattaaca +acaacttacgttggtatttcaccggacgtatcaaatgattctgattttaatgactgagag +taaacatcaacgaatcttatgtatctttaagccgctgcttgacaagtcacattactgtta +gaatgaacgcttcattactacaaaacctaccaccaactcccacattaatattatactaga +tgtttgaagtttatttgacaaaggttttcaaaaagcacagaatcgttacgaacacgtaca +ttaaattgttagggtattaattgtggtcggtgcatttccggccccatagcgctccgcggg +gagaaactatggccttcatgacagcccccccataacatctaggtaatggtcggataacta +taaacaaccctctccagagaactgtgaaaataaaatctcttagtacacaagcgtatactg +gtttaagtcttgcccatcttaaagactcttttcactattttcttgatgcctcattcttct +aatattaggtgattttttaatccgagaatataaaaagacgatagaaagtgttaaaacacg +gcgtagcgacatattttaaagaaatgaaatactttttgactatccctcatgatctaaact +tacgcggagctatctttttgtataacatgtacagagaattaatccgatgcttcttccgat +taaggacatagcgccgaaaacgtcatggcggcttatcgatatcgtaacgcactataccaa +gtgattaagtgatcaatgaatacgggtttcgggatttctgttaagtcatgcacggcaaat +acttggagtcttgaataacgccgcgcgtagtacgaaggttctcaagctcgcgtgacgtat +agaccgtattgctatttcctgccttctcaattgtccgaggattgctgataacttaaaata +aggttgagtttttaataacgatttgtcgagtttgggaaaatcctcgtttgtgtgtttgtc +attttcaagttatcaagaactacgggtataatttacgacgtaatgttggtttgatgcccg +attgcgaatatcgtacgaatggtatttgtacaactgctttcctttatcgattgctcgaga +acattataaagtctattactatggattaagactgtatacaagtgtttaagcggagcccgt +gataatctataaggttttggtacctttatctgttacttttgccttgaaacatacatacgt +acacgggaatatttacctaaacgccgtatagtccagcctcgtatttgggccgtgttttgt +cagcattttaaactgaaagcgcccacttgcattataacccggtgcggaatctcttagtga +ctcgtcaggagtttacgcctttgagacctctcgacaggacccattttgatctagtcgtta +taggtagagtgcctttcctatcgcaccattaccttctagcaaacttagagtattcaatga +aatcatatcctgtttatactaaatgttataggctaatgacacagctgacactaagaggtc +tcttcgggttacccgaatgagttgtttatacgatgttgacaactcgggggagtcatttca +atgaagactgaggactcttgatcagattaaaacgcttaatgactgataatttagattatg +ccgtgtattatttaagtgggcgaaccctcccctagaatgggtttcctgagaaaagtctta +gaacacagtattctgaatccagatgcaaatcgctaacgttagtaagcggctgtagctctt +ggcagtttggtcaatagtcaatcgcaatccgtttaaccgtctactattcctagagcgaag +agctatgttctgacacgtccccaatattaggcaaaggctccaaaagaacagtcaattgat +taactacgggcttggtttctccgtgaatccttgcgccgctataccacataaaaggatagc +ggtgataccacaagtttgcgacgttaaagcgtcgaccctcaacaagtacactagcaaccc +cttagcaattaattttgtccatcactactgccaagagttgactggaccagttggaaatga +catttgatatattaatagagctacatattgtaccactttactgtcacttacactaaccct +agcgtgattactcatacatatattcgtaaattctaagttatgatactagttttgtaaatt +taatcggcgaagacacgttctcttgtacgagcttcaactaaatatttcactgtagccaac +cactttaaccagaaggataccttaatgccgatataatattgtccaggaaacgttaatact +ttcacaagacaaagcttggaagaggtactttacgatcacctgatagatcgaccggaacga +ttctatataggtttggtctgagaaatttgtagctaaaaccatgttccataggaactcctc +tgtaatgggcaaaatgcagatagcgttcaatcgttgcttaactatctatcacagcatcct +aactcctcaacagcttctttcctaaagacatcagcaggtaagttgacggcacccgataac +ccagagcacgattggaatctaatactctgtatggatcattacgctaagtaaatataatga +ttttctgactcaaagttacactgcgaattttatattaactggttctatttgttaaatacc +acaacctctcgtcaacaggtcgcgatgcaagtgatccaaaaatatctaacttataccaac +cattacttctggcgcagaaaaacatagatatctgaacaatcgaccgttaagactgtctcg +ccgatcttaggaacctaatactgctcagtagttattgtttatttgggccatccccggatt +atgtcagccatggaacactaaaagtcctaatctaacctatggacaaaaagctcactttta +taaaattgctcaccttatgttgattgttatttgtccgaaatgtctataactcagtgtact +atctattggaaaattatggccggagttttattgaatatacttttgtatgttgagaaagaa +tgttgtcgtaataattatcagctggaaaatcatctaatatatattatattgagatattac +gacagacctaagtgctttcccgtcatgagcagatggactaacactcttggtaatccttct +cgttttagttggtaatgtttagtctaagtaatatcccgactcttacttactcagagcgga +aatgactttttaaactaacgtttaaaggcacttagtatgcgtcagggttatttttttaat +tacgtacccttgtgcagagagtttagctattcgatcctacttagtatgaaccatgagagt +acaggttggtaattcacagagaaggtcgagaagattatttttgatgtttaccaatactat +gaggcgtattcatcgaaataattttatggctgcgcacttcacatacgcaggaagaccact +gcagcttgctagatctggatgtatcattgtacttctaagagcctgaaaggtaatacattc +ccagcgagcgtaacagattgtatggggacatattcaatcttagcaatgcattcgttcttc +gaaatcaggcatttttgatgtcataagttctgtcaactataaccctggaactttaatctg +ttgttcgtcgaatcaaggatcaagaaagcttctaaaaggcccaaagcaaaacccaccact +acttcagttttaaattagaatcacaccctagggtattagataataattaaatgtcttagg +aagagatatcaaaagatgcagacatcctcaagtgaataagtctccggtctttcacaaaca +catggttaagcgatgtggttttgactagagacgttcgccaccatcgtaatatttctggtt +acctgcgaacgtgaaccaaatcttacttcatacattgcttaaacagtacaacttatctct +tatcctatagagatctcaaaagtttgtatttttactggtttcaaattgagagaaaaactg +cgttctccgatttctatattattgtttaaatgatgccaaacatccagtttaaaacacggt +gtgatcagccgactcagattcgtatcctatgttagaatgagtcatcaaactacggtcacg +cgtacattacagagtaaactacacgaatgaaagagataagaagatgaaagagttaatagg +tctcctgttaattatgagaaccctaactactacggattggcctactagtgggttggaacg +gatataaaattcgactaagttcgcggcatgtcaggctcctaaatatgaagagaactcggc +atcgaattatccacagtaatagttggaacatgattcctctatgcatggtgtatatccacg +tacgccagtgtgcagtgtagccatgcgaccacgggcgttgtgaatattcttcctcagaaa +aggactgttgagcaaggaattggattctgtgaacggaatatagtcgagtagatggaattt +cctacactgcgaaaaggtcatagtaaatcaaacgccgcgcgcagacatatcttcttggca +attagtactccactaaatcaattggttataaacttttagaatatctttatataagttcac +tacttacgctgcgggtagtatatttaaagtgatgtcttaggaatcttatggcggcggaat +aaacggcttgactatagataccctaattctggcataaccctgtaacgtgtgaagcatgct +ttaatagacgactagatcagcttatagaatggatatgactgccacattgaagagattaac +attagcgggtataatgttacgaacttgtttaacaaaatagctctaccacacacgcatagt +ataatataaaggtcctggagttcgctacgagcctggaattgcagttcccctaccctgagt +aaacaagatcagtatggacctatcttctgacccacgtgtaaaaactaccgttagcggccc +tgagaacggtgaagttgattatcggctaacactcgctttaccaaggaacaaacaattgat +ggaacaggtaagcggctggattctatcctgaatacagcataataatatttgctttcaata +tatagttatgacactcccaatatcactaactctttacaaatcggatatgaagagtgaatt +agagatggagccgatcgttccttgtattctggtaagtactcgactaatgtgtgtagtcta +ggggtaaaggtccttaaccgtcgagtctagaactcacgcattatgaaatcctccgagcat +agagactctaaattcgccaagcaataagtcccgacgcgaaggatgagaagctcattgaac +tgtaacatttacgtcgggctcaccatgttacatatgcagcgggtaaaagtttttgcctgg +agtggttgagtttcgcgatacataaaaggccccactttcatatggtcaaatatctatatc +gtgctttggacgactcgataaactaaagtagcctagtaatgccctaaaccgctgcatttg +tgcaataaaaaatttagagtatatataacttccggacgtatggctgccttgaatcctcgg +atatcgtccttatacaacgatgaacggtatagctcggaactatgcagattaggcgatcct +tgggttgaatttttagtttccatagatatgagttagttttgatatggttaccatacgtcc +ctgcattgaaacttaatctgtatattgattgatccttagcaatagcggcacatttctggg +caatatgacttaattaggttacggtttttactatgatggatacgttttatatgatagaat +aacagttgctatttaaacaggtactacattcaactaatactgtttcactattgtgtccaa +catagggaatatattgcctgaatagatgtattatcaggcatcttttacgctccaggtaga +actaattaaaaatgatccttagaaactttcaagcaacataagctaaaagttacgccaatt +ataagccacatcggtaggatcttcaggcattcccatatccttctctatcaatcccgtctg +ttgctaattggttatctaagcatatcgcggcgagcatctacgataggtataaagttgctg +ctatctaattcgtcataatatatacatggaattacagattcatacgtcttcagtctcgtg +gtgtttctaagagcggacccaagaattacgtaatatctctctcgtgttacccaagaagtt +gacacgtgattgtcagctatctttttctggcgatgttaatagttataaacaattgcatat +agctgcaaattagctaatcaaatactcgtttcttaaatgttatcagcaaagctttaggtt +ctgtaatttcactgtgtaaagagggcgctaagttcaaaattggtttttggcaacaaacaa +tttaatagcgcagtgcaaaaataatatctcagggtgtaattatttctctaattggtcttt +acggttggaccaggcaatgggttttttatctatgtgataccaattaaaagtaatttcaaa +gtgacattaaacttaagtattgctgtcaagaccattacgacacttcaccaacacatttat +gtattgtgctacgcggtatggcccgtagtaatttctgatattgaccgcgttatcagcaag +tacgctgtacaaatgccaaatttagtaaagctctgtgtgcattccaaggtgcccacatca +cacattatcaacatatcatgtcgttgtattacgtccttttactagcctgggaaataccgg +tgattcagagtgaacataaatctctgaaagctactagacaaagctagtatagttaaaata +tatatttcttttaatattaggatctttgcgattgcacatttcaagcatcgcattaaccta +cctccgtactcttctacaacggttgcatgtacgatttctatgcgatgaaatacttatgtt +cttagtttggggttactttgttcacctagtcctcgaacgcaaattagcttcgaatatctg +aaaagtgtatgcgggcaccaaaacgatctcgattcttaggtttataattatagtcagaag +ataaatacatgcatatctggacactcttccacatgtcatgtcgactaactttgaactaca +gtcatatatagactgttatctgatccgtatgtgtctattactactcttatctgagaaagg +acccaatggagtcacagtaagcgatcatgtcatcggggctttttccctgattataagatt +acactattgctgtgcttggggcctcctactttttctatcttaatcattttgtacattaaa +aagctaagaagtaggtacaacttatctttcccatacgagctggaccattaatttaacagc +cgcaaggcgagttttaatgttaatctggaagggctttatgttctaagcttttagcactga +gaaattaatccgtaggaaattaatcccacataacccggtaagagaaccttacgccccgtt +actaataatgttctgcgcaatgtaggaagtgacaagctcactcttgcgacgagctcctta +atacaggccctgcgttatattcgaccgtacctataactagaccaccatcttaaatgtaca +gttatggttttcgacgcatagagtatgggaccacctcgaaatgctcagctgcaaattgta +ctgggggtggttatcaaacatttaatatgaatctatggtaaagtactagtttatagatag +ccgaacactaaaggtttgcagaccttcctcccctgaggaacttcgtgtcacaaattagat +tgagaaggtggtgataaaatcgcgtatctacaatgatttggtgcaaatatttatcgattg +cccaatcgttctactcgtactctttatagcctaacgccttttcttggcgctaattagcct +aatccaagaaggagtctaacaaaattacttaaccatactcttgtctattcggcccacgca +tgcgcaagctcaaaaagttctcaacgggcgtttttacttgagtcccaggaggtaacattg +gatctatgagtcttaacagtggaaatatgatttttagattgtgttcagatttattgtctt +attttggtctatctcatcagctatagctacataatgacgtcttaactgtttcgactaacc +ttcagatctgactaccccaaatacaacatagcaaaagaatgatgctaacgcttaactatc +ctttcacgatcttaacaaaaaagctccatttaaaagaatcgaaaacagatctaccattcg +tggaatcaatttttggacgagtactggtcgggtcgtgcttatttgctacaggattgtttc +gtataacgttcaagcactttagcggttccatccttgatggcgttaactgatgatgcgtaa +gtttatggtgatctaaaactctactacgaaccaggtcccagcacgaaacgtcatctttaa +tgagtttttaggtctccaggcactaggctgcgaagtggaatatgtgtcatcagagacaaa +tagatgattcctatagctttttgcagttaagccactaagtaggcggttctatagggtttc +attcaaatcgatcgtaattcccgactctgcatagcgtgggtcttgtatagaccattcttc +aggcccgccacaatggtttcaagtttcaacttccgtttattggctgtccctcaatagagt +cgttctcagggcacgactctcgttcgttattcataagtccagtttgatccacgaatacag +aacacgcatatctgataataaaagcttaacgataactttcacgcgcatggtttatttttg +atttattaggcaaccaaataccagaatgtagtcagcgatatgtagtaaaatttagacaaa +cataaaacaaagtatcgccattacagtctcctgttaggagaacctttttatcaatatgtg +taggcgtgtattggcgcccttgatttaataataattacggctaaacgtattgatattttc +caggaactgccccatctcatgagatgaccctaaattttattcacacctcatttttaattc +ttttatatcacgattatttatctgagcaagcatctttgcaagcattcatagtgacggtgc +tgtctctatgaatgcatgctaatatacggtgcgctaaacatattggttcaattcaatgta +agctacctcggaatttgcttgcactaagacggggaagccaaaacggtaaatcgccgtata +tgctagtgccaagggacttgtccgttggagtcactatggagttacaagcattataaatct +aaggaaatcgcagtatcagtccttaccccaaagatacttcgcattccctggggtacggac +catgaaatacttctttcatacatgataaacgatggagactcggttaccaccctggtagtt +actccatcaattggagttaactaagatcgctattacaggctttattagccaatcatcaca +agcctctttttagagattcacaagttagcaaaccaaagttcctttgataagtctttaacg +agatctatcccaattccggctaggagtaaaatttatatatttgagatcggggttaaagtc +acacgcaatgcaaggggtttttatatggtaatgtccttccctaattaggtaattttcaga +cctccgagagagagtagatcaacaacgcgttatactcctaaaatgcttgtcgataacatg +acactacagatcatccctggatgagcatcgactttcattacttgattagttcagttaatt +cgtttcaaaccattttcaacaaaatcccccagtagatatgtatatgcacatcttagacta +aataacagttttcataccctgggatttgtgtcactatctcaggaacgtcgagacgtcccc +tatcaccgcagcgagggtaactggccctgttccattgtaatcgatgggacgggacgttat +attgcagacccaaagtagtaataaattcagccatatggacggagggggggaattgttaag +aatataattcgattttcagctgaatgtaaaagctccagccattcctcctccacttgacat +tagttcgaagaaggtctgagaattggaattgcttgtgacgttttttgtttccagacaagg +aaatagcccagtaccaagtataatattatgacaatagaagcttaaattcacaacgtaaca +tatctgttagcatgctctaatagaccgagaaaataagtgtctatgtgtgcgagaactgtc +aattcacggcagtagtcacctaatctaacgtctagttcccgactatgaagtcttcacaaa +tggttagtaataatttcccagtggagtagaagtggcataacgtgcactctctgttaataa +tacctttagactactcccatttcgccagaacgtcttgatggtaccctatgggaaacactc +acacatgcttattgcctgcaacctcagcaatgtgtcgtatgcggtatttctacgaacagc +tagtgaaaggactgatgacctaattttggtttctcaagtccagacgtgatattttgatga +ccgtatctgacatctctgggcaattcggttaacctctggtacgaaatagtccgtcgcgta +ggtaaaaatgataatgctgtcatcactatcatgttttagctaagctacactaccccatcg +ctcgcacgtggcaaagtgtgaggattccgatatcatccatgtgtacgaattcctaatact +cttgctcagggcacttagggttattgtagcctgtgttaccgtctcgcatattagatcatt +aatcaacagtcttataatcaccgtaatcggtaaacagttgttatttgttctgataggtag +acagctaataaagatgctgttgaacagttacgtcccacctttattgccctacagtgaaac +tagttcttactctgttgctgtaatatgtctagggttattgatttgctgccacttcaaaac +ggaaattaagtcattaacgaaaatggttccttcataggtaaagatcaatccccaattgaa +gccagaaattttgagatgtcgattcctgatcattcgccaaatttacagctcgtaaacgag +ttccatgtgtaaaaaaatgttgagtccactagcttgtttattctggctcaaggtacgtgg +aacacgtagtattttgatactaatgccagacccgctacgatccctgtactgtgagcagag +ccgatcctcagaaatagctaaatcttgtgcttcgttagaagtctcgactacgtgtagcct +agtgtttgtgttgcgttatagtctatttgtggacacagtatggtcaaatgacgtcttttg +atctgacggcgttaacaaagatactctgggcaacacacatacttctctcatgttgtttct +tcggacctttcataacctttcctggcacatggttagctgcacatcacaggattgtaaggg +tctagtggttcagtgagcggaatatcattcgtcggtggtgttaatctatctcggtgtagc +ttataaatgcatccgtaagaatattatgtttatttgtcggtacgttcatggtagtggtgt +cgccgatttagacgtaaaggcatgtatggatcttgatctatgcaaaggtaggtccatcta +tatacgttgcacagcggatacaaataagataagaatttactaacatttaaattttcttat +tgtcgagcatagattggaggaaaaacttatttacttggtatttaaacggaagtttctaat +gtttatgattggatgcacggacagtttactgcttactttcttaggtttcttgaacaacag +gatgcactagtaacatgtctcgttcatgcttccattaagttcttcttaaacttacacaaa +ctacctaatttagagttgacgagatggttgaacgtgttgtgacaaacgtttgcaaaatgc +acagtatcgttaccaaaaagtacatttaagtgtgtgcgtaggaattctgctacgtccatt +gcaggccacattcacatcccacccctgaatatatggactgaatcacacacaccaaatttc +atctaccttatcgtagcataactattaacaaacatatacagacttcgcggtaaataaaat +atattagtacacaaccgtatactggttgaactattgcccagctttaagacgcttttaact +aggtgcttgatcaagaagtattattatatgacggcagtgtgtaatacctgaatagatata +gacgttagattgtctgaaaacacgccgtagagacatttttgttagatatgtatttctttt +tgacgagccagcatcttagtatctgaagacgagctatatgtttgtagaaaatcgactgac +attgtatacgaggcggcgtaagattaaccaaattccccagaattagtaatggcgccttat +cgatttactaacgatatataacttgtgatgttgtctgcaatgtatacccgtgtaggctgt +gctcttatcgaaggaaacgcattgaagtccaggctggatgaaaccaccgcgtacttccat +gcgtctatacatagcgtcaccgatactacgttttgctatgtaatccattctaatgggtaa +gaggattcctcttatagtaaaatatgcttgactttttaagaaccattgggagtggttggc +aaaataatagtgggtgtctttctcagtgtatagttttctacaactacccctattaggtta +caagtaatctggctttcttgccacttggcgatgatagttagattcgtatttctacaacgc +agttactgtatccatggcgcgagataattagatacgatttgaatttggatgtagactcgt +tactactgttgtagaccagcacgtgagtatctagatgggtttgctaccttgttagcggac +ttttgccgggaaaaagacatacgtacaaccgtatattttactataagcagtattggccac +cctcgtattgcggcagggtgtgctcacctggttaaaatgaaagagaaaaattccatttta +aaacccggaggaatctattactgacgaggaaggtgtttaacccgttgagacatctcctaa +cgtaaaaggttcatattctagttattccgagagtcactttcctatccaaacatgaactga +tagcataatgacaggttgaatggaaagcatatcctgtttattctaaatctgtttcgctaa +tcaatatgctgtcacgaactcggagcttacccttacaactatgtgttctgtttaccaggt +gctaatatcccggcactcttttcatgcatgtcgctcctagcgtcatctgatttaatagct +taatgtctcatattttacagtagccagtgtagtatggaaggcggcgaaccagcccctaca +ttgggtttcctgacataagtattacatatcacttgtctgattacacagcaaaatcgctaa +ccttactttgcgcatgtagctattggaactttgggctagtgtctatcccattaagtttaa +cagtagactagtccgtgagcgatcaccgagcttatgtctcgtacccaagttttggatttg +gatcaaaaactactcgatattcatgatctacgggcttcctttctccgggtatcattgcgc +cgagattaaaaataaaacgatagcgctgtgaaaacatgtttgacacgggatagcgtagaa +actaaacaacgaatagaccatccaatttgaattttattgggtccagcacttcgccatagt +gttgaatggtaaagttcgaaaggaaatttgttatattaattctgctacattttcgaccac +ttgtatctcaaggacaatatcccttgaggcttttagcagaaagagatgccgtaattctaa +gggatgataataggttgggaaatttaagagcagtagtaacggtcgcgggttcgaccttaa +actatatatttaaatctagccaaacaagttaacaacaaccataaagttatgaccttatta +tattggcaagcttaacgttttaattgctctagtaatagagtggtagaggtaagggaccat +cacctgattcttcctccgcaaccattatatagacgtgtcgtctgacaaatttcgagataa +aacattcgtccttagcaacgaatatcgaatggcaattagccacattgagttaaatagttg +aggatatttcttgcacagaatcagatctaatctaatgattcgttactaaacacttcacca +ggtatcgtgaaggctcaagattacccagagaacctttgcaatataagaatatgtatgcag +cattaccctaagtaattatattctttttctgactcaaagtgacaagccctagtgtatatt +aaatcggtatatttgggaaattcctcaaactatcctaatcaggtagccatgaaagtgatc +aaaaaagttcgtacttataccatacatgaattctggccaagtaaaaaatagattgcgcaa +aattcgtaccttaagtctctcgccaagatattaggatcctattactcatatcgtgttttt +ctttattgccgccatccccggagtatctcacccatccttctcttaaaggcctaatattac +ctatgcaaataaacatatattgttgaaaattgagaacctgatcgtgattcttatgtgtac +catatgtatagtaatcacgcgactatatagtgctttagtatcgcccgtgggtgagtgaat +attctgggctagcgtgagatagtttcttgtcctaatatttttcagatcgaatagcttcta +tttttgtgtttattgacatatgtcgaaactccttactcagtgaaagtcatgaccagatcc +acgaacaatcttcggaatcagtctcgttttacggcggaatcttgagtctaacttatatcc +cgtcgcttactttctaacaccccttatgtatttttaaaattacgtttattcgaacgtact +tggcggaagcgttattttttgaagtaagttacattgggcagactcttgacattttcgata +cgactttctttcatccatcacaggactcgttcgtattgatatcagaagctcgtgatgatt +agttgtcttctttaccaatactttgaggcctattctgcgaaatttttgttgccctgcgaa +cttcacataccaaggaacacctcgcaacatgccttcatatccatcgttcattgtaattct +tacacaatgaatcctaagtaattacatccctgcgtaaaagatggtaggggcactgaggat +atattaccaagcatttagttatgagtaatcagcaatgtttcttgtattaagttctctaaa +atagttacatcgtaatgttatctcgggttccgcgaataaacgagatagattcattatata +tggccctaagcaaaaacctcctcgtattctgttggtaattagaatcacacaatacgggtt +gagatattaattatttgtagtacgaagagatataaaaagatgaacaattactcaagtcaa +gatgtatacgggatttataataaaaatcgggtagagatctgctttgcaattcagacgtgc +cactaaatcgtaatatgtcgcgttacatcagaaagggtaactattattaattaataaagg +gcttaatcactacatattagatcttatccgatagtcttatctattcgttgtatttttaag +cggttctaattcagtcattatatcagtgctccgagttctttattattgttttaaggatga +caaaatgcctcttgttataacgctgggagaagcagactaagagtcggagcagttggtaga +atgaggctgcaaaagacggtctcgacgaatggacagactttactaaaccaatgaaagaca +gaagtagagcaaagtctgaagtggtatcagcttaattatgacaacccttaatacttccct +ttcgccgaatactggcgtggaaaggttttaaaagtcgaagtagttagaggcatctctcgc +tcataaataggtagactactcgcaatccaatgtgactatgtaatactgggaacatcagtc +cgcgatgcagcgtgtttatcaaccgtccccactcgcctggggagacatgagaccaccccc +gtggggattattagtccgcagtaatcgactcttgacaatccttttcgattatgtcatagc +aatttacgacagttcagcgaagtgactactcggcgaaatggtattactaaagcattcgaa +cccacatgaatgtgattcttggcaatttctaatccactaaagcttttccgttgaatctgg +ttgtagatatttatataagttcactaattaagatcacggtagtatattgatagtgatgtc +tttgcaagaggttggccgaggaatttacggattctctattgatacaatttgtctggctta +taactcttaaggctgaaccaggcgtttttagacgacttgatcagctgttagaatggtttg +gactccctctttcatgtcagtaacatttcagccgttattgttacgatatgcttgaacaat +attgatctaccacacacccatagtatattttataggtcatgctgttacctacgagcatgg +tattccacttcccattcaatgagtattcaacatcactagcctcagagatgatgacccacc +tctaataacgtcacgttgcggccatgtgaaacctgaacttgagtagacgatatcaagcgc +tttaaattgcatataacatttgagggtaaagctaagcggatgctttatataatcaatact +caataataagatttgattgcattttagagttatgacacgacatagttcactaacgagtta +ctattcccagatctagactgaagtactgatcgagacgatccttacgtcgatgatcgttag +ttatcgacttaggtcgggtctctagcggtattggtacttaaccggacactatactaataa +cccatgatcaaagcataacagaatacagacgataatttcgccaacatatatgtacagacc +ccaagcatgagaagctcattgaaagctatcattgaagtcccgctcacaatgtgtcttttc +cagacggtttaactggttcccgggagtcctggagtttcgacttacataaatggaaacaat +gtattttgctaatttatctatagcgtcatttggaccaatacagaatattatgttgcctag +taatccactataacccgcaagtgctgatagaaaatttttagacgatttataaatgcccca +agtatccctcccgtgaatcctccgttatactaattagtattcgttcatacgtataccgcg +catatatgaacatttggcgataaggcgcgtgaattgttacgtgacagagatagcagtttc +ttgtgatatggttaacagacgtacatgaagggaaactttatatctatagtgatgcttccg +tagaaataccgccactggtctgccaatgatgaagtatgtagctttaggtttgtactatga +ggctttcgtttgtttgcagagtataacagttgcgagtgaaaaaccgacgaatttatacta +atacgctttcactattggctacaaaatagggaagagtttcaatcatgagagggagtatat +ggatgctttgtagctaaaggtagaacgtatgtatatgctgccgttcattcttgaaagata +cataagcgataagttacgacaattataagcaacatccctaccttcgtaacgatttcactg +ttactgcgcttgaaatacactatggggctattggcggagagaagcagatcgcgccgagca +tatacgagacctataatgttgatgatagagaaggcgtctgaattgatacatcgaagtaca +ctttctttcgtagtatctctcgtcctctttctatctccggacacaagaattaagttatat +atatagagtcttaccaatcatgttgaatcctgattctcagagttctttggcgggccttgt +gatgactgagaaacaatgcaatattgctccaaatttcctaagcaaattctcggttatgtt +atgttatcagcaaagcgttacgttatgttatttaaatctggaatgacggagcgaagttct +tatgtcggtgtgggaataattcttttgaagacagcactccttaaataatatcgctccgtg +tttgtatttatcgaatgggtctgtaaccttgcacaagcaaatcggtggtgtatatatcgg +ataacaattaatacgatgttcatagtgacagtatactgatcgagtcctctaaagtcaatt +acctcacttaacaatctcattgatgttgtgtcattcccggtatcgcccgtagtatgtgct +ctgattgaccgagtgtgaaccaaggaacatctactaatgcctttgttaggtaagatctct +ctgaattccttcgtgccaacttaaaacattatcaaaatttcttctacttggattaactac +ttttacgagcatggcaaattcccctgtggaagacggttcattattatcggaaaccttata +gaaattgcgtgttgactgaaattagatttttattgtaagagttgcatctttgcgattcct +ctggtctagcttccaatgaacagtcctcccttctattcgacatcgggtccttcgtacatg +tctttgcgatgtaataattaggttcggagtgtggccttaatgggtgcaactaggaataca +acgcaaatttgctgacatgatagcaaatcggtatgccggcaccaaaacgtgctccttgct +tagcttgtgaatgagactcagtagttaaataaatccatatctgcaatcgattccacaggt +attgtccactatctttgaactactctaagagatacaagcttagctgagaccgaggtgtat +atgactacgctgatatctgtaaggtaccaatgcaggcaaagtatgcgagaagctaatacc +ggctgtttccagctttataagattaaaatttggctgtcctggcggcctcagaattgttct +atcgtaatcagttggttcattaattagctaagtacgaggtacaacttatctgtcccagaa +cagctccacaagtttttttacagccgaaacccctgtgtgaatcttaatatccaagcgcgt +tatctgattagagtttacaactcagtattttatcagtacgttttgtttccaacattaccc +ggtatgacaaaatgacgccacgtgtcgaataatggtctgaccaatgtaggaagtgaaaag +ataaatattgcctacacatactgaattcaggcaatgcgttttattcgaaaggtcatataa +ctagaaaacatgatgaattcttatcggatccttttactagcatagtgttggcgaacacct +cgtaatgctcagcggcaaattggactgcgggtccttatcatacattttttttcaatatag +gcgattggtctaggttagtgattccccaacacttaaggtttgctgacattcataccctca +gcaacttcctctcaaaaattagagtgagttggtggtcttataagaccgttgattatttga +ggtggtcaaatgatggtgcgatgcacaaatcgttataatcgtactctgtagacaataacc +cattgtagtgccgattttgtgcataatacaagaaggaggatataaaaatgacttttcaat +aatattggctattagcaacaagaaggagaatcctcattaagttagcaaccgcagggggta +ctgcagtccaaggaggtttcattggagagagcagtatgaaaacggcaattatgattgtga +gattcgctgaagattgtgtctctgattttcctagatagaataagctatagctacttaatc +aactcttaactgtggagactatcctgatgatctgaataccccatttacaaaattccatat +caatgaggctaacgcttaaatttcatttctccatcgtaacaaaaatcagcctttttatac +aagacaaaacactgcttccattacgggtagcaatggttgctcgactactggtagcgtcgt +gatgtggtgataaagctgtcttgcgtttatacttaaacaaattttgacctgacataatgg +agcgacttatcggatgttgccgatctttagggtcatctattaagcttatacgaaaaaggg +acaagcacgttacgtaatctggtaggactgggtacctagaaacgcaagaggaggcgaact +ccaatatctgtaagaacagaaaaatacaggagtccttttcatttttcaagttaacaatat +aagtaggagcttagagaggcttgcatgaaaatcgttaggaattacagaataggcagagag +tggggcgtgtagactacattcttcaggccccacaatatgggttataggttaaactgcact +ttttgcgatctcccgaaatactgtcgttctctgcgaaccacgctcgttccttttgctgta +gtccacgttcatccaactattcagataaacaagatcgcagaattaaagcttaaccatatc +ttgatagcccatcgtgtatggggcatgtatgtgcaaacaaaagacctcaatcttgtctgc +gagagggaggaaaatttagacaaacataattcattctttcgactggacacgctaaggttt +ggacaaactttgtatctatatctggaggcctgtattccagcccttcttttaataagattt +acggcttaaactatggatatttgccaggaaatgacactgctattgacaggaacataattt +tgattcaaacctcattgttaattattttatatctcctgtttttatatcagaatgcttctg +tcctagaaggcatactcaaggtgagggctcgaggaatgaatcataatagaccggccccta +ttaatattggttcaattctttcttacataacgcggaatttgattgcacgaacaccgggaa +cacataaccgtatagcgcccgttatgctagtgcctagcgactgggaccgtggagtctata +tcgtctttctaccattattaatctaaggatataccactttaagtcctttcaactaacata +aggcgcattccatgcgctaaggaccttgaatttattatttcttacatgataaaagatcga +gtcgacgggaacaaaaggctacgtactcaataaagtgcagtttactaagagccctttttc +tggcttgtggagactatcataacatgaagatgttttgacattcaatagtttgcaaaacaa +acttactttgtgtagtattgaacgagatctttccaattgccccatagcaggaatagttat +atattgcagatcgcggtgtaacgcactccaaatccatcgcggtgtgtgagggtaagcgac +ttaaagaattacggtttttgatcaaagcacagtgagagttgagcaaattacagttatacg +acttaattcagtctccataaattgaaacgacacttcttaacgggaggaccagacacgttc +attaagtgaggagtgcactttttgactttaaaaacatggtaatcaatttaaaccacttga +tatgtatatgaacagatttgaagttatttctgttttaatacactgggagttctgtcaata +tcgcaggaaccgcctgacgtcccctatcacacctcagagggtaaagggacaggggaaagg +gtaatcgaggggtagggaacgtagttggcacacccaatggacgaataaatgctgccatat +ccacggagggcgggattgcggttgattttaaggcgatggtaacctgaatgtaatagatca +tcaaatgcctcctccactggaaattactgcgtacatccgctgagaattgcaatggagtgt +ctcggtttttctttaaacaaaaccaaattgacaacttcatagtataatttttgcacatta +caagcgttaattaacaaacttactttgctgttagctgcctatatttgtccgacaatataa +ctggatatctctgcgagaactgtaaattaacggcacttggaacataatagttcctattgg +taacgacgttgtaggcggcaattatccggtggaagaattgacaactgcagttgaactgca +tgaaagtcaaatctctcgtaagtataactttagaagactccaaggtacccagaacctctt +cagcggacacgatcgctatcaatcaataaggattattcactgaaaccgctcatatctgga +ggtggacgtttttcttcgaaaagcttgtcaaaggactcatcaaatttttggccgtgctaa +tcgacacacctgttattttcatgaccggataggacatctcgcggaaattcgggtaacagc +tgggtagatataggacctcccctacgtattaatgataagcctgtcataactagcttggtt +taccgaagagacaataaacattcgagcgctcgtgccaaactcggtgcattacgtttgaat +aaatcggtaacatgtactattactctgcctaacggcacttacccgtttgggtccatgggg +taaccgctcgatgttgacagaattatgctaaagtcgtttaagatcccgattaccgaaaat +ctggttatgtctgagcattcgtacactgcgtattaagatcaggttgaacaggttcctaac +aaattttgtgacctaaagtgaaactaggtcgtactctgggcatgttttatgtcgtggcgt +atgcatgtgctgacacttctaaaaccaaattaaggctttatccaatatgggtccttaagt +gctaaacatcattcacaatttcaagacagattgttggtcttgtcgattccgcatctgtcg +ccaaattgacacatcgtaaaccaggtacatcggtaattatatgttgactaaactaccgtg +tgtattctggctctaggtacggcgaacaagtacgatgtgcttaagaagccctcaccccag +acgagcccgcgtaggtcacatcagcagatcctaagtaattccgttttattgtcctgaggg +agtaggatcgacgaactctacaagtcgctttgtcgtgccttataggctatttcgggtcaa +tgtagcgtcaaatgaactattgtcatctgtacgagttaactaagtgtctatcgccaacta +aaagacgtctcgatggttctttatgcggacctgtcatatcattgactggcacttgcttac +atccaaataacacgtttgttagcggatagtcgttaagtgtgcgcaagatcatgaggcggg +gggggtaatatttcgccctctacatgataaatgaataagtaagaagatgatctttttgtg +gcggtaccttaagcgtactcctgtcgacgagttactactaaaggaatgtagggttctgga +tctatgaaaagcgacctccatatatatacgggcctaagcggagtaaaataagtgatcaat +ggactaacattgaaatgttagtattgtcgaccattgagggctggtaaatcttatttacgg +gcgtgggaaaacgaacgtgatatggtttagcatgggatgcaagcactcgttaatgcttac +tttagttggttgcgggaacaacaggaggctatactaactggtagcgttcttgcttccatt +atgttattattataattaaaaataagacatatggtagagttgtagtcagggtggatcggg +ttgtctataacgttggaataatcaaaactatcgttaacaaaaacgaaatttaagtcggtg +cggtggaatgcgcctacctcatgtgcaccacacattcacagcacacccctcattataggc +aaggaagcaaacaaaaaaaagttaatcgaccgtatccgaccttaaattttaaaataaata +gaaacacttagcggtaatgaaaagataggactaaaattcactagtatcctggaacgaggc +aacagagttatctagatggtaacgaggtgctgcatcaagatgtatgatttttggtccgct +gtgtggaatacctctattgatatacaagtgactttctcggtaataacgcacttcacaatg +tgttgtttcttttctatgtattttgcaagagaaagaagcttagtataggtacacctcaga +gatgtttcgtgtaaatcgtatcacatggtataactgcaggaggaacattatccaaattca +ccacaattactaatccacccttttacttttactaaagatatattaattctcatgttgtct +gaattgtataacccggtaccctgggagcgtatcgaaggataccaattgaagtcctcgagg +catgttacaacacacgacttccttccgtctattcagacactcaacgagactaacttttcc +taggtaatcaatgatattgggtaactcgtggcatcttatagttattgatccggctctttt +gtagatcctgtgcgactcgtgcgctaattaagactggctctcttgcgcaggggatacgtt +tattctacgtacccgatttggttactactaagcggcctttcttcaaacttgcagttgtga +cttacattcctatttcttcaaagcagggaagggttacagggagagacttattgagatacg +attggaatttccatgtacaatcgttaatacgcttgtagaccagcaactcagtatagagat +ccgtttcctaaagggtgagcggtaggggcaaggcaataagaaattactaaaaccctagtt +gttaatataagaacgattcgaaacaataggattgcccaagggggtgcgaacatggtgtaa +atcaaagagaaataggcattgttaaaacccgcacgtttctagtacgcaagaggaacgtcg +gtaaccagttctcaaagatcctaacctaaaaggggcttattctactttttccgacactca +atggacgagacaaacatgaacggatagctttaggtctcgttgaatgcaaagaatagaatc +gttattattaatcggtttccattatctatatgcggtatagatctccgagaggaccctgta +aactagctctgcggtttaactggtgctaatagaccgccactatgttattgcttctagctc +ctagcgtcttatcatgttatacattaatgtcgcatattggacagtagccaggcttggatg +gatcgccgacaaaaagaaaagactttccctgtaaggacttaactattacatataacttgg +atcattaatctgcaaattagagtaacggtctttcaccagcttcatattccaacgtggcgc +tagtcgatatcccatgaagtttaaaactagaattggcagtctcacttcacagtgcgtatc +tatacgacaaaagtggtcgatttgcataaatatcttatcgatattcaggttattaccgat +tccttgctaacgctagaagtcacaccagagtaataataattccagacacctgtgaaataa +tcggtcactacggatagactagtaacgataatacgtatagtccataaaagttgaatttta +ggggctaaagatattagcaatactggtctagcctaatcgtcgatagcaaagggctgtgag +gatttctcctacattttcgaccaattgtatcgataggaatagttacagtcacgcttgtag +atgtaagagatgacgttattcttagggttcttaagtcggggggtaatttaagaccactag +taaaggtagaggcgtacacagtaaacgatattttgaaatcgtcaaaaaaaagtttacaac +atcctttaagttagcaactgattttagtggcaaccttaacggttgaattgatctactaat +acaggcctacaccgaagggtacagataatgattcttactaccctaacatgatagagtcct +gtcctatctcataggtcgacattttaaattcgtaatgagcaacgaagatcgtttcccaat +ttgcaacattcacttatagacttcaggttatttcgtgctaacattaagatagaatataat +cagtcgttaagaaactattatccagctttcgtcaaccataaagattaaaaactgaaactt +ggcaagatatgaatagctatcctgctttaaccgatcgtatgagatgctttgtagcaagaa +aagtgactagcacttgtgtttagtaaagcgggagagtgcggtaattaatattaatatact +attaagctacacagcaaaggctgcaataatgttagtaagtagaacataaaggtattctcc +acaagtaataaatagtgtgagctaattgactaacttaactctcgcgacaagtgatgtgga +taagatgactcatatcgtctttttctgtagtgccgacatcccacctggatcgaacaattc +cttctagttatcgactttgattacctatcctattaaacagatagggttgtaaagtcagaa +aatgatcggcttgcgttggtctaccatagctagagttagaacgcgtagatagaggccttt +tgttgccaacgtgggggtgggatgagtctgggcgagcgtgactttctttcgtgtccgaat +ttgtttaacatccattagattagatgtttgtgttttgggtctgatgtcctaactactttc +tcagtgaaactaatgtcatcatccaagtaaaatagtccgatgaagtctccgttttcggcc +gaagcttgtctataacgtatataaagtcgctgaatttagaacacaccttatctatgttgt +aaagttactttattccaaaggacgtgcacgaagcgtgagtgtgggaaggaacttaaagtc +ggatcactcttgtcagtgtagataagaatttctttcatacttcactggaatccggcgtat +ggatatctctaccgcgtcatctggtggtgtctgcggtaaaaagtcttgctgcacgagtct +gagaaatttttggtgccatcacatcgtaactgtacaacgaacaaatagcatcaggccttc +ttatccagcgtgaagtctaattatttcacaagctttcctaagtatgtaaatccctcactt +aatgatgcttgcgccaatgaggatagaggacattgcatgtacgtaggactattctccaag +gggtcttctattttgttagcgaaaattgttacagcctaatgttagagcggcgtacgactt +tataccagatactttcattagatatgcaaatatccaattaaatcatagtagtatcgtggt +atggacaatcaaaaaagacccgttgtgatatgatgtttttctagttcgttctcatatata +tagatcaacaatgaataatctcatgatctataaccgatgtatatttatattccggttgac +tgctccggtgcaattcactacggacactaatgactaatatggcgcctttcatcagaaacg +ctaaatatgattaatgaattaagggagtattatctaattattagagagtagcagttagtc +tgatattttcggtgtatgtgttagccgttataatgctgtctttttatcagtgagaacagg +gagtgtgtagtgttgtatgcttcactttatgactctggttatatccctcggagaacaaga +ataagagtacgagaagttcggtcattgaggatgaaatagaaccgctagacgaatggactc +acgtttataaaactatgtatcacagtactacagctaactctgaagtccgagaagcttttg +taggacaaaacgttataagtacctttcgcagaatacggccgtgcatacctgttataaggc +gtagtagggacaccatgctatccctcatatagagctacactaataccattacatggtgac +tatcgtttacggccatcatctgtaagcgatcatgcctcgttagcatccgtacaatctcgc +atggcgtcactgcagaaaaaccccgtgcggattttgagtcagaactattcgaagcttctc +aatccttttccattatggcatagcaagtgacgactcgtcagccatgggaataatagcact +aatccgattacttatgaattagaacccacatgaatgtgattctgcgaattgtctaagaat +ctaatgattttccggtgaatatggttgttgttatttattgaacttatattattaacatca +cccttcgttagtgatagtcagctatttccaagaggttccccgagcatttttaccattctc +tagtcatacaagttggagcgcttttaaatctttaggctgatcaaggcgttttgtctagaa +ttctgcagatgttagattcgtgtgcaatccctcttgcatgtcagtaacaggtcacccgtt +tttcgttacatatgctggtaaaatattcatagtaataactacaatacttgatttgttacg +taatgctcgtacataacacaatcgtattccacggaacagtaaagctctattattctgatc +gagcctaagagaggatcacactacgctattaaagtcacgttcacgaaatctcaaacctca +actgctggtgaccagttatagacagtgtaattccatattacatgtcaggcttaagctaac +ccgagcctttatataagctataatcaagaattagattggagtgcattttagacttatcta +tcgaaatagtgatagtaagagtttatatgacctgatctagactgatgttctcttccacaa +cagccttaaggcgtggagcctttcttatactattaggtcgcgtcgagagccctattcgta +atgttaacgacactagactaatatacaatgagctaagaataacacaagtcacaagataat +ttacaaatcatatatctacagtccacaaccatcactagcgattgcaaagcgttattggta +ctaccgctctaaatcggtatgtgcaagacgcgttaactggttcaagcctctcctgctcgt +gagactgaaagaaatcgaaaatatggatgtgcctaattgttcttgtgagtcatgtgcaac +tatacagtttagtttggtcaagactatgcaactattaacagcatgtgcgcattgaatatt +tggtgtcgattgataaatgccccaacgttccatcacgtctataagccgtgttactaatgt +gtattagtgcatacctattcagaccatagttcaactgttggactgaaggcccgtcttggg +gttcgtgaatgagagtgcagtttcttgtcttttccttaactgacctaaatgaaggcaatc +ggtttatctagagtcatgcttaaggtgaatttcagccaatgggctcccattgagctagta +tggtgctttacctttgtaagtggtggctttccttggtgtgctgactttaacacggcagag +tgattatccgaagaatggataataagacgctggcaatattggctaataaagtccgatgag +tttcaatcatgactgcgaggagatccatgcggtgtacctaaacctacatcgtatgtattt +gctgacgttcattcttgatacataaagatccgatatcggtccactttgtttaccaaaagc +cctaccttcgtaacgatggaaatgtgaatgagagtgaaatacacgatggggatattgccg +gtgagtacaagttagaccacacattagaactgacctatattcgtcatcatagagatggag +tatgaattgattctgcgaagtacactggctttacgagtatctagacgccgcggtatatct +cccgtcaatactatgaaggtatatatatagaggctgaaaattcatgttcaatcctctttc +taagagtgagtgggagccccttctgttgtcggagtaaaaaggcattattcctcaaattgt +cagaagcaaagtatacgtgatgtttgcttagaacaaaagagttaccttagggtaggtaaa +tctcgattcaccgagagaagtgattttggcggtgtgcgattaattcttttgatgacagat +ctcattattttatatagctccctctttgtatttagagtttgcgtaggtaacctggcaaaa +ccatatcccggggggagagtgcgctgaacattttatacgatgtgattactcaaaggataa +ggttcgaggcctctatactcatggaactatcttataattataatggatcgtggctcattc +cacctatccaaacttctttgtgatctgatgctacgagtgtgaacaaacgtacatcttcta +aggaatttgggacgtttcatagctcgcatttcattcctgaaaacttaaatatttttaaaa +attgattctactgcgaggaactaaggtgtagacaagcccttagtaaccggtggatgtcgc +ttcagttttatagcaaacattattcaatttcagtcttgactgaaattagtttgttagtgt +tagaggtccatatgtcacatgcatatggtctagatgccattgtacagtaataccttagat +tagtattagcggcatgcgtacttggatttcacttgtaagaatgagcttaggacggtcgcc +tgtagggctgcaaataggaatacttacaatttttgatgacttgttagcatatcgctatca +cccataaaaaacctgatacttgatgagcgggtgattgagactatgtactgatataattca +atagctccaatagatgaaacagctatgcgcctatttatgtcaaataatcgatgtgataca +agcttagagctgaacgagcgcgagtggaattagcggtgatctctatcctaaaaagccacg +aaatcgatcccagaagctaatacccgaggtgtcaagcttgagttcagttaaatttgcatc +tcatgccccacgaagaatgggtagagagtttgaaggtgcttctggattttcctaagtacg +tggtaaaaatttgatgtaaatgaacacctcctaatggttgtgttaaccacaaacccctgg +gtgaatctgattagccaacccagtgatctgatttcagttgtcaaatctcttttttataac +taccttttgtttccataatttaaccggatctcataatgaacaaacgggtagaataatggt +agcacatagcgagcttgtctattcagaaatatggcctactcagaatgtattctccaaatc +agtgttatgcgaaacgtaattttacgtgtaataatgatgatttcttatcggttccttgta +ctacaatactcttgcccaacaaatactaagcataacagcaaaattcgaatccccctcctt +ttaataaatggtttttcaatatagccgattcgtattcgttagtctttcaccaactattaa +cctggcatctaattaataaaatcaccaaaggactctataatatgacagtcacttcggcct +cttttaagacagttgattattgcaggtccgcaattgatggtgacatgcacaattagttag +aatccgactatggagacaattaacaattgtagtgcccatttggtccagttgacttcaacc +acgagttataaaggtattttaatttatagtcgatagtaccaacaacaagcacaatcataa +ttatgttagaaaacccagggggtaatgctctaaatccagctttaaggccagagtgcacta +tgaaatcgccattgatcattgtgtcattcgctgaacttggtgtctaggaggtgccgagtg +agaatatcagataccttatgaagcaacgattatatctggactagatcatgatgatcggaa +taaaacattgaaataagtccttatcaaggagcataaacattttatttaatttatacttcg +taaataaattcagaattttttttcaagacattaatctgagtaaatgacggctagaaaggg +ttcctactcgaatcgtagcctacgcatgtgggcagtaacctggcttgcgtttttactgaa +acaaaggttcaccggaaagaaggctgccacttttagcttcttgacgatctttagcgtcat +atttttagattagtcgaaaaacggaaaacaaacttaacgaagctggttgcacggggtacc +gagaaaccaaagagcaggacaactccttgatcgggaagaactgaaatagacagctgtcat +tttcattggtcaacttatcaatataacgaccaccgtagtgacgcttgcatgaaaatactg +aggatgtaaactatagccagtcaggcccgcgtgttgactaattgatgaagcaaacaaaat +agccggtattcgttaaaaggaacgggttgccagctacagatatactctaggtatatccca +aacaagagacgtcctttggctgttgtaatcggtcataatacttgtcacataaacaagatc +gctgaattaaacattaaacagttagtgatacacaatcgtggttggggctgggatgtgcaa +taaaaagtcatctatcgtctatcacagagcgacgtaaatttagacaaacattattatttc +ttgacaatggaatcgataagcgttcctctaacttggtatatatatctcgaccccgggatt +ccagccattcttgtatgaagatttaaccatttaactatgcatagttgaatggtaaggaaa +atgatattgactgcaacagattttggatgcaaaaatatttgtgaattattggttatatac +tggttgtatagcacaatcattaggtcctagaaggcatactcaacctcagcgagagagcta +gcatgcataattgtaccgcccatattaatattcctgaaatgatttcttacattacgccca +atttcagtcatcgaacacccccatcaatttacccgatagagaacgtgatcatacgcaata +ccctatgcgaacgtccactctatagcgtctgtatacaatgattattcgttccatttacaa +cgttaagtaatttaaacttacataaggacaaggaaatccgcgaacctcctggaatgtatg +agttatttatgcagttaacttcgtctcgaccggaactaaaggcgtcgtacgaatgaaagg +ccacttttagaagagacctttgtatccattgtggagaatatcataaattcaagatggggt +gtcatgctattcggtcctaaacattcttaatggctgttctattgttagtctgatttaaaa +tggaaccatagcacgaatagttagatagggctcatacccctgtaacgatctacaaatcct +tccccgggtgtgtgcgttagcgacggaaagttttacggtttgtgatcaaagaacactcac +acgtcagattattacactgatacgaattatttcagtcgacagtaattgaatagaaactta +ttaacgccagcacctgacacggtaagtaaggcaggtctgaactgtttgactgtaaaaaaa +tggtaatatttttaaaaatcttgatttctatatcaaatgatgtgtagttttttctctgtt +attaaaatcccagtgcgcgaaatttagatcgttacgactcacgtacaagatcacacatca +cacgcgttagcgaaagcggaatggctaatacagccctacgcaacgtagtgggatcaacat +atggacgaatttatgctcaatgagccaacctcccccgcattgcggttcattttaaggcct +gggtaacatctatcgtttagataatcaaaggaatccgactatgcaattgtctgacttcat +ccgctctcaagtccaatgcaggcgctacgtgtttctttaatcaataccatattgaaatcg +taatacgataattgttgctattgactacaggttatgaaaaaacttactttgcgggtacat +gcatatttttgtaccacattattacgcgatatctctcagtgtactctaaattaaaccctc +ttcgaacattttagttcctattcgtaaacacgtgctacgcggcaatttgccggtcgtaga +atggacaactccagttcaactgcatgtaactcatagctcgcgttagtataaattgactag +tagccatgggacaaagtaactagtcagcggaaaagatccctttaaagatatatgcaggtt +gcaagcataaagctcattgctcgaggtgcaccgtggtattccaaaagcgtctctatcgta +tcttctaattttgggccgtgagaatcgaaactactctgatttgctgcacacgttaggtaa +tatcgcccattttcccgtataagctccgtacttatacgaactacacgaccttttaagcat +tagccgctcatatcgtgattcgtgtacagatgagtctattaaaattacagacatactcca +tatctcgctccttgaactttgaataatgcgctaacttgtactatgaataggcagaaccca +actttcccgtttgcgtcaagcggggaaacgatacatgttgtcagatttatgattatctag +ttttagatcacgtttaccgataatcggctgtggtctgagcagtcctacactgagtattta +cttcagcttcatatcggtccgaaaaaaggttgtgaccgaatgtcaaaatacggagtacga +tgggcatcttttttcgagtcgcggttgcagggcagcaaaaggcttaaaccatttttacga +tttttactatagcggtcatgaagtgcgaaactgcttgcaaattttctacacacattgtgg +ctcttgtccttgaagcttatggcgaaaatttgaaacatagtataccagggaaagcgcgaa +ttatttggtgactaatagtccgtgggtttgagccatatacctaacgccataaactacgtg +gtgctttagatgcaatctaaacagaacagaaagcgtagcgctcatcagcacagactaact +ttttcagtttgagtcgccggagggacttcgagacaagaacgcgtcaagtcgcttgcgcgg +cacggattcgattgggcggctcaatcttgcctaatttctactattgtcagctgtacgact +gtactaagtgtatagccccaaataaaagaagtatcgatgcgtctttatgaccaaaggtct +tataattgaagcgcacttccgttcatcaaattaaatcctggcttacccgattctccggaa +gtctgacctagagattgacgacggccgcgtattattgagacctcttcaggattaatcaat +aacgaagtagttgatctgtttggcgacgtaccttaagccgactccgctacacgagtttct +actaaaccaatgtagccttatgcttagatgaataccgtcctaattagatattccggcata +acagcagtaaattatctgttcaatggacgaacattgaattgttagtattctacacaagtc +aggcctcgtaaatattaggtaaggccgtgggataacctacgtgatatgcttgagcttgcg +ttgcaagctctcgttaatcattaatttaggtgcgtgagggttaaacaccagcatattcta +tatgctagacgtcttccttaaaggatcgtagtattataattaataataagaaatatggtt +gacgtctagtcagcgggcatacgctgctctatatactggcattattcaaaacttgacggt +aaaaaaacgaattttaaggcgctcacgtcgaatgagccgaactcatgggaaccaaaatgt +cacagaaaacacctctttattgccaagcatgcaataaaaaaaatgttaatagtacgttta +cgacattttattttataataaagagaaactattacacctattgatatgataggacgtaaa +ttaacgagtagcctgcatagaggcaaatgaggtttctacatggtatagacctgatgctga +aacatcgatgagttttggtcccctcgctcgttgaaatctagtcatttactactgtctttc +gagctattataccacttcactatgtggtgtttctttgctatgtatggggctagtcaaaca +tgatgactatagctacaactcagagagcgggcgtgttaagagtatctcatgctagaactg +cacgacgaacttgatacaaagtaacaacatttacgattccacaaggtgactttgaagaaa +catagtttaattctctgcttcgatcatttctataaaccggtaccatcgcagcggatagat +gcataacatttctactactccaggcatcttaaaacacacgtagtacttcactagattaag +acacgataagtgtataacttggcagtgggaagcaaggagattggcgaactcctggcatct +gttacgttttgttcaggctcggttgttgataatgtccgactcctgccatattgaagactc +gctcgagggagatcgggattcgttgattataagtacacgtgttccgtaatactatgaggc +agtgattcaaaatggcacttctgacttacatgactaggtattattaccacggaagcgtta +aaggcacactcttatggacttaagattgcaagtgccttcttctagcctgaattcgcgggt +tcaacacaaactctctttagacatccgttgcctaaaggctgagacgtaggggcaaccctt +taactatgtactaaaaaactagttggtaatttaacaacgtgtccaatcaagacgatgcac +caacgcggtgcgaaaatcgggttaagcaaacacaaataggaattgtgataaaccccacct +tgagaggtcgcaagaccaacctcgggaacaacggctctaagagaataacctaaatccgga +tgagtagactgtgtaactctctaaagggaagtgaaaaaaagctaagcatacatttaggtc +tcctgcattgcattcaattgaatcgtttgtattatgagctgtacagtagctatatcagct +atagttatcccagaggaacaggtaaactagctctgagcgtgaaatccggatattagaacc +cctagatgggattgattctagctaatacaggcttatctggttttacagttatctagatga +ttggtaaggtgaaacgcttggtgccttccaccacttaaacaaaagtattgcccgggaagc +tattttctaggtattataaagtcgagcattaatatcaatttgacagtaaaggtctttcac +cagcttcatatgccatagggcccatactcgatttaaattgaacggtttaacgagtattgg +aactctcacttataactgagtagctatacgaaaaatctggtccatttccagaaatttatt +atcgatttgctgcttagtacccaggaagtgataacccttgaaggcacaacactgtaataa +gttttcctgtcacatctgtaatattcggtcactacgcattcacgactaaagataattact +atactaattaaaagttcaatgttagggccgaatcatagtagaaattctcgtctagcctaa +tcggacttacctatgggctgtgaggatttatcagtatgtggacaaaaatgctagagatag +gtatagttaaagtcaccatggtacatctatgtgaggaagtttgtagttcgcttctttagt +ccgggcgtttgggatgacaactactatacgtagagccgtactcaggattagatagtgtga +aagagtcaaataaaagggttaatattaatttaacgttgcaaatgtgtttaggccaaacat +taaccgttgtagggatattctaatacaggccttcaccgaaccctaatgataatctgtctt +aataacattaaatgattgtctccgctacgagctcttagggcctcattttaaatgactaat +gtccaaagaagagactttcccaatttcaatctgtcacgtatagacggcaccttagtgagt +catatcattaagatagaagattatcaggagggaagtttctattatcaaccgttacgcaac +cataaacttttaaatctcataatggcattgagatcaagagctttcatgatggtaaagttc +gtatgtgatgctggggagctagatatcggtataccacttcggttgtggtaagcccgagtg +ggccgttagtaatattaatagacgattatccgacaatgcattcgctgaaataatcttact +taggagaaattaatgctatgagccaaaactatttatgtctgtcacattattgactaaagt +atctatcgacaaaactgatgtccataagttgtagcagatagtcggtgtatggtgtcacca +atgaaaacctcgagcgaaaaatgaattatagttatccaatttgagtaaattgcctattat +acagataggcttgtttagtcagataaggttccgcttgaggtgctctaacttagcgagagt +tagaaagcctagtgagaggcattttggtgccaaactccggctcgcatgagtaggccagag +agtcactttctttcgtcgaagaagttggtgaacagccttttgattagttgtttgtcttgt +ggctatgtgctactatataagttagaacgcaaactaatctaatcagcaaagtaaaatagg +accttgaacgagacggggtacgccgttgaggctcgagatagtagataaactagaggaatg +tagataaaacattagctagggggtttagttactggattacataggaagtgcaccatcacg +gtgtgggggttcgtacgtaaagtcgcatcaatattgtcagtggacttaacaagttcgtgc +ataatgaaatcctatacggactttgcatatctctaccgactcatctggtcgtctatgcgg +gtaattgtattgctccaagtggatgactattttggcgtcccagcacatagtaaatgtaaa +tccttataatagcataagcaattattagactgcgtgaagtcttagtagttctcaagcttt +acgttgtatgtaaataactcacgtaatcagccgtccccaaatcaccattgaggtcattga +atgtacggagcactattatcaatgcggtatgcgattttctgagcgattattgttaaagac +ttagcgttgagccccggaacacttgattacagattctttaaggagttatccaaatatcat +tttaaataatagtagtatcgtgctttggacaataaaaaaagacccgttctcttatgttgt +tttgcgacgtacttctctgatatatacttcaactatgaagattctattcatcgataaccc +aggtatatttatatgcccgttcactgcgcagggcaaattatctacggacaataatgacgt +agttggacccggtaagaactaacgcttaatatgattaaggatgtatgccagtattatctt +attatgtcagagtagaagtttctctgagattttccgtcgttgtggtacaccggatttggc +tctctttttagaactgagaactcggagtgtgtagtcttgtttccttcaatttatcaatat +gcttttataccgccctcatcaactataacaggacgacaagttccgtcttgctccatcata +tactaccgatacaccaatcgtatcaagtttagtatacttgctttctctcttctacagctt +actcgcttgtccgagaagcggttggtgctcataaagttagtagtaaatgtacaactagta +gccagtccttacctgtttttacgactactacggacaccatgagatacagaagttagtgct +acaattataccattacatgctcaatatcgttgtcggccataagatcgaagagtgcatcac +gcgtgtgaatacgtaaaatctaccatcccgtcaatgcacaaaaacacactccccttgttg +actaacatcttttacaagaggctaaatcattgtccaggatcgaataccttgtgtacaatc +gtcacccatcggaagaataccacttttccgatgtagtatgatttacaaaaaacatctatg +tgagtaggccaattgtagtagaatatattcatttgaccgtcattagccttcttcttaggt +tgtgtacggatagtaggtacataaaccgtcgtgtggcatacgctgcgatttcatacagct +gccaacaccttttttaccaggctagagtcagaaaagttggagccatgttaaatagttacc +atcataaaccactgttgtctactagtctgatcagctttcatgcctgtgcaagcaatatgg +attctcacgtaatggtaacaactgttgcgttacttaggctggttaatttgtcagagtaat +aaatacatgtcttgttgtgtttcctaatcctcggaaagtacacaagcctaggaataggaa +aagtaaagctcttttattctgatagtgactaactcaggatctaaatacgcgattatacta +accttcaccaaagctcaaaaatcatctgctggtgaccagttatagacagggtaattcaat +atttaatgtctcccttaacatttcaccagcatggattgaagatagtataaagttttacat +ggcagtcattgtgtcacggttctatacaaattctgatagttagacggtatttgaaatgtg +cttctagcatggtatcttacacaactgaatgaacgactggagccgttcgtatactatttg +cgagcctcgagaccccgtttcctaatgttaacgaatatagtataatataaattgtgatat +gaataacacaagtaactacagtttggacaattaattgttctaaactaaaaatcattcact +tcagatggcatagagttatggctactacacatataaagcggtatgtgaaacacccgtttt +agccggaaaccctctactgctcgggacaatgaatgatttccaaaatatggatgtgcagaa +ttgttagtgtgactcaggtccaaatagacactttagtttcgtcaagtcgttgcaaagttt +aaaaccatcgcagcattctttatttggtctacattgagaaatgaaaaaacgtgacagaaa +gtctagaagaactgtgaataatgtctattactgattaactagtaagacattagtgcatct +ggtccactgaagcacccgcttggcgttaggcaatctctgtgaactgtcgtggctgttccg +gtaatgtacgaaagcaagcctataggttgatcgagtcgcttcattaaggtcaatttcaca +atatccgatcacattgtgctaggttcgtcctttaccttgcttagtgctgcatgtacgggg +tgtcatgacttgttatcggcagactctttatcccaagaatggataatatgtacatggaaa +gtgtccataattaagtcccttcactgtaaagaatgactgccacgtgatccatgaggtcta +cagaaaccgacttacttgctttttgatcaacttaattatggattcataaagttcagatat +cggtacaattggtgtacaatatgaaattaatgaggaaacatggaaatctgaatgacagtg +atagaaaagatccccatttgcccggtcagttcatgttacaccactcattagtactgtaag +tgtttcgtcagcattgagatccacgatcatgtgtttatgccttcgaaactggatgtacga +cgatcgagacgaagaggtatatataacctaaatactaggtacgttgttagagagacgatg +aaaattaatcgtcaatacgctggcgaacactgagggggacccaatgctcttctcggtcta +aaaaggaatgtgtcagaaattggtcagttcaaaagtagaccggatctttgcggagaacaa +ttcacggaacgtagcgttgggaaatatcctttctaccacacatcggattttcgccctctc +ccattatttattgtgttctcacatagaattattgtttagacatccctcgttgtatggaga +gttgcccgagcgtaaaggcataatccatataccgccgggtgagtgacctgaaattgtttt +tagttgggatttcgctatggattagcttacacgaagagattctaatggtactataggata +attataatgctgcgtggcgcagtacaccgttacaaacgtcgttcgcatatgtggctaaca +cggtgaaaatacctacatcgtatttgcaatttcggtcgtttcatagagcgcattgaatta +ctcaaaaattatatatgttgattatttgattagactgcgtggaaagaaggggtactcaag +ccatttgtaaaagctgcatctcgcttaagtttgagagcttacattagtctatttcagtct +tctaggaaatgtctgtgtgagtggttgtcgtccataggtcactggcatatgcgattcatg +acatgctaaactaagaaagtagattactattaccggcatgcctaatgcgattgcactgct +atgaaggtgcggacgtcgcgcccatgtagccctgataataccaatacttacatttggtca +gcaattctgacattatacctagcacccataaatttactcagacttgaggacaggctcttg +gagtcgatcttctgtttgtatgcatgtgatcatatagatgaataagcgatgcgactagtt +agggcatagtatagatctgtgtatacagttcagctgaacgtccgcgagtggaagtacagc +tgagatctatcctaaaatgcaaccatatcgttcacacatgatatgaacccagggggaaac +attgagttcagttaaattggcagcgaatcccccaagaagaaggcggagtgacgttgaacg +ggcttatggtttttcagtacttcctccgtataagttgagcgaaatgtaaacagaataatc +gttgtgttaacaacattaaaatcgcggaatatgatgagaatacacagtgtgagcatttca +cttgtaaaatatctttggtagaacttactttgctttaaatatgttaaaccgatctaataa +tctacaaaacggtagattttgcctagcacattgcgtccttctctattcagatagaggcaa +tactcagaaggttttatccaaagcactgtgttgactaacctaagttttagtctaataatc +atgattgattataggtgccgtggactacatgactcgtccacaaataatacttagcagatc +agcaattggccaagcacccgacttttatttaatggttgtgcaatagtccagattcgtatt +cgggactctttcaaataatagtttcctggcatctaagtaagaaaagctcataaggaagcg +atattatgacacgctcttccgccgctgttttgaaacttgagtattgctcgtccgaaattg +agggtcacttcaaaatttactgagaagacgaagatcgactaaagttaaaatgctagtcca +cagttggtcaagttgaattcatccacgagttatatagctattttaatttatagtcgagtg +tacaaaaaacatccacaataagatttatcttagaataacaacccccgtatcatcgaaatc +ctccgttatggcctgactcctcgagcttatagcatttgtgctggcgctcttgccaggaac +ttgctcgcgaggtggtgacgagtgagatgatcagtttcattatgatgatacgattttatc +gcgactagttaatcatcatagcaagtaaaatttgaattatgtcattatcatgctccatta +acaggttatttaattgatactgacgaaattttttcacaatgggttttctagaatttaata +tcagtaattgaagccttcataggggtcctactagtatcctacacgacgcaggtccgcagt +atcctggagggacgtgttactgattaaaagggtcaaaggaatgaaggctcacaatgttac +ctgcttcaccatagtgagccgatgagttttacattagtactaaatcccaaatcatacttt +acgatgaggcttgctagcgctaaagagaatacatacaccaccacatagaattgttagcga +tgatatcaaatagactcctggaagtgtcagggggaaactgttcaatatttcgtccacagg +actgaccaggcatggaaaagactgacgttggaaactataccatctcacgcccgacgcttc +actaattgatgatccaaaaaatatagcccggattcctgattagcaaagggttcacagaga +aagatattatcgacgtatatcccaaaaaacagacgtaatgtgcatcttcgaatcgggatg +aatacttgtatcataaaaatgtgacctctagtatacaggttaatgttagtgatacacaat +actcgtgggccatgggttctcaaataaaatgtaatattgcgtcgatcactcacccacgta +tttggtctaattatgttttatttagtgacaatccaatagataaccggtcctattaagggc +tatatttttagcgaccacgcgtttaaacaaaggattgtatgtagatggtaccagtttaat +tgccagtgggcaatcctaagcaaaatgagattctatcctaaagtttgggcttgatataag +atttcggatgtatgggttttataatcgttggagagctcaatcatgagctaatacatggat +ttcgctacctcaccgagagaccttgcatgaagaattctaaccaaaagtttaataggccgg +attggattgagttaattaagaccttgttcagtcatagtaaaaacccttaaattttaccga +ttgacaaagtgagcagtcgcaataccctatgcgaaacgcctcgatagtgactaggtatac +aaggtttttgagttcctttgaaatagttaactaatttaaaattaattaacgacatggaaa +tcacagaacctaatgctttgtaggagttatttatgctgtttactgcctctacaaccctaa +taaagcagtcctaagaatgaaacgcatcttttagttcagaaagtggtatccagggtggtc +aatttaataaattcaacatcgggtctcaggatattcggtcatataatttattaagggctc +ttcgagtcttactctgagtgaaattggaaacagtcatccttttcgttgtgaggcatctta +caccgctatcgatatacaatgcattccaccgcggtgtcccgtacacaaggaaacttgtta +ccttggggatataagaaaactcacacgtctcattattaaactgagtacaatttttgcacg +agaaagtaatgcaatacaatatgatgaaagccagctaatgaaaagggatggaacgcacct +cggatctgttgcactggattaaaatccgattatttttaaaaatattcagtgctagagcat +atcaggtctacttttttatctggtatgtaaagcccacggagcgatagtgagatccttacg +actcaacgaaaagttataacataactcccgttagccaaagcccaatcccgattactgccc +taccctaacgtctgccatctaaatatcgaacttgttatgatcaatgtgactacctcccac +cctttccccttcatttgttccactggggataagctagcgttttcagaatcaatgcaataa +gaatagccaattgtctcacttcatcagagctcttggcaattccaggcgctacgtggttct +ggaatatattcatttttcaaatagtaatacgtttagtgttgctattgtctacacgtttgg +atattacgttatgtgagcggacatcaatagttgtctaactctttagtaagccagagatag +cactcttagcgaatggataccatcttccataagtttagttaatagtccgaaacaactgct +tcgagcatatttgaacctccttgtaggcaaatagcctcttcaaagcaatcttactaatag +atagagtttgttttaagggactactagaaatgggacaatcttaatagtatgacctaaact +gacatttaaagatatatccaggtggcaagcataaagatcattgcgccacctccaccgtgg +gattacttatcagtcgatatcctatatgctaagtttgcgacggcagaatacaaactaagc +tgagttgatgctaaccttacctatgataccccattggaccggttaacagccctacttatt +ccaaataaaagaacttttatgctgtagaagctattatagtgatgcctggtaacttcagta +tattaaaatgacacacatacgccatatagagctcctggaactttgaataatgagcgaact +tcgaagttgaagagcaagaaaccatatgtcacggttgcctaaagcccggtaaccagacat +gtgctatcattgatcattatcgaggttttcataaccttgacccattatcggctgtgcgcg +gacaagtacttaaatcactagtttcttcacctgcttatcggtaagaaataaggttggcaa +agaatcgcataagacggacgtagagccgcagcgttgtgcgagtccaggtgcatgcgcagc +aataggattttaaattttgttccatttttaatttagccgtaaggatgtccgtaaatgatt +gaaaattggattcaatctttgggcctatgctactggaacctgatcgacaaaatttcaaac +atacgttaactccgaaagaccgtatttttgcggctagaatagtcagtcgcttggagccat +ataccttaccacttaaacgacgtgctcctgtagttgaaatataaacagaacacaaagact +accgatcatatcaactgaagatctttgtaactttgaggcgaagcaccctcttcgagacaa +ctaagagtaaagtaccgggcgccgcaaggagtcgattgggaccctaaatcttgacgaatt +gctaagaggctcagagctaccactgtaatttctctagagcccataataaatgaacgatac +atccgtaggtagcacctaagggattataatggaagccaaatgcagttaataatattatat +actggcgtacacgattcgacggatctctcacatagtgattcacgacccccccctttgatt +gacacagcgtcagcattttgcaagaacgatcttctgcatagggtgcgccaccgtaaggat +gacgtcgaagctacaactgggtataatttaccatgcttccctgatgctgagtgcaataca +ctaagaatgagtttttaccccatatcaccagtatttgttctgttattgcgaagaaatggc +tatgctgagttggcgactaaagtcacccatcctttttattaggtaaccccctcccttaaa +ctaactgatttgctggagctgccctgcatacatatactttatcatttatggacgtccgtg +acgcttattatccaccatagtcgatatgctacacggattcattaatggatcgtaggagtt +taagttatatttactaagatcggtctcggctactatcccgccttacccggcgctatttac +ggccatttttaatatattgacggtaattattcctatggtttcgaccgcacgtccttggac +aagaaagaatggcaaaaaaaatgtaaaagaaaaaaaatattgagtccctaccatcatata +aaaaatatgtgatgagtaacttgacgaaatgttagtggttattaaagactatctattaca +ccttttgttttctgtcgtagtatattaaagtctagaagccttacaggaaaatcagggtta +tacagccgatactccgcagcatgaatcatcgaggaggtgtcctaccatcgcgccttgtaa +tcttgtctgtgtatactgtatttagaccttttatacaaagtaaatatctcggctttatgt +gattgggaggggcctactcaaacatgatgacttgacctaataatcactgtgcgggcgtct +tatgactagctattccttgaaatccaccaccaaatggttaatatgtaaaaactttgacga +tgaaacaaggtgaatgtgtagttactttgtgtaattagctgcgtcgagcattgcttgtaa +aaccgtcaatcgcacacgttacttccataaaatttctacgaatacacccttcttaaaaaa +aacgtaggaattcacgagtttaacaaacgataactgtataaagtggaagtccgaagaaag +cagatgcccgaactactcgaagatgtttcgttttcttaaccataggggcttcttaatggc +ccactacgcacattttgttcaagcccgagagggacatccccattacgggagtattactaa +aactgttccgtaatacgttcagcaagggatgaaaaaggccactgctcaagttattgacgt +gggagtattacatcggaagcctgaatcccacactatgatggtctgtacaggcctagggac +tgcgtctagacggtattaccggcttctaatcatacgatcgtgagtcttaacgggaagtaa +ggctcacacctaccccaaaccatttatctatgtaagtataaaattgtgcgtaagtgttca +aagtggacaataaagacgtggcaaaaacccccgcacataagccgctttagatttcacaaa +taccaatgcggttaaaaacatccttgagtcgtacatacaccatactcgcgttaaacggat +ataacagaagataataaatccggatgtggagtcggtgtaactatagaaagccaagtgaaa +taatgcttaccagtcatttagctatacggctttcatttcatgtcaagagggtggagtttg +acctgtacagttgatatatcaccgatacttagaactcacctaaagctaaaattgctcgca +gcgtgtaatccgcatattacaaacaatagatgggattcattatacataagacacgatgat +ctgctttttcaggttgcgagatgttgcctatcgtcaatcgagtcctgccttacaccactt +aaacaaaagtattgacagggaacctattttcgaggtattatatagtccagcttgaatatc +aatttgacagttaacctagtgaaaatcagtaagaggaaatacgccacattctccagtgaa +attctacgggttatcgtctagtccaactatcaattataactcacgagatataagtaaatt +ctcgtacttggcctgatttttattatactttggatccttagtaaacaggaagggagaaac +cttcaacgaaaaacactggattttgttttactctcaaagctcttatatgacggaaatacc +ctgtcaagtcttaactttattactagactaatgaaatgggcttggggtggccagaatcat +agtacaatttagcggatacactattcggactttcctatcggctgtctggttggataagta +tggggactaataggctagacatacctatacttaaactatacaggcgtcatctatctctgc +aactttggagttccctgatgttctcccgccctttgggttcacatcttctataccgacacc +cctaataacgattagtttgtgggttagagtaaattaatacggttaatattaatgtatcgt +tgaaaagctggtgtcgccaataaggtaaccggctaggcagagtatatgtcacgaagtata +actaccctaatgataagctgtaggaataaaattaatgctgtctctaagcgaagagatatt +tccgactctgttttaatgacgaatctcattacttctgacttgcaaatgttcaatatggca +cggtttcacggcacctttgtgacgcatataatgaacttagaagattataacgacggaact +ttatatgataatccgttacgattaaagaatctgttaaatatcataatggcattcagttct +agaccgtgcatcatggtaaacttactttctctgcatggcgacatacatttcgctattcaa +attcgcgtgtggttacacccactcgcacctttggaatattaagagaagatgatcagaaaa +tccattcgctcaatttttctgacgtacgtctaatttatcctaggagacaaatcgttttat +gtctctcacatttttgaagaaaggttcgagagacaatactcaggtcctgaactgctagaa +gatactcggtggagcgtggcaacaatgaaaaactcgtgacataaatgaatgatacttttc +caagttcagttaagtgaatatgtttaacatacccggcttttcgatcttaagctgacgctg +gacgtgcgagtaatgtcagtctcttacatacactagtgactccaagtttcgtcaaaaacg +ccccctcccttctcgagcccactcacgctatgtattgacgcgaacttgttcgggatcaga +cttttcaggagttcggtcgcgtgtccctatgtgctaatatataagttagatcgcattaga +tgctaatctgaatacttatagacgaccttcaacgagaacgggtaccaccttgaggctaga +gttaggtgtgaaacgacaggtagggacatataaaatttgagtgcggctttagttaagggt +ttaattacctactcaaacatcacgctcgcgcccttcgtacgtaatcgaccatctagaggc +taaggggactgtactaggtagtgattaatgatatcctagacgcacgtgccttagatcttc +agactctgatggtccgcgatcaccgtaattgtagtcctccaactcgatcactttgttggc +gtcaaagaaattacgatatctaaatacttataatacaataaccaaggatgagaatgactc +atcgcgttggagttatattgcttgaagttctatggaatgaaagcacgttatctgccgtcc +caatatctccagtgagctaattcattggacggtccactttgatcaatccccgaggagatg +ttcggacactttagtctgtaacacttagcgttgagaccacgaacaattgattactcagtc +ttgaaggtgttttccaaagttcattttaaataagactacgataggcctttcctattgata +taaactacccggctctgttgttcgtgtgagtcgtacttctctgtgtttttctgattatag +caagattcgattcttagtgtaaacagcgatttttatttgacccgtcaatgagaagcgcat +aggatctaagcaaaattatcaagttgtgccacaaggtaagatctttccagttattgcagg +taggatgtatcccacgttgatagtatgaggtctgacgtcaactgtctaggagagttgacc +gcgtgcgggtacaccggatttgcatcgatgttgagaacgcagaactcccactgtcgtggc +ggcgttcctgatatttagcaagaggcgttgataaagccctcatcatctagatctcgacct +catctgccctcttgctccatcattttctacacagactactttcctatctacgttagtata +attgctttctatcttagtatcatttagagcttctccgtcaacaggttcgtgctattaaag +ttagtacgaaagggacaacttgtagcaacgcatttaatcggttttcgactacttcgcaca +aaatcagataaagaagtttgtcattctattagacattgaattgcgcaattgacttgtacc +acttatgatcgaacactgaatcaagactgtgattaactaaaatagacaagccactatatc +aactaataaaaacgcccctggtggtcgaacatagttgactacaggataattaattggact +ggagccattacattctctacaatcgtatcacttcccaagtagacaactttgaccttgtag +tttcatgtacaaaaaaatgctttcgcaggagcacattggtagttcaatagtttcatggga +acctcttgagccgtcttctgtgggtgtgttcggatagtaggtactgataaagtcgtgtcg +ctttcgatgagagggaattcaccggaaaacaccttggttaacaggatagtctatgtaaac +ttcgagacatgtttaagagttaccagcttaatccacggtgctctactagtatcatcagct +gtcttgcctcgcctagaaatatgcattctatcgttatcctatcaacggttgccgtactga +gcagccttattgtggaagagtaatatataaatgtagtcttgtctttacgaagcagacgta +agtaataatgacttggaataccaaaactaaacatagtggattatcatactcaagaactct +ccagataaataacagtttttacgatacgtcaccaatgagcttaaagattaggatcctcaa +aactgatacaaacgctaattcatttgttattggatccagtatcagttaaactgaatggag +tgaagattgtagaatgttgttctggcctcgcatggggtctaggtgatatacaatttctca +tacttacacggtagtggaaatctgattctagcttcgtagctgactatactcaaggaacca +ctgctcaaggtaggagactagttccgaccctacagtcaaagtggccgaagcttaaactat +agactagttgttaaatgctgatttcaagatatcatctatatacagtttggacaattatgt +gtgcgaaactaaaattcatgctattcagatggatttcacttatgccttagaaacagatat +tgcccgagctcaatcaacagttttagccggaaacaatcgaagcatagggacaatgtatct +tttcctaaattgccatgtgcagatttctgagtgtcacgaagcgcataatagaatcttgtg +ttgcctcaactcgttgaaaagtttaaaacaatcgcagcagtctttttggggtctactgtg +tgtttgcaaaataactgaaagaaacgcttgaacaactctgaagtagctcgagtactcatt +aaagtgtaacacattagtgaatatcggccaatgaaccaaacgcttcccggtacgctatct +ctctcatcgggaggcgatgtgcaggttatctacgaaagcatccctttacgttgagagtgt +cgatgcatgaacctcattgtaacaatagcccagcaaattctcatacgtgcctcagggtcc +gggcgtactcctccatggaagggcgcgcatctagtgttataccaactcgctttttaacta +ctatgctgtagttctacaggcatagtggccagtattttctaacttctctggatagatgct +ctcactcctcatccatcacggcttcagtttacgtcttacttgcttgttcagcaacggatg +gaggcattaagtatcttcactgttccctaaaattgctgttcaatatcaaagtaaggacga +tacagggaaagctcaagcacactcattgaatactgccccagttgcaacctcacttaatct +gacaaaaataatgactactctaagtgttgcggaagcagtctcttccacgagcttgtctgt +atcacttcgtataggcatgtaactcgatagacacgaacaccgagtgagaaactatattct +tgcttccgtgtgtgtgacaccaggtaattgatgcggatataagctggagatcactcacgc +ccacacaaggcgctgctacctctttattccaatgtgtaagaatttgctaacttcatttct +agaccgcagctttgcggtcataatttcacggtacggacccttgggttagagacttgataa +cacacttcgcagtttccaccgcgcacatgttttagtggcttctaacatagaatttttgtt +gtgacataaagagtgcgtgggagacttgcccgaccgttaagccataatcaattgaaagcc +ccgtgagtcacatctaattggttgtactgcgcatttagctatcctttagctgactcgaag +agattcgattcctaatataggttaattagatggctgccgcgcgaagtaaaacgtgaaaaa +cgtagtgcgcagatctgcataactcgcgcttaattacttatgagtagttccaagttcgct +acgttatgagagagattggaattaagcaaatatgttttatggtgattttgggatgagaag +gactgctaagtacggctactaaacaaatttctaaaaccgccatctaccttatcttggaga +catttaagttgtatatgtcactagtctagcttttgtctgtgggacgcgttctcggaatga +gggaaatgcaagagccgattcatcaaatgcttatctaagaaagtagtggactattacacc +aagcacgaatgccagggaactgctttcttgctcaggacctcgcgacaaggtaccccgcat +aagtcctagaattacatttggtcagcaatgctgacatttgaccgtgaaaacataatttta +atcagaaggcagctcacccgcttgctctagatcttatctttgtatgaatgtcagaattta +ctgcaatatccgttccgaatagtgagggcttagtatagttctctgtatacaggtcacatc +aaactccccctgtcctagtacagctctgagctttaattaattgcatacatttccttcaat +catcagatgaaaacaccgcgaatcatgctcttctcgtatagggcaagagaagcaacaaac +aactagcccgactcacgttcatccgccgtatccttgttcagttcttactccgtattaggt +cagcgaaatctaatcagaataatcggtcgcgtatcaaaattaaaatcccgcttgaggttg +acaattaaaacgctgagcagttatcggctattagatagtggggtgaaagtaattggctgg +aattatgttaaaacgtgatattaagctaaaatacgctacttgttgccgacctaattcagt +cattcgatattcagttagagccaagaataacaagcttgtataaattgaacggggtgcact +aaacgatgtgttactctaatattcagcttggagtatacctgaaggcgaattcatgtatcg +gccaataataagacgttgaagatcacaatttggactagcaaaagaaggtgatttatgcgt +ggggattgagtccactgtacgagtacggtctctggaaaattataggttcagggaatataa +ggaagtaaagataattaccaagagatttttggtatcgctatgacccagaggtgttctaac +gtctgttttgatccgcagaatttctgcctcaatgcatatttgacggacttgaactagagc +ctctaaagttaaatggcgacgcaactgttcctaaacttcaattattactactcttttttt +cctagggtattgtagaggccagtggacaaaataaatcaaatttaagatgtttcggacatt +aacatcccccgtagcatagaaatcatcagttatccaatctctcatcgagcttttacaatt +tctgctggcgctatggacagcatatgccgcgagacctccgcaagactcacttgatcactg +taagtatcttcattagaggttagagcctatagttaagctgctgacctagtaaaattggta +ttttctaattttattgctcaagttaaaggttagtgaagggataatgacgttatttttgaa +caatgggttgtattcaattttatatcacgaatggaacccttcattcccggcataatacta +gacgacacgaacaagctccgatctatcagccaggcacgtgttaaggtttaattccggcaa +accaatgaagcatcaaaaggtgacctgatgcaacttagggtcacgatgagtttttcagga +ctacttattacctattaataagttaacatgagccttcataccccgtaagacaatacatac +tccaccaattagaattctgagccatcttatctttttgtatcatcgaagggtatggccgaa +taggttaattagttactcctaacgtctctacaggcatgcatttgacgcaccttcgaaaat +agtcaatctctcgccacacgcgtctagtatgcagcatcaaaaatatagtccacggtttcc +ggattaccaaacgcggcaaagagaaacattgtatcgacggagataacttaatacagaagg +aaggggcatcttcgaatacggatgaataattctatctgtttattctgacatcttgttttc +aggttaatcttacgcattcaaatgacgcctgccccatgcgtgcgcaattattttctaata +ttgacgagagcaatctcactccttttgggtctatttatgttttattgaggcacaagccta +tacagaacaggtactattaaggccgtgagtgtgagactcaaaccgtggaaacaaaggatg +ggttgttcttggtacaagttttagtgcatgtgggcaatccttaccaaaatcagatgctat +ccttaactttgggctgcatttaagatggcggttggaggcctgtgagaatcctgcgtgtca +tctttaatgaccgaattcatccatgtagattcagatcacacactcattccttgatgttgt +ctaaacaaaagttgttgtggacgcattggagggagttaagtaacaacttgggatcgcata +cttataaaaattatatgttaaactttcacaaacgctgaagtccaaagtaactagcccaaa +cgcctcgagagtcactaggtattaatggtgtttgagttcctgtgaaatagtgttcgaagg +taaaatttatgtaccaaatcgaaagaacacttaataaggcttgcttgcacggaggtatga +tgtttactgactctacaaccctaattttccagtacgtacattcattccaataggttagtt +ctcaaagtgctatacaggctcctcaattgatgatatgcttcagccgctctatggatatta +gctcattttatttaggaagcccgcttagaggcttactatgagggaaatgccaaaatgtca +tacttttcggtgtgtcccatatgacaccgctttacatagaatttgaattaaaacgcgctc +tcccgttcactaccatacttggtaccgtgcgcatattacatatagatataggatcatttt +ttaaagctgtactaggtttgatcgacaatcttatgctatactatatgatgtaaccctcat +aatcaataccgatcgtacgatcctagcataggtggcaagcgattttatgccgattattgt +gttaaatagtctgtgagtgtgattatcagggctacgttggtagaggggttgtatagacct +cgcacacattgtgacatacttaacaatatacgaaaactgatataataaatccccttaccc +aaacaccaatcccgttgaatcaactaccataacgtctcccatataaattgcctacttgtt +tgcataaatctgaatacataacaccattgcaccttcttgtgttccaatcccgttaagatt +gccttgtcagatgatatgcaagaacaatagcatttgctagcaattattaacagctcttcg +aattgcctccacataacgcgggagggtatattttaatttggcaaatactaagtactgttg +gcgtcatatgctattaacggttggatattaagttatgtcagccgtaagcaagagtgggcg +aaatattttgttacccagtgagagcactcttagagtttggatacaataggccatatgttg +acttaagaggacgtaactacgccgtacaccattgttcaaccgacttcttggcaaatagaa +tcgtattagcaatcttaagaatagagacacgttcgtgttagggtatactacaaatccgaa +aatcttaagaggatcacctaaactgaaatttatacatatttcaacgtggatagatttaac +ataattcagccacctccaacctgggagtaattttcagtagatttactagatgattagtgg +cccaacgcacttgactatataagatctggggatcctaacctgacctatgagacaaaattg +gaaacgttaacagcccttatgtgtacaaagaaaagtaagttgttgctgttcaacagatga +tagtcatgacgcgtaacttcactatagtaaattgaaacaaatacgcaatttagacagaat +ggtacggtcatgaatgacagtaattcgaagtgctagaccaacttaaaataggtaaacgtg +cccgaaaccccccttaacagaaagctgctatcatggtgcagtatcgacgtgttcagaaac +ttgtaacttttgagcaggtccgagcacatggaagtatatcacgtgtttctgaaccggctt +atccctaagatatatccgtcgcaaactttcgatttagtcccacgtagagcccaagcgttg +tgcgactccacgtgcatgcccagaaatacgagtttaaatttggttacatggttaattttg +accgaagcatcgcactttatgattgataattggattcaatatgtcgccctatgcgaatgc +aacatgatccacaatttggctataagacgtttaatccgtatcacactttgtttgcggcta +gtatagtaacgcccgtgcaccaagagtcagtaacaattataagtactccgcaggtacttc +aaatataaaaactaatcaaacacgacccatatgatcatctgaagatatttggaactttct +cgacaaccaccctcgtactcaatacttacactaatcgacaggcacacgcaacgtgtacag +tcgcaccatattgagtcaagatttgcttagtggcgatgagcgtacacgcttatttctcta +gtcacaattagttatctacgagacatcacgagggagcaaataagcgatgttatggctaca +cataggcacgtatgaatatgatataagccagttaaacagtcgaaccatcgagcaaattct +catgcaccaacccacacgttgaggcacaaagagtaagctgtttgaatgtaacttcttctg +ctgagcgggccccaacgtaaggatcaactagaagagaaaactcggtattagtttaaatgc +gtcacggagcatgagtgcatttcactaagaatgtctgtgtaaccaatataacatctattt +gttatctgattgcctacttatggctttgcggtcgtggcgactaatgtctccaatcctttt +gaggtcggtaccaactccctttaaattacgctgtgcaggctcatgcactgcatacatata +cggtagcaggtagggacctcacgcacccttattataatcaatagtagttatcagtcaacg +aggcaggaatgctgaggtcgaggtgttggtatattttctatgtgccgtctaggcgactat +cacgcattaccaggcgagatttaagccaattttgaatatagtcaacgtaatttttactat +gggttccaccgaaacgccttgcacaactaagaatcccataaaatatcgatatcaaataaa +agattgtgtcaataccttcatatatattttttcggttgactaacgtgaactaaggttagg +ggttttgtatgtctatataggaaacagtttcttttctgtcctactttagtaaagtcttca +agccttactccaaaatcacggtgattaagccgttactcagcagcatgattctgcctgctc +gggtcctaaaatccagccttgtaagagtcgctgtgtattagctagggagacctttgttaa +aaaggatatatcgcggcgggatgtgagtgcgtggcgcatactcaatcttcagctcgtgtc +attataatatctctcccccacgcttttcactagatatgccgtgtaagcaaacaccttatg +cttaatttcgaaaatattggtacttgaaaaaagctgtaggggtacttaatgtctggtagg +agatcaggagagaattgagtgtaaaaccgtaaagccctcacctgacttcatgtaaatggc +ttagaagactccatgatttaataaatactacgaaggaaagactggatctaaagataactc +tagtaaggccaactcccttcaatgctgttgccagttataatccaagagctgtccttttct +gaaccatagcggcttctgaagcgaactagaagcaaagttggttctagccagacagccaca +taccctgtacgggtgtattactaaaactggtccggtattagttcaccaagggaggaatta +ggcaaaggatctaggtatgcaagtcggagtattacatccctaccctgaatccatcaatag +gttcctctgtactggccttcgcaatgagtattcaaggttgtacagccgtataataataag +atagtgactatgaacgggaagtaacccgctcaccttccccaaaacattgttatatctaag +tattaaagtctgccgtagtgttaatactcgaaaataaacaactggcaaattacaccgcac +ttaagccgcttttgatttatatttttccaatgcgcttttaaaaataattcagtcctacat +actaattaagacccttaaacggagatatcacaagttaagttttaaccatctcgactaggt +ggaactatagatacccaactcaatttatcattacctgtaatgttcctagaaggattgcat +ttcatgtcaagacggtggagtttcacagcgaaacttcagtgtgaacagattctgagaaat +cacctaaacctattagtcagagcacccggttagaaccagttgtcaaaaaatagagcggtt +gcatgagacagaagtaacgatgagatccgttgtaacgttgagacatctggcctatcgtca +atacagtcctcccttaaaaatatttttaaatactaggcaaacccaacataggttagtcct +atgtgatacgccacatggtatatcattttgtaacgttacctagggataatcaggaagtgg +aattacgcaaaagtagacagtgaaatgcttagggttatagtctagtccaaagataaagga +taaagcacgtcagagaactatattagccgaatgggaatcattgttaggagactgtggatc +atgtctaaaaagcaacgcagaaacagtcatcgaaaaaatctcgtttttgtttgaatctaa +aagagctttgatgaccgatagtacctgtatactagttactgtattacgtgtctaatgatt +tcggattggggtccccagaatcagacgtcattgtagacgattcaagtttaccaatttaat +ttcccagctctccttggagaactatcgccaataattgcagtcactttccttttctgaaac +gataaagccgtcagagttctctgcaacgttggacttacctgaggttctaacccactttcg +gttctaatagtagttaacgacacaacgaataacctttactgtggggctttcacgatattt +tttcgcttattattaatggttacgtcataagctggtgtccaaattaaggttaccggcttc +gcagagtagttgtatccaagtataacttccctaatcataagatcgaggtagaaaattaat +gctgtctctaaccgaacagatatgtcccactatgtggtatggacgttgctaattacttct +gaagggaaattggtcattatggatacgtgtctaccatcaggtcggacgcagatatggttc +tgtcttcagttgatccaccgttctttataggataataactgacgattaaagattatggta +aatagattaagccaattctcttcttgtcagtgaagcatccttaactgacttgctctgcag +cccctcatacatttagctattcaaagtaccggctcgtttcaaactctcccacctttggaa +gaggttgtcaacttgataagtatatcatttacagcattttttcggacgtacctctaatgt +ttcattgcagaaaattagttttttctatcgcacattttgcaagtaacgttagagacacaa +ttatctgcgaatgaactgctagatctgacgaccgggagcctcgcaaatatcaaaaaagac +tgacatatatcaaggagtcgttgacaagtgctggtaagtcaattggtttatctgtcccgg +cgtttcgatcttaagctgaccatgcacggcagagtaatgtcactctcgttcttacaagtc +tgtctccaagggtcggcaaaaaagacccctccattctcgagcccactcacgatatgtagg +gacgacaacttgtgcggcttatgaattgtctggactgcgggcgagggtccatatctccga +agttagaagggacatacctttagatgataagatcaattcttattgacgaaattcatccac +aacggggaacaacttcaccctagacttacgtctgaaaagacacctagcgtcttataaaag +gtcagtgccccgtttcgtaaggctggaattacctacgcaaacttaaacctcgcgcccttc +cttacgtatcgacaagatagaggctatcgcgaatgtactacggaggcatgaatcatatac +tagaaccaagtgcctgtgatattaacaagatgatccgacgcgagcaccgtaattctaggc +ataaaactccagcaatttgggggccgaaaacaaatgacgttagctaattaattatatgac +atgatcaaaggaggtcaatcacgcatcgagttcgacgtatattcattgaacttcgtgcgt +ttgaaagaaacttttatgaaggcaaaattgatcctgtctcctatttcatgcgtacctcct +agttgataattccccgagcagtggttaggacacttttgtcggtatcaagttccggtctca +aaacgtaaaattctgtaatctgtatggatggtctgtgaattagttaatttttatgaagtc +gtcgagacgcagttcctattgatttattctaaacggagatgtgcttcgtgggactcggaa +gtagatctgtgtttatgattattgctactttagatgctgactgttaactccgtgttgttt +ttcaaccgtatatcacaaccgaattggatagaacctatagtttcaagttctgccacaagg +tatcatatttacagttagtgctggttgcttctttcaaacgtggtgagtttgtgctatcac +gtcaacggtagagctcagtggaccgagtgcgcgttcaaccctgttccagagagggtgtga +tagcacatataccacgctcgtcgaggcgttcatgatagtttgcaagagccggtgttaaac +acatattattattgttatccaactaatcggacctatgcataaagcattgtctaaacagaa +taattgcctatatacggtagttttagtgatttatatcttagtatcagttagagcttcgaa +ctcttcaggttcctcatatttaacgttcttcgaaagcgaaaacttctacaaacgaatgta +agcggttttccaagtagtacctataaatcacagaaagatctgtctcagtatagttgaaat +ggtattcagctagtgacgtgtaccaattatcatagttcactcaagcaagacgctcattaa +cgaatatagacaagacactatatcatataataaaaaagaacatggtgctcgaacatagtt +gaattcaccatattgaaggggaatgctgacatgtaattcgctactagacgatcaattccc +tacttgtcaaagttgaactggtacgttcttggaattaaatatgattgcgctggaccaaat +tgcgacttcttgagtttcagggcaaacgattgagccggaggatgtccgtctcttaccttt +cttgcttatgataaacgacggtccctgtacatcactgggaattctcagcaaaaataattg +ggtaaatcgagactcgatgtattcggccacaaaggtgttagacgttaaagattattcaac +ggggcgataataggatcataaccggtatgcaagcgcattgaaagagccatgagatcctta +tccgataaacgctgcacggtatgtgcagccttattgtcgatcacgaatttataaatgtag +tctgggctgtaagttgaagacctaagttataatgaagtgcaataccaaatcgattcatag +tggattatcagactcaagatatctcctgataaattacagttgttaagatacggataaaat +gagatttaagattagcagcctctaatctgtttcaatcccgttggaatgtggtatgcgatc +aaggttaagttaaaatcaagcctgtcttcagtcttgattcttgttctgccatcgcatgcg +gtctacgtgagttaatatgtagcttacgttctagcttgtgctaatctgagtatagattcg +tagaggaatattatcaagcttccacgcctcaacgtacgtgtattggtcacacaagacact +aaaagtggaagtagcgtaaactatagtctagttgttaaatgctcagttcttgttatattc +gatatactcttggctaatttatgtctgagtatataaaattaatgatattaacttgcattt +cacggatcccttagaaaaagattttgaccgagcgcattataaacggttacaccgaatcaa +tagaagcatacccaatagctttctttgaatttattgcctgcgcaacttggctgactctct +agatccgaataattctatatggtcgtgacgaaactagttcattactgtttaaaatgccaa +catgtcttttgggccgataatggctctttgcaaaattactcaatgatacgattgatcaaa +gcggtagttgctagtggtagcatgtaagtctatcaaatgtctgattatccgaaaatcttc +caaaagagtccacgtaccatatctatctcatagcgacgcgaggggaaccttatctaacta +tcattccatttaccgggtgactctcgatgcaggatccgattgggataaattgcccagaaa +tggctcattcctgactaagggtaaggccgttctcagcaagggaaccccgcgaatctaggc +ttataccatctagattgttaactacttgcctgtagttctacagccatactggacagttgt +ttctaaatgatcgggattcatgctagcactcctctgaatgcaccgcgtaagtttaactat +tacgtccgtgggcagataaggatggaggctgtatgtatcttaactgttacctaatatggc +tggtaattatcaaagtaaggaccttaatgccatagcgctagcaatcgctttgtatactga +ccatgtgccaacctctcttaatctgtaaaatataatgtcttagctaactgtggacgatca +tgtctctgcctagagcttcgctgtatcaattcctatagccagcgtactagtgacacaaca +acaccgtgtgagaaaagatattagtccttacgtctgtctctctacagcttattgatgagg +attgaacatggacatatagctccccctcaaaagcagatgctacctctttattccattctc +gaacatttgccgaacttaatttcgacaaacctgaggtcacgtcttaatttatcggtaacg +tcacgtccctttgagactggataaatatattaccaggggccaacgagcaattgttggagg +cgcttctataatacaaggtgtcttgtcaaagaaagacggcgtgcgtctcgtgcaactcac +ttaaccaatattaatgtgaaacccccctctctcacatcttatgcggtgtactgccctggt +acatttcctgtacaggactccaacagtgtagattcctaagatagctgttggagttgcctc +acgccagatcgaaaaactgaataaactagtgagctgagctgcagaaataccgcttaatta +cttatgactagttcaaagggacctacgtgatgtcagacattgcaaggaagaaattaggtt +tgtgcgtcattttggctggactagcactccttacttcccctactattcaaatgtcgtaaa +cagcatgagacaggatcgtgctgacatttaaggtctattgggaacgaggctacctttggt +cgcgcgctcgcgttctccgaatgaccgaaatgcatgagcacagtatgcaattgcttatag +atctaaggtctggtcgttgaaaccaagcacgtaggcctgggaaatcagttcttcctcagc +aactacacaaaagcgtccaagcattagtacttgtagtaaatgtccgaacctatgcgctca +tttgaaagtcaaaaaatatttttaagcagtaggcacctaacccgattcctctacttagta +gctttctttgattctcagaattgactgcaatatcactgcacaattctgtgccattactag +acttctctgtattaacgtctcatcttactaacactcgcctaggacacatctgagagtgaa +gtatttcaatacatttactgaaatcttcagttctaaaatccccgaataaggctcttatcg +gtttggccaacacaagaaaaaaacttcttgcaccactcaccttcatacgcaggagcctgg +ggaacttagtaataactatttcggcagacaaagcttataacaagttgccggcgcgtataa +tatttaaaagaccccttgagctgctcaattaaaacgctcacctggtataggctattagat +agtgccgtcttagtaaggggcgggaattatcggataaactgatattttgataaaataacc +gacttgttcacgacataagtcactaaggagattttatctttctccaaagtatatcttcct +tggataatttcaaagcgctgcaatttaagttctgttactagtttatgctgctgggaggtg +accggaaggcgtagtaatctagaggcaaattataagaagttcatcatatcattttcgact +acaaaaacaaggtgttgtatgccggcgcattgtgtaaactggacgagtaccctagatgga +aaattatacgttaagccaagatttcgatgtaatgataattacctacacatttttgctatc +cataggaacaagagctgttctataggctcgtggcatacgaacatttgctgccgctatgaa +tattggaagctcttcaactacagactctattcttaattgccgtcgaaaatgggccgaatc +ggctattattaatactcggtttttccgaggggattgttgtcgacagtcgtaattattatt +aatattgatgttggtgaggtcatttaaatacaaccttgcagacaatgaataagggatcca +atctctcatactccttttacaattgctcatgcccctatgcaaaccttatgccgccacacc +tccgcaactctctcttctgaactgtaagtagcttcattactggtttgagactatactgaa +gctgatgacattctaaaatggctattttcgaatgtgattcataatgtttatcgtttggga +tggcagaatcacgttatttttgatatagcccgggtattctattgtatagaacgtatgcta +caagtcattccccgaagaagactagaagtaaacaacatgcgaccatcgttaagccacgca +aggctgtagctttatttcccgataacctatcttccataaatagcggacagcaggatactg +acgctcaacatcagtggttatggtctaatttttaacttttaataaggtaacttcagcagg +catacacagtaactctttaatttataatcaaattagaagtctgacacttcttatattttt +ctatcatccaacgcgatcgcccattagcttattgtgttactaataacgtatctaaaccaa +tccttttcaagctactgcctatattgtcaatatatacaaacaacaggatagtaggctgct +taaaaaatattgtcaaccgtgtacgctttacaatacccggaaatcacaaactttgtagac +aacgagtgaaatttatacactacgaagggccagcgtacaagacccatgaattaggcgata +tgtttattctgacatattggtttatccttaatctgtcgctgtaaaatgaagccgccccca +tccctgcgaattttttttcgaagattcacgactgaaatataaatacgtttggctatattt +atgttggagggaggcaatagcctttactgttaaccgaagatttagccagtgagtgtgaca +ctaaaacactggaataaatgcaggcgttcttctgggtaaaaggtttagtcaatctcgcct +ataagttcatatagctctggatataattatctggcccatgcatttatcatggcgcttggt +gccctgtgtgaagccggcctctcatattgaaggtccgaagtattccatgtacattaagat +cactctctcattcatgcatcttggcttaacaaatctggttgtccaagctttccaggcacg +tatggtacaaattcggatcgaatacttataaaaatgatatgttaaactgtctaaaacgct +catctacaaagtaaagtgcactaaccaatagagtctcaagaccgtgtaatgctggtgcac +tgaatgtgtaatacggttagaagggattagttatgttacaaatccattgaaaacttaaga +agcattgcgtgctcggagggtgcatcttttatcaagagactaacattattttcaacgacg +tacatgctttacaatagggtacttatcaaacgccgagaaacgcgcctatagtgatgttat +gattatgacccgatatccattggaccgaattttatgtaggttcccagcgtactcgcgtaa +tatctcggtattgccataatgtaatacttgtcggtctctcccagatgaaaaagcgttaca +gagtatttcaatgaaaaacagcgcgcaacgtcaatacctttaggggtaacggccgctgat +ttcatatagatatacgataagttggtatagctctactaggtggcatccacaatcgttgca +tttactatagctggttacaatcataatctataccgttccttacatactaccatagcggga +tagcgtttttttgccgttgattgggtttaagaggatgtcagtctcattatatccgattcg +gtgggagagccgttgttttcaaatcgcacactttgtgacataatgtacaagataacaaaa +ctgatataagatataaactgtcaatatcaccttgacacttgaatcaaagtaaattaactc +gcaaatataatttgactaattgggtgcagatttctcaattaataaaaaaatggcaccgga +tgggcttacaagccccttatcattcacttgtatcatgatttccaagaacaatagaatttg +ctagcaagtatgaacagagattcgaattgcatccacagtacgccggagcgtttattttaa +tgtggatatgacgatgtactgttggcggcatttgctagtaaccggtccttatttacgtag +cgcacacgtaagcatgtctgggagaaatatggtggtacaatctcagagaaagattacagt +ttggtttaaataggacttatcgggtcggaagtggaacttaataagcagtacacaattggg +caacagacgtcttgcctattacaataggattacaatgcgttagatttcagacacgttcgt +gtttggctattcgtcaattccctaaatagttagacgatcaactattatcaaagtgattct +ttgttcatcctccattcatgtaacagatggcacactacgcataacgccgaggaattttaa +cgagatttaagagagcagttcgggcacaacccacttgactttataacagctcggcagcat +aaacggtaatatgtgacaaatttccaaacgttataagaacgtatgtgtacttagaaaact +aagtggttcatgttcaacagatgtgacgcagcaagcctaacttatctattggttttgcta +taaaagaacaaagttacacagaatcctaagggcttgtttcacacttatgcctagtgcttc +accatcttaaaatagcgaaaccggcacgaatcaaaccttaaaacaatgcgcagatattgg +tgatggtgactccgggtatgataatggtaactgttgaccagcgcccacctcatcgaagta +tagaaagtggttaggataaggatgagaccgaacttatttccggccataactttagatttt +ctacctagtacacaacatcagggcggacacgaaaccgccatcacatcatataccaggttt +aatttgcttaatgggggaagtgtcaacgaaccttcgaactttagcaggcatatggccatt +atatatggccccagagcagaatgctacagcagacaaaatttggatttatgtagtttaata +cctatcaaacttggtgtgaccatacttgtctaacgacagtgcacaaagtgtaagttacaa +ttattactactcagcagcttctgcaatgataaaatcttatcatacacgtcacatatgata +atatctacttagggggaacgggctccacaacctacatagtactcaatacttacactattc +gacaggcacaccaaacctgtacagtcccaaaagattgagtcaactttgcagtactgcaga +tcacagtaatagcttagttagcgagtcaaaattagttttctacgagactgcacgaccgtg +caaatttccgatgtgttggctacaaatagcaacgtatgaatttgtttgaagccacgtaaa +ctgtacaaccttagagataagtctcaggctactaaaaacacgttgtggcactaacaggat +catggttgattcttacttattcggctgaccggcccaataagtaaccttcaactagaacag +aataatcgggagtagtttaattcagtcaaggtgcaggtctcattgtaactaacaagctct +gtgtaaccaagttaaaatcgttttcttagcggattccctacttatggatttgagctcgtc +cacaatattcgatacaagaagtttgtggtccgtaacaacgaaattttaattacgctgtgc +agcctcatccaaggaattaatagaaggttgatggtaggctccgaacgctccatgattata +atcaagtggactgtgcagtaaacgaggaaggtatcctgacgtcgtggtgttcgtttttgt +tatttgtgccctatacgagtagataaaccatgaacagcacagtgtgaacccatggttgat +tttaggctaccttatttttaatttccgttacacagaaacgaattccacaactaacatgcc +attaatttttcgatatcttataaaagatggtcgaaattcattcatttattttttttcggt +tctcgaaagtcaactaagctgtcgcgttttgtttctctttagaggtaaaagtggctttga +tctcctacgtttggatactagtcaaccattactccatttgatccgtgagtatcacctgtc +taacatccagcattatgactcctcggcgaagaaaagacacacttcttagagtcgatgtgt +attagctagggacacagttgtttaatacgatagtgagcccagggagggcagtgcgtcccc +cagtagatttattcagctagtgtaagtataagatatctcacccacgaggttcaagtgata +tgcagtcttagaataatacttatcctgaatttcgatattatgggtacttcaataatccgc +tagcgctactttatgtctcgttggacagcaggacacatggcagtcttaaacactaaagac +atcacctgaatgaatgtaatgggattacaagaatcaatgaggtattatatacgacgtagg +aaactctggatatatacagtaatctagttacgccatcgcacttcattcctctggaaactt +agaagacatcagctgtacgtggaggaaccagacccccgtatgtagccaaatagaaccaaa +gttgcttatacaaacacacccaatgacaatggaccgctggagttcgtaaactcggaacgt +agtactgcacaaacccagcatttagcaataggagctacgtatgcaactcccacgtggtaa +taccttcaagctatcaatatataggtgcctagctaatcgcattcgcaagcagtattcaag +cttgtaaaccagtataataattacagaggctctatgaaacccaactttccagctaaaagt +cccaattaaatggttatttc diff --git a/extern/phmap/examples/knucleotide.cc b/extern/phmap/examples/knucleotide.cc new file mode 100644 index 0000000..48f5c79 --- /dev/null +++ b/extern/phmap/examples/knucleotide.cc @@ -0,0 +1,236 @@ +// ------------------------------------------------------------------ +// run with: knucleotide 0 < ../examples/knucleotide-input.txt +// ------------------------------------------------------------------ +// +// output should be: +// +// T 31.520 +// A 29.600 +// C 19.480 +// G 19.400 +// +// AT 9.922 +// TT 9.602 +// TA 9.402 +// AA 8.402 +// GA 6.321 +// TC 6.301 +// TG 6.201 +// GT 6.041 +// CT 5.961 +// AG 5.841 +// CA 5.461 +// AC 5.441 +// CC 4.041 +// CG 4.021 +// GC 3.701 +// GG 3.341 +// +// 54 GGT +// 24 GGTA +// 4 GGTATT +// 0 GGTATTTTAATT +// 0 GGTATTTTAATTTATAGT +// ------------------------------------------------------------------ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ------------------------------------------------------------------ +constexpr size_t thread_count = 4; + +struct Cfg { + unsigned char *to_char; + unsigned char to_num[128]; + using Data = std::vector; + + Cfg() { + static unsigned char __tochar[] = {'A', 'C', 'T', 'G'}; + to_char = __tochar; + to_num[static_cast('A')] = to_num[static_cast('a')] = 0; + to_num[static_cast('C')] = to_num[static_cast('c')] = 1; + to_num[static_cast('T')] = to_num[static_cast('t')] = 2; + to_num[static_cast('G')] = to_num[static_cast('g')] = 3; + } +} const cfg; + +// ------------------------------------------------------------------ +template +struct Key +{ + // select type to use for 'data', if hash key can fit on 32-bit integer + // then use uint32_t else use uint64_t. + using Data = typename std::conditional::type; + + struct Hash { + Data operator()(const Key& t)const{ return t._data; } + }; + + Key() : _data(0) { + } + + Key(const char *str) { + _data = 0; + for(unsigned i = 0; i < size; ++i){ + _data <<= 2; + _data |= cfg.to_num[unsigned(str[i])]; + } + } + + // initialize hash from input data + void InitKey(const unsigned char *data) { + for(unsigned i = 0; i < size; ++i){ + _data <<= 2; + _data |= data[i]; + } + } + + // updates the key with 1 byte + void UpdateKey(const unsigned char data) { + _data <<= 2; + _data |= data; + } + + // masks out excess information + void MaskKey() { + _data &= _mask; + } + + // implicit casting operator to string + operator std::string() const { + std::string tmp; + Data data = _data; + for(size_t i = 0; i != size; ++i, data >>= 2) + tmp += cfg.to_char[data & 3ull]; + std::reverse(tmp.begin(), tmp.end()); + return tmp; + } + + bool operator== (const Key& in) const { + return _data == in._data; + } +private: + static constexpr Data _mask = ~(Data(-1) << (2 * size)); + Data _data; +}; + +// ------------------------------------------------------------------ +template > +using HashTable = phmap::flat_hash_map; + +// ------------------------------------------------------------------ +template +void Calculate(const Cfg::Data& input, size_t begin, HashTable& table) +{ + // original implementation fully recomputes the hash key for each + // insert to the hash table. This implementation only partially + // updates the hash, this is the same with C GCC, Rust #6 and Rust #4 + Key key; + // initialize key + key.InitKey(input.data() + begin); + // use key to increment value + ++table[key]; + + auto itr_begin = input.data() + begin + thread_count; + auto itr_end = (input.data() + input.size() + 1) - size; + size_t nsize = std::min(size, thread_count); + for(;itr_begin < itr_end; itr_begin += thread_count) { + // update the key 1 byte at a time + for(unsigned i = 0; i < nsize; ++i) + key.UpdateKey( itr_begin[i] ); + + // then finally mask out excess information + key.MaskKey(); + + // then use key to increment value + ++table[key]; + } +} + +// ------------------------------------------------------------------ +template +HashTable CalculateInThreads(const Cfg::Data& input) +{ + HashTable hash_tables[thread_count]; + std::thread threads[thread_count]; + + auto invoke = [&](unsigned begin) { + Calculate(input, begin, hash_tables[begin]); + }; + + for(unsigned i = 0; i < thread_count; ++i) + threads[i] = std::thread(invoke, i); + + for(auto& i : threads) + i.join(); + + auto& frequencies = hash_tables[0]; + for(unsigned i = 1 ; i < thread_count; ++i) + for(auto& j : hash_tables[i]) + frequencies[j.first] += j.second; + + // return the 'frequency' by move instead of copy. + return std::move(frequencies); +} + +// ------------------------------------------------------------------ +template +void WriteFrequencies(const Cfg::Data& input) +{ + // we "receive" the returned object by move instead of copy. + auto&& frequencies = CalculateInThreads(input); + std::map> freq; + for(const auto& i: frequencies) + freq.insert({i.second, i.first}); + + const unsigned sum = static_cast(input.size()) + 1 - size; + for(const auto& i : freq) + std::cout << i.second << ' ' << (sum ? double(100 * i.first) / sum : 0.0) << '\n'; + std::cout << '\n'; +} + +// ------------------------------------------------------------------ +template +void WriteCount( const Cfg::Data& input, const char *text ) { + // we "receive" the returned object by move instead of copy. + auto&& frequencies = CalculateInThreads(input); + std::cout << frequencies[Key(text)] << '\t' << text << '\n'; +} + +// ------------------------------------------------------------------ +int main() +{ + Cfg::Data data; + std::array buf; + + while(fgets(buf.data(), static_cast(buf.size()), stdin) && memcmp(">THREE", buf.data(), 6)); + while(fgets(buf.data(), static_cast(buf.size()), stdin) && buf.front() != '>') { + if(buf.front() != ';'){ + auto i = std::find(buf.begin(), buf.end(), '\n'); + data.insert(data.end(), buf.begin(), i); + } + } + std::transform(data.begin(), data.end(), data.begin(), [](unsigned char c){ + return cfg.to_num[c]; + }); + std::cout << std::setprecision(3) << std::setiosflags(std::ios::fixed); + + WriteFrequencies<1>(data); + WriteFrequencies<2>(data); + // value at left is the length of the passed string. + WriteCount<3>(data, "GGT"); + WriteCount<4>(data, "GGTA"); + WriteCount<6>(data, "GGTATT"); + WriteCount<12>(data, "GGTATTTTAATT"); + WriteCount<18>(data, "GGTATTTTAATTTATAGT"); +} diff --git a/extern/phmap/examples/lazy_emplace_l.cc b/extern/phmap/examples/lazy_emplace_l.cc new file mode 100644 index 0000000..30a040f --- /dev/null +++ b/extern/phmap/examples/lazy_emplace_l.cc @@ -0,0 +1,54 @@ +// ------------------------ +// Windows specific example +// curtesy of @kanonka +// ------------------------ +#include +#include "parallel_hashmap/phmap.h" +#include +#include +#include + +class srwlock { + SRWLOCK _lock; + +public: + srwlock() { InitializeSRWLock(&_lock); } + void lock() { AcquireSRWLockExclusive(&_lock); } + void unlock() { ReleaseSRWLockExclusive(&_lock); } +}; + +using Map = phmap::parallel_flat_hash_map, + phmap::priv::hash_default_eq, + std::allocator>, 8, srwlock>; + +class Dict +{ + Map m_stringsMap; + +public: + int addParallel(std::string&& str, volatile long* curIdx) + { + int newIndex = -1; + m_stringsMap.lazy_emplace_l(std::move(str), + [&](int& v) { newIndex = v; }, // called only when key was already present + [&](const Map::constructor& ctor) // construct value_type in place when key not present + { newIndex = InterlockedIncrement(curIdx); ctor(std::move(str), newIndex); }); + + return newIndex; + } +}; + +int main() +{ + size_t totalSize = 6000000; + std::vector values(totalSize); + Dict dict; + volatile long index = 0; + concurrency::parallel_for(size_t(0), size_t(totalSize), + [&](size_t i) { + std::string s = "ab_uu_" + std::to_string(i % 1000000); + values[i] = dict.addParallel(std::move(s), &index); + }); + + return 0; +} diff --git a/extern/phmap/examples/matt.cc b/extern/phmap/examples/matt.cc new file mode 100644 index 0000000..51afcce --- /dev/null +++ b/extern/phmap/examples/matt.cc @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ------------------------------------------------------------------- +// ------------------------------------------------------------------- +class Timer +{ +public: + Timer(std::string name) : _name(name), _start(std::chrono::high_resolution_clock::now()) {} + + ~Timer() + { + std::chrono::duration elapsed_seconds = std::chrono::high_resolution_clock::now() - _start; + printf("%s: %.3fs\n", _name.c_str(), elapsed_seconds.count()); + } + +private: + std::string _name; + std::chrono::high_resolution_clock::time_point _start; +}; + +// -------------------------------------------------------------------------- +// from: https://github.com/preshing/RandomSequence +// -------------------------------------------------------------------------- +class RSU +{ +private: + uint32_t m_index; + uint32_t m_intermediateOffset; + + static uint32_t permuteQPR(uint32_t x) + { + static const uint32_t prime = 4294967291u; + if (x >= prime) + return x; // The 5 integers out of range are mapped to themselves. + uint32_t residue = ((unsigned long long) x * x) % prime; + return (x <= prime / 2) ? residue : prime - residue; + } + +public: + RSU(uint32_t seedBase, uint32_t seedOffset) + { + m_index = permuteQPR(permuteQPR(seedBase) + 0x682f0161); + m_intermediateOffset = permuteQPR(permuteQPR(seedOffset) + 0x46790905); + } + + uint32_t next() + { + return permuteQPR((permuteQPR(m_index++) + m_intermediateOffset) ^ 0x5bf03635); + } +}; + +using Perturb = std::function &)>; + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +template +void test(const char *name, Perturb perturb1, Perturb /* perturb2 */) +{ + //phmap::btree_set s; + Set s; + + unsigned int seed = 76687; + RSU rsu(seed, seed + 1); + + for (uint32_t i=0; i order(s.begin(), s.end()); // contains sorted, randomly generated keys (when using phmap::btree_set) + // or keys in the final order of a Set (when using Set). + + perturb1(order); // either keep them in same order, or shuffle them + +#if 0 + order.resize(N/4); + perturb2(order); +#endif + + Timer t(name); // start timer + Set c; + //c.reserve(order.size()); // whether this "reserve()" is present or not makes a huge difference + c.insert(order.begin(), order.end()); // time for inserting the same keys into the set + // should not depend on them being sorted or not. +} + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +template +using pset = phmap::parallel_flat_hash_set, + phmap::priv::hash_default_eq, + phmap::priv::Allocator, // alias for std::allocator + N>; + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +int main() +{ + auto shuffle = [](std::vector &order) { + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(order.begin(), order.end(), g); + }; + + auto noop = [](std::vector &) {}; + + auto perturb2 = noop; + + constexpr uint32_t num_keys = 10000000; + using T = uint64_t; + + test, num_keys>("flat_hash_set ordered ", noop, perturb2); + + test, num_keys>("flat_hash_set shuffled", shuffle, perturb2); + + test, num_keys>("parallel (16) ordered ", noop, perturb2); + + test, num_keys>("parallel (16) shuffled", shuffle, perturb2); + + test, num_keys>("parallel (64) ordered ", noop, perturb2); + + test, num_keys>("parallel (64) shuffled", shuffle, perturb2); + + test, num_keys>("parallel (256) ordered ", noop, perturb2); + + test, num_keys>("parallel (256) shuffled", shuffle, perturb2); +} + + + + diff --git a/extern/phmap/examples/serialize.cc b/extern/phmap/examples/serialize.cc new file mode 100644 index 0000000..0d44109 --- /dev/null +++ b/extern/phmap/examples/serialize.cc @@ -0,0 +1,204 @@ +#include +#include +#include + +#define USE_CEREAL 0 + +#if USE_CEREAL + #include "cereal/types/unordered_map.hpp" + #include "cereal/types/memory.hpp" + #include "cereal/types/bitset.hpp" + #include "cereal/archives/binary.hpp" + #include +#endif + +#include "parallel_hashmap/phmap_dump.h" + +#include +#include +#include + +using phmap::flat_hash_map; +using namespace std; +template using milliseconds = std::chrono::duration; + +// -------------------------------------------------------------------------- +// from: https://github.com/preshing/RandomSequence +// -------------------------------------------------------------------------- +class RSU +{ +private: + unsigned int m_index; + unsigned int m_intermediateOffset; + + static unsigned int permuteQPR(unsigned int x) + { + static const unsigned int prime = 4294967291u; + if (x >= prime) + return x; // The 5 integers out of range are mapped to themselves. + unsigned int residue = ((unsigned long long) x * x) % prime; + return (x <= prime / 2) ? residue : prime - residue; + } + +public: + RSU(unsigned int seedBase, unsigned int seedOffset) + { + m_index = permuteQPR(permuteQPR(seedBase) + 0x682f0161); + m_intermediateOffset = permuteQPR(permuteQPR(seedOffset) + 0x46790905); + } + + unsigned int next() + { + return permuteQPR((permuteQPR(m_index++) + m_intermediateOffset) ^ 0x5bf03635); + } +}; + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +void showtime(const char *name, std::function doit) +{ + auto t1 = std::chrono::high_resolution_clock::now(); + doit(); + auto t2 = std::chrono::high_resolution_clock::now(); + auto elapsed = milliseconds(t2 - t1).count(); + printf("%s: %.3fs\n", name, (int)elapsed / 1000.0f); +} + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +template +void testMapSerialization(const char *maptype, const char *fname) +{ + MapType table; + const int num_items = 100000000; + + printf("Building test %s\n", maptype); + + // Iterate and add keys and values + // ------------------------------- + showtime("build time", [&table, num_items]() { + unsigned int seed = 76687; + RSU rsu(seed, seed + 1); + + table.reserve(num_items); + for (int i=0; i < num_items; ++i) + table.insert(typename MapType::value_type(rsu.next(), i)); + }); + + // cerealize and save data + // ----------------------- + showtime("serialize", [&]() { +#if !USE_CEREAL + phmap::BinaryOutputArchive ar_out(fname); + table.phmap_dump(ar_out); +#else + ofstream os(fname, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary); + cereal::BinaryOutputArchive archive(os); + archive(table.size()); + archive(table); +#endif + }); + + MapType table_in; + + // deserialize + // ----------- + showtime("deserialize", [&]() { +#if !USE_CEREAL + phmap::BinaryInputArchive ar_in(fname); + table_in.phmap_load(ar_in); +#else + ifstream is(fname, std::ofstream::in | std::ofstream::binary); + cereal::BinaryInputArchive archive_in(is); + size_t table_size; + + archive_in(table_size); + table_in.reserve(table_size); + archive_in(table_in); // deserialize from file out.cereal into table_in +#endif + }); + + + if (table == table_in) + printf("All checks out, table size: %zu\n\n", table_in.size()); + else + printf("FAILURE\n"); +} + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +template +void testSetSerialization(const char *settype, const char *fname) +{ + SetType table; + const int num_items = 100000000; + + printf("Building test %s\n", settype); + + // Iterate and add keys and values + // ------------------------------- + showtime("build time", [&]() { + unsigned int seed = 76687; + RSU rsu(seed, seed + 1); + + table.reserve(num_items); + for (int i=0; i < num_items; ++i) + table.insert(typename SetType::value_type(rsu.next())); + }); + + // cerealize and save data + // ----------------------- + showtime("serialize", [&]() { +#if !USE_CEREAL + phmap::BinaryOutputArchive ar_out(fname); + table.phmap_dump(ar_out); +#else + ofstream os(fname, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary); + cereal::BinaryOutputArchive archive(os); + archive(table.size()); + archive(table); +#endif + }); + + SetType table_in; + + // deserialize + // ----------- + showtime("deserialize", [&]() { +#if !USE_CEREAL + phmap::BinaryInputArchive ar_in(fname); + table_in.phmap_load(ar_in); +#else + ifstream is(fname, std::ofstream::in | std::ofstream::binary); + cereal::BinaryInputArchive archive_in(is); + size_t table_size; + + archive_in(table_size); + table_in.reserve(table_size); + archive_in(table_in); // deserialize from file out.cereal into table_in +#endif + }); + + + if (table == table_in) + printf("All checks out, table size: %zu\n\n", table_in.size()); + else + printf("FAILURE\n"); +} + + + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +int main() +{ + testSetSerialization>("flat_hash_set", "dump1.bin"); +#if 0 + testSetSerialization>("parallel_flat_hash_set", "dump1.bin"); + + testMapSerialization>("flat_hash_map", "dump1.bin"); + testMapSerialization>("parallel_flat_hash_map", "dump1.bin"); +#endif + + return 0; +} diff --git a/extern/phmap/html/Makefile b/extern/phmap/html/Makefile new file mode 100644 index 0000000..6f1e09c --- /dev/null +++ b/extern/phmap/html/Makefile @@ -0,0 +1,48 @@ +PANDOC = stack exec pandoc -- +MATHJAX = "http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" +FLAGS = --standalone --toc --toc-depth=2 --mathjax=$(MATHJAX) --highlight-style pygments +PNG_IMAGES = $(patsubst %.pdf,%.png,$(wildcard img/*.pdf)) +IFORMAT = -f gfm +FILTER = includes.exe +FILTER_OPT = --filter=${FILTER} # includes.hs + +############################### html +STYLE = css/style.css +TEMPLATE_HTML = template.html +HTML_OPT = -c ${STYLE} --template ${TEMPLATE_HTML} -t html +PGTITLE = --metadata pagetitle="The Parallel Hashmap" + +############################### pdf +TEMPLATE_TEX = template.latex +TEX_OPT = --template $(TEMPLATE_TEX) --pdf-engine=xelatex + +############################### epub +EPUB_COVER = --epub-cover-image=img/cover-kindle.jpg + + +SRC = parallel_hashmap.md + +OBJ = $(SRC:.md=.html) + +all: html + +includes.exe: includes.hs + stack exec ghc -- -o $@ -no-keep-hi-files -no-keep-o-files includes.hs + +html: parallel_hashmap.md $(FILTER) ${TEMPLATE_HTML} ${STYLE} + $(PANDOC) ${FILTER_OPT} ${IFORMAT} ${HTML_OPT} $(FLAGS) ${PGTITLE} -o ../index.html parallel_hashmap.md + +%.pdf: %.md $(FILTER) ${TEMPLATE_TEX} + $(PANDOC) ${FILTER_OPT} ${IFORMAT} ${TEX_OPT} $(FLAGS) -o $@ $< + +pdf: $(FILTER) ${TEMPLATE_TEX} + rm -f parallel_hashmap.pdf; $(PANDOC) ${FILTER_OPT} ${IFORMAT} ${TEX_OPT} $(FLAGS) -o parallel_hashmap.pdf title.md $(SRC) + +native: + $(PANDOC) -s -t native $(SRC) + +native_filt: $(FILTER) + $(PANDOC) ${FILTER_OPT} -s -t native $(SRC) + +clean: + -rm -f *.html *.pdf cppi.epub diff --git a/extern/phmap/html/bench_results/martinus_mod/InsertManyInt.html b/extern/phmap/html/bench_results/martinus_mod/InsertManyInt.html new file mode 100644 index 0000000..39059cb --- /dev/null +++ b/extern/phmap/html/bench_results/martinus_mod/InsertManyInt.html @@ -0,0 +1,69 @@ + + + +
+ + + diff --git a/extern/phmap/html/bench_results/martinus_mod/Lookup.html b/extern/phmap/html/bench_results/martinus_mod/Lookup.html new file mode 100644 index 0000000..21ea085 --- /dev/null +++ b/extern/phmap/html/bench_results/martinus_mod/Lookup.html @@ -0,0 +1,84 @@ + + + +
+ + + diff --git a/extern/phmap/html/bench_results/martinus_mod/index2.html b/extern/phmap/html/bench_results/martinus_mod/index2.html new file mode 100644 index 0000000..d679632 --- /dev/null +++ b/extern/phmap/html/bench_results/martinus_mod/index2.html @@ -0,0 +1,12 @@ + + + + +

Benchmark Results

+ +insert 100m values in map

+ +Lookup 100m ints, all present | Lookup 100m ints, few present

+ + + diff --git a/extern/phmap/html/css/bootstrap-responsive.min.css b/extern/phmap/html/css/bootstrap-responsive.min.css new file mode 100644 index 0000000..ab59da3 --- /dev/null +++ b/extern/phmap/html/css/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.1.0 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:auto;margin-left:0}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade.in{top:auto}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#555;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/extern/phmap/html/css/bootstrap.min.css b/extern/phmap/html/css/bootstrap.min.css new file mode 100644 index 0000000..4a4440c --- /dev/null +++ b/extern/phmap/html/css/bootstrap.min.css @@ -0,0 +1,10 @@ +/*! + * Bootstrap v2.1.0 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + * Augmented by Eric Kryski @ekryski + */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map-canvas img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:20px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:1;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1{font-size:36px;line-height:40px}h2{font-size:30px;line-height:40px}h3{font-size:24px;line-height:40px}h4{font-size:18px;line-height:20px}h5{font-size:14px;line-height:20px}h6{font-size:12px;line-height:20px}h1 small{font-size:24px}h2 small{font-size:18px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal dt{float:left;width:120px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:130px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:9px;font-size:14px;line-height:20px;color:#555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}input,textarea{width:210px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal;cursor:pointer}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #bbb}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:18px;padding-left:18px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"]{float:left}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning .checkbox:focus,.control-group.warning .radio:focus,.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error .checkbox:focus,.control-group.error .radio:focus,.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success .checkbox:focus,.control-group.success .radio:focus,.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;font-size:14px;vertical-align:top;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn{margin-left:-1px;vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:160px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:160px}.form-horizontal .help-block{margin-top:10px;margin-bottom:0}.form-horizontal .form-actions{padding-left:160px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child,.table-bordered tfoot:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child,.table-bordered tfoot:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-right-topleft:4px}.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9}.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5}table [class*=span],.row-fluid table [class*=span]{display:table-cell;float:none;margin-left:0}table .span1{float:none;width:44px;margin-left:0}table .span2{float:none;width:124px;margin-left:0}table .span3{float:none;width:204px;margin-left:0}table .span4{float:none;width:284px;margin-left:0}table .span5{float:none;width:364px;margin-left:0}table .span6{float:none;width:444px;margin-left:0}table .span7{float:none;width:524px;margin-left:0}table .span8{float:none;width:604px;margin-left:0}table .span9{float:none;width:684px;margin-left:0}table .span10{float:none;width:764px;margin-left:0}table .span11{float:none;width:844px;margin-left:0}table .span12{float:none;width:924px;margin-left:0}table .span13{float:none;width:1004px;margin-left:0}table .span14{float:none;width:1084px;margin-left:0}table .span15{float:none;width:1164px;margin-left:0}table .span16{float:none;width:1244px;margin-left:0}table .span17{float:none;width:1324px;margin-left:0}table .span18{float:none;width:1404px;margin-left:0}table .span19{float:none;width:1484px;margin-left:0}table .span20{float:none;width:1564px;margin-left:0}table .span21{float:none;width:1644px;margin-left:0}table .span22{float:none;width:1724px;margin-left:0}table .span23{float:none;width:1804px;margin-left:0}table .span24{float:none;width:1884px;margin-left:0}.table tbody tr.success td{background-color:#dff0d8}.table tbody tr.error td{background-color:#f2dede}.table tbody tr.info td{background-color:#d9edf7}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:32px;height:32px;margin-top:1px;margin-right:.3em;line-height:32px;vertical-align:text-top;background-image:url("../img/glyphicons.png");background-position:32px 32px;background-repeat:no-repeat}.icon-white,.nav>.active>a>[class^="icon-"],.nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"]{background-image:url("../img/glyphicons-white.png")}.icon-glass{background-position:0 0}.icon-leaf{background-position:-56px 0}.icon-dog{background-position:-112px 0}.icon-user{background-position:-170px 0}.icon-girl{background-position:-225px 0}.icon-car{background-position:-279px 0}.icon-user-add{background-position:-337px 0}.icon-user-remove{background-position:-397px 0}.icon-film{background-position:-455px 0}.icon-magic{background-position:-509px 0}.icon-envelope{background-position:-565px 0}.icon-camera{background-position:-621px 0}.icon-heart{background-position:-679px 0}.icon-beach-umbrella{background-position:-735px 0}.icon-train{background-position:-792px 0}.icon-print{background-position:-844px 0}.icon-bin{background-position:-900px 0}.icon-music{background-position:-952px 0}.icon-note{background-position:-1005px 0}.icon-cogwheel{background-position:-1055px 0}.icon-home{background-position:-1111px 0}.icon-snowflake{background-position:-1170px 0}.icon-fire{background-position:-1230px 0}.icon-cogwheels{background-position:-1282px 0}.icon-parents{background-position:-1340px 0}.icon-binoculars{background-position:-1404px 0}.icon-road{background-position:-1460px 0}.icon-search{background-position:-1520px 0}.icon-cars{background-position:-1576px 0}.icon-notes-2{background-position:-1644px 0}.icon-pencil{background-position:-1696px 0}.icon-bus{background-position:-1753px 0}.icon-wifi-alt{background-position:-1817px 0}.icon-luggage{background-position:-1875px 0}.icon-old-man{background-position:-1927px 0}.icon-woman{background-position:0 -60px}.icon-file{background-position:-54px -60px}.icon-credit{background-position:-105px -60px}.icon-airplane{background-position:-163px -60px}.icon-notes{background-position:-219px -60px}.icon-stats{background-position:-271px -60px}.icon-charts{background-position:-329px -60px}.icon-pie-chart{background-position:-388px -60px}.icon-group{background-position:-446px -60px}.icon-keys{background-position:-513px -60px}.icon-calendar{background-position:-569px -60px}.icon-router{background-position:-624px -60px}.icon-camera-small{background-position:-683px -60px}.icon-dislikes{background-position:-737px -60px}.icon-star{background-position:-795px -60px}.icon-link{background-position:-852px -60px}.icon-eye-open{background-position:-905px -60px}.icon-eye-close{background-position:-968px -60px}.icon-alarm{background-position:-1031px -60px}.icon-clock{background-position:-1091px -60px}.icon-stopwatch{background-position:-1147px -60px}.icon-projector{background-position:-1202px -60px}.icon-history{background-position:-1262px -60px}.icon-truck{background-position:-1319px -60px}.icon-cargo{background-position:-1383px -60px}.icon-compass{background-position:-1440px -60px}.icon-keynote{background-position:-1496px -60px}.icon-attach{background-position:-1548px -60px}.icon-power{background-position:-1606px -60px}.icon-lightbulb{background-position:-1660px -60px}.icon-tag{background-position:-1712px -60px}.icon-tags{background-position:-1768px -60px}.icon-cleaning{background-position:-1830px -60px}.icon-ruler{background-position:-1886px -60px}.icon-gift{background-position:-1945px -60px}.icon-umbrella{background-position:0 -122px}.icon-book{background-position:-58px -122px}.icon-bookmark{background-position:-112px -122px}.icon-signal{background-position:-160px -122px}.icon-cup{background-position:-223px -122px}.icon-stroller{background-position:-277px -122px}.icon-headphones{background-position:-334px -122px}.icon-headset{background-position:-390px -122px}.icon-warning-sign{background-position:-446px -122px}.icon-signal{background-position:-507px -122px}.icon-retweet{background-position:-563px -122px}.icon-refresh{background-position:-625px -122px}.icon-roundabout{background-position:-682px -122px}.icon-random{background-position:-741px -122px}.icon-heat{background-position:-801px -122px}.icon-repeat{background-position:-862px -122px}.icon-display{background-position:-918px -122px}.icon-log-book{background-position:-978px -122px}.icon-adress-book{background-position:-1032px -122px}.icon-magnet{background-position:-1086px -122px}.icon-table{background-position:-1139px -122px}.icon-adjust{background-position:-1195px -122px}.icon-tint{background-position:-1253px -122px}.icon-crop{background-position:-1308px -122px}.icon-vector-path-square{background-position:-1366px -122px}.icon-vector-path-circle{background-position:-1422px -122px}.icon-vector-path-polygon{background-position:-1478px -122px}.icon-vector-path-line{background-position:-1536px -122px}.icon-vector-path-curve{background-position:-1592px -122px}.icon-vector-path-all{background-position:-1648px -122px}.icon-font{background-position:-1704px -122px}.icon-italic{background-position:-1763px -122px}.icon-bold{background-position:-1809px -122px}.icon-text-underline{background-position:-1860px -122px}.icon-text-strike{background-position:-1912px -122px}.icon-text-height{background-position:-1964px -122px}.icon-text-width{background-position:0 -184px}.icon-text-resize{background-position:-54px -184px}.icon-left-indent{background-position:-112px -184px}.icon-right-indent{background-position:-168px -184px}.icon-align-left{background-position:-224px -184px}.icon-align-center{background-position:-280px -184px}.icon-align-right{background-position:-336px -184px}.icon-justify{background-position:-392px -184px}.icon-list{background-position:-448px -184px}.icon-text-smaller{background-position:-504px -184px}.icon-text-bigger{background-position:-558px -184px}.icon-embed{background-position:-614px -184px}.icon-embed-close{background-position:-676px -184px}.icon-adjust{background-position:-738px -184px}.icon-message-full{background-position:-793px -184px}.icon-message-empty{background-position:-849px -184px}.icon-message-in{background-position:-905px -184px}.icon-message-out{background-position:-961px -184px}.icon-message-plus{background-position:-1017px -184px}.icon-message-minus{background-position:-1078px -184px}.icon-message-ban{background-position:-1139px -184px}.icon-message-flag{background-position:-1200px -184px}.icon-message-lock{background-position:-1259px -184px}.icon-message-new{background-position:-1319px -184px}.icon-inbox{background-position:-1379px -184px}.icon-inbox-plus{background-position:-1435px -184px}.icon-inbox-minus{background-position:-1494px -184px}.icon-inbox-lock{background-position:-1553px -184px}.icon-inbox-in{background-position:-1611px -184px}.icon-inbox-out{background-position:-1667px -184px}.icon-computer-locked{background-position:-1723px -184px}.icon-computer-service{background-position:-1783px -184px}.icon-computer-process{background-position:-1843px -184px}.icon-phone{background-position:-1903px -184px}.icon-database-lock{background-position:-1950px -184px}.icon-database-plus{background-position:0 -246px}.icon-database-minus{background-position:-59px -246px}.icon-database-ban{background-position:-118px -246px}.icon-folder-open{background-position:-176px -246px}.icon-folder-plus{background-position:-238px -246px}.icon-folder-minus{background-position:-299px -246px}.icon-folder-lock{background-position:-360px -246px}.icon-folder-flag{background-position:-420px -246px}.icon-folder-new{background-position:-479px -246px}.icon-check{background-position:-539px -246px}.icon-edit{background-position:-593px -246px}.icon-new-window{background-position:-649px -246px}.icon-more-windows{background-position:-707px -246px}.icon-show-big-thumbnails{background-position:-762px -246px}.icon-show-thumbnails{background-position:-816px -246px}.icon-show-thumbnails-with-lines{background-position:-870px -246px}.icon-show-lines{background-position:-926px -246px}.icon-playlist{background-position:-982px -246px}.icon-picture{background-position:-1043px -246px}.icon-imac{background-position:-1099px -246px}.icon-macbook{background-position:-1157px -246px}.icon-ipad{background-position:-1217px -246px}.icon-iphone{background-position:-1269px -246px}.icon-iphone-transfer{background-position:-1315px -246px}.icon-iphone-exchange{background-position:-1376px -246px}.icon-ipod{background-position:-1437px -246px}.icon-ipod-shuffle{background-position:-1483px -246px}.icon-ear-plugs{background-position:-1530px -246px}.icon-albums{background-position:-1582px -246px}.icon-step-backward{background-position:-1642px -246px}.icon-fast-backward{background-position:-1688px -246px}.icon-rewind{background-position:-1745px -246px}.icon-play{background-position:-1800px -246px}.icon-pause{background-position:-1848px -246px}.icon-stop{background-position:-1890px -246px}.icon-forward{background-position:-1936px -246px}.icon-fast-forward{background-position:0 -308px}.icon-step-forward{background-position:-57px -308px}.icon-eject{background-position:-103px -308px}.icon-facetime-video{background-position:-153px -308px}.icon-download-alt{background-position:-209px -308px}.icon-mute{background-position:-265px -308px}.icon-volume-down{background-position:-319px -308px}.icon-volume-up{background-position:-367px -308px}.icon-screenshot{background-position:-423px -308px}.icon-move{background-position:-482px -308px}.icon-more{background-position:-538px -308px}.icon-brightness-reduce{background-position:-592px -308px}.icon-brightness-increase{background-position:-644px -308px}.icon-circle-plus{background-position:-700px -308px}.icon-circle-minus{background-position:-758px -308px}.icon-circle-remove{background-position:-816px -308px}.icon-circle-ok{background-position:-874px -308px}.icon-circle-question-mark{background-position:-932px -308px}.icon-circle-info{background-position:-990px -308px}.icon-circle-exclamation-mark{background-position:-1048px -308px}.icon-remove{background-position:-1106px -308px}.icon-ok{background-position:-1164px -308px}.icon-ban{background-position:-1222px -308px}.icon-download{background-position:-1280px -308px}.icon-upload{background-position:-1338px -308px}.icon-shopping-cart{background-position:-1396px -308px}.icon-lock{background-position:-1454px -308px}.icon-unlock{background-position:-1507px -308px}.icon-electricity{background-position:-1560px -308px}.icon-ok-2{background-position:-1603px -308px}.icon-remove-2{background-position:-1660px -308px}.icon-cart-out{background-position:-1710px -308px}.icon-cart-in{background-position:-1768px -308px}.icon-left-arrow{background-position:-1826px -308px}.icon-right-arrow{background-position:-1878px -308px}.icon-down-arrow{background-position:-1930px -308px}.icon-up-arrow{background-position:0 -370px}.icon-resize-small{background-position:-50px -370px}.icon-resize-full{background-position:-106px -370px}.icon-circle-arrow-left{background-position:-162px -370px}.icon-circle-arrow-right{background-position:-220px -370px}.icon-circle-arrow-up{background-position:-278px -370px}.icon-circle-arrow-down{background-position:-336px -370px}.icon-play-button{background-position:-394px -370px}.icon-unshare{background-position:-452px -370px}.icon-share{background-position:-508px -370px}.icon-thin-arrow-right{background-position:-564px -370px}.icon-thin-arrow-left{background-position:-611px -370px}.icon-bluetooth{background-position:-658px -370px}.icon-euro{background-position:-704px -370px}.icon-usd{background-position:-758px -370px}.icon-bp{background-position:-807px -370px}.icon-retweet-2{background-position:-856px -370px}.icon-moon{background-position:-921px -370px}.icon-sun{background-position:-975px -370px}.icon-cloud{background-position:-1031px -370px}.icon-direction{background-position:-1090px -370px}.icon-brush{background-position:-1148px -370px}.icon-pen{background-position:-1205px -370px}.icon-zoom-in{background-position:-1261px -370px}.icon-zoom-out{background-position:-1318px -370px}.icon-pin{background-position:-1375px -370px}.icon-riflescope{background-position:-1417px -370px}.icon-rotation-lock{background-position:-1474px -370px}.icon-flash{background-position:-1533px -370px}.icon-google-maps{background-position:-1579px -370px}.icon-anchor{background-position:-1626px -370px}.icon-conversation{background-position:-1682px -370px}.icon-chat{background-position:-1739px -370px}.icon-male{background-position:-1795px -370px}.icon-female{background-position:-1849px -370px}.icon-asterisk{background-position:-1897px -370px}.icon-divide{background-position:-1949px -370px}.icon-snorkel-diving{background-position:0 -432px}.icon-scuba-diving{background-position:-59px -432px}.icon-oxygen-bottle{background-position:-118px -432px}.icon-fins{background-position:-172px -432px}.icon-fishes{background-position:-235px -432px}.icon-boat{background-position:-295px -432px}.icon-delete-point{background-position:-351px -432px}.icon-sheriffs-star{background-position:-409px -432px}.icon-qrcode{background-position:-465px -432px}.icon-barcode{background-position:-521px -432px}.icon-pool{background-position:-577px -432px}.icon-buoy{background-position:-633px -432px}.icon-spade{background-position:-689px -432px}.icon-bank{background-position:-745px -432px}.icon-vcard{background-position:-801px -432px}.icon-electrical-plug{background-position:-855px -432px}.icon-flag{background-position:-905px -432px}.icon-credit-card{background-position:-958px -432px}.icon-keyboard-wireless{background-position:-1016px -432px}.icon-keyboard-wired{background-position:-1075px -432px}.icon-shield{background-position:-1134px -432px}.icon-ring{background-position:-1188px -432px}.icon-cake{background-position:-1241px -432px}.icon-drink{background-position:-1295px -432px}.icon-beer{background-position:-1350px -432px}.icon-fast-food{background-position:-1405px -432px}.icon-cutlery{background-position:-1465px -432px}.icon-pizza{background-position:-1510px -432px}.icon-birthday-cake{background-position:-1568px -432px}.icon-tablet{background-position:-1626px -432px}.icon-settings{background-position:-1683px -432px}.icon-bullets{background-position:-1739px -432px}.icon-cardio{background-position:-1798px -432px}.icon-t-shirt{background-position:-1855px -432px}.icon-pants{background-position:-1915px -432px}.icon-sweater{background-position:-1966px -432px}.icon-fabric{background-position:0 -494px}.icon-leather{background-position:-59px -494px}.icon-scissors{background-position:-114px -494px}.icon-podium{background-position:-170px -494px}.icon-skull{background-position:-230px -494px}.icon-celebration{background-position:-284px -494px}.icon-tea-kettle{background-position:-340px -494px}.icon-french-press{background-position:-398px -494px}.icon-coffe-cup{background-position:-453px -494px}.icon-pot{background-position:-510px -494px}.icon-grater{background-position:-569px -494px}.icon-kettle{background-position:-619px -494px}.icon-hospital{background-position:-674px -494px}.icon-hospital-h{background-position:-730px -494px}.icon-microphone{background-position:-786px -494px}.icon-webcam{background-position:-835px -494px}.icon-temple-christianity-church{background-position:-886px -494px}.icon-temple-islam{background-position:-942px -494px}.icon-temple-hindu{background-position:-999px -494px}.icon-temple-buddhist{background-position:-1055px -494px}.icon-electrical-socket-eu{background-position:-1115px -494px}.icon-electrical-socket-us{background-position:-1170px -494px}.icon-bomb{background-position:-1225px -494px}.icon-comments{background-position:-1284px -494px}.icon-flower{background-position:-1340px -494px}.icon-baseball{background-position:-1391px -494px}.icon-rugby{background-position:-1448px -494px}.icon-ax{background-position:-1503px -494px}.icon-table-tennis{background-position:-1562px -494px}.icon-bowling{background-position:-1618px -494px}.icon-tree-conifer{background-position:-1674px -494px}.icon-tree-deciduous{background-position:-1727px -494px}.icon-more-items{background-position:-1779px -494px}.icon-sort{background-position:-1832px -494px}.icon-filter{background-position:-1889px -494px}.icon-gamepad{background-position:-1941px -494px}.icon-playing-dices{background-position:0 -556px}.icon-calculator{background-position:-59px -556px}.icon-tie{background-position:-112px -556px}.icon-wallet{background-position:-155px -556px}.icon-share{background-position:-212px -556px}.icon-sampler{background-position:-266px -556px}.icon-piano{background-position:-325px -556px}.icon-web-browser{background-position:-380px -556px}.icon-blog{background-position:-436px -556px}.icon-dashboard{background-position:-489px -556px}.icon-certificate{background-position:-545px -556px}.icon-bell{background-position:-594px -556px}.icon-candle{background-position:-650px -556px}.icon-pin-classic{background-position:-702px -556px}.icon-iphone-shake{background-position:-758px -556px}.icon-pin-flag{background-position:-814px -556px}.icon-turtle{background-position:-876px -556px}.icon-rabbit{background-position:-936px -556px}.icon-globe{background-position:-994px -556px}.icon-briefcase{background-position:-1050px -556px}.icon-hdd{background-position:-1106px -556px}.icon-thumbs-up{background-position:-1162px -556px}.icon-thumbs-down{background-position:-1218px -556px}.icon-hand-right{background-position:-1274px -556px}.icon-hand-left{background-position:-1332px -556px}.icon-hand-up{background-position:-1390px -556px}.icon-hand-down{background-position:-1441px -556px}.icon-fullscreen{background-position:-1492px -556px}.icon-shopping-bag{background-position:-1548px -556px}.icon-book-open{background-position:-1603px -556px}.icon-nameplate{background-position:-1660px -556px}.icon-nameplate-alt{background-position:-1716px -556px}.icon-vases{background-position:-1772px -556px}.icon-announcement{background-position:-1828px -556px}.icon-dumbbell{background-position:-1885px -556px}.icon-suitcase{background-position:-1943px -556px}.icon-file-import{background-position:0 -618px}.icon-file-export{background-position:-54px -618px}.icon-pinterest{background-position:-109px -618px}.icon-dropbox{background-position:-165px -618px}.icon-google-alt{background-position:-221px -618px}.icon-jolicloud{background-position:-277px -618px}.icon-yahoo{background-position:-333px -618px}.icon-blogger{background-position:-389px -618px}.icon-picasa{background-position:-445px -618px}.icon-amazon{background-position:-501px -618px}.icon-tumblr{background-position:-557px -618px}.icon-wordpress{background-position:-613px -618px}.icon-instapaper{background-position:-669px -618px}.icon-evernote{background-position:-725px -618px}.icon-xing{background-position:-781px -618px}.icon-zootool{background-position:-837px -618px}.icon-dribbble{background-position:-893px -618px}.icon-deviantart{background-position:-949px -618px}.icon-read-it-later{background-position:-1005px -618px}.icon-linked-in{background-position:-1061px -618px}.icon-forrst{background-position:-1117px -618px}.icon-pinboard{background-position:-1173px -618px}.icon-behance{background-position:-1229px -618px}.icon-github{background-position:-1285px -618px}.icon-youtube{background-position:-1341px -618px}.icon-skitch{background-position:-1397px -618px}.icon-4square{background-position:-1453px -618px}.icon-quora{background-position:-1509px -618px}.icon-google-plus{background-position:-1565px -618px}.icon-spotify{background-position:-1621px -618px}.icon-stumbleupon{background-position:-1677px -618px}.icon-readability{background-position:-1733px -618px}.icon-facebook{background-position:-1789px -618px}.icon-twitter-t{background-position:-1845px -618px}.icon-twitter{background-position:-1901px -618px}.icon-buzz{background-position:-1957px -618px}.icon-vimeo{background-position:0 -680px}.icon-flickr{background-position:-56px -680px}.icon-last-fm{background-position:-112px -680px}.icon-rss{background-position:-168px -680px}.icon-skype{background-position:-224px -680px}.icon-e-mail{background-position:-280px -680px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{color:#fff;text-decoration:none;background-color:#08c;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#08c;background-color:#0081c2;background-image:linear-gradient(to bottom,#08c,#0077b3);background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:"\2191"}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover .dropdown-menu{display:block}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;overflow:visible \9;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 14px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;*line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbb;*border:0;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:9px 14px;font-size:16px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.btn-large [class^="icon-"]{margin-top:2px}.btn-small{padding:3px 9px;font-size:12px;line-height:18px}.btn-small [class^="icon-"]{margin-top:0}.btn-mini{padding:2px 6px;font-size:11px;line-height:16px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#c5c5c5;border-color:rgba(0,0,0,0.15) rgba(0,0,0,0.15) rgba(0,0,0,0.25)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-image:-moz-linear-gradient(top,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-image:-moz-linear-gradient(top,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-image:-moz-linear-gradient(top,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-group{position:relative;*margin-left:.3em;font-size:0;white-space:nowrap}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1}.btn-toolbar .btn+.btn,.btn-toolbar .btn-group+.btn,.btn-toolbar .btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu{font-size:14px}.btn-group>.btn-mini{font-size:11px}.btn-group>.btn-small{font-size:12px}.btn-group>.btn-large{font-size:16px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-top:0;border-bottom:5px solid #000}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical .btn{display:block;float:none;width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical .btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical .btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical .btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical .btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical .btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;color:#c09853;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible;color:#555}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar .container{width:auto}.nav-collapse.collapse{height:auto}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#555;text-shadow:0 1px 0 #fff}.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px}.navbar-link{color:#555}.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:6px}.navbar .btn-group .btn{margin:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;width:100%;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner,.navbar-static-top .navbar-inner{border:0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1);box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#555;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse{color:#999}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-image:-moz-linear-gradient(top,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb .divider{padding:0 5px;color:#ccc}.breadcrumb .active{color:#999}.pagination{height:40px;margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination li{display:inline}.pagination a,.pagination span{float:left;padding:0 14px;line-height:38px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination a:hover,.pagination .active a,.pagination .active span{background-color:#f5f5f5}.pagination .active a,.pagination .active span{color:#999;cursor:default}.pagination .disabled span,.pagination .disabled a,.pagination .disabled a:hover{color:#999;cursor:default;background-color:transparent}.pagination li:first-child a,.pagination li:first-child span{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.pagination li:last-child a,.pagination li:last-child span{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next a{float:right}.pager .previous a{float:left}.pager .disabled a,.pager .disabled a:hover{color:#999;cursor:default;background-color:#fff}.modal-open .dropdown-menu{z-index:2050}.modal-open .dropdown.open{*z-index:2050}.modal-open .popover{z-index:2060}.modal-open .tooltip{z-index:2080}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:50%;left:50%;z-index:1050;width:560px;margin:-250px 0 0 -280px;overflow:auto;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:50%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px}.tooltip.right{margin-left:3px}.tooltip.bottom{margin-top:3px}.tooltip.left{margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-bottom:10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-right:10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0}.popover .arrow,.popover .arrow:after{position:absolute;display:inline-block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow:after{z-index:-1;content:""}.popover.top .arrow{bottom:-10px;left:50%;margin-left:-10px;border-top-color:#fff;border-width:10px 10px 0}.popover.top .arrow:after{bottom:-1px;left:-11px;border-top-color:rgba(0,0,0,0.25);border-width:11px 11px 0}.popover.right .arrow{top:50%;left:-10px;margin-top:-10px;border-right-color:#fff;border-width:10px 10px 10px 0}.popover.right .arrow:after{bottom:-11px;left:-1px;border-right-color:rgba(0,0,0,0.25);border-width:11px 11px 11px 0}.popover.bottom .arrow{top:-10px;left:50%;margin-left:-10px;border-bottom-color:#fff;border-width:0 10px 10px}.popover.bottom .arrow:after{top:-1px;left:-11px;border-bottom-color:rgba(0,0,0,0.25);border-width:0 11px 11px}.popover.left .arrow{top:50%;right:-10px;margin-top:-10px;border-left-color:#fff;border-width:10px 0 10px 10px}.popover.left .arrow:after{right:-1px;bottom:-11px;border-left-color:rgba(0,0,0,0.25);border-width:11px 0 11px 11px}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.label,.badge{font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{padding:1px 4px 2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding:1px 9px 2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel .item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel .item>img{display:block;line-height:1}.carousel .active,.carousel .next,.carousel .prev{display:block}.carousel .active{left:0}.carousel .next,.carousel .prev{position:absolute;top:0;width:100%}.carousel .next{left:100%}.carousel .prev{left:-100%}.carousel .next.left,.carousel .prev.right{left:0}.carousel .active.left{left:-100%}.carousel .active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit p{font-size:18px;font-weight:200;line-height:30px;color:inherit}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} \ No newline at end of file diff --git a/extern/phmap/html/css/colors.css b/extern/phmap/html/css/colors.css new file mode 100644 index 0000000..8774c02 --- /dev/null +++ b/extern/phmap/html/css/colors.css @@ -0,0 +1,302 @@ +/*** + + colors.css v2.0.0 + http://clrs.cc + @mrmrs + MIT License + +***/ +/* + + SKINS + - Backgrounds + - Colors + - Border colors + - SVG fills + - SVG Strokes + +*/ +/* Backgrounds */ +.bg-navy { + background-color: #001F3F; } + +.bg-blue { + background-color: #0074D9; } + +.bg-aqua { + background-color: #7FDBFF; } + +.bg-teal { + background-color: #39CCCC; } + +.bg-olive { + background-color: #3D9970; } + +.bg-green { + background-color: #2ECC40; } + +.bg-lime { + background-color: #01FF70; } + +.bg-yellow { + background-color: #FFDC00; } + +.bg-orange { + background-color: #FF851B; } + +.bg-red { + background-color: #FF4136; } + +.bg-fuchsia { + background-color: #F012BE; } + +.bg-purple { + background-color: #B10DC9; } + +.bg-maroon { + background-color: #85144B; } + +.bg-white { + background-color: #fff; } + +.bg-gray { + background-color: #aaa; } + +.bg-silver { + background-color: #ddd; } + +.bg-black { + background-color: #111; } + +/* Colors */ +.navy { + color: #001F3F; } + +.blue { + color: #0074D9; } + +.aqua { + color: #7FDBFF; } + +.teal { + color: #39CCCC; } + +.olive { + color: #3D9970; } + +.green { + color: #2ECC40; } + +.lime { + color: #01FF70; } + +.yellow { + color: #FFDC00; } + +.orange { + color: #FF851B; } + +.red { + color: #FF4136; } + +.fuchsia { + color: #F012BE; } + +.purple { + color: #B10DC9; } + +.maroon { + color: #85144B; } + +.white { + color: #fff; } + +.silver { + color: #ddd; } + +.gray { + color: #aaa; } + +.black { + color: #111; } + +/* Border colors + + Use with another border utility that sets border-width and style + i.e .border { border-width: 1px; border-style: solid; } +*/ +.border--navy { + border-color: #001F3F; } + +.border--blue { + border-color: #0074D9; } + +.border--aqua { + border-color: #7FDBFF; } + +.border--teal { + border-color: #39CCCC; } + +.border--olive { + border-color: #3D9970; } + +.border--green { + border-color: #2ECC40; } + +.border--lime { + border-color: #01FF70; } + +.border--yellow { + border-color: #FFDC00; } + +.border--orange { + border-color: #FF851B; } + +.border--red { + border-color: #FF4136; } + +.border--fuchsia { + border-color: #F012BE; } + +.border--purple { + border-color: #B10DC9; } + +.border--maroon { + border-color: #85144B; } + +.border--white { + border-color: #fff; } + +.border--gray { + border-color: #aaa; } + +.border--silver { + border-color: #ddd; } + +.border--black { + border-color: #111; } + +/* Fills for SVG */ +.fill-navy { + fill: #001F3F; } + +.fill-blue { + fill: #0074D9; } + +.fill-aqua { + fill: #7FDBFF; } + +.fill-teal { + fill: #39CCCC; } + +.fill-olive { + fill: #3D9970; } + +.fill-green { + fill: #2ECC40; } + +.fill-lime { + fill: #01FF70; } + +.fill-yellow { + fill: #FFDC00; } + +.fill-orange { + fill: #FF851B; } + +.fill-red { + fill: #FF4136; } + +.fill-fuchsia { + fill: #F012BE; } + +.fill-purple { + fill: #B10DC9; } + +.fill-maroon { + fill: #85144B; } + +.fill-white { + fill: #fff; } + +.fill-gray { + fill: #aaa; } + +.fill-silver { + fill: #ddd; } + +.fill-black { + fill: #111; } + +/* Strokes for SVG */ +.stroke-navy { + stroke: #001F3F; } + +.stroke-blue { + stroke: #0074D9; } + +.stroke-aqua { + stroke: #7FDBFF; } + +.stroke-teal { + stroke: #39CCCC; } + +.stroke-olive { + stroke: #3D9970; } + +.stroke-green { + stroke: #2ECC40; } + +.stroke-lime { + stroke: #01FF70; } + +.stroke-yellow { + stroke: #FFDC00; } + +.stroke-orange { + stroke: #FF851B; } + +.stroke-red { + stroke: #FF4136; } + +.stroke-fuchsia { + stroke: #F012BE; } + +.stroke-purple { + stroke: #B10DC9; } + +.stroke-maroon { + stroke: #85144B; } + +.stroke-white { + stroke: #fff; } + +.stroke-gray { + stroke: #aaa; } + +.stroke-silver { + stroke: #ddd; } + +.stroke-black { + stroke: #111; } + +/* PRETTIER LINKS */ +a { + text-decoration: none; + -webkit-transition: color .3s ease-in-out; + transition: color .3s ease-in-out; } + +a:link { + -webkit-transition: color .3s ease-in-out; + transition: color .3s ease-in-out; } + +a:visited { } + +a:hover { + color: #001F3F; + -webkit-transition: color .3s ease-in-out; + transition: color .3s ease-in-out; } + +a:active { + -webkit-transition: color .3s ease-in-out; + transition: color .3s ease-in-out; } diff --git a/extern/phmap/html/css/style.css b/extern/phmap/html/css/style.css new file mode 100644 index 0000000..82ff12c --- /dev/null +++ b/extern/phmap/html/css/style.css @@ -0,0 +1,271 @@ +/* main stylesheet */ + +@import url(http://fonts.googleapis.com/css?family=Signika); + +html { + overflow-y: scroll; +} + +body { + font-size: 15px; + font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, sans-serif; + color: #332; +} + +h1, h2, h3, h4, h5 { + color: #332; + font-family: "Signika"; + font-weight: 400; + font-size: 1.4em; + line-height: 1.1; + margin-top: 30px; +} + +pre code { + font: 14px/19px Inconsolata, Monaco,"Lucida Console",Terminal,"Courier New",Courier; +} + +.figure { + text-align: center; +} + +.small .figure img { + height: 200px; +} + +.pagetitle .figure { + text-align: left !important; +} + +.pagetitle .figure img { + height: 36px; +} + +table{ + background:#fff; + border:1px solid #ccc; + border-width:2px; + border-collapse:collapse; + margin:5px 0 10px; + + margin-top: 20px; + margin-bottom: 20px; +} + +th, td{ + border:1px solid #ccc; + padding:3px 10px; + text-align:left; + vertical-align:top; +} + +tr.even td{ + background:#f7f7f7; +} + +th{ + background:#edeff0; +} + +td code { + border: 0px; +} + +img { + max-width: 100%; + height: auto; +} + +hr { + border: 0px; + height: 0; + border-bottom: 1px solid #ccc; + margin-bottom: 100px; +} + +/* Logo */ + +.logo { + text-align: center; +} + +.tagline { + font-family: Georgia; + font-size: 18px; + font-style: italic; + line-height: 1.45; + color: #383838; +} + +.author { +} + +.halfbreak { + padding-bottom: 100px; +} + +.break { + padding-bottom: 200px; +} + +/* TOC Links */ + +a { + color: #111111; + text-decoration: none; +} + +.body li a { + text-decoration: underline; +} + +/* Math */ + +.MathJax_Display { + padding-top: 20px; + padding-bottom: 20px; +} + +/* Body Links */ + +p a { + text-decoration: underline; +} + +li code, p code { + font-size: 12px; + border: 1px solid #ccc; + margin-left: 3px; + margin-right: 3px; + padding-left: 2px; + padding-right: 2px; +} + +/* */ + +.center { + text-align: center; +} + +.bigger img { + width: 120%; + height: 120%; +} + +pre { + font-size: 0.9em; + + margin-bottom: 18px; + margin-top: 18px; + + border-left: 1px solid #ccc; + +} + +h1 { + margin-top: 0px; +} + +.annotation { + font-size: 10pt; +} + +.annotation pre { + display: block; + margin: 0; + padding: 7px 10px; + overflow-x: auto; +} + +.annotation.span2 { + /* Override bootstrap */ + margin-left: 0px !important; + margin-top: 18px !important; +} + +.annotation pre code { + border: 0; + padding: 0; + background: transparent; +} + +blockquote { + border-left: 1px solid #ccc; + font-family: Georgia, serif; + font-size: 14px; + font-style: italic; + margin: 0.25em 0; + padding-left: 10px; + line-height: 1.45; + color: #383838; + left: 20px; +} + + +blockquote cite { + color: #999999; + font-size: 14px; + display: block; + margin-top: 5px; +} + +ul.sections { + list-style: none; + padding:0 0 5px 0; + margin:0; +} + +code.sourceCode { + padding: 0; + background: inherit; +} + +pre.sourceCode { + padding: 10px; +} + +ul.sections > li > div { + -moz-box-sizing: border-box; /* firefox */ + -ms-box-sizing: border-box; /* ie */ + -webkit-box-sizing: border-box; /* webkit */ + -khtml-box-sizing: border-box; /* konqueror */ + box-sizing: border-box; /* css3 */ +} + + +/* Make the naviation centered and larger on small screens */ +/*---------------------- (> 481px) ---------------------*/ + +@media only screen and (max-width: 481px) { + +} + +@media only screen and (min-width: 1025px) { + body { + padding: 10px; + } + + .side { + position: fixed; + width: 120px !important; + margin-left: 0px; + z-index: 1000; + } + + .side ul ul { + display: none; + } + + .side ul ul.active { + display: block; + } + + .side .active { + font-weight: bold; + } + + .body { + margin-left: 120px !important; + } + +} diff --git a/extern/phmap/html/diagrams/closed_hashing b/extern/phmap/html/diagrams/closed_hashing new file mode 100644 index 0000000..5e901b5 --- /dev/null +++ b/extern/phmap/html/diagrams/closed_hashing @@ -0,0 +1,28 @@ + + + + +----------------+ + |"(keyi, valuei)"| "(key, value) pairs are stored directly" + +----+-----------+ "into the array (no pointers)" + | +--------+---------------------+ + | | | | + | | | | + | | | | + | | | | + | | | | + | +--------+---------------------+ + +---------------> | keyi | valuei | + hasher(keyi) +--------+---------------------+ + | | | + | | | + | | | + +--------+---------------------+ + | | | + +--------+---------------------+ + | | | + | | | + | | | + +--------+---------------------+ + + absl::flat_hash_map + diff --git a/extern/phmap/html/diagrams/closed_hashing.svg b/extern/phmap/html/diagrams/closed_hashing.svg new file mode 100644 index 0000000..7c2bd24 --- /dev/null +++ b/extern/phmap/html/diagrams/closed_hashing.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +(keyi, valuei) + + + + +hasher(keyi) + + + + +absl::flat_hash_map + + + + +(key, value) pairs are stored directly + + + + +into the array (no pointers) + + + + +keyi + + + + +valuei + + + diff --git a/extern/phmap/html/diagrams/index_computation b/extern/phmap/html/diagrams/index_computation new file mode 100644 index 0000000..e79cfc1 --- /dev/null +++ b/extern/phmap/html/diagrams/index_computation @@ -0,0 +1,29 @@ + + + + +----------------+ + |"(keyi, valuei)"| + +------+---------+ + | + | hasher(keyi) "Parallel Hash Map" + v "(with 8 submaps)" + +--------+-------------+ +----------------+ + | h=0x7d84ea13707f4657 | | submap0 | + +---------+------------+ +----------------+ + | | submap1 | + | "(h ^ (h >> 3)) & 0x7" +----------------+ + v | submap2 | + +----+----+ +----------------+ + |"idx = 5"| | submap3 | + +----+----+ +----------------+ + | | submap4 | + | +----------------+ + +------------------------------->| submap5 | + +----------------+ + | submap6 | + +----------------+ + | submap7 | + +----------------+ + + "parallel_hash_map with 8 submaps, each submap is an absl::flat_hash_map" + diff --git a/extern/phmap/html/diagrams/index_computation.svg b/extern/phmap/html/diagrams/index_computation.svg new file mode 100644 index 0000000..b986a93 --- /dev/null +++ b/extern/phmap/html/diagrams/index_computation.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +parallel_hash_map with 8 submaps, each submap is an absl::flat_hash_map + + + + +h=0x7d84ea13707f4657 + + + + +(keyi, valuei) + + + + +idx = 5 + + + + +(h ^ (h >> 3)) & 0x7 + + + + +hasher(keyi) + + + + +Parallel Hash Map + + + + +(with 8 submaps) + + + + +submap0 + + + + +submap1 + + + + +submap2 + + + + +submap3 + + + + +submap4 + + + + +submap5 + + + + +submap6 + + + + +submap7 + + + diff --git a/extern/phmap/html/img/closed_hashing.png b/extern/phmap/html/img/closed_hashing.png new file mode 100644 index 0000000..0662041 Binary files /dev/null and b/extern/phmap/html/img/closed_hashing.png differ diff --git a/extern/phmap/html/img/flat_mem_usage.gif b/extern/phmap/html/img/flat_mem_usage.gif new file mode 100644 index 0000000..f14b098 Binary files /dev/null and b/extern/phmap/html/img/flat_mem_usage.gif differ diff --git a/extern/phmap/html/img/flat_mem_usage.png b/extern/phmap/html/img/flat_mem_usage.png new file mode 100644 index 0000000..800a53c Binary files /dev/null and b/extern/phmap/html/img/flat_mem_usage.png differ diff --git a/extern/phmap/html/img/flat_par_mutex_4.PNG b/extern/phmap/html/img/flat_par_mutex_4.PNG new file mode 100644 index 0000000..4f7cb5a Binary files /dev/null and b/extern/phmap/html/img/flat_par_mutex_4.PNG differ diff --git a/extern/phmap/html/img/flat_par_mutex_5.PNG b/extern/phmap/html/img/flat_par_mutex_5.PNG new file mode 100644 index 0000000..e437872 Binary files /dev/null and b/extern/phmap/html/img/flat_par_mutex_5.PNG differ diff --git a/extern/phmap/html/img/flat_par_mutex_5_speed.PNG b/extern/phmap/html/img/flat_par_mutex_5_speed.PNG new file mode 100644 index 0000000..4768a20 Binary files /dev/null and b/extern/phmap/html/img/flat_par_mutex_5_speed.PNG differ diff --git a/extern/phmap/html/img/flat_par_mutex_6_speed.PNG b/extern/phmap/html/img/flat_par_mutex_6_speed.PNG new file mode 100644 index 0000000..af1b2ae Binary files /dev/null and b/extern/phmap/html/img/flat_par_mutex_6_speed.PNG differ diff --git a/extern/phmap/html/img/flat_par_speed.PNG b/extern/phmap/html/img/flat_par_speed.PNG new file mode 100644 index 0000000..df36c83 Binary files /dev/null and b/extern/phmap/html/img/flat_par_speed.PNG differ diff --git a/extern/phmap/html/img/flat_peak.gif b/extern/phmap/html/img/flat_peak.gif new file mode 100644 index 0000000..eefbad6 Binary files /dev/null and b/extern/phmap/html/img/flat_peak.gif differ diff --git a/extern/phmap/html/img/flat_peak.png b/extern/phmap/html/img/flat_peak.png new file mode 100644 index 0000000..167edb8 Binary files /dev/null and b/extern/phmap/html/img/flat_peak.png differ diff --git a/extern/phmap/html/img/hashtable_benchmarks.PNG b/extern/phmap/html/img/hashtable_benchmarks.PNG new file mode 100644 index 0000000..d18a31b Binary files /dev/null and b/extern/phmap/html/img/hashtable_benchmarks.PNG differ diff --git a/extern/phmap/html/img/idx_computation_cost.PNG b/extern/phmap/html/img/idx_computation_cost.PNG new file mode 100644 index 0000000..7e78e8f Binary files /dev/null and b/extern/phmap/html/img/idx_computation_cost.PNG differ diff --git a/extern/phmap/html/img/index_computation.png b/extern/phmap/html/img/index_computation.png new file mode 100644 index 0000000..550d743 Binary files /dev/null and b/extern/phmap/html/img/index_computation.png differ diff --git a/extern/phmap/html/img/lock_various_sizes.PNG b/extern/phmap/html/img/lock_various_sizes.PNG new file mode 100644 index 0000000..e1a486e Binary files /dev/null and b/extern/phmap/html/img/lock_various_sizes.PNG differ diff --git a/extern/phmap/html/img/mt_stl_flat_par_both.PNG b/extern/phmap/html/img/mt_stl_flat_par_both.PNG new file mode 100644 index 0000000..b78efe6 Binary files /dev/null and b/extern/phmap/html/img/mt_stl_flat_par_both.PNG differ diff --git a/extern/phmap/html/img/mt_stl_flat_par_both_run2.PNG b/extern/phmap/html/img/mt_stl_flat_par_both_run2.PNG new file mode 100644 index 0000000..1e024b1 Binary files /dev/null and b/extern/phmap/html/img/mt_stl_flat_par_both_run2.PNG differ diff --git a/extern/phmap/html/img/mt_stl_flat_par_mem.PNG b/extern/phmap/html/img/mt_stl_flat_par_mem.PNG new file mode 100644 index 0000000..8e34553 Binary files /dev/null and b/extern/phmap/html/img/mt_stl_flat_par_mem.PNG differ diff --git a/extern/phmap/html/img/mt_stl_flat_par_mem_run2.PNG b/extern/phmap/html/img/mt_stl_flat_par_mem_run2.PNG new file mode 100644 index 0000000..27281e7 Binary files /dev/null and b/extern/phmap/html/img/mt_stl_flat_par_mem_run2.PNG differ diff --git a/extern/phmap/html/img/mt_stl_flat_par_mem_run2_zoomed.PNG b/extern/phmap/html/img/mt_stl_flat_par_mem_run2_zoomed.PNG new file mode 100644 index 0000000..bd56cbe Binary files /dev/null and b/extern/phmap/html/img/mt_stl_flat_par_mem_run2_zoomed.PNG differ diff --git a/extern/phmap/html/img/mt_stl_flat_par_mem_zoomed.PNG b/extern/phmap/html/img/mt_stl_flat_par_mem_zoomed.PNG new file mode 100644 index 0000000..bd7d34c Binary files /dev/null and b/extern/phmap/html/img/mt_stl_flat_par_mem_zoomed.PNG differ diff --git a/extern/phmap/html/img/mt_stl_flat_par_speed.PNG b/extern/phmap/html/img/mt_stl_flat_par_speed.PNG new file mode 100644 index 0000000..4aece96 Binary files /dev/null and b/extern/phmap/html/img/mt_stl_flat_par_speed.PNG differ diff --git a/extern/phmap/html/img/mt_stl_flat_par_speed_run2.PNG b/extern/phmap/html/img/mt_stl_flat_par_speed_run2.PNG new file mode 100644 index 0000000..38d9882 Binary files /dev/null and b/extern/phmap/html/img/mt_stl_flat_par_speed_run2.PNG differ diff --git a/extern/phmap/html/img/no_preselection.PNG b/extern/phmap/html/img/no_preselection.PNG new file mode 100644 index 0000000..22fa8d4 Binary files /dev/null and b/extern/phmap/html/img/no_preselection.PNG differ diff --git a/extern/phmap/html/img/node_mem_usage.gif b/extern/phmap/html/img/node_mem_usage.gif new file mode 100644 index 0000000..77dec05 Binary files /dev/null and b/extern/phmap/html/img/node_mem_usage.gif differ diff --git a/extern/phmap/html/img/node_mem_usage.png b/extern/phmap/html/img/node_mem_usage.png new file mode 100644 index 0000000..15cb1e0 Binary files /dev/null and b/extern/phmap/html/img/node_mem_usage.png differ diff --git a/extern/phmap/html/img/node_peak.gif b/extern/phmap/html/img/node_peak.gif new file mode 100644 index 0000000..82e47ec Binary files /dev/null and b/extern/phmap/html/img/node_peak.gif differ diff --git a/extern/phmap/html/img/node_peak.png b/extern/phmap/html/img/node_peak.png new file mode 100644 index 0000000..e818cb3 Binary files /dev/null and b/extern/phmap/html/img/node_peak.png differ diff --git a/extern/phmap/html/img/par_align_test.png b/extern/phmap/html/img/par_align_test.png new file mode 100644 index 0000000..b28ae35 Binary files /dev/null and b/extern/phmap/html/img/par_align_test.png differ diff --git a/extern/phmap/html/img/par_mt_memory.PNG b/extern/phmap/html/img/par_mt_memory.PNG new file mode 100644 index 0000000..c0c955b Binary files /dev/null and b/extern/phmap/html/img/par_mt_memory.PNG differ diff --git a/extern/phmap/html/img/par_mt_speed.PNG b/extern/phmap/html/img/par_mt_speed.PNG new file mode 100644 index 0000000..f3ad52a Binary files /dev/null and b/extern/phmap/html/img/par_mt_speed.PNG differ diff --git a/extern/phmap/html/img/parallel_flat_peak.gif b/extern/phmap/html/img/parallel_flat_peak.gif new file mode 100644 index 0000000..45e8ee6 Binary files /dev/null and b/extern/phmap/html/img/parallel_flat_peak.gif differ diff --git a/extern/phmap/html/img/parallel_flat_peak.png b/extern/phmap/html/img/parallel_flat_peak.png new file mode 100644 index 0000000..019104e Binary files /dev/null and b/extern/phmap/html/img/parallel_flat_peak.png differ diff --git a/extern/phmap/html/img/parallel_node_peak.gif b/extern/phmap/html/img/parallel_node_peak.gif new file mode 100644 index 0000000..c968685 Binary files /dev/null and b/extern/phmap/html/img/parallel_node_peak.gif differ diff --git a/extern/phmap/html/img/parallel_node_peak.png b/extern/phmap/html/img/parallel_node_peak.png new file mode 100644 index 0000000..9efca9a Binary files /dev/null and b/extern/phmap/html/img/parallel_node_peak.png differ diff --git a/extern/phmap/html/img/phash.png b/extern/phmap/html/img/phash.png new file mode 100644 index 0000000..18d1894 Binary files /dev/null and b/extern/phmap/html/img/phash.png differ diff --git a/extern/phmap/html/img/phmap_logo.png b/extern/phmap/html/img/phmap_logo.png new file mode 100644 index 0000000..2331458 Binary files /dev/null and b/extern/phmap/html/img/phmap_logo.png differ diff --git a/extern/phmap/html/img/spp_flat_par_both.png b/extern/phmap/html/img/spp_flat_par_both.png new file mode 100644 index 0000000..ae040b1 Binary files /dev/null and b/extern/phmap/html/img/spp_flat_par_both.png differ diff --git a/extern/phmap/html/img/stl_flat_both.PNG b/extern/phmap/html/img/stl_flat_both.PNG new file mode 100644 index 0000000..5799f5c Binary files /dev/null and b/extern/phmap/html/img/stl_flat_both.PNG differ diff --git a/extern/phmap/html/img/stl_flat_mem.PNG b/extern/phmap/html/img/stl_flat_mem.PNG new file mode 100644 index 0000000..96fb4b8 Binary files /dev/null and b/extern/phmap/html/img/stl_flat_mem.PNG differ diff --git a/extern/phmap/html/img/stl_flat_par_both.PNG b/extern/phmap/html/img/stl_flat_par_both.PNG new file mode 100644 index 0000000..c92bca1 Binary files /dev/null and b/extern/phmap/html/img/stl_flat_par_both.PNG differ diff --git a/extern/phmap/html/img/stl_flat_par_mem.PNG b/extern/phmap/html/img/stl_flat_par_mem.PNG new file mode 100644 index 0000000..87e6eca Binary files /dev/null and b/extern/phmap/html/img/stl_flat_par_mem.PNG differ diff --git a/extern/phmap/html/img/stl_flat_par_mem_zoomed.PNG b/extern/phmap/html/img/stl_flat_par_mem_zoomed.PNG new file mode 100644 index 0000000..6424b7f Binary files /dev/null and b/extern/phmap/html/img/stl_flat_par_mem_zoomed.PNG differ diff --git a/extern/phmap/html/img/stl_flat_par_speed.PNG b/extern/phmap/html/img/stl_flat_par_speed.PNG new file mode 100644 index 0000000..12f18e3 Binary files /dev/null and b/extern/phmap/html/img/stl_flat_par_speed.PNG differ diff --git a/extern/phmap/html/img/stl_flat_speed.PNG b/extern/phmap/html/img/stl_flat_speed.PNG new file mode 100644 index 0000000..b7a0bce Binary files /dev/null and b/extern/phmap/html/img/stl_flat_speed.PNG differ diff --git a/extern/phmap/html/includes.hs b/extern/phmap/html/includes.hs new file mode 100644 index 0000000..1edf2dc --- /dev/null +++ b/extern/phmap/html/includes.hs @@ -0,0 +1,65 @@ +{-# LANGUAGE OverloadedStrings #-} + +import Text.Read +import Control.Monad.State +import Control.Monad +import Text.Pandoc +import Data.Monoid +import Control.Applicative + +import Text.Pandoc.JSON +import Text.Pandoc.Walk + +slice :: Int -> Int -> [a] -> [a] +slice from to xs = take (to - from + 1) (drop from xs) + +doSlice :: Block -> IO Block +doSlice cb@(CodeBlock (id, classes, namevals) contents) = do + res <- return $ do + upper <- readMaybe =<< lookup "upper" namevals + lower <- readMaybe =<< lookup "lower" namevals + file <- lookup "slice" namevals + return (upper, lower, file) + + case res of + Nothing -> return cb + Just (upper, lower, f) -> do + contents <- readFile f + let lns = unlines $ slice lower upper (lines contents) + return (CodeBlock (id, classes, namevals) lns) +doSlice x = return x + +doInclude :: Block -> IO Block +doInclude cb@(CodeBlock (id, classes, namevals) contents) = + case lookup "include" namevals of + Just f -> return . (CodeBlock (id, classes, namevals)) =<< readFile f + Nothing -> return cb +doInclude x = return x + +doHtml :: Block -> IO Block +doHtml cb@(CodeBlock (id, classes, namevals) contents) = + case lookup "literal" namevals of + Just f -> return . (RawBlock "html") =<< readFile f + Nothing -> return cb +doHtml x = return x + +injectLatexMacros :: Maybe Format -> Pandoc -> IO Pandoc +injectLatexMacros (Just fmt) p = do + macros <- readFile "latex_macros" + let block = + case fmt of + Format "html" -> + Div ("",[],[("style","display:none")]) . (:[]) + . Para . (:[]) . Math DisplayMath $ macros + Format "latex" -> RawBlock "latex" macros + Format "epub" -> RawBlock "latex" macros + _ -> RawBlock "latex" macros + return (Pandoc nullMeta [block] <> p) +injectLatexMacros _ _ = return mempty + +main :: IO () +main = toJSONFilter + ((\fmt -> injectLatexMacros fmt + >=> walkM doInclude + >=> walkM doSlice + >=> walkM doHtml) :: Maybe Format -> Pandoc -> IO Pandoc) diff --git a/extern/phmap/html/latex_macros b/extern/phmap/html/latex_macros new file mode 100644 index 0000000..396f08f --- /dev/null +++ b/extern/phmap/html/latex_macros @@ -0,0 +1,15 @@ +\newcommand{\andalso}{\quad\quad} +\newcommand{\infabbrev}[2]{\infax{#1 \quad\eqdef\quad #2}} +\newcommand{\infrule}[2]{\displaystyle \dfrac{#1}{#2}} +\newcommand{\ar}{\rightarrow} +\newcommand{\Int}{\mathtt{Int}} +\newcommand{\Bool}{\mathtt{Bool}} +\newcommand{\becomes}{\Downarrow} +\newcommand{\trule}[1]{(\textbf{#1})} +\newcommand{\FV}[1]{\mathtt{fv}(#1)} +\newcommand{\FTV}[1]{\mathtt{ftv}(#1)} +\newcommand{\BV}[1]{\mathtt{bv}(#1)} +\newcommand{\compiles}[1]{\text{C}\llbracket{#1}\rrbracket} +\newcommand{\exec}[1]{\text{E}\llbracket{#1}\rrbracket} +\renewcommand{\t}[1]{\mathtt{#1}} +\newcommand{\ite}[3]{\text{if }#1\text{ then }#2\text{ else }#3} diff --git a/extern/phmap/html/parallel_hashmap.html b/extern/phmap/html/parallel_hashmap.html new file mode 100644 index 0000000..9599923 --- /dev/null +++ b/extern/phmap/html/parallel_hashmap.html @@ -0,0 +1,343 @@ + + + + + The Parallel Hashmap (Gregory Popovitch) + + + + + + + + + + + + + + + + +

+ +
+ +
+ +
+

\[\newcommand{\andalso}{\quad\quad} +\newcommand{\infabbrev}[2]{\infax{#1 \quad\eqdef\quad #2}} +\newcommand{\infrule}[2]{\displaystyle \dfrac{#1}{#2}} +\newcommand{\ar}{\rightarrow} +\newcommand{\Int}{\mathtt{Int}} +\newcommand{\Bool}{\mathtt{Bool}} +\newcommand{\becomes}{\Downarrow} +\newcommand{\trule}[1]{(\textbf{#1})} +\newcommand{\FV}[1]{\mathtt{fv}(#1)} +\newcommand{\FTV}[1]{\mathtt{ftv}(#1)} +\newcommand{\BV}[1]{\mathtt{bv}(#1)} +\newcommand{\compiles}[1]{\text{C}\llbracket{#1}\rrbracket} +\newcommand{\exec}[1]{\text{E}\llbracket{#1}\rrbracket} +\renewcommand{\t}[1]{\mathtt{#1}} +\newcommand{\ite}[3]{\text{if }#1\text{ then }#2\text{ else }#3} +\]

+
+

The Parallel Hashmap

+

or Abseiling from the shoulders of giants - © Gregory Popovitch - March 10, 2019

+

[tl;dr] We present a novel hashmap design, the Parallel Hashmap. Built on top of Abseil's flat_hash_map, the Parallel Hashmap has lower space requirements, is nearly as fast as the underlying flat_hash_map, and can be used from multiple threads with high levels of concurrency.

+

A quick look at the current state of the art

+

If you haven't been living under a rock, you know that Google open sourced late last year their Abseil library, which includes a very efficient flat hash table implementation. The absl::flat_hash_map stores the values directly in a memory array, which avoids memory indirections (this is referred to as closed hashing).

+

closed_hashing

+

Using parallel SSE2 instructions, the flat hash table is able to look up items by checking 16 slots in parallel, which allows the implementation to remain fast even when the table is filled to 87.5% capacity.

+

The graphs below show a comparison of time and memory usage necessary to insert up to 100 million values (each value is composed of two 8-byte integers), between the default hashmap of Visual Studio 2017 (std::unordered_map), and Abseil's flat_hash_map:

+

stl_flat comparison

+

On the bottom graph, we can see that, as expected, the Abseil flat_hash_map is significantly faster that the default stl implementation, typically about three times faster.

+

The peak memory usage issue

+

The top graph shown the memory usage for both tables.

+

I used a separate thread to monitor the memory usage, which allows to track the increased memory usage when the table resizes. Indeed, both tables have a peak memory usage that is significantly higher than the memory usage seen between insertions.

+

In the case of Abseil's flat_hash_map, the values are stored directly in a memory array. The memory usage is constant until the table needs to resize, which is why we see these horizontal sections of memory usage.

+

When the flat_hash_map reaches 87.5% occupancy, a new array of twice the size is allocated, the values are moved (rehashed) from the smaller to the larger array, and then the smaller array, now empty, is freed. So we see that during the resize, the occupancy is only one third of 87.5%, or 29.1%, and when the smaller array is released, occupancy is half of 87.5% or 43.75%.

+

The default STL implementation is also subject to this higher peak memory usage, since it typically is implemented with an array of buckets, each bucket having a pointer to a linked list of nodes containing the values. In order to maintain O(1) lookups, the array of buckets also needs to be resized as the table size grows, requiring a 3x temporary memory requirement for moving the old bucket array (1x) to the newly allocated, larger (2x) array. In between the bucket array resizes, the default STL implementation memory usage grows at a constant rate as new values are added to the linked lists.

+
+

Instead of having a separate linked list for each bucket, std::unordered_map implementations often use a single linked list (making iteration faster), with buckets pointing to locations within the single linked list. absl::node_hash_map, on the other hand, has each bucket pointing to a single value, and collisions are handled with open addressing like for the absl::flat_hash_map.

+
+

This peak memory usage can be the limiting factor for large tables. Suppose you are on a machine with 32 GB of ram, and the flat_hash_map needs to resize when you inserted 10 GB of values in it. 10 GB of values means the array size is 11.42 GB (resizing at 87.5% occupancy), and we need to allocate a new array of double size (22.85 GB), which obviously will not be possible on our 32 GB machine.

+

For my work developing mechanical engineering software, this has kept me from using flat hash maps, as the high peak memory usage was the limiting factor for the size of FE models which could be loaded on a given machine. So I used other types of maps, such as sparsepp or Google's cpp-btree.

+

When the Abseil library was open sourced, I started pondering the issue again. Compared to Google's old dense_hash_map which resized at 50% capacity, the new absl::flat_hash_map resizing at 87.5% capacity was more memory friendly, but it still had these significant peaks of memory usage when resizing.

+

If only there was a way to eliminate those peaks, the flat_hash_map would be close to perfect. But how?

+

The peak memory usage solution

+

Suddenly, it hit me. I had a solution. I would create a hash table that internally is made of an array of 16 hash tables (the submaps). When inserting or looking up an item, the index of the target submap would be decided by the hash of the value to insert. For example, if for a given size_t hashval, the index for the internal submap would be computed with:

+

submap_index = (hashval ^ (hashval >> 4)) & 0xF;

+

providing an index between 0 and 15.

+
+

In the actual implementation, the size of the array of hash tables is configurable to a power of two, so it can be 2, 4, 8, 16, 32, ... The following illustration shows a parallel_hash_map with 8 submaps.

+
+

index_computation

+

The benefit of this approach would be that the internal tables would each resize on its own when they reach 87.5% capacity, and since each table contains approximately one sixteenth of the values, the memory usage peak would be only one sixteenth of the size we saw for the single flat_hash_map.

+

The rest of this article describes my implementation of this concept that I have done inside the Abseil library (I have submitted a pull request in the hope it will be merged into the main Abseil codebase). The current name for it is parallel_flat_hash_map or parallel_flat_hash_set. It does provide the same external API as Abseil's other hash tables, and internally it uses a std::array of N flat_hash_maps.

+

I was delighted to find out that not only the parallel_flat_hash_map has significant memory usage benefits compared to the flat_hash_map, but it also has significant advantages for concurrent programming as I will show later.

+
+

I will use the names parallel_hash_map and parallel_flat_hash_map interchangably. They refer to the same data structure. The name used in my Abseil fork is absl::parallel_flat_hash_map, as it may be desirable to also provide a absl::parallel_node_hash_map.

+
+

The Parallel Hashmap: memory usage

+

So, without further ado, let's see the same graphs graphs as above, with the addition of the parallel_flat_hash_map. Let us first look at memory usage (the second graph provides a "zoomed-in" view of the location where resizing occurs):

+

stl_flat_par comparison

+

stl_flat_par_zoomed comparison

+

We see that the parallel_hash_map behaves as expected. The memory usage matches exactly the memory usage of its base flat_hash_map, except that the peaks of memory usage which occur when the table resizes are drastically reduced, to the point that they are not objectionable anymore. In the "zoomed-in" view, we can see the sixteen dots corresponding to each of the individual submaps resizing. The fact that those resizes are occuring at roughly the same x location in the graph shows that we have a good hash function distribution, distributing the values evenly between the sixteen individual submaps.

+

The Parallel Hashmap: speed

+

But what about the speed? After all, for each value inserted into the parallel hashmap, we have to do some extra work (steps 1 and 2 below):

+
    +
  1. compute the hash for the value to insert
  2. +
  3. compute the index of the target submap from the hash)
  4. +
  5. insert the value into the submap
  6. +
+

The first step (compute the hash) is the most problematic one, as it can potentially be costly. As we mentioned above, the second step (computing the index from the hash) is very simple and its cost in minimal (3 processor instruction as shown below in Matt Godbolt's compiler explorer):

+

index computation cost

+

As for the hash value computation, fortunately we can eliminate this cost by providing the computed hash to the submap functions, so that it is computed only once. This is exactly what I have done in my implementation of the parallel_hash_map within the Abseil library, adding a few extra APIs to the Abseil internal raw_hash_map.h header, which allow the parallel_hash_map to pass the precomputed hash value to the underlying submaps.

+

So we have all but eliminated the cost of the first step, and seen that the cost of the second step is very minimal. At this point we expect that the parallel_hash_map performance will be close to the one of its underlying flat_hash_map, and this is confirmed by the chart below:

+

stl_flat_par comparison

+

Indeed, because of the scale is somewhat compressed due to the longer times of the std::unordered_map, we can barely distinguish between the blue curve of the flat_hash_map and the red curve of the parallel_hash_map. So let's look at a graph without the std::unordered_map:

+

flat_par comparison

+

This last graph shows that the parallel_hash_map is slightly slower especially for smaller table sizes. For a reason not obvious to me (maybe better memory locality), the speeds of the parallel_hash_map and flat_hash_map are essentially undistinguishable for larger map sizes (> 80 million values).

+

Are we done yet?

+

This is already looking pretty good. For large hash_maps, the parallel_flat_hash_map is a very appealing solution, as it provides essentially the excellent performance of the flat_hash_map, while virtually eliminating the peaks of memory usage which occur when the hash table resizes.

+

But there is another aspect of the inherent parallelism of the parallel_hash_map which is interesting to explore. As we know, typical hashmaps cannot be modified from multiple threads without explicit synchronization. And bracketing write accesses to a shared hash_map with synchronization primitives, such as mutexes, can reduce the concurrency of our program, and even cause deadlocks.

+

Because the parallel_hash_map is made of sixteen separate submaps, it posesses some intrinsic parallelism. Indeed, suppose you can make sure that different threads will use different submaps, you would be able to insert into the same parallel_hash_map at the same time from the different threads without any locking.

+

Using the intrinsic parallelism of the parallel_hash_map to insert values from multiple threads, lock free.

+

So, if you can iterate over the values you want to insert into the hash table, the idea is that each thread will iterate over all values, and then for each value:

+
    +
  1. compute the hash for that value
  2. +
  3. compute the submap index for that hash
  4. +
  5. if the submap index is one assigned to this thread, then insert the value, otherwise do nothing and continue to the next value
  6. +
+

Here is the code for the single-threaded insert:

+ +

and here is the code for the multi-threaded insert:

+
template <class HT>
+void _fill_random_inner_mt(int64_t cnt, HT &hash, RSU &rsu)
+{
+    constexpr int64_t num_threads = 8;   // has to be a power of two
+    std::unique_ptr<std::thread> threads[num_threads];
+
+    auto thread_fn = [&hash, cnt, num_threads](int64_t thread_idx, RSU rsu) {
+        typename HT::hasher hasher;                         // get hasher object from the hash table
+        size_t modulo = hash.subcnt() / num_threads;        // subcnt() returns the number of submaps
+
+        for (int64_t i=0; i<cnt; ++i)                       // iterate over all values
+        {
+            unsigned int key = rsu.next();                  // get next key to insert
+            size_t hashval = hash.hash(key);                // compute its hash
+            size_t idx  = hash.subidx(hashval);             // compute the submap index for this hash
+            if (idx / modulo == thread_idx)                 // if the submap is suitable for this thread
+            {
+                hash.insert(typename HT::value_type(key, 0)); // insert the value
+                ++(num_keys[thread_idx]);                     // increment count of inserted values
+            }
+        }
+    };
+
+    // create and start 8 threads - each will insert in their own submaps
+    // thread 0 will insert the keys whose hash direct them to submap0 or submap1
+    // thread 1 will insert the keys whose hash direct them to submap2 or submap3
+    // --------------------------------------------------------------------------
+    for (int64_t i=0; i<num_threads; ++i)
+        threads[i].reset(new std::thread(thread_fn, i, rsu));
+
+    // rsu passed by value to threads... we need to increment the reference object
+    for (int64_t i=0; i<cnt; ++i)
+        rsu.next();
+    
+    // wait for the threads to finish their work and exit
+    for (int64_t i=0; i<num_threads; ++i)
+        threads[i]->join();
+}
+

Using multiple threads, we are able to populate the parallel_flat_hash_map (inserting 100 million values) three times faster than the standard flat_hash_map (which we could not have populated from multiple threads without explicit locks, which would have prevented performance improvements).

+

And the graphical visualization of the results:

+

mt_stl_flat_par comparison

+

We notice in this last graph that the memory usage peaks, while still smaller than those of the flat_hash_map, are larger that those we saw when populating the parallel_hash_map using a single thread. The obvious reason is that, when using a single thread, only one of the submaps would resize at a time, ensuring that the peak would only be 1/16th of the one for the flat_hash_map (provided of course that the hash function distributes the values somewhat evenly between the submaps).

+

When running in multi-threaded mode (in this case eight threads), potentially as many as eight submaps can resize simultaneaously, so for a parallel_hash_map with sixteen submaps the memory peak size can be half as large as the one for the flat_hash_map.

+

Still, this is a pretty good result, we are now inserting values into our parallel_hash_map three times faster than we were able to do using the flat_hash_map, while using a lower memory ceiling.

+

This is significant, as the speed of insertion into a hash map is important in many algorithms, for example removing duplicates in a collection of values.

+

Using the intrinsic parallelism of the parallel_hash_map with internal mutexes

+

It may not be practical to add logic into your program to ensure you use different internal submaps from each thread. Still, locking the whole parallel_hash_map for each access would forego taking advantage of its intrinsic parallelism.

+

For that reason, the parallel_hash_map can provide internal locking using the absl::Mutex (the default template parameter is absl::NullMutex, which does no locking and has no size cost). When selecting absl::Mutex, one mutex is created for each internal submap at a cost of 8 bytes per submap, and the parallel_hash_map internally protects each submap access with its associated mutex.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
mapNumber of submapssizeof(map)
std::unordered_map (vs2017)-64
absl::flat_hash_map-48
absl::parallel_flat_hash_map, N=4, absl::NullMutex16768
absl::parallel_flat_hash_map, N=4, absl::Mutex16896
+

It is about time we provide the complete parallel_flat_hash_map class declaration (the declaration for parallel_flat_hash_set is similar):

+
template <class K, class V,
+          class Hash      = absl::priv::hash_default_hash<K>,
+          class Eq        = absl::priv::hash_default_eq<K>,
+          class Allocator = std::allocator<std::pair<const K, V>>,
+          size_t N        = 4,                 // 2**N submaps
+          class Mutex     = absl::NullMutex>   // use absl::Mutex to enable internal locks
+class parallel_flat_hash_map;
+
+

Let's see what result we get for the insertion of random values from multiple threads, however this time we create a parallel_hash_map with internal locking (by providing absl::Mutex as the last template argument), and modify the code so that each thread inserts values in any submap (no pre-selection).

+

no_preselection

+

If we were to do a intensive insertion test into a hash map from multiple threads, where we lock the whole hash table for each insertion, we would be likely to get even worse results than for a single threaded insert, because of heavy lock contention.

+

In this case, our expectation is that the finer grained locking of the parallel_hash_map (separate locks for each internal submap) will provide a speed benefit when compared to the single threaded insertion, and this is indeed what the benchmarks show:

+

flat_par_mutex_4

+

Interestingly, we notice that the memory peaks (when resizing occur) are again very small, in the order of 1/16th of those for the flat_hash_map. This is likely because, as soon as one of the submaps resizes (which takes much longer than a regular insertion), the other threads very soon have to wait on the resizing submap's mutex for an insertion, before they reach their own resizing threashold.

+

Since threads statistically will insert on a different submap for each value, it would be a surprising coincidence indeed if two submaps reached their resizing threshold without the resizing of the first submap blocking all the other threads first.

+

If we increase the number of submaps, we should see more parallelism (less lock contention across threads, as the odds of two separate threads inserting in the same subhash is lower), but with diminishing returns as every submap resize will quickly block the other threads until the resize is completed.

+

This is indeed what we see:

+

lock_various_sizes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
mapNumber of submapssizeof(map)time 100M insertions
absl::flat_hash_map-4814.77s
absl::parallel_flat_hash_map, N=4, absl::Mutex168968.36s
absl::parallel_flat_hash_map, N=5, absl::Mutex3217927.14s
absl::parallel_flat_hash_map, N=6, absl::Mutex6435846.61s
+

There is still some overhead from the mutex lock/unlock, and the occasional lock contention, which prevents us from reaching the performance of the previous multithreaded lock-free insertion (5.12s for inserting 100M elements).

+

In Conclusion

+

We have seen that the novel parallel hashmap approach, used within a single thread, provides significant space advantages, with a very minimal time penalty. When used in a multi-thread context, the parallel hashmap still provides a significant space benefit, in addition to a consequential time benefit by reducing (or even eliminating) lock contention when accessing the parallel hashmap.

+

Future work

+
    +
  1. It would be beneficial to provide additional APIs for the parallel_flat_hash_map and parallel_flat_hash_set taking a precomputed hash value. This would enable the lock-free usage of the parallel_flat_hash_map, described above for multi-threaded environments, without requiring a double hash computation.

  2. +
  3. We may consider providing parallel_node_hash_map and parallel_node_hash_set in Abseil, for the cases when pointer stability is required for keys and/or values. This would be a simple addition.

  4. +
+

Thanks

+

I would like to thank Google's Matt Kulukundis for his eye-opening presentation of the flat_hash_map design at CPPCON 2017 - my frustration with not being able to use it helped trigger my insight into the parallel_hash_map. Also many thanks to the Abseil container developers - I believe the main contributors are Alkis Evlogimenos and Roman Perepelitsa - who created an excellent codebase into which the graft of this new hashmap took easily, and finally to Google for open-sourcing Abseil. Thanks also to my son Andre for reviewing this paper, and for his patience when I was rambling about the parallel_hash_map and its benefits.

+ +

Github repository for the benchmark code used in this paper

+

Swiss Tables doc

+

My fork of Google Abseil repository, with the parallel_flat_hash_map implementation

+

Google Abseil repository

+

Matt Kulukindis: Designing a Fast, Efficient, Cache-friendly Hash Table, Step by Step

+ + + + + + + diff --git a/extern/phmap/html/parallel_hashmap.md b/extern/phmap/html/parallel_hashmap.md new file mode 100644 index 0000000..d0b5345 --- /dev/null +++ b/extern/phmap/html/parallel_hashmap.md @@ -0,0 +1,274 @@ +# The Parallel Hashmap + or Abseiling from the shoulders of giants - © Gregory Popovitch - March 10, 2019 + +[tl;dr] We present a novel hashmap design, the Parallel Hashmap. Built on a modified version of Abseil's *flat_hash_map*, the Parallel Hashmap has lower space requirements, is nearly as fast as the underlying *flat_hash_map*, and can be used from multiple threads with high levels of concurrency. The [parallel hashmap](https://github.com/greg7mdp/parallel-hashmap) repository provides header-only version of the flat and node hashmaps, and their parallel versions as well. + +### A quick look at the current state of the art + +If you haven't been living under a rock, you know that Google open sourced late last year their Abseil library, which includes a very efficient flat hash table implementation. The *absl::flat_hash_map* stores the values directly in a memory array, which avoids memory indirections (this is referred to as closed hashing). + +![closed_hashing](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/closed_hashing.png?raw=true) + +Using parallel SSE2 instructions, the flat hash table is able to look up items by checking 16 slots in parallel, which allows the implementation to remain fast even when the table is filled to 87.5% capacity. + +The graphs below show a comparison of time and memory usage necessary to insert up to 100 million values (each value is composed of two 8-byte integers), between the default hashmap of Visual Studio 2017 (std::unordered_map), and Abseil's flat_hash_map: + +![stl_flat comparison](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/stl_flat_both.PNG?raw=true) + +On the bottom graph, we can see that, as expected, the Abseil *flat_hash_map* is significantly faster that the default stl implementation, typically about three times faster. + +### The peak memory usage issue + +The top graph shown the memory usage for both tables. + +I used a separate thread to monitor the memory usage, which allows to track the increased memory usage when the table resizes. Indeed, both tables have a peak memory usage that is significantly higher than the memory usage seen between insertions. + +In the case of Abseil's *flat_hash_map*, the values are stored directly in a memory array. The memory usage is constant until the table needs to resize, which is why we see these horizontal sections of memory usage. + +When the *flat_hash_map* reaches 87.5% occupancy, a new array of twice the size is allocated, the values are moved (rehashed) from the smaller to the larger array, and then the smaller array, now empty, is freed. So we see that during the resize, the occupancy is only one third of 87.5%, or 29.1%, and when the smaller array is released, occupancy is half of 87.5% or 43.75%. + +The default STL implementation is also subject to this higher peak memory usage, since it typically is implemented with an array of buckets, each bucket having a pointer to a linked list of nodes containing the values. In order to maintain O(1) lookups, the array of buckets also needs to be resized as the table size grows, requiring a 3x temporary memory requirement for moving the old bucket array (1x) to the newly allocated, larger (2x) array. In between the bucket array resizes, the default STL implementation memory usage grows at a constant rate as new values are added to the linked lists. + +> Instead of having a separate linked list for each bucket, *std::unordered_map* implementations often use a single linked list (making iteration faster), with buckets pointing to locations within the single linked list. *absl::node_hash_map*, on the other hand, has each bucket pointing to a single value, and collisions are handled with open addressing like for the *absl::flat_hash_map*. + +This peak memory usage can be the limiting factor for large tables. Suppose you are on a machine with 32 GB of ram, and the *flat_hash_map* needs to resize when you inserted 10 GB of values in it. 10 GB of values means the array size is 11.42 GB (resizing at 87.5% occupancy), and we need to allocate a new array of double size (22.85 GB), which obviously will not be possible on our 32 GB machine. + +For my work developing mechanical engineering software, this has kept me from using flat hash maps, as the high peak memory usage was the limiting factor for the size of FE models which could be loaded on a given machine. So I used other types of maps, such as [sparsepp](https://github.com/greg7mdp/sparsepp) or Google's [cpp-btree](https://code.google.com/archive/p/cpp-btree/). + +When the Abseil library was open sourced, I started pondering the issue again. Compared to Google's old dense_hash_map which resized at 50% capacity, the new *absl::flat_hash_map* resizing at 87.5% capacity was more memory friendly, but it still had these significant peaks of memory usage when resizing. + +If only there was a way to eliminate those peaks, the *flat_hash_map* would be close to perfect. But how? + +### The peak memory usage solution + +Suddenly, it hit me. I had a solution. I would create a hash table that internally is made of an array of 16 hash tables (the submaps). When inserting or looking up an item, the index of the target submap would be decided by the hash of the value to insert. For example, if for a given `size_t hashval`, the index for the internal submap would be computed with: + +`submap_index = (hashval ^ (hashval >> 4)) & 0xF;` + +providing an index between 0 and 15. + +> In the actual implementation, the size of the array of hash tables is configurable to a power of two, so it can be 2, 4, 8, 16, 32, ... The following illustration shows a parallel_hash_map with 8 submaps. + +![index_computation](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/index_computation.png?raw=true) + +The benefit of this approach would be that the internal tables would each resize on its own when they reach 87.5% capacity, and since each table contains approximately one sixteenth of the values, the memory usage peak would be only one sixteenth of the size we saw for the single *flat_hash_map*. + +The rest of this article describes my implementation of this concept that I have done in my [parallel hashmap](https://github.com/greg7mdp/parallel-hashmap) repository. This is a header only library, which provides the following eight hashmaps: + +- phmap::flat_hash_set +- phmap::flat_hash_map +- phmap::node_hash_set +- phmap::node_hash_map +- phmap::parallel_flat_hash_set +- phmap::parallel_flat_hash_map +- phmap::parallel_node_hash_set +- phmap::parallel_node_hash_map + +This implementation requires a C++11 compatible compiler, and provides full compatibility with the std::unordered_map (with the exception of *pointer stability* for the `flat` versions. C++14 and C++17 methods, like `try-emplace`, are provided as well. +The names for it are *parallel_flat_hash_map* or *parallel_flat_hash_set*, and the *node* equivalents. These hashmaps provide the same external API as the *flat_hash_map*, and internally use a std::array of 2**N *flat_hash_maps*. + +I was delighted to find out that not only the *parallel_flat_hash_map* has significant memory usage benefits compared to the *flat_hash_map*, but it also has significant advantages for concurrent programming as I will show later. In the rest of this article, we will focus on the *parallel_flat_hash_map*, but similar results are seen for the *parallel_node_hash_map*, and the *set* versions of course. + + +### The Parallel Hashmap: memory usage + +So, without further ado, let's see the same graphs graphs as above, with the addition of the *parallel_flat_hash_map*. Let us first look at memory usage (the second graph provides a "zoomed-in" view of the location where resizing occurs): + +![stl_flat_par comparison](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/stl_flat_par_mem.PNG?raw=true) + +![stl_flat_par_zoomed comparison](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/stl_flat_par_mem_zoomed.PNG?raw=true) + +We see that the *parallel_flat_hash_map* behaves as expected. The memory usage matches exactly the memory usage of its base *flat_hash_map*, except that the peaks of memory usage which occur when the table resizes are drastically reduced, to the point that they are not objectionable anymore. In the "zoomed-in" view, we can see the sixteen dots corresponding to each of the individual submaps resizing. The fact that those resizes are occuring at roughly the same x location in the graph shows that we have a good hash function distribution, distributing the values evenly between the sixteen individual submaps. + + +### The Parallel Hashmap: speed + +But what about the speed? After all, for each value inserted into the parallel hashmap, we have to do some extra work (steps 1 and 2 below): +1. compute the hash for the value to insert +2. compute the index of the target submap from the hash) +3. insert the value into the submap + +The first step (compute the hash) is the most problematic one, as it can potentially be costly. As we mentioned above, the second step (computing the index from the hash) is very simple and its cost in minimal (3 processor instruction as shown below in *Matt Godbolt*'s compiler explorer): + +![index computation cost](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/idx_computation_cost.PNG?raw=true) + +As for the hash value computation, fortunately we can eliminate this cost by providing the computed hash to the submap functions, so that it is computed only once. This is exactly what I have done in my implementation of the *parallel_flat_hash_map*, adding a few extra APIs to the internal raw_hash_map.h header, which allow the *parallel_flat_hash_map* to pass the precomputed hash value to the underlying submaps. + +So we have all but eliminated the cost of the first step, and seen that the cost of the second step is very minimal. At this point we expect that the *parallel_flat_hash_map* performance will be close to the one of its underlying *flat_hash_map*, and this is confirmed by the chart below: + +![stl_flat_par comparison](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/stl_flat_par_speed.PNG?raw=true) + +Indeed, because of the scale is somewhat compressed due to the longer times of the std::unordered_map, we can barely distinguish between the blue curve of the *flat_hash_map* and the red curve of the *parallel_flat_hash_map*. So let's look at a graph without the std::unordered_map: + +![flat_par comparison](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/flat_par_speed.PNG?raw=true) + +This last graph shows that the *parallel_flat_hash_map* is slightly slower especially for smaller table sizes. For a reason not obvious to me (maybe better memory locality), the speeds of the *parallel_flat_hash_map* and *flat_hash_map* are essentially undistinguishable for larger map sizes (> 80 million values). + +### Are we done yet? + +This is already looking pretty good. For large hash_maps, the *parallel_flat_hash_map* is a very appealing solution, as it provides essentially the excellent performance of the *flat_hash_map*, while virtually eliminating the peaks of memory usage which occur when the hash table resizes. + +But there is another aspect of the inherent parallelism of the *parallel_flat_hash_map* which is interesting to explore. As we know, typical hashmaps cannot be modified from multiple threads without explicit synchronization. And bracketing write accesses to a shared hash_map with synchronization primitives, such as mutexes, can reduce the concurrency of our program, and even cause deadlocks. + +Because the *parallel_flat_hash_map* is made of sixteen separate submaps, it posesses some intrinsic parallelism. Indeed, suppose you can make sure that different threads will use different submaps, you would be able to insert into the same *parallel_flat_hash_map* at the same time from the different threads without any locking. + +### Using the intrinsic parallelism of the *parallel_flat_hash_map* to insert values from multiple threads, lock free. + +So, if you can iterate over the values you want to insert into the hash table, the idea is that each thread will iterate over all values, and then for each value: + +1. compute the hash for that value +2. compute the submap index for that hash +3. if the submap index is one assigned to this thread, then insert the value, otherwise do nothing and continue to the next value + +Here is the code for the single-threaded insert: + +```c++ +template +void _fill_random_inner(int64_t cnt, HT &hash, RSU &rsu) +{ + for (int64_t i=0; i +void _fill_random_inner_mt(int64_t cnt, HT &hash, RSU &rsu) +{ + constexpr int64_t num_threads = 8; // has to be a power of two + std::unique_ptr threads[num_threads]; + + auto thread_fn = [&hash, cnt, num_threads](int64_t thread_idx, RSU rsu) { + size_t modulo = hash.subcnt() / num_threads; // subcnt() returns the number of submaps + + for (int64_t i=0; ijoin(); +} +``` + +Using multiple threads, we are able to populate the *parallel_flat_hash_map* (inserting 100 million values) three times faster than the standard *flat_hash_map* (which we could not have populated from multiple threads without explicit locks, which would have prevented performance improvements). + +And the graphical visualization of the results: + +![mt_stl_flat_par comparison](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/mt_stl_flat_par_both_run2.PNG?raw=true) + +We notice in this last graph that the memory usage peaks, while still smaller than those of the *flat_hash_map*, are larger that those we saw when populating the *parallel_flat_hash_map* using a single thread. The obvious reason is that, when using a single thread, only one of the submaps would resize at a time, ensuring that the peak would only be 1/16th of the one for the *flat_hash_map* (provided of course that the hash function distributes the values somewhat evenly between the submaps). + +When running in multi-threaded mode (in this case eight threads), potentially as many as eight submaps can resize simultaneaously, so for a *parallel_flat_hash_map* with sixteen submaps the memory peak size can be half as large as the one for the *flat_hash_map*. + +Still, this is a pretty good result, we are now inserting values into our *parallel_flat_hash_map* three times faster than we were able to do using the *flat_hash_map*, while using a lower memory ceiling. + +This is significant, as the speed of insertion into a hash map is important in many algorithms, for example removing duplicates in a collection of values. + + +### Using the intrinsic parallelism of the *parallel_flat_hash_map* with internal mutexes + +It may not be practical to add logic into your program to ensure you use different internal submaps from each thread. Still, locking the whole *parallel_flat_hash_map* for each access would forego taking advantage of its intrinsic parallelism. + +For that reason, the *parallel_flat_hash_map* can provide internal locking using the `std::mutex` (the default template parameter is `phmap::NullMutex`, which does no locking and has no size cost). When selecting `std::mutex`, one mutex is created for each internal submap at a cost of 8 bytes per submap, and the *parallel_flat_hash_map* internally protects each submap access with its associated mutex. + + +| map | Number of submaps |sizeof(map) | +| :--- | :---: | ---: | +| std::unordered_map (vs2017) | - | 64 | +| phmap::flat_hash_map | - |48 | +| phmap::parallel_flat_hash_map, N=4, phmap::NullMutex | 16 |768 | +| phmap::parallel_flat_hash_map, N=4, std::mutex | 16 | 896 | + +It is about time we provide the complete parallel_flat_hash_map class declaration (the declaration for parallel_flat_hash_set is similar): + +``` +template , + class Eq = phmap::priv::hash_default_eq, + class Allocator = phmap::priv::Allocator>, // alias for std::allocator + size_t N = 4, // 2**N submaps + class Mutex = phmap::NullMutex> // use std::mutex to enable internal locks +class parallel_flat_hash_map; +``` + +Let's see what result we get for the insertion of random values from multiple threads, however this time we create a *parallel_flat_hash_map* with internal locking (by providing std::mutex as the last template argument), and modify the code so that each thread inserts values in any submap (no pre-selection). + +![no_preselection](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/no_preselection.PNG?raw=true) + +If we were to do a intensive insertion test into a hash map from multiple threads, where we lock the whole hash table for each insertion, we would be likely to get even worse results than for a single threaded insert, because of heavy lock contention. + +In this case, our expectation is that the finer grained locking of the *parallel_flat_hash_map* (separate locks for each internal submap) will provide a speed benefit when compared to the single threaded insertion, and this is indeed what the benchmarks show: + +![flat_par_mutex_4](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/flat_par_mutex_4.PNG?raw=true) + +Interestingly, we notice that the memory peaks (when resizing occur) are again very small, in the order of 1/16th of those for the *flat_hash_map*. This is likely because, as soon as one of the submaps resizes (which takes much longer than a regular insertion), the other threads very soon have to wait on the resizing submap's mutex for an insertion, before they reach their own resizing threashold. + +Since threads statistically will insert on a different submap for each value, it would be a surprising coincidence indeed if two submaps reached their resizing threshold without the resizing of the first submap blocking all the other threads first. + +If we increase the number of submaps, we should see more parallelism (less lock contention across threads, as the odds of two separate threads inserting in the same subhash is lower), but with diminishing returns as every submap resize will quickly block the other threads until the resize is completed. + +This is indeed what we see: + +![lock_various_sizes](https://github.com/greg7mdp/parallel-hashmap/blob/master/html/img/lock_various_sizes.PNG?raw=true) + +| map | Number of submaps |sizeof(map) | time 100M insertions | +| :--- | :---: | ---: | ---: | +| phmap::flat_hash_map | - |48 | 14.77s | +| phmap::parallel_flat_hash_map, N=4, std::mutex | 16 | 896 | 8.36s | +| phmap::parallel_flat_hash_map, N=5, std::mutex | 32 | 1792 | 7.14s | +| phmap::parallel_flat_hash_map, N=6, std::mutex | 64 | 3584 | 6.61s | + +There is still some overhead from the mutex lock/unlock, and the occasional lock contention, which prevents us from reaching the performance of the previous multithreaded lock-free insertion (5.12s for inserting 100M elements). + + +### In Conclusion + +We have seen that the novel parallel hashmap approach, used within a single thread, provides significant space advantages, with a very minimal time penalty. When used in a multi-thread context, the parallel hashmap still provides a significant space benefit, in addition to a consequential time benefit by reducing (or even eliminating) lock contention when accessing the parallel hashmap. + + +### Future work + +1. It would be beneficial to provide additional APIs for the *parallel_flat_hash_map* and *parallel_flat_hash_set* taking a precomputed hash value. This would enable the lock-free usage of the *parallel_flat_hash_map*, described above for multi-threaded environments, without requiring a double hash computation. + + +### Thanks + +I would like to thank Google's *Matt Kulukundis* for his eye-opening presentation of the *flat_hash_map* design at CPPCON 2017 - my frustration with not being able to use it helped trigger my insight into the *parallel_flat_hash_map*. Also many thanks to the Abseil container developers - I believe the main contributors are *Alkis Evlogimenos* and *Roman Perepelitsa* - who created an excellent codebase into which the graft of this new hashmap took easily, and finally to Google for open-sourcing Abseil. Thanks also to my son *Andre* for reviewing this paper, and for his patience when I was rambling about the *parallel_flat_hash_map* and its benefits. + + +### Links + +[Repository for the Parallel Hashmap, including the benchmark code used in this paper](https://github.com/greg7mdp/parallel-hashmap) + +[Swiss Tables doc](https://abseil.io/blog/20180927-swisstables) + +[Google Abseil repository](https://github.com/abseil/abseil-cpp) + +[Matt Kulukindis: Designing a Fast, Efficient, Cache-friendly Hash Table, Step by Step](https://www.youtube.com/watch?v=ncHmEUmJZf4) + diff --git a/extern/phmap/html/parallel_hashmap.pdf b/extern/phmap/html/parallel_hashmap.pdf new file mode 100644 index 0000000..28d05c0 Binary files /dev/null and b/extern/phmap/html/parallel_hashmap.pdf differ diff --git a/extern/phmap/html/template.html b/extern/phmap/html/template.html new file mode 100644 index 0000000..a48f9d2 --- /dev/null +++ b/extern/phmap/html/template.html @@ -0,0 +1,50 @@ + + + + + The Parallel Hashmap (Gregory Popovitch) + + + + + + + + + + + $if(highlighting-css)$ + + $endif$ + $for(css)$ + + $endfor$ + $if(math)$ + $if(html5)$ + $else$ + $math$ + $endif$ + $endif$ + $for(header-includes)$ + $header-includes$ + $endfor$ + + + + +
+ +
+ +
+ +$body$ +
+
+ +
+ + + diff --git a/extern/phmap/html/template.latex b/extern/phmap/html/template.latex new file mode 100644 index 0000000..e78902e --- /dev/null +++ b/extern/phmap/html/template.latex @@ -0,0 +1,308 @@ +\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$lang$,$endif$$if(papersize)$$papersize$,$endif$$for(classoption)$$classoption$$sep$,$endfor$]{$documentclass$} +\usepackage{geometry} +\usepackage{xcolor} +\usepackage{graphicx} +\usepackage[labelformat=empty]{caption} +\usepackage{afterpage} + +\newcommand\blankpage{% + \null + \thispagestyle{empty}% + \addtocounter{page}{-1}% + \newpage} + +$if(fontfamily)$ +\usepackage{$fontfamily$} +$else$ +\usepackage{lmodern} +$endif$ +$if(linestretch)$ +\usepackage{setspace} +\setstretch{$linestretch$} +$endif$ +\usepackage{amssymb,amsmath} +\usepackage{ifxetex,ifluatex} +\usepackage{fixltx2e} % provides \textsubscript +\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex + \usepackage[T1]{fontenc} + \usepackage[utf8]{inputenc} +$if(euro)$ + \usepackage{eurosym} +$endif$ +\else % if luatex or xelatex + \ifxetex + \usepackage{mathspec} + \usepackage{xltxtra,xunicode} + \else + \usepackage{fontspec} + \fi + \defaultfontfeatures{Mapping=tex-text,Scale=MatchLowercase} + \newcommand{\euro}{€} +$if(mainfont)$ + \setmainfont{$mainfont$} +$endif$ +$if(sansfont)$ + \setsansfont{$sansfont$} +$endif$ +$if(monofont)$ + %\setmonofont[Mapping=tex-ansi]{$monofont$} + % custom override +$endif$ + +$if(mathfont)$ + \setmathfont(Digits,Latin,Greek){$mathfont$} +$endif$ + +\usepackage{fontspec} +\setmainfont[Ligatures=Common, + ItalicFont={Adobe Garamond Pro Italic}] + {Adobe Garamond Pro} +\setmonofont[Ligatures=NoCommon]{Source Code Pro} + +\fi +% use upquote if available, for straight quotes in verbatim environments +\IfFileExists{upquote.sty}{\usepackage{upquote}}{} +% use microtype if available +\IfFileExists{microtype.sty}{% +\usepackage{microtype} +\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts +}{} +$if(geometry)$ +\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry} +$endif$ +$if(lang)$ +\ifxetex + \usepackage{polyglossia} + \setmainlanguage{$mainlang$} +\else + \usepackage[shorthands=off,$lang$]{babel} +\fi +$endif$ +$if(natbib)$ +\usepackage{natbib} +\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$} +$endif$ +$if(biblatex)$ +\usepackage{biblatex} +$if(biblio-files)$ +\bibliography{$biblio-files$} +$endif$ +$endif$ +$if(listings)$ +\usepackage{listings} +$endif$ +$if(lhs)$ +\lstnewenvironment{code}{\lstset{language=C++,basicstyle=\small\ttfamily}}{} +$endif$ +$if(highlighting-macros)$ +$highlighting-macros$ +$endif$ +$if(verbatim-in-note)$ +\usepackage{fancyvrb} +\VerbatimFootnotes +$endif$ +$if(tables)$ +\usepackage{longtable,booktabs} +$endif$ +$if(graphics)$ +\usepackage{graphicx} +% Redefine \includegraphics so that, unless explicit options are +% given, the image width will not exceed the width or the height of the page. +% Images get their normal width if they fit onto the page, but +% are scaled down if they would overflow the margins. +\makeatletter +\def\ScaleWidthIfNeeded{% + \ifdim\Gin@nat@width>\linewidth + \linewidth + \else + \Gin@nat@width + \fi +} +\def\ScaleHeightIfNeeded{% + \ifdim\Gin@nat@height>0.9\textheight + 0.9\textheight + \else + \Gin@nat@width + \fi +} +\makeatother +\setkeys{Gin}{width=\ScaleWidthIfNeeded,height=\ScaleHeightIfNeeded,keepaspectratio}% +$endif$ +\ifxetex + \usepackage[setpagesize=false, % page size defined by xetex + unicode=false, % unicode breaks when used with xetex + xetex]{hyperref} +\else + \usepackage[unicode=true]{hyperref} +\fi +\hypersetup{breaklinks=true, + bookmarks=true, + pdfauthor={$author-meta$}, + pdftitle={$title-meta$}, + colorlinks=true, + citecolor=$if(citecolor)$$citecolor$$else$blue$endif$, + urlcolor=$if(urlcolor)$$urlcolor$$else$blue$endif$, + linkcolor=$if(linkcolor)$$linkcolor$$else$magenta$endif$, + pdfborder={0 0 0}} +\urlstyle{same} % don't use monospace font for urls +$if(links-as-notes)$ +% Make links footnotes instead of hotlinks: +\renewcommand{\href}[2]{#2\footnote{\url{#1}}} +$endif$ +$if(strikeout)$ +\usepackage[normalem]{ulem} +% avoid problems with \sout in headers with hyperref: +\pdfstringdefDisableCommands{\renewcommand{\sout}{}} +$endif$ +\setlength{\parindent}{0pt} +\setlength{\parskip}{6pt plus 2pt minus 1pt} +\setlength{\emergencystretch}{3em} % prevent overfull lines +\providecommand{\tightlist}{% + \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} +$if(numbersections)$ +\setcounter{secnumdepth}{5} +$else$ +\setcounter{secnumdepth}{0} +$endif$ +$if(verbatim-in-note)$ +\VerbatimFootnotes % allows verbatim text in footnotes +$endif$ + +$if(title)$ +\title{$title$$if(subtitle)$\\\vspace{0.5em}{\large $subtitle$}$endif$} +$endif$ +$if(author)$ +\author{$for(author)$$author$$sep$ \and $endfor$} +$endif$ +\date{$date$} +$for(header-includes)$ +$header-includes$ +$endfor$ + +\begin{document} +$if(title)$ +% ---------- +% Title page +% ---------- + +\begin{titlepage} + +\definecolor{titlepagecolor}{cmyk}{1,.60,0,.40} +\definecolor{namecolor}{cmyk}{1,.50,0,.10} +\newgeometry{left=7.5cm} %defines the geometry for the titlepage +\pagecolor{titlepagecolor} +\begin{figure} + \centering + \includegraphics[width=3.2in]{img/c-plus-plus_logo.eps} +\end{figure} + +\color{white} +\makebox[0pt][l]{\rule{1.3\textwidth}{1pt}} +\par +\noindent +{\huge \textsf{C++ Insights}} +\par +\noindent +{\textit{\textsf{Some stuff that is good to know}}} +%\textbf{\textsf{Something}} \textcolor{namecolor}{\textsf{Else}} +\vfill +\noindent +%{\huge \textsf{C++ Insights}} +\vskip\baselineskip +\noindent +{\huge \textsf{Gregory Popovitch}} +\par +\textsf{Feb 2019 (Draft)} + +\end{titlepage} +\pagecolor{white} +\restoregeometry % restores the geometry + +% Filler page +%\null +%\thispagestyle{empty} +%\addtocounter{page}{-1} +%\newpage + +% Subtitle page +%\vfill{3in} +%\begin{centering} +%{\HUGE \textsf{C++ Insights}} +%\end{centering} + +%\thispagestyle{empty} +%\addtocounter{page}{-1} +%\newpage + +% Copyright page +\thispagestyle{empty} +\addtocounter{page}{-1} + +\begin{minipage}[b]{0.9\textwidth} +\footnotesize\raggedright +\setlength{\parskip}{0.5\baselineskip} + +\begin{textsf} +{\textbf{C++ Insights}}\\ +by Gregory Popovitch + +\par +Copyright \copyright\ 2019. \\ +\href{http://www.tbd.com}{www.tbd.com} + +\par +(c) copyright 2019, Steven Gregory Popovitch +\end{textsf} +\end{minipage} +\vspace*{2\baselineskip} +\cleardoublepage + +$endif$ +$if(abstract)$ +\begin{abstract} +$abstract$ +\end{abstract} +$endif$ + +$for(include-before)$ +$include-before$ + +$endfor$ +$if(toc)$ +{ +\hypersetup{linkcolor=black} +\setcounter{tocdepth}{$toc-depth$} +\tableofcontents +} +\pagebreak +$endif$ +$if(lot)$ +\listoftables +$endif$ +$if(lof)$ +\listoffigures +$endif$ +$body$ + +$if(natbib)$ +$if(biblio-files)$ +$if(biblio-title)$ +$if(book-class)$ +\renewcommand\bibname{$biblio-title$} +$else$ +\renewcommand\refname{$biblio-title$} +$endif$ +$endif$ +\bibliography{$biblio-files$} + +$endif$ +$endif$ +$if(biblatex)$ +\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$ + +$endif$ +$for(include-after)$ +$include-after$ + +$endfor$ +\end{document} diff --git a/extern/phmap/index.html b/extern/phmap/index.html new file mode 100644 index 0000000..4d269b9 --- /dev/null +++ b/extern/phmap/index.html @@ -0,0 +1,348 @@ + + + + + The Parallel Hashmap (Gregory Popovitch) + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+

\[\newcommand{\andalso}{\quad\quad} +\newcommand{\infabbrev}[2]{\infax{#1 \quad\eqdef\quad #2}} +\newcommand{\infrule}[2]{\displaystyle \dfrac{#1}{#2}} +\newcommand{\ar}{\rightarrow} +\newcommand{\Int}{\mathtt{Int}} +\newcommand{\Bool}{\mathtt{Bool}} +\newcommand{\becomes}{\Downarrow} +\newcommand{\trule}[1]{(\textbf{#1})} +\newcommand{\FV}[1]{\mathtt{fv}(#1)} +\newcommand{\FTV}[1]{\mathtt{ftv}(#1)} +\newcommand{\BV}[1]{\mathtt{bv}(#1)} +\newcommand{\compiles}[1]{\text{C}\llbracket{#1}\rrbracket} +\newcommand{\exec}[1]{\text{E}\llbracket{#1}\rrbracket} +\renewcommand{\t}[1]{\mathtt{#1}} +\newcommand{\ite}[3]{\text{if }#1\text{ then }#2\text{ else }#3} +\]

+
+

The Parallel Hashmap

+

or Abseiling from the shoulders of giants - © Gregory Popovitch - March 10, 2019

+

[tl;dr] We present a novel hashmap design, the Parallel Hashmap. Built on a modified version of Abseil's flat_hash_map, the Parallel Hashmap has lower space requirements, is nearly as fast as the underlying flat_hash_map, and can be used from multiple threads with high levels of concurrency. The parallel hashmap repository provides header-only version of the flat and node hashmaps, and their parallel versions as well.

+

A quick look at the current state of the art

+

If you haven't been living under a rock, you know that Google open sourced late last year their Abseil library, which includes a very efficient flat hash table implementation. The absl::flat_hash_map stores the values directly in a memory array, which avoids memory indirections (this is referred to as closed hashing).

+

closed_hashing

+

Using parallel SSE2 instructions, the flat hash table is able to look up items by checking 16 slots in parallel, which allows the implementation to remain fast even when the table is filled to 87.5% capacity.

+

The graphs below show a comparison of time and memory usage necessary to insert up to 100 million values (each value is composed of two 8-byte integers), between the default hashmap of Visual Studio 2017 (std::unordered_map), and Abseil's flat_hash_map:

+

stl_flat comparison

+

On the bottom graph, we can see that, as expected, the Abseil flat_hash_map is significantly faster that the default stl implementation, typically about three times faster.

+

The peak memory usage issue

+

The top graph shown the memory usage for both tables.

+

I used a separate thread to monitor the memory usage, which allows to track the increased memory usage when the table resizes. Indeed, both tables have a peak memory usage that is significantly higher than the memory usage seen between insertions.

+

In the case of Abseil's flat_hash_map, the values are stored directly in a memory array. The memory usage is constant until the table needs to resize, which is why we see these horizontal sections of memory usage.

+

When the flat_hash_map reaches 87.5% occupancy, a new array of twice the size is allocated, the values are moved (rehashed) from the smaller to the larger array, and then the smaller array, now empty, is freed. So we see that during the resize, the occupancy is only one third of 87.5%, or 29.1%, and when the smaller array is released, occupancy is half of 87.5% or 43.75%.

+

The default STL implementation is also subject to this higher peak memory usage, since it typically is implemented with an array of buckets, each bucket having a pointer to a linked list of nodes containing the values. In order to maintain O(1) lookups, the array of buckets also needs to be resized as the table size grows, requiring a 3x temporary memory requirement for moving the old bucket array (1x) to the newly allocated, larger (2x) array. In between the bucket array resizes, the default STL implementation memory usage grows at a constant rate as new values are added to the linked lists.

+
+

Instead of having a separate linked list for each bucket, std::unordered_map implementations often use a single linked list (making iteration faster), with buckets pointing to locations within the single linked list. absl::node_hash_map, on the other hand, has each bucket pointing to a single value, and collisions are handled with open addressing like for the absl::flat_hash_map.

+
+

This peak memory usage can be the limiting factor for large tables. Suppose you are on a machine with 32 GB of ram, and the flat_hash_map needs to resize when you inserted 10 GB of values in it. 10 GB of values means the array size is 11.42 GB (resizing at 87.5% occupancy), and we need to allocate a new array of double size (22.85 GB), which obviously will not be possible on our 32 GB machine.

+

For my work developing mechanical engineering software, this has kept me from using flat hash maps, as the high peak memory usage was the limiting factor for the size of FE models which could be loaded on a given machine. So I used other types of maps, such as sparsepp or Google's cpp-btree.

+

When the Abseil library was open sourced, I started pondering the issue again. Compared to Google's old dense_hash_map which resized at 50% capacity, the new absl::flat_hash_map resizing at 87.5% capacity was more memory friendly, but it still had these significant peaks of memory usage when resizing.

+

If only there was a way to eliminate those peaks, the flat_hash_map would be close to perfect. But how?

+

The peak memory usage solution

+

Suddenly, it hit me. I had a solution. I would create a hash table that internally is made of an array of 16 hash tables (the submaps). When inserting or looking up an item, the index of the target submap would be decided by the hash of the value to insert. For example, if for a given size_t hashval, the index for the internal submap would be computed with:

+

submap_index = (hashval ^ (hashval >> 4)) & 0xF;

+

providing an index between 0 and 15.

+
+

In the actual implementation, the size of the array of hash tables is configurable to a power of two, so it can be 2, 4, 8, 16, 32, ... The following illustration shows a parallel_hash_map with 8 submaps.

+
+

index_computation

+

The benefit of this approach would be that the internal tables would each resize on its own when they reach 87.5% capacity, and since each table contains approximately one sixteenth of the values, the memory usage peak would be only one sixteenth of the size we saw for the single flat_hash_map.

+

The rest of this article describes my implementation of this concept that I have done in my parallel hashmap repository. This is a header only library, which provides the following eight hashmaps:

+
    +
  • phmap::flat_hash_set
  • +
  • phmap::flat_hash_map
  • +
  • phmap::node_hash_set
  • +
  • phmap::node_hash_map
  • +
  • phmap::parallel_flat_hash_set
  • +
  • phmap::parallel_flat_hash_map
  • +
  • phmap::parallel_node_hash_set
  • +
  • phmap::parallel_node_hash_map
  • +
+

This implementation requires a C++11 compatible compiler, and provides full compatibility with the std::unordered_map (with the exception of pointer stability for the flat versions. C++14 and C++17 methods, like try-emplace, are provided as well. The names for it are parallel_flat_hash_map or parallel_flat_hash_set, and the node equivalents. These hashmaps provide the same external API as the flat_hash_map, and internally use a std::array of 2**N flat_hash_maps.

+

I was delighted to find out that not only the parallel_flat_hash_map has significant memory usage benefits compared to the flat_hash_map, but it also has significant advantages for concurrent programming as I will show later. In the rest of this article, we will focus on the parallel_flat_hash_map, but similar results are seen for the parallel_node_hash_map, and the set versions of course.

+

The Parallel Hashmap: memory usage

+

So, without further ado, let's see the same graphs graphs as above, with the addition of the parallel_flat_hash_map. Let us first look at memory usage (the second graph provides a "zoomed-in" view of the location where resizing occurs):

+

stl_flat_par comparison

+

stl_flat_par_zoomed comparison

+

We see that the parallel_flat_hash_map behaves as expected. The memory usage matches exactly the memory usage of its base flat_hash_map, except that the peaks of memory usage which occur when the table resizes are drastically reduced, to the point that they are not objectionable anymore. In the "zoomed-in" view, we can see the sixteen dots corresponding to each of the individual submaps resizing. The fact that those resizes are occuring at roughly the same x location in the graph shows that we have a good hash function distribution, distributing the values evenly between the sixteen individual submaps.

+

The Parallel Hashmap: speed

+

But what about the speed? After all, for each value inserted into the parallel hashmap, we have to do some extra work (steps 1 and 2 below):

+
    +
  1. compute the hash for the value to insert
  2. +
  3. compute the index of the target submap from the hash)
  4. +
  5. insert the value into the submap
  6. +
+

The first step (compute the hash) is the most problematic one, as it can potentially be costly. As we mentioned above, the second step (computing the index from the hash) is very simple and its cost in minimal (3 processor instruction as shown below in Matt Godbolt's compiler explorer):

+

index computation cost

+

As for the hash value computation, fortunately we can eliminate this cost by providing the computed hash to the submap functions, so that it is computed only once. This is exactly what I have done in my implementation of the parallel_flat_hash_map, adding a few extra APIs to the internal raw_hash_map.h header, which allow the parallel_flat_hash_map to pass the precomputed hash value to the underlying submaps.

+

So we have all but eliminated the cost of the first step, and seen that the cost of the second step is very minimal. At this point we expect that the parallel_flat_hash_map performance will be close to the one of its underlying flat_hash_map, and this is confirmed by the chart below:

+

stl_flat_par comparison

+

Indeed, because of the scale is somewhat compressed due to the longer times of the std::unordered_map, we can barely distinguish between the blue curve of the flat_hash_map and the red curve of the parallel_flat_hash_map. So let's look at a graph without the std::unordered_map:

+

flat_par comparison

+

This last graph shows that the parallel_flat_hash_map is slightly slower especially for smaller table sizes. For a reason not obvious to me (maybe better memory locality), the speeds of the parallel_flat_hash_map and flat_hash_map are essentially undistinguishable for larger map sizes (> 80 million values).

+

Are we done yet?

+

This is already looking pretty good. For large hash_maps, the parallel_flat_hash_map is a very appealing solution, as it provides essentially the excellent performance of the flat_hash_map, while virtually eliminating the peaks of memory usage which occur when the hash table resizes.

+

But there is another aspect of the inherent parallelism of the parallel_flat_hash_map which is interesting to explore. As we know, typical hashmaps cannot be modified from multiple threads without explicit synchronization. And bracketing write accesses to a shared hash_map with synchronization primitives, such as mutexes, can reduce the concurrency of our program, and even cause deadlocks.

+

Because the parallel_flat_hash_map is made of sixteen separate submaps, it posesses some intrinsic parallelism. Indeed, suppose you can make sure that different threads will use different submaps, you would be able to insert into the same parallel_flat_hash_map at the same time from the different threads without any locking.

+

Using the intrinsic parallelism of the parallel_flat_hash_map to insert values from multiple threads, lock free.

+

So, if you can iterate over the values you want to insert into the hash table, the idea is that each thread will iterate over all values, and then for each value:

+
    +
  1. compute the hash for that value
  2. +
  3. compute the submap index for that hash
  4. +
  5. if the submap index is one assigned to this thread, then insert the value, otherwise do nothing and continue to the next value
  6. +
+

Here is the code for the single-threaded insert:

+ +

and here is the code for the multi-threaded insert:

+
template <class HT>
+void _fill_random_inner_mt(int64_t cnt, HT &hash, RSU &rsu)
+{
+    constexpr int64_t num_threads = 8;   // has to be a power of two
+    std::unique_ptr<std::thread> threads[num_threads];
+
+    auto thread_fn = [&hash, cnt, num_threads](int64_t thread_idx, RSU rsu) {
+        size_t modulo = hash.subcnt() / num_threads;        // subcnt() returns the number of submaps
+
+        for (int64_t i=0; i<cnt; ++i)                       // iterate over all values
+        {
+            unsigned int key = rsu.next();                  // get next key to insert
+            size_t hashval = hash.hash(key);                // compute its hash
+            size_t idx  = hash.subidx(hashval);             // compute the submap index for this hash
+            if (idx / modulo == thread_idx)                 // if the submap is suitable for this thread
+            {
+                hash.insert(typename HT::value_type(key, 0)); // insert the value
+                ++(num_keys[thread_idx]);                     // increment count of inserted values
+            }
+        }
+    };
+
+    // create and start 8 threads - each will insert in their own submaps
+    // thread 0 will insert the keys whose hash direct them to submap0 or submap1
+    // thread 1 will insert the keys whose hash direct them to submap2 or submap3
+    // --------------------------------------------------------------------------
+    for (int64_t i=0; i<num_threads; ++i)
+        threads[i].reset(new std::thread(thread_fn, i, rsu));
+
+    // rsu passed by value to threads... we need to increment the reference object
+    for (int64_t i=0; i<cnt; ++i)
+        rsu.next();
+    
+    // wait for the threads to finish their work and exit
+    for (int64_t i=0; i<num_threads; ++i)
+        threads[i]->join();
+}
+

Using multiple threads, we are able to populate the parallel_flat_hash_map (inserting 100 million values) three times faster than the standard flat_hash_map (which we could not have populated from multiple threads without explicit locks, which would have prevented performance improvements).

+

And the graphical visualization of the results:

+

mt_stl_flat_par comparison

+

We notice in this last graph that the memory usage peaks, while still smaller than those of the flat_hash_map, are larger that those we saw when populating the parallel_flat_hash_map using a single thread. The obvious reason is that, when using a single thread, only one of the submaps would resize at a time, ensuring that the peak would only be 1/16th of the one for the flat_hash_map (provided of course that the hash function distributes the values somewhat evenly between the submaps).

+

When running in multi-threaded mode (in this case eight threads), potentially as many as eight submaps can resize simultaneaously, so for a parallel_flat_hash_map with sixteen submaps the memory peak size can be half as large as the one for the flat_hash_map.

+

Still, this is a pretty good result, we are now inserting values into our parallel_flat_hash_map three times faster than we were able to do using the flat_hash_map, while using a lower memory ceiling.

+

This is significant, as the speed of insertion into a hash map is important in many algorithms, for example removing duplicates in a collection of values.

+

Using the intrinsic parallelism of the parallel_flat_hash_map with internal mutexes

+

It may not be practical to add logic into your program to ensure you use different internal submaps from each thread. Still, locking the whole parallel_flat_hash_map for each access would forego taking advantage of its intrinsic parallelism.

+

For that reason, the parallel_flat_hash_map can provide internal locking using the std::mutex (the default template parameter is phmap::NullMutex, which does no locking and has no size cost). When selecting std::mutex, one mutex is created for each internal submap at a cost of 8 bytes per submap, and the parallel_flat_hash_map internally protects each submap access with its associated mutex.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
mapNumber of submapssizeof(map)
std::unordered_map (vs2017)-64
phmap::flat_hash_map-48
phmap::parallel_flat_hash_map, N=4, phmap::NullMutex16768
phmap::parallel_flat_hash_map, N=4, phmap::Mutex16896
+

It is about time we provide the complete parallel_flat_hash_map class declaration (the declaration for parallel_flat_hash_set is similar):

+
template <class K, class V,
+          class Hash      = phmap::priv::hash_default_hash<K>,
+          class Eq        = phmap::priv::hash_default_eq<K>,
+          class Allocator = phmap::priv::Allocator<std::pair<const K, V>>, // alias for std::allocator
+          size_t N        = 4,                 // 2**N submaps
+          class Mutex     = phmap::NullMutex>   // use std::mutex to enable internal locks
+class parallel_flat_hash_map;
+
+

Let's see what result we get for the insertion of random values from multiple threads, however this time we create a parallel_flat_hash_map with internal locking (by providing std::mutex as the last template argument), and modify the code so that each thread inserts values in any submap (no pre-selection).

+

no_preselection

+

If we were to do a intensive insertion test into a hash map from multiple threads, where we lock the whole hash table for each insertion, we would be likely to get even worse results than for a single threaded insert, because of heavy lock contention.

+

In this case, our expectation is that the finer grained locking of the parallel_flat_hash_map (separate locks for each internal submap) will provide a speed benefit when compared to the single threaded insertion, and this is indeed what the benchmarks show:

+

flat_par_mutex_4

+

Interestingly, we notice that the memory peaks (when resizing occur) are again very small, in the order of 1/16th of those for the flat_hash_map. This is likely because, as soon as one of the submaps resizes (which takes much longer than a regular insertion), the other threads very soon have to wait on the resizing submap's mutex for an insertion, before they reach their own resizing threashold.

+

Since threads statistically will insert on a different submap for each value, it would be a surprising coincidence indeed if two submaps reached their resizing threshold without the resizing of the first submap blocking all the other threads first.

+

If we increase the number of submaps, we should see more parallelism (less lock contention across threads, as the odds of two separate threads inserting in the same subhash is lower), but with diminishing returns as every submap resize will quickly block the other threads until the resize is completed.

+

This is indeed what we see:

+

lock_various_sizes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
mapNumber of submapssizeof(map)time 100M insertions
phmap::flat_hash_map-4814.77s
phmap::parallel_flat_hash_map, N=4, std::mutex168968.36s
phmap::parallel_flat_hash_map, N=5, std::mutex3217927.14s
phmap::parallel_flat_hash_map, N=6, std::mutex6435846.61s
+

There is still some overhead from the mutex lock/unlock, and the occasional lock contention, which prevents us from reaching the performance of the previous multithreaded lock-free insertion (5.12s for inserting 100M elements).

+

In Conclusion

+

We have seen that the novel parallel hashmap approach, used within a single thread, provides significant space advantages, with a very minimal time penalty. When used in a multi-thread context, the parallel hashmap still provides a significant space benefit, in addition to a consequential time benefit by reducing (or even eliminating) lock contention when accessing the parallel hashmap.

+

Future work

+
    +
  1. It would be beneficial to provide additional APIs for the parallel_flat_hash_map and parallel_flat_hash_set taking a precomputed hash value. This would enable the lock-free usage of the parallel_flat_hash_map, described above for multi-threaded environments, without requiring a double hash computation.
  2. +
+

Thanks

+

I would like to thank Google's Matt Kulukundis for his eye-opening presentation of the flat_hash_map design at CPPCON 2017 - my frustration with not being able to use it helped trigger my insight into the parallel_flat_hash_map. Also many thanks to the Abseil container developers - I believe the main contributors are Alkis Evlogimenos and Roman Perepelitsa - who created an excellent codebase into which the graft of this new hashmap took easily, and finally to Google for open-sourcing Abseil. Thanks also to my son Andre for reviewing this paper, and for his patience when I was rambling about the parallel_flat_hash_map and its benefits.

+ +

Repository for the Parallel Hashmap, including the benchmark code used in this paper

+

Swiss Tables doc

+

Google Abseil repository

+

Matt Kulukindis: Designing a Fast, Efficient, Cache-friendly Hash Table, Step by Step

+
+
+ +
+ + + diff --git a/extern/phmap/parallel_hashmap/btree.h b/extern/phmap/parallel_hashmap/btree.h new file mode 100644 index 0000000..cbfb8ee --- /dev/null +++ b/extern/phmap/parallel_hashmap/btree.h @@ -0,0 +1,4050 @@ +// --------------------------------------------------------------------------- +// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp) +// with modifications. +// +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// --------------------------------------------------------------------------- + +#ifndef PHMAP_BTREE_BTREE_CONTAINER_H_ +#define PHMAP_BTREE_BTREE_CONTAINER_H_ + +#ifdef _MSC_VER + #pragma warning(push) + + #pragma warning(disable : 4127) // conditional expression is constant + #pragma warning(disable : 4324) // structure was padded due to alignment specifier + #pragma warning(disable : 4355) // 'this': used in base member initializer list + #pragma warning(disable : 4365) // conversion from 'int' to 'const unsigned __int64', signed/unsigned mismatch + #pragma warning(disable : 4514) // unreferenced inline function has been removed + #pragma warning(disable : 4623) // default constructor was implicitly defined as deleted + #pragma warning(disable : 4625) // copy constructor was implicitly defined as deleted + #pragma warning(disable : 4626) // assignment operator was implicitly defined as deleted + #pragma warning(disable : 4710) // function not inlined + #pragma warning(disable : 4711) // selected for automatic inline expansion + #pragma warning(disable : 4820) // '6' bytes padding added after data member + #pragma warning(disable : 4868) // compiler may not enforce left-to-right evaluation order in braced initializer list + #pragma warning(disable : 5026) // move constructor was implicitly defined as deleted + #pragma warning(disable : 5027) // move assignment operator was implicitly defined as deleted + #pragma warning(disable : 5045) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +#endif + + +#include +#include +#include +#include +#include + +#include "phmap_fwd_decl.h" +#include "phmap_base.h" + +#if PHMAP_HAVE_STD_STRING_VIEW + #include +#endif + +// MSVC constructibility traits do not detect destructor properties and so our +// implementations should not use them as a source-of-truth. +#if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) + #define PHMAP_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION 1 +#endif + +namespace phmap { + + // Defined and documented later on in this file. + template + struct is_trivially_destructible; + + // Defined and documented later on in this file. + template + struct is_trivially_move_assignable; + + namespace type_traits_internal { + + // Silence MSVC warnings about the destructor being defined as deleted. +#if defined(_MSC_VER) && !defined(__GNUC__) + #pragma warning(push) + #pragma warning(disable : 4624) +#endif // defined(_MSC_VER) && !defined(__GNUC__) + + template + union SingleMemberUnion { + T t; + }; + + // Restore the state of the destructor warning that was silenced above. +#if defined(_MSC_VER) && !defined(__GNUC__) + #pragma warning(pop) +#endif // defined(_MSC_VER) && !defined(__GNUC__) + + template + struct IsTriviallyMoveConstructibleObject + : std::integral_constant< + bool, std::is_move_constructible< + type_traits_internal::SingleMemberUnion>::value && + phmap::is_trivially_destructible::value> {}; + + template + struct IsTriviallyCopyConstructibleObject + : std::integral_constant< + bool, std::is_copy_constructible< + type_traits_internal::SingleMemberUnion>::value && + phmap::is_trivially_destructible::value> {}; + + template + struct IsTriviallyMoveAssignableReference : std::false_type {}; + + template + struct IsTriviallyMoveAssignableReference + : phmap::is_trivially_move_assignable::type {}; + + template + struct IsTriviallyMoveAssignableReference + : phmap::is_trivially_move_assignable::type {}; + + } // namespace type_traits_internal + + + template + using void_t = typename type_traits_internal::VoidTImpl::type; + + + template + struct is_function + : std::integral_constant< + bool, !(std::is_reference::value || + std::is_const::type>::value)> {}; + + + namespace type_traits_internal { + + template + class is_trivially_copyable_impl { + using ExtentsRemoved = typename std::remove_all_extents::type; + static constexpr bool kIsCopyOrMoveConstructible = + std::is_copy_constructible::value || + std::is_move_constructible::value; + static constexpr bool kIsCopyOrMoveAssignable = + phmap::is_copy_assignable::value || + phmap::is_move_assignable::value; + + public: + static constexpr bool kValue = + (__has_trivial_copy(ExtentsRemoved) || !kIsCopyOrMoveConstructible) && + (__has_trivial_assign(ExtentsRemoved) || !kIsCopyOrMoveAssignable) && + (kIsCopyOrMoveConstructible || kIsCopyOrMoveAssignable) && + is_trivially_destructible::value && + // We need to check for this explicitly because otherwise we'll say + // references are trivial copyable when compiled by MSVC. + !std::is_reference::value; + }; + + template + struct is_trivially_copyable + : std::integral_constant< + bool, type_traits_internal::is_trivially_copyable_impl::kValue> {}; + } // namespace type_traits_internal + + namespace swap_internal { + + // Necessary for the traits. + using std::swap; + + // This declaration prevents global `swap` and `phmap::swap` overloads from being + // considered unless ADL picks them up. + void swap(); + + template + using IsSwappableImpl = decltype(swap(std::declval(), std::declval())); + + // NOTE: This dance with the default template parameter is for MSVC. + template (), std::declval()))>> + using IsNothrowSwappableImpl = typename std::enable_if::type; + + template + struct IsSwappable + : phmap::type_traits_internal::is_detected {}; + + template + struct IsNothrowSwappable + : phmap::type_traits_internal::is_detected {}; + + template ::value, int> = 0> + void Swap(T& lhs, T& rhs) noexcept(IsNothrowSwappable::value) { + swap(lhs, rhs); + } + + using StdSwapIsUnconstrained = IsSwappable; + + } // namespace swap_internal + + namespace type_traits_internal { + + // Make the swap-related traits/function accessible from this namespace. + using swap_internal::IsNothrowSwappable; + using swap_internal::IsSwappable; + using swap_internal::Swap; + using swap_internal::StdSwapIsUnconstrained; + + } // namespace type_traits_internal + + namespace compare_internal { + + using value_type = int8_t; + + template + struct Fail { + static_assert(sizeof(T) < 0, "Only literal `0` is allowed."); + }; + + template + struct OnlyLiteralZero { + constexpr OnlyLiteralZero(NullPtrT) noexcept {} // NOLINT + + template < + typename T, + typename = typename std::enable_if< + std::is_same::value || + (std::is_integral::value && !std::is_same::value)>::type, + typename = typename Fail::type> + OnlyLiteralZero(T); // NOLINT + }; + + enum class eq : value_type { + equal = 0, + equivalent = equal, + nonequal = 1, + nonequivalent = nonequal, + }; + + enum class ord : value_type { less = -1, greater = 1 }; + + enum class ncmp : value_type { unordered = -127 }; + +#if defined(__cpp_inline_variables) && !defined(_MSC_VER) + +#define PHMAP_COMPARE_INLINE_BASECLASS_DECL(name) + +#define PHMAP_COMPARE_INLINE_SUBCLASS_DECL(type, name) \ + static const type name; + +#define PHMAP_COMPARE_INLINE_INIT(type, name, init) \ + inline constexpr type type::name(init) + +#else // __cpp_inline_variables + +#define PHMAP_COMPARE_INLINE_BASECLASS_DECL(name) \ + static const T name; + +#define PHMAP_COMPARE_INLINE_SUBCLASS_DECL(type, name) + +#define PHMAP_COMPARE_INLINE_INIT(type, name, init) \ + template \ + const T compare_internal::type##_base::name(init) + +#endif // __cpp_inline_variables + + // These template base classes allow for defining the values of the constants + // in the header file (for performance) without using inline variables (which + // aren't available in C++11). + template + struct weak_equality_base { + PHMAP_COMPARE_INLINE_BASECLASS_DECL(equivalent) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(nonequivalent) + }; + + template + struct strong_equality_base { + PHMAP_COMPARE_INLINE_BASECLASS_DECL(equal) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(nonequal) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(equivalent) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(nonequivalent) + }; + + template + struct partial_ordering_base { + PHMAP_COMPARE_INLINE_BASECLASS_DECL(less) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(equivalent) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(greater) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(unordered) + }; + + template + struct weak_ordering_base { + PHMAP_COMPARE_INLINE_BASECLASS_DECL(less) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(equivalent) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(greater) + }; + + template + struct strong_ordering_base { + PHMAP_COMPARE_INLINE_BASECLASS_DECL(less) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(equal) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(equivalent) + PHMAP_COMPARE_INLINE_BASECLASS_DECL(greater) + }; + + } // namespace compare_internal + + class weak_equality + : public compare_internal::weak_equality_base { + explicit constexpr weak_equality(compare_internal::eq v) noexcept + : value_(static_cast(v)) {} + friend struct compare_internal::weak_equality_base; + + public: + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(weak_equality, equivalent) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(weak_equality, nonequivalent) + + // Comparisons + friend constexpr bool operator==( + weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ == 0; + } + friend constexpr bool operator!=( + weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ != 0; + } + friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>, + weak_equality v) noexcept { + return 0 == v.value_; + } + friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>, + weak_equality v) noexcept { + return 0 != v.value_; + } + + private: + compare_internal::value_type value_; + }; + PHMAP_COMPARE_INLINE_INIT(weak_equality, equivalent, + compare_internal::eq::equivalent); + PHMAP_COMPARE_INLINE_INIT(weak_equality, nonequivalent, + compare_internal::eq::nonequivalent); + + class strong_equality + : public compare_internal::strong_equality_base { + explicit constexpr strong_equality(compare_internal::eq v) noexcept + : value_(static_cast(v)) {} + friend struct compare_internal::strong_equality_base; + + public: + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, equal) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, nonequal) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, equivalent) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, nonequivalent) + + // Conversion + constexpr operator weak_equality() const noexcept { // NOLINT + return value_ == 0 ? weak_equality::equivalent + : weak_equality::nonequivalent; + } + // Comparisons + friend constexpr bool operator==( + strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ == 0; + } + friend constexpr bool operator!=( + strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ != 0; + } + friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>, + strong_equality v) noexcept { + return 0 == v.value_; + } + friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>, + strong_equality v) noexcept { + return 0 != v.value_; + } + + private: + compare_internal::value_type value_; + }; + + PHMAP_COMPARE_INLINE_INIT(strong_equality, equal, compare_internal::eq::equal); + PHMAP_COMPARE_INLINE_INIT(strong_equality, nonequal, + compare_internal::eq::nonequal); + PHMAP_COMPARE_INLINE_INIT(strong_equality, equivalent, + compare_internal::eq::equivalent); + PHMAP_COMPARE_INLINE_INIT(strong_equality, nonequivalent, + compare_internal::eq::nonequivalent); + + class partial_ordering + : public compare_internal::partial_ordering_base { + explicit constexpr partial_ordering(compare_internal::eq v) noexcept + : value_(static_cast(v)) {} + explicit constexpr partial_ordering(compare_internal::ord v) noexcept + : value_(static_cast(v)) {} + explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept + : value_(static_cast(v)) {} + friend struct compare_internal::partial_ordering_base; + + constexpr bool is_ordered() const noexcept { + return value_ != + compare_internal::value_type(compare_internal::ncmp::unordered); + } + + public: + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, less) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, equivalent) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, greater) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, unordered) + + // Conversion + constexpr operator weak_equality() const noexcept { // NOLINT + return value_ == 0 ? weak_equality::equivalent + : weak_equality::nonequivalent; + } + // Comparisons + friend constexpr bool operator==( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.is_ordered() && v.value_ == 0; + } + friend constexpr bool operator!=( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return !v.is_ordered() || v.value_ != 0; + } + friend constexpr bool operator<( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.is_ordered() && v.value_ < 0; + } + friend constexpr bool operator<=( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.is_ordered() && v.value_ <= 0; + } + friend constexpr bool operator>( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.is_ordered() && v.value_ > 0; + } + friend constexpr bool operator>=( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.is_ordered() && v.value_ >= 0; + } + friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return v.is_ordered() && 0 == v.value_; + } + friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return !v.is_ordered() || 0 != v.value_; + } + friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return v.is_ordered() && 0 < v.value_; + } + friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return v.is_ordered() && 0 <= v.value_; + } + friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return v.is_ordered() && 0 > v.value_; + } + friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return v.is_ordered() && 0 >= v.value_; + } + + private: + compare_internal::value_type value_; + }; + + PHMAP_COMPARE_INLINE_INIT(partial_ordering, less, compare_internal::ord::less); + PHMAP_COMPARE_INLINE_INIT(partial_ordering, equivalent, + compare_internal::eq::equivalent); + PHMAP_COMPARE_INLINE_INIT(partial_ordering, greater, + compare_internal::ord::greater); + PHMAP_COMPARE_INLINE_INIT(partial_ordering, unordered, + compare_internal::ncmp::unordered); + + class weak_ordering + : public compare_internal::weak_ordering_base { + explicit constexpr weak_ordering(compare_internal::eq v) noexcept + : value_(static_cast(v)) {} + explicit constexpr weak_ordering(compare_internal::ord v) noexcept + : value_(static_cast(v)) {} + friend struct compare_internal::weak_ordering_base; + + public: + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, less) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, equivalent) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, greater) + + // Conversions + constexpr operator weak_equality() const noexcept { // NOLINT + return value_ == 0 ? weak_equality::equivalent + : weak_equality::nonequivalent; + } + constexpr operator partial_ordering() const noexcept { // NOLINT + return value_ == 0 ? partial_ordering::equivalent + : (value_ < 0 ? partial_ordering::less + : partial_ordering::greater); + } + // Comparisons + friend constexpr bool operator==( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ == 0; + } + friend constexpr bool operator!=( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ != 0; + } + friend constexpr bool operator<( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ < 0; + } + friend constexpr bool operator<=( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ <= 0; + } + friend constexpr bool operator>( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ > 0; + } + friend constexpr bool operator>=( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ >= 0; + } + friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 == v.value_; + } + friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 != v.value_; + } + friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 < v.value_; + } + friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 <= v.value_; + } + friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 > v.value_; + } + friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 >= v.value_; + } + + private: + compare_internal::value_type value_; + }; + + PHMAP_COMPARE_INLINE_INIT(weak_ordering, less, compare_internal::ord::less); + PHMAP_COMPARE_INLINE_INIT(weak_ordering, equivalent, + compare_internal::eq::equivalent); + PHMAP_COMPARE_INLINE_INIT(weak_ordering, greater, + compare_internal::ord::greater); + + class strong_ordering + : public compare_internal::strong_ordering_base { + explicit constexpr strong_ordering(compare_internal::eq v) noexcept + : value_(static_cast(v)) {} + explicit constexpr strong_ordering(compare_internal::ord v) noexcept + : value_(static_cast(v)) {} + friend struct compare_internal::strong_ordering_base; + + public: + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, less) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equal) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equivalent) + PHMAP_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, greater) + + // Conversions + constexpr operator weak_equality() const noexcept { // NOLINT + return value_ == 0 ? weak_equality::equivalent + : weak_equality::nonequivalent; + } + constexpr operator strong_equality() const noexcept { // NOLINT + return value_ == 0 ? strong_equality::equal : strong_equality::nonequal; + } + constexpr operator partial_ordering() const noexcept { // NOLINT + return value_ == 0 ? partial_ordering::equivalent + : (value_ < 0 ? partial_ordering::less + : partial_ordering::greater); + } + constexpr operator weak_ordering() const noexcept { // NOLINT + return value_ == 0 + ? weak_ordering::equivalent + : (value_ < 0 ? weak_ordering::less : weak_ordering::greater); + } + // Comparisons + friend constexpr bool operator==( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ == 0; + } + friend constexpr bool operator!=( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ != 0; + } + friend constexpr bool operator<( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ < 0; + } + friend constexpr bool operator<=( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ <= 0; + } + friend constexpr bool operator>( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ > 0; + } + friend constexpr bool operator>=( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ >= 0; + } + friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 == v.value_; + } + friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 != v.value_; + } + friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 < v.value_; + } + friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 <= v.value_; + } + friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 > v.value_; + } + friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 >= v.value_; + } + + private: + compare_internal::value_type value_; + }; + PHMAP_COMPARE_INLINE_INIT(strong_ordering, less, compare_internal::ord::less); + PHMAP_COMPARE_INLINE_INIT(strong_ordering, equal, compare_internal::eq::equal); + PHMAP_COMPARE_INLINE_INIT(strong_ordering, equivalent, + compare_internal::eq::equivalent); + PHMAP_COMPARE_INLINE_INIT(strong_ordering, greater, + compare_internal::ord::greater); + +#undef PHMAP_COMPARE_INLINE_BASECLASS_DECL +#undef PHMAP_COMPARE_INLINE_SUBCLASS_DECL +#undef PHMAP_COMPARE_INLINE_INIT + + namespace compare_internal { + // We also provide these comparator adapter functions for internal phmap use. + + // Helper functions to do a boolean comparison of two keys given a boolean + // or three-way comparator. + // SFINAE prevents implicit conversions to bool (such as from int). + template ::value, int> = 0> + constexpr bool compare_result_as_less_than(const BoolType r) { return r; } + constexpr bool compare_result_as_less_than(const phmap::weak_ordering r) { + return r < 0; + } + + template + constexpr bool do_less_than_comparison(const Compare &compare, const K &x, + const LK &y) { + return compare_result_as_less_than(compare(x, y)); + } + + // Helper functions to do a three-way comparison of two keys given a boolean or + // three-way comparator. + // SFINAE prevents implicit conversions to int (such as from bool). + template ::value, int> = 0> + constexpr phmap::weak_ordering compare_result_as_ordering(const Int c) { + return c < 0 ? phmap::weak_ordering::less + : c == 0 ? phmap::weak_ordering::equivalent + : phmap::weak_ordering::greater; + } + constexpr phmap::weak_ordering compare_result_as_ordering( + const phmap::weak_ordering c) { + return c; + } + + template < + typename Compare, typename K, typename LK, + phmap::enable_if_t>::value, + int> = 0> + constexpr phmap::weak_ordering do_three_way_comparison(const Compare &compare, + const K &x, const LK &y) { + return compare_result_as_ordering(compare(x, y)); + } + template < + typename Compare, typename K, typename LK, + phmap::enable_if_t>::value, + int> = 0> + constexpr phmap::weak_ordering do_three_way_comparison(const Compare &compare, + const K &x, const LK &y) { + return compare(x, y) ? phmap::weak_ordering::less + : compare(y, x) ? phmap::weak_ordering::greater + : phmap::weak_ordering::equivalent; + } + + } // namespace compare_internal +} + + +namespace phmap { + +namespace priv { + + // A helper class that indicates if the Compare parameter is a key-compare-to + // comparator. + template + using btree_is_key_compare_to = + std::is_convertible, + phmap::weak_ordering>; + + struct StringBtreeDefaultLess { + using is_transparent = void; + + StringBtreeDefaultLess() = default; + + // Compatibility constructor. + StringBtreeDefaultLess(std::less) {} // NOLINT +#if PHMAP_HAVE_STD_STRING_VIEW + StringBtreeDefaultLess(std::less) {} // NOLINT + StringBtreeDefaultLess(phmap::Less) {} // NOLINT + + phmap::weak_ordering operator()(std::string_view lhs, + std::string_view rhs) const { + return compare_internal::compare_result_as_ordering(lhs.compare(rhs)); + } +#else + phmap::weak_ordering operator()(std::string lhs, + std::string rhs) const { + return compare_internal::compare_result_as_ordering(lhs.compare(rhs)); + } +#endif + }; + + struct StringBtreeDefaultGreater { + using is_transparent = void; + + StringBtreeDefaultGreater() = default; + + StringBtreeDefaultGreater(std::greater) {} // NOLINT +#if PHMAP_HAVE_STD_STRING_VIEW + StringBtreeDefaultGreater(std::greater) {} // NOLINT + + phmap::weak_ordering operator()(std::string_view lhs, + std::string_view rhs) const { + return compare_internal::compare_result_as_ordering(rhs.compare(lhs)); + } +#else + phmap::weak_ordering operator()(std::string lhs, + std::string rhs) const { + return compare_internal::compare_result_as_ordering(rhs.compare(lhs)); + } +#endif + }; + + // A helper class to convert a boolean comparison into a three-way "compare-to" + // comparison that returns a negative value to indicate less-than, zero to + // indicate equality and a positive value to indicate greater-than. This helper + // class is specialized for less, greater, + // less, and greater. + // + // key_compare_to_adapter is provided so that btree users + // automatically get the more efficient compare-to code when using common + // google string types with common comparison functors. + // These string-like specializations also turn on heterogeneous lookup by + // default. + template + struct key_compare_to_adapter { + using type = Compare; + }; + + template <> + struct key_compare_to_adapter> { + using type = StringBtreeDefaultLess; + }; + + template <> + struct key_compare_to_adapter> { + using type = StringBtreeDefaultLess; + }; + + template <> + struct key_compare_to_adapter> { + using type = StringBtreeDefaultGreater; + }; + +#if PHMAP_HAVE_STD_STRING_VIEW + template <> + struct key_compare_to_adapter> { + using type = StringBtreeDefaultLess; + }; + + template <> + struct key_compare_to_adapter> { + using type = StringBtreeDefaultLess; + }; + + template <> + struct key_compare_to_adapter> { + using type = StringBtreeDefaultGreater; + }; +#endif + + template + struct common_params { + // If Compare is a common comparator for a std::string-like type, then we adapt it + // to use heterogeneous lookup and to be a key-compare-to comparator. + using key_compare = typename key_compare_to_adapter::type; + // A type which indicates if we have a key-compare-to functor or a plain old + // key-compare functor. + using is_key_compare_to = btree_is_key_compare_to; + + using allocator_type = Alloc; + using key_type = Key; + using size_type = std::size_t ; + using difference_type = ptrdiff_t; + + // True if this is a multiset or multimap. + using is_multi_container = std::integral_constant; + + using slot_policy = SlotPolicy; + using slot_type = typename slot_policy::slot_type; + using value_type = typename slot_policy::value_type; + using init_type = typename slot_policy::mutable_value_type; + using pointer = value_type *; + using const_pointer = const value_type *; + using reference = value_type &; + using const_reference = const value_type &; + + enum { + kTargetNodeSize = TargetNodeSize, + + // Upper bound for the available space for values. This is largest for leaf + // nodes, which have overhead of at least a pointer + 4 bytes (for storing + // 3 field_types and an enum). + kNodeValueSpace = + TargetNodeSize - /*minimum overhead=*/(sizeof(void *) + 4), + }; + + // This is an integral type large enough to hold as many + // ValueSize-values as will fit a node of TargetNodeSize bytes. + using node_count_type = + phmap::conditional_t<(kNodeValueSpace / sizeof(value_type) > + (std::numeric_limits::max)()), + uint16_t, uint8_t>; // NOLINT + + // The following methods are necessary for passing this struct as PolicyTraits + // for node_handle and/or are used within btree. + static value_type &element(slot_type *slot) { + return slot_policy::element(slot); + } + static const value_type &element(const slot_type *slot) { + return slot_policy::element(slot); + } + template + static void construct(Alloc *alloc, slot_type *slot, Args &&... args) { + slot_policy::construct(alloc, slot, std::forward(args)...); + } + static void construct(Alloc *alloc, slot_type *slot, slot_type *other) { + slot_policy::construct(alloc, slot, other); + } + static void destroy(Alloc *alloc, slot_type *slot) { + slot_policy::destroy(alloc, slot); + } + static void transfer(Alloc *alloc, slot_type *new_slot, slot_type *old_slot) { + construct(alloc, new_slot, old_slot); + destroy(alloc, old_slot); + } + static void swap(Alloc *alloc, slot_type *a, slot_type *b) { + slot_policy::swap(alloc, a, b); + } + static void move(Alloc *alloc, slot_type *src, slot_type *dest) { + slot_policy::move(alloc, src, dest); + } + static void move(Alloc *alloc, slot_type *first, slot_type *last, + slot_type *result) { + slot_policy::move(alloc, first, last, result); + } + }; + + // A parameters structure for holding the type parameters for a btree_map. + // Compare and Alloc should be nothrow copy-constructible. + template + struct map_params : common_params> { + using super_type = typename map_params::common_params; + using mapped_type = Data; + // This type allows us to move keys when it is safe to do so. It is safe + // for maps in which value_type and mutable_value_type are layout compatible. + using slot_policy = typename super_type::slot_policy; + using slot_type = typename super_type::slot_type; + using value_type = typename super_type::value_type; + using init_type = typename super_type::init_type; + + using key_compare = typename super_type::key_compare; + // Inherit from key_compare for empty base class optimization. + struct value_compare : private key_compare { + value_compare() = default; + explicit value_compare(const key_compare &cmp) : key_compare(cmp) {} + + template + auto operator()(const T &left, const U &right) const + -> decltype(std::declval()(left.first, right.first)) { + return key_compare::operator()(left.first, right.first); + } + }; + using is_map_container = std::true_type; + + static const Key &key(const value_type &x) { return x.first; } + static const Key &key(const init_type &x) { return x.first; } + static const Key &key(const slot_type *x) { return slot_policy::key(x); } + static mapped_type &value(value_type *value) { return value->second; } + }; + + // This type implements the necessary functions from the + // btree::priv::slot_type interface. + template + struct set_slot_policy { + using slot_type = Key; + using value_type = Key; + using mutable_value_type = Key; + + static value_type &element(slot_type *slot) { return *slot; } + static const value_type &element(const slot_type *slot) { return *slot; } + + template + static void construct(Alloc *alloc, slot_type *slot, Args &&... args) { + phmap::allocator_traits::construct(*alloc, slot, + std::forward(args)...); + } + + template + static void construct(Alloc *alloc, slot_type *slot, slot_type *other) { + phmap::allocator_traits::construct(*alloc, slot, std::move(*other)); + } + + template + static void destroy(Alloc *alloc, slot_type *slot) { + phmap::allocator_traits::destroy(*alloc, slot); + } + + template + static void swap(Alloc * /*alloc*/, slot_type *a, slot_type *b) { + using std::swap; + swap(*a, *b); + } + + template + static void move(Alloc * /*alloc*/, slot_type *src, slot_type *dest) { + *dest = std::move(*src); + } + + template + static void move(Alloc *alloc, slot_type *first, slot_type *last, + slot_type *result) { + for (slot_type *src = first, *dest = result; src != last; ++src, ++dest) + move(alloc, src, dest); + } + }; + + // A parameters structure for holding the type parameters for a btree_set. + // Compare and Alloc should be nothrow copy-constructible. + template + struct set_params : common_params> { + using value_type = Key; + using slot_type = typename set_params::common_params::slot_type; + using value_compare = typename set_params::common_params::key_compare; + using is_map_container = std::false_type; + + static const Key &key(const value_type &x) { return x; } + static const Key &key(const slot_type *x) { return *x; } + }; + + // An adapter class that converts a lower-bound compare into an upper-bound + // compare. Note: there is no need to make a version of this adapter specialized + // for key-compare-to functors because the upper-bound (the first value greater + // than the input) is never an exact match. + template + struct upper_bound_adapter { + explicit upper_bound_adapter(const Compare &c) : comp(c) {} + template + bool operator()(const K &a, const LK &b) const { + // Returns true when a is not greater than b. + return !phmap::compare_internal::compare_result_as_less_than(comp(b, a)); + } + + private: + Compare comp; + }; + + enum class MatchKind : uint8_t { kEq, kNe }; + + template + struct SearchResult { + V value; + MatchKind match; + + static constexpr bool HasMatch() { return true; } + bool IsEq() const { return match == MatchKind::kEq; } + }; + + // When we don't use CompareTo, `match` is not present. + // This ensures that callers can't use it accidentally when it provides no + // useful information. + template + struct SearchResult { + V value; + + static constexpr bool HasMatch() { return false; } + static constexpr bool IsEq() { return false; } + }; + + // A node in the btree holding. The same node type is used for both internal + // and leaf nodes in the btree, though the nodes are allocated in such a way + // that the children array is only valid in internal nodes. + template + class btree_node { + using is_key_compare_to = typename Params::is_key_compare_to; + using is_multi_container = typename Params::is_multi_container; + using field_type = typename Params::node_count_type; + using allocator_type = typename Params::allocator_type; + using slot_type = typename Params::slot_type; + + public: + using params_type = Params; + using key_type = typename Params::key_type; + using value_type = typename Params::value_type; + using pointer = typename Params::pointer; + using const_pointer = typename Params::const_pointer; + using reference = typename Params::reference; + using const_reference = typename Params::const_reference; + using key_compare = typename Params::key_compare; + using size_type = typename Params::size_type; + using difference_type = typename Params::difference_type; + + // Btree decides whether to use linear node search as follows: + // - If the key is arithmetic and the comparator is std::less or + // std::greater, choose linear. + // - Otherwise, choose binary. + // TODO(ezb): Might make sense to add condition(s) based on node-size. + using use_linear_search = std::integral_constant< + bool, + std::is_arithmetic::value && + (std::is_same, key_compare>::value || + std::is_same, key_compare>::value || + std::is_same, key_compare>::value)>; + + + ~btree_node() = default; + btree_node(btree_node const &) = delete; + btree_node &operator=(btree_node const &) = delete; + + // Public for EmptyNodeType. + constexpr static size_type Alignment() { + static_assert(LeafLayout(1).Alignment() == InternalLayout().Alignment(), + "Alignment of all nodes must be equal."); + return (size_type)InternalLayout().Alignment(); + } + + protected: + btree_node() = default; + + private: + using layout_type = phmap::priv::Layout; + constexpr static size_type SizeWithNValues(size_type n) { + return (size_type)layout_type(/*parent*/ 1, + /*position, start, count, max_count*/ 4, + /*values*/ (size_t)n, + /*children*/ 0) + .AllocSize(); + } + // A lower bound for the overhead of fields other than values in a leaf node. + constexpr static size_type MinimumOverhead() { + return (size_type)(SizeWithNValues(1) - sizeof(value_type)); + } + + // Compute how many values we can fit onto a leaf node taking into account + // padding. + constexpr static size_type NodeTargetValues(const int begin, const int end) { + return begin == end ? begin + : SizeWithNValues((begin + end) / 2 + 1) > + params_type::kTargetNodeSize + ? NodeTargetValues(begin, (begin + end) / 2) + : NodeTargetValues((begin + end) / 2 + 1, end); + } + + enum { + kTargetNodeSize = params_type::kTargetNodeSize, + kNodeTargetValues = NodeTargetValues(0, params_type::kTargetNodeSize), + + // We need a minimum of 3 values per internal node in order to perform + // splitting (1 value for the two nodes involved in the split and 1 value + // propagated to the parent as the delimiter for the split). + kNodeValues = kNodeTargetValues >= 3 ? kNodeTargetValues : 3, + + // The node is internal (i.e. is not a leaf node) if and only if `max_count` + // has this value. + kInternalNodeMaxCount = 0, + }; + + // Leaves can have less than kNodeValues values. + constexpr static layout_type LeafLayout(const int max_values = kNodeValues) { + return layout_type(/*parent*/ 1, + /*position, start, count, max_count*/ 4, + /*values*/ (size_t)max_values, + /*children*/ 0); + } + constexpr static layout_type InternalLayout() { + return layout_type(/*parent*/ 1, + /*position, start, count, max_count*/ 4, + /*values*/ kNodeValues, + /*children*/ kNodeValues + 1); + } + constexpr static size_type LeafSize(const int max_values = kNodeValues) { + return (size_type)LeafLayout(max_values).AllocSize(); + } + constexpr static size_type InternalSize() { + return (size_type)InternalLayout().AllocSize(); + } + + // N is the index of the type in the Layout definition. + // ElementType is the Nth type in the Layout definition. + template + inline typename layout_type::template ElementType *GetField() { + // We assert that we don't read from values that aren't there. + assert(N < 3 || !leaf()); + return InternalLayout().template Pointer(reinterpret_cast(this)); + } + + template + inline const typename layout_type::template ElementType *GetField() const { + assert(N < 3 || !leaf()); + return InternalLayout().template Pointer( + reinterpret_cast(this)); + } + + void set_parent(btree_node *p) { *GetField<0>() = p; } + field_type &mutable_count() { return GetField<1>()[2]; } + slot_type *slot(size_type i) { return &GetField<2>()[i]; } + const slot_type *slot(size_type i) const { return &GetField<2>()[i]; } + void set_position(field_type v) { GetField<1>()[0] = v; } + void set_start(field_type v) { GetField<1>()[1] = v; } + void set_count(field_type v) { GetField<1>()[2] = v; } + void set_max_count(field_type v) { GetField<1>()[3] = v; } + + public: + // Whether this is a leaf node or not. This value doesn't change after the + // node is created. + bool leaf() const { return GetField<1>()[3] != kInternalNodeMaxCount; } + + // Getter for the position of this node in its parent. + field_type position() const { return GetField<1>()[0]; } + + // Getter for the offset of the first value in the `values` array. + field_type start() const { return GetField<1>()[1]; } + + // Getters for the number of values stored in this node. + field_type count() const { return GetField<1>()[2]; } + field_type max_count() const { + // Internal nodes have max_count==kInternalNodeMaxCount. + // Leaf nodes have max_count in [1, kNodeValues]. + const field_type max_cnt = GetField<1>()[3]; + return max_cnt == field_type{kInternalNodeMaxCount} + ? field_type{kNodeValues} + : max_cnt; + } + + // Getter for the parent of this node. + btree_node *parent() const { return *GetField<0>(); } + // Getter for whether the node is the root of the tree. The parent of the + // root of the tree is the leftmost node in the tree which is guaranteed to + // be a leaf. + bool is_root() const { return parent()->leaf(); } + void make_root() { + assert(parent()->is_root()); + set_parent(parent()->parent()); + } + + // Getters for the key/value at position i in the node. + const key_type &key(size_type i) const { return params_type::key(slot(i)); } + reference value(size_type i) { return params_type::element(slot(i)); } + const_reference value(size_type i) const { return params_type::element(slot(i)); } + + // Getters/setter for the child at position i in the node. + btree_node *child(size_type i) const { return GetField<3>()[i]; } + btree_node *&mutable_child(size_type i) { return GetField<3>()[i]; } + void clear_child(size_type i) { + phmap::priv::SanitizerPoisonObject(&mutable_child(i)); + } + void set_child(size_type i, btree_node *c) { + phmap::priv::SanitizerUnpoisonObject(&mutable_child(i)); + mutable_child(i) = c; + c->set_position((field_type)i); + } + void init_child(int i, btree_node *c) { + set_child(i, c); + c->set_parent(this); + } + + // Returns the position of the first value whose key is not less than k. + template + SearchResult lower_bound( + const K &k, const key_compare &comp) const { + return use_linear_search::value ? linear_search(k, comp) + : binary_search(k, comp); + } + // Returns the position of the first value whose key is greater than k. + template + int upper_bound(const K &k, const key_compare &comp) const { + auto upper_compare = upper_bound_adapter(comp); + return use_linear_search::value ? linear_search(k, upper_compare).value + : binary_search(k, upper_compare).value; + } + + template + SearchResult::value> + linear_search(const K &k, const Compare &comp) const { + return linear_search_impl(k, 0, count(), comp, + btree_is_key_compare_to()); + } + + template + SearchResult::value> + binary_search(const K &k, const Compare &comp) const { + return binary_search_impl(k, 0, count(), comp, + btree_is_key_compare_to()); + } + + // Returns the position of the first value whose key is not less than k using + // linear search performed using plain compare. + template + SearchResult linear_search_impl( + const K &k, int s, const int e, const Compare &comp, + std::false_type /* IsCompareTo */) const { + while (s < e) { + if (!comp(key(s), k)) { + break; + } + ++s; + } + return {s}; + } + + // Returns the position of the first value whose key is not less than k using + // linear search performed using compare-to. + template + SearchResult linear_search_impl( + const K &k, int s, const int e, const Compare &comp, + std::true_type /* IsCompareTo */) const { + while (s < e) { + const phmap::weak_ordering c = comp(key(s), k); + if (c == 0) { + return {s, MatchKind::kEq}; + } else if (c > 0) { + break; + } + ++s; + } + return {s, MatchKind::kNe}; + } + + // Returns the position of the first value whose key is not less than k using + // binary search performed using plain compare. + template + SearchResult binary_search_impl( + const K &k, int s, int e, const Compare &comp, + std::false_type /* IsCompareTo */) const { + while (s != e) { + const int mid = (s + e) >> 1; + if (comp(key(mid), k)) { + s = mid + 1; + } else { + e = mid; + } + } + return {s}; + } + + // Returns the position of the first value whose key is not less than k using + // binary search performed using compare-to. + template + SearchResult binary_search_impl( + const K &k, int s, int e, const CompareTo &comp, + std::true_type /* IsCompareTo */) const { + if (is_multi_container::value) { + MatchKind exact_match = MatchKind::kNe; + while (s != e) { + const int mid = (s + e) >> 1; + const phmap::weak_ordering c = comp(key(mid), k); + if (c < 0) { + s = mid + 1; + } else { + e = mid; + if (c == 0) { + // Need to return the first value whose key is not less than k, + // which requires continuing the binary search if this is a + // multi-container. + exact_match = MatchKind::kEq; + } + } + } + return {s, exact_match}; + } else { // Not a multi-container. + while (s != e) { + const int mid = (s + e) >> 1; + const phmap::weak_ordering c = comp(key(mid), k); + if (c < 0) { + s = mid + 1; + } else if (c > 0) { + e = mid; + } else { + return {mid, MatchKind::kEq}; + } + } + return {s, MatchKind::kNe}; + } + } + + // Emplaces a value at position i, shifting all existing values and + // children at positions >= i to the right by 1. + template + void emplace_value(size_type i, allocator_type *alloc, Args &&... args); + + // Removes the value at position i, shifting all existing values and children + // at positions > i to the left by 1. + void remove_value(int i, allocator_type *alloc); + + // Removes the values at positions [i, i + to_erase), shifting all values + // after that range to the left by to_erase. Does not change children at all. + void remove_values_ignore_children(int i, size_type to_erase, + allocator_type *alloc); + + // Rebalances a node with its right sibling. + void rebalance_right_to_left(int to_move, btree_node *right, + allocator_type *alloc); + void rebalance_left_to_right(int to_move, btree_node *right, + allocator_type *alloc); + + // Splits a node, moving a portion of the node's values to its right sibling. + void split(int insert_position, btree_node *dest, allocator_type *alloc); + + // Merges a node with its right sibling, moving all of the values and the + // delimiting key in the parent node onto itself. + void merge(btree_node *sibling, allocator_type *alloc); + + // Swap the contents of "this" and "src". + void swap(btree_node *src, allocator_type *alloc); + + // Node allocation/deletion routines. + static btree_node *init_leaf(btree_node *n, btree_node *parent, + int max_cnt) { + n->set_parent(parent); + n->set_position(0); + n->set_start(0); + n->set_count(0); + n->set_max_count((field_type)max_cnt); + phmap::priv::SanitizerPoisonMemoryRegion( + n->slot(0), max_cnt * sizeof(slot_type)); + return n; + } + static btree_node *init_internal(btree_node *n, btree_node *parent) { + init_leaf(n, parent, kNodeValues); + // Set `max_count` to a sentinel value to indicate that this node is + // internal. + n->set_max_count(kInternalNodeMaxCount); + phmap::priv::SanitizerPoisonMemoryRegion( + &n->mutable_child(0), (kNodeValues + 1) * sizeof(btree_node *)); + return n; + } + void destroy(allocator_type *alloc) { + for (int i = 0; i < count(); ++i) { + value_destroy(i, alloc); + } + } + + public: + // Exposed only for tests. + static bool testonly_uses_linear_node_search() { + return use_linear_search::value; + } + + private: + template + void value_init(const size_type i, allocator_type *alloc, Args &&... args) { + phmap::priv::SanitizerUnpoisonObject(slot(i)); + params_type::construct(alloc, slot(i), std::forward(args)...); + } + void value_destroy(const size_type i, allocator_type *alloc) { + params_type::destroy(alloc, slot(i)); + phmap::priv::SanitizerPoisonObject(slot(i)); + } + + // Move n values starting at value i in this node into the values starting at + // value j in node x. + void uninitialized_move_n(const size_type n, const size_type i, + const size_type j, btree_node *x, + allocator_type *alloc) { + phmap::priv::SanitizerUnpoisonMemoryRegion( + x->slot(j), n * sizeof(slot_type)); + for (slot_type *src = slot(i), *end = src + n, *dest = x->slot(j); + src != end; ++src, ++dest) { + params_type::construct(alloc, dest, src); + } + } + + // Destroys a range of n values, starting at index i. + void value_destroy_n(const size_type i, const size_type n, + allocator_type *alloc) { + for (size_type j = 0; j < n; ++j) { + value_destroy(i + j, alloc); + } + } + + template + friend class btree; + template + friend struct btree_iterator; + friend class BtreeNodePeer; + }; + + template + struct btree_iterator { + private: + using key_type = typename Node::key_type; + using size_type = typename Node::size_type; + using params_type = typename Node::params_type; + + using node_type = Node; + using normal_node = typename std::remove_const::type; + using const_node = const Node; + using normal_pointer = typename params_type::pointer; + using normal_reference = typename params_type::reference; + using const_pointer = typename params_type::const_pointer; + using const_reference = typename params_type::const_reference; + using slot_type = typename params_type::slot_type; + + using iterator = + btree_iterator; + using const_iterator = + btree_iterator; + + public: + // These aliases are public for std::iterator_traits. + using difference_type = typename Node::difference_type; + using value_type = typename params_type::value_type; + using pointer = Pointer; + using reference = Reference; + using iterator_category = std::bidirectional_iterator_tag; + + btree_iterator() : node(nullptr), position(-1) {} + btree_iterator(Node *n, int p) : node(n), position(p) {} + + // NOTE: this SFINAE allows for implicit conversions from iterator to + // const_iterator, but it specifically avoids defining copy constructors so + // that btree_iterator can be trivially copyable. This is for performance and + // binary size reasons. + template , iterator>::value && + std::is_same::value, + int> = 0> + btree_iterator(const btree_iterator &x) // NOLINT + : node(x.node), position(x.position) {} + + private: + // This SFINAE allows explicit conversions from const_iterator to + // iterator, but also avoids defining a copy constructor. + // NOTE: the const_cast is safe because this constructor is only called by + // non-const methods and the container owns the nodes. + template , const_iterator>::value && + std::is_same::value, + int> = 0> + explicit btree_iterator(const btree_iterator &x) + : node(const_cast(x.node)), position(x.position) {} + + // Increment/decrement the iterator. + void increment() { + if (node->leaf() && ++position < node->count()) { + return; + } + increment_slow(); + } + void increment_slow(); + + void decrement() { + if (node->leaf() && --position >= 0) { + return; + } + decrement_slow(); + } + void decrement_slow(); + + public: + bool operator==(const const_iterator &x) const { + return node == x.node && position == x.position; + } + bool operator!=(const const_iterator &x) const { + return node != x.node || position != x.position; + } + + // Accessors for the key/value the iterator is pointing at. + reference operator*() const { + return node->value(position); + } + pointer operator->() const { + return &node->value(position); + } + + btree_iterator& operator++() { + increment(); + return *this; + } + btree_iterator& operator--() { + decrement(); + return *this; + } + btree_iterator operator++(int) { + btree_iterator tmp = *this; + ++*this; + return tmp; + } + btree_iterator operator--(int) { + btree_iterator tmp = *this; + --*this; + return tmp; + } + + private: + template + friend class btree; + template + friend class btree_container; + template + friend class btree_set_container; + template + friend class btree_map_container; + template + friend class btree_multiset_container; + template + friend struct btree_iterator; + template + friend class base_checker; + + const key_type &key() const { return node->key(position); } + slot_type *slot() { return node->slot(position); } + + // The node in the tree the iterator is pointing at. + Node *node; + // The position within the node of the tree the iterator is pointing at. + // TODO(ezb): make this a field_type + int position; + }; + + template + class btree { + using node_type = btree_node; + using is_key_compare_to = typename Params::is_key_compare_to; + + // We use a static empty node for the root/leftmost/rightmost of empty btrees + // in order to avoid branching in begin()/end(). + struct alignas(node_type::Alignment()) EmptyNodeType : node_type { + using field_type = typename node_type::field_type; + node_type *parent; + field_type position = 0; + field_type start = 0; + field_type count = 0; + // max_count must be != kInternalNodeMaxCount (so that this node is regarded + // as a leaf node). max_count() is never called when the tree is empty. + field_type max_count = node_type::kInternalNodeMaxCount + 1; + +#ifdef _MSC_VER + // MSVC has constexpr code generations bugs here. + EmptyNodeType() : parent(this) {} +#else + constexpr EmptyNodeType(node_type *p) : parent(p) {} +#endif + }; + + static node_type *EmptyNode() { +#ifdef _MSC_VER + static EmptyNodeType empty_node; + // This assert fails on some other construction methods. + assert(empty_node.parent == &empty_node); + return &empty_node; +#else + static constexpr EmptyNodeType empty_node( + const_cast(&empty_node)); + return const_cast(&empty_node); +#endif + } + + enum { + kNodeValues = node_type::kNodeValues, + kMinNodeValues = kNodeValues / 2, + }; + + struct node_stats { + using size_type = typename Params::size_type; + + node_stats(size_type l, size_type i) + : leaf_nodes(l), + internal_nodes(i) { + } + + node_stats& operator+=(const node_stats &x) { + leaf_nodes += x.leaf_nodes; + internal_nodes += x.internal_nodes; + return *this; + } + + size_type leaf_nodes; + size_type internal_nodes; + }; + + public: + using key_type = typename Params::key_type; + using value_type = typename Params::value_type; + using size_type = typename Params::size_type; + using difference_type = typename Params::difference_type; + using key_compare = typename Params::key_compare; + using value_compare = typename Params::value_compare; + using allocator_type = typename Params::allocator_type; + using reference = typename Params::reference; + using const_reference = typename Params::const_reference; + using pointer = typename Params::pointer; + using const_pointer = typename Params::const_pointer; + using iterator = btree_iterator; + using const_iterator = typename iterator::const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using node_handle_type = node_handle; + + // Internal types made public for use by btree_container types. + using params_type = Params; + using slot_type = typename Params::slot_type; + + private: + // For use in copy_or_move_values_in_order. + const value_type &maybe_move_from_iterator(const_iterator x) { return *x; } + value_type &&maybe_move_from_iterator(iterator x) { return std::move(*x); } + + // Copies or moves (depending on the template parameter) the values in + // x into this btree in their order in x. This btree must be empty before this + // method is called. This method is used in copy construction, copy + // assignment, and move assignment. + template + void copy_or_move_values_in_order(Btree *x); + + // Validates that various assumptions/requirements are true at compile time. + constexpr static bool static_assert_validation(); + + public: + btree(const key_compare &comp, const allocator_type &alloc); + + btree(const btree &x); + btree(btree &&x) noexcept + : root_(std::move(x.root_)), + rightmost_(phmap::exchange(x.rightmost_, EmptyNode())), + size_(phmap::exchange(x.size_, 0)) { + x.mutable_root() = EmptyNode(); + } + + ~btree() { + // Put static_asserts in destructor to avoid triggering them before the type + // is complete. + static_assert(static_assert_validation(), "This call must be elided."); + clear(); + } + + // Assign the contents of x to *this. + btree &operator=(const btree &x); + btree &operator=(btree &&x) noexcept; + + iterator begin() { + return iterator(leftmost(), 0); + } + const_iterator begin() const { + return const_iterator(leftmost(), 0); + } + iterator end() { return iterator(rightmost_, rightmost_->count()); } + const_iterator end() const { + return const_iterator(rightmost_, rightmost_->count()); + } + reverse_iterator rbegin() { + return reverse_iterator(end()); + } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + reverse_iterator rend() { + return reverse_iterator(begin()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + // Finds the first element whose key is not less than key. + template + iterator lower_bound(const K &key) { + return internal_end(internal_lower_bound(key)); + } + template + const_iterator lower_bound(const K &key) const { + return internal_end(internal_lower_bound(key)); + } + + // Finds the first element whose key is greater than key. + template + iterator upper_bound(const K &key) { + return internal_end(internal_upper_bound(key)); + } + template + const_iterator upper_bound(const K &key) const { + return internal_end(internal_upper_bound(key)); + } + + // Finds the range of values which compare equal to key. The first member of + // the returned pair is equal to lower_bound(key). The second member pair of + // the pair is equal to upper_bound(key). + template + std::pair equal_range(const K &key) { + return {lower_bound(key), upper_bound(key)}; + } + template + std::pair equal_range(const K &key) const { + return {lower_bound(key), upper_bound(key)}; + } + + // Inserts a value into the btree only if it does not already exist. The + // boolean return value indicates whether insertion succeeded or failed. + // Requirement: if `key` already exists in the btree, does not consume `args`. + // Requirement: `key` is never referenced after consuming `args`. + template + std::pair insert_unique(const key_type &key, Args &&... args); + + // Inserts with hint. Checks to see if the value should be placed immediately + // before `position` in the tree. If so, then the insertion will take + // amortized constant time. If not, the insertion will take amortized + // logarithmic time as if a call to insert_unique() were made. + // Requirement: if `key` already exists in the btree, does not consume `args`. + // Requirement: `key` is never referenced after consuming `args`. + template + std::pair insert_hint_unique(iterator position, + const key_type &key, + Args &&... args); + + // Insert a range of values into the btree. + template + void insert_iterator_unique(InputIterator b, InputIterator e); + + // Inserts a value into the btree. + template + iterator insert_multi(const key_type &key, ValueType &&v); + + // Inserts a value into the btree. + template + iterator insert_multi(ValueType &&v) { + return insert_multi(params_type::key(v), std::forward(v)); + } + + // Insert with hint. Check to see if the value should be placed immediately + // before position in the tree. If it does, then the insertion will take + // amortized constant time. If not, the insertion will take amortized + // logarithmic time as if a call to insert_multi(v) were made. + template + iterator insert_hint_multi(iterator position, ValueType &&v); + + // Insert a range of values into the btree. + template + void insert_iterator_multi(InputIterator b, InputIterator e); + + // Erase the specified iterator from the btree. The iterator must be valid + // (i.e. not equal to end()). Return an iterator pointing to the node after + // the one that was erased (or end() if none exists). + // Requirement: does not read the value at `*iter`. + iterator erase(iterator iter); + + // Erases range. Returns the number of keys erased and an iterator pointing + // to the element after the last erased element. + std::pair erase(iterator begin, iterator end); + + // Erases the specified key from the btree. Returns 1 if an element was + // erased and 0 otherwise. + template + size_type erase_unique(const K &key); + + // Erases all of the entries matching the specified key from the + // btree. Returns the number of elements erased. + template + size_type erase_multi(const K &key); + + // Finds the iterator corresponding to a key or returns end() if the key is + // not present. + template + iterator find(const K &key) { + return internal_end(internal_find(key)); + } + template + const_iterator find(const K &key) const { + return internal_end(internal_find(key)); + } + + // Returns a count of the number of times the key appears in the btree. + template + size_type count_unique(const K &key) const { + const iterator beg = internal_find(key); + if (beg.node == nullptr) { + // The key doesn't exist in the tree. + return 0; + } + return 1; + } + // Returns a count of the number of times the key appears in the btree. + template + size_type count_multi(const K &key) const { + const auto range = equal_range(key); + return std::distance(range.first, range.second); + } + + // Clear the btree, deleting all of the values it contains. + void clear(); + + // Swap the contents of *this and x. + void swap(btree &x); + + const key_compare &key_comp() const noexcept { + return root_.template get<0>(); + } + template + bool compare_keys(const K &x, const LK &y) const { + return compare_internal::compare_result_as_less_than(key_comp()(x, y)); + } + + value_compare value_comp() const { return value_compare(key_comp()); } + + // Verifies the structure of the btree. + void verify() const; + + // Size routines. + size_type size() const { return size_; } + size_type max_size() const { return (std::numeric_limits::max)(); } + bool empty() const { return size_ == 0; } + + // The height of the btree. An empty tree will have height 0. + size_type height() const { + size_type h = 0; + if (!empty()) { + // Count the length of the chain from the leftmost node up to the + // root. We actually count from the root back around to the level below + // the root, but the calculation is the same because of the circularity + // of that traversal. + const node_type *n = root(); + do { + ++h; + n = n->parent(); + } while (n != root()); + } + return h; + } + + // The number of internal, leaf and total nodes used by the btree. + size_type leaf_nodes() const { + return internal_stats(root()).leaf_nodes; + } + size_type internal_nodes() const { + return internal_stats(root()).internal_nodes; + } + size_type nodes() const { + node_stats stats = internal_stats(root()); + return stats.leaf_nodes + stats.internal_nodes; + } + + // The total number of bytes used by the btree. + size_type bytes_used() const { + node_stats stats = internal_stats(root()); + if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) { + return sizeof(*this) + + node_type::LeafSize(root()->max_count()); + } else { + return sizeof(*this) + + stats.leaf_nodes * node_type::LeafSize() + + stats.internal_nodes * node_type::InternalSize(); + } + } + + // The average number of bytes used per value stored in the btree. + static double average_bytes_per_value() { + // Returns the number of bytes per value on a leaf node that is 75% + // full. Experimentally, this matches up nicely with the computed number of + // bytes per value in trees that had their values inserted in random order. + return node_type::LeafSize() / (kNodeValues * 0.75); + } + + // The fullness of the btree. Computed as the number of elements in the btree + // divided by the maximum number of elements a tree with the current number + // of nodes could hold. A value of 1 indicates perfect space + // utilization. Smaller values indicate space wastage. + // Returns 0 for empty trees. + double fullness() const { + if (empty()) return 0.0; + return static_cast(size()) / (nodes() * kNodeValues); + } + // The overhead of the btree structure in bytes per node. Computed as the + // total number of bytes used by the btree minus the number of bytes used for + // storing elements divided by the number of elements. + // Returns 0 for empty trees. + double overhead() const { + if (empty()) return 0.0; + return (bytes_used() - size() * sizeof(value_type)) / + static_cast(size()); + } + + // The allocator used by the btree. + allocator_type get_allocator() const { + return allocator(); + } + + private: + // Internal accessor routines. + node_type *root() { return root_.template get<2>(); } + const node_type *root() const { return root_.template get<2>(); } + node_type *&mutable_root() noexcept { return root_.template get<2>(); } + key_compare *mutable_key_comp() noexcept { return &root_.template get<0>(); } + + // The leftmost node is stored as the parent of the root node. + node_type *leftmost() { return root()->parent(); } + const node_type *leftmost() const { return root()->parent(); } + + // Allocator routines. + allocator_type *mutable_allocator() noexcept { + return &root_.template get<1>(); + } + const allocator_type &allocator() const noexcept { + return root_.template get<1>(); + } + + // Allocates a correctly aligned node of at least size bytes using the + // allocator. + node_type *allocate(const size_type sz) { + return reinterpret_cast( + phmap::priv::Allocate( + mutable_allocator(), (size_t)sz)); + } + + // Node creation/deletion routines. + node_type* new_internal_node(node_type *parent) { + node_type *p = allocate(node_type::InternalSize()); + return node_type::init_internal(p, parent); + } + node_type* new_leaf_node(node_type *parent) { + node_type *p = allocate(node_type::LeafSize()); + return node_type::init_leaf(p, parent, kNodeValues); + } + node_type *new_leaf_root_node(const int max_count) { + node_type *p = allocate(node_type::LeafSize(max_count)); + return node_type::init_leaf(p, p, max_count); + } + + // Deletion helper routines. + void erase_same_node(iterator begin, iterator end); + iterator erase_from_leaf_node(iterator begin, size_type to_erase); + iterator rebalance_after_delete(iterator iter); + + // Deallocates a node of a certain size in bytes using the allocator. + void deallocate(const size_type sz, node_type *node) { + phmap::priv::Deallocate( + mutable_allocator(), node, (size_t)sz); + } + + void delete_internal_node(node_type *node) { + node->destroy(mutable_allocator()); + deallocate(node_type::InternalSize(), node); + } + void delete_leaf_node(node_type *node) { + node->destroy(mutable_allocator()); + deallocate(node_type::LeafSize(node->max_count()), node); + } + + // Rebalances or splits the node iter points to. + void rebalance_or_split(iterator *iter); + + // Merges the values of left, right and the delimiting key on their parent + // onto left, removing the delimiting key and deleting right. + void merge_nodes(node_type *left, node_type *right); + + // Tries to merge node with its left or right sibling, and failing that, + // rebalance with its left or right sibling. Returns true if a merge + // occurred, at which point it is no longer valid to access node. Returns + // false if no merging took place. + bool try_merge_or_rebalance(iterator *iter); + + // Tries to shrink the height of the tree by 1. + void try_shrink(); + + iterator internal_end(iterator iter) { + return iter.node != nullptr ? iter : end(); + } + const_iterator internal_end(const_iterator iter) const { + return iter.node != nullptr ? iter : end(); + } + + // Emplaces a value into the btree immediately before iter. Requires that + // key(v) <= iter.key() and (--iter).key() <= key(v). + template + iterator internal_emplace(iterator iter, Args &&... args); + + // Returns an iterator pointing to the first value >= the value "iter" is + // pointing at. Note that "iter" might be pointing to an invalid location as + // iter.position == iter.node->count(). This routine simply moves iter up in + // the tree to a valid location. + // Requires: iter.node is non-null. + template + static IterType internal_last(IterType iter); + + // Returns an iterator pointing to the leaf position at which key would + // reside in the tree. We provide 2 versions of internal_locate. The first + // version uses a less-than comparator and is incapable of distinguishing when + // there is an exact match. The second version is for the key-compare-to + // specialization and distinguishes exact matches. The key-compare-to + // specialization allows the caller to avoid a subsequent comparison to + // determine if an exact match was made, which is important for keys with + // expensive comparison, such as strings. + template + SearchResult internal_locate( + const K &key) const; + + template + SearchResult internal_locate_impl( + const K &key, std::false_type /* IsCompareTo */) const; + + template + SearchResult internal_locate_impl( + const K &key, std::true_type /* IsCompareTo */) const; + + // Internal routine which implements lower_bound(). + template + iterator internal_lower_bound(const K &key) const; + + // Internal routine which implements upper_bound(). + template + iterator internal_upper_bound(const K &key) const; + + // Internal routine which implements find(). + template + iterator internal_find(const K &key) const; + + // Deletes a node and all of its children. + void internal_clear(node_type *node); + + // Verifies the tree structure of node. + int internal_verify(const node_type *node, + const key_type *lo, const key_type *hi) const; + + node_stats internal_stats(const node_type *node) const { + // The root can be a static empty node. + if (node == nullptr || (node == root() && empty())) { + return node_stats(0, 0); + } + if (node->leaf()) { + return node_stats(1, 0); + } + node_stats res(0, 1); + for (int i = 0; i <= node->count(); ++i) { + res += internal_stats(node->child(i)); + } + return res; + } + + public: + // Exposed only for tests. + static bool testonly_uses_linear_node_search() { + return node_type::testonly_uses_linear_node_search(); + } + + private: + // We use compressed tuple in order to save space because key_compare and + // allocator_type are usually empty. + phmap::priv::CompressedTuple + root_; + + // A pointer to the rightmost node. Note that the leftmost node is stored as + // the root's parent. + node_type *rightmost_; + + // Number of values. + size_type size_; + }; + + //// + // btree_node methods + template + template + inline void btree_node

::emplace_value(const size_type i, + allocator_type *alloc, + Args &&... args) { + assert(i <= count()); + // Shift old values to create space for new value and then construct it in + // place. + if (i < count()) { + value_init(count(), alloc, slot(count() - 1)); + for (size_type j = count() - 1; j > i; --j) + params_type::move(alloc, slot(j - 1), slot(j)); + value_destroy(i, alloc); + } + value_init(i, alloc, std::forward(args)...); + set_count((field_type)(count() + 1)); + + if (!leaf() && count() > i + 1) { + for (int j = count(); j > (int)(i + 1); --j) { + set_child(j, child(j - 1)); + } + clear_child(i + 1); + } + } + + template + inline void btree_node

::remove_value(const int i, allocator_type *alloc) { + if (!leaf() && count() > i + 1) { + assert(child(i + 1)->count() == 0); + for (size_type j = i + 1; j < count(); ++j) { + set_child(j, child(j + 1)); + } + clear_child(count()); + } + + remove_values_ignore_children(i, /*to_erase=*/1, alloc); + } + + template + inline void btree_node

::remove_values_ignore_children( + int i, size_type to_erase, allocator_type *alloc) { + params_type::move(alloc, slot(i + to_erase), slot(count()), slot(i)); + value_destroy_n(count() - to_erase, to_erase, alloc); + set_count((field_type)(count() - to_erase)); + } + + template + void btree_node

::rebalance_right_to_left(const int to_move, + btree_node *right, + allocator_type *alloc) { + assert(parent() == right->parent()); + assert(position() + 1 == right->position()); + assert(right->count() >= count()); + assert(to_move >= 1); + assert(to_move <= right->count()); + + // 1) Move the delimiting value in the parent to the left node. + value_init(count(), alloc, parent()->slot(position())); + + // 2) Move the (to_move - 1) values from the right node to the left node. + right->uninitialized_move_n(to_move - 1, 0, count() + 1, this, alloc); + + // 3) Move the new delimiting value to the parent from the right node. + params_type::move(alloc, right->slot(to_move - 1), + parent()->slot(position())); + + // 4) Shift the values in the right node to their correct position. + params_type::move(alloc, right->slot(to_move), right->slot(right->count()), + right->slot(0)); + + // 5) Destroy the now-empty to_move entries in the right node. + right->value_destroy_n(right->count() - to_move, to_move, alloc); + + if (!leaf()) { + // Move the child pointers from the right to the left node. + for (int i = 0; i < to_move; ++i) { + init_child(count() + i + 1, right->child(i)); + } + for (int i = 0; i <= right->count() - to_move; ++i) { + assert(i + to_move <= right->max_count()); + right->init_child(i, right->child(i + to_move)); + right->clear_child(i + to_move); + } + } + + // Fixup the counts on the left and right nodes. + set_count((field_type)(count() + to_move)); + right->set_count((field_type)(right->count() - to_move)); + } + + template + void btree_node

::rebalance_left_to_right(const int to_move, + btree_node *right, + allocator_type *alloc) { + assert(parent() == right->parent()); + assert(position() + 1 == right->position()); + assert(count() >= right->count()); + assert(to_move >= 1); + assert(to_move <= count()); + + // Values in the right node are shifted to the right to make room for the + // new to_move values. Then, the delimiting value in the parent and the + // other (to_move - 1) values in the left node are moved into the right node. + // Lastly, a new delimiting value is moved from the left node into the + // parent, and the remaining empty left node entries are destroyed. + + if (right->count() >= to_move) { + // The original location of the right->count() values are sufficient to hold + // the new to_move entries from the parent and left node. + + // 1) Shift existing values in the right node to their correct positions. + right->uninitialized_move_n(to_move, right->count() - to_move, + right->count(), right, alloc); + for (slot_type *src = right->slot(right->count() - to_move - 1), + *dest = right->slot(right->count() - 1), + *end = right->slot(0); + src >= end; --src, --dest) { + params_type::move(alloc, src, dest); + } + + // 2) Move the delimiting value in the parent to the right node. + params_type::move(alloc, parent()->slot(position()), + right->slot(to_move - 1)); + + // 3) Move the (to_move - 1) values from the left node to the right node. + params_type::move(alloc, slot(count() - (to_move - 1)), slot(count()), + right->slot(0)); + } else { + // The right node does not have enough initialized space to hold the new + // to_move entries, so part of them will move to uninitialized space. + + // 1) Shift existing values in the right node to their correct positions. + right->uninitialized_move_n(right->count(), 0, to_move, right, alloc); + + // 2) Move the delimiting value in the parent to the right node. + right->value_init(to_move - 1, alloc, parent()->slot(position())); + + // 3) Move the (to_move - 1) values from the left node to the right node. + const size_type uninitialized_remaining = to_move - right->count() - 1; + uninitialized_move_n(uninitialized_remaining, + count() - uninitialized_remaining, right->count(), + right, alloc); + params_type::move(alloc, slot(count() - (to_move - 1)), + slot(count() - uninitialized_remaining), right->slot(0)); + } + + // 4) Move the new delimiting value to the parent from the left node. + params_type::move(alloc, slot(count() - to_move), parent()->slot(position())); + + // 5) Destroy the now-empty to_move entries in the left node. + value_destroy_n(count() - to_move, to_move, alloc); + + if (!leaf()) { + // Move the child pointers from the left to the right node. + for (int i = right->count(); i >= 0; --i) { + right->init_child(i + to_move, right->child(i)); + right->clear_child(i); + } + for (int i = 1; i <= to_move; ++i) { + right->init_child(i - 1, child(count() - to_move + i)); + clear_child(count() - to_move + i); + } + } + + // Fixup the counts on the left and right nodes. + set_count((field_type)(count() - to_move)); + right->set_count((field_type)(right->count() + to_move)); + } + + template + void btree_node

::split(const int insert_position, btree_node *dest, + allocator_type *alloc) { + assert(dest->count() == 0); + assert(max_count() == kNodeValues); + + // We bias the split based on the position being inserted. If we're + // inserting at the beginning of the left node then bias the split to put + // more values on the right node. If we're inserting at the end of the + // right node then bias the split to put more values on the left node. + if (insert_position == 0) { + dest->set_count((field_type)(count() - 1)); + } else if (insert_position == kNodeValues) { + dest->set_count(0); + } else { + dest->set_count((field_type)(count() / 2)); + } + set_count((field_type)(count() - dest->count())); + assert(count() >= 1); + + // Move values from the left sibling to the right sibling. + uninitialized_move_n(dest->count(), count(), 0, dest, alloc); + + // Destroy the now-empty entries in the left node. + value_destroy_n(count(), dest->count(), alloc); + + // The split key is the largest value in the left sibling. + set_count((field_type)(count() - 1)); + parent()->emplace_value(position(), alloc, slot(count())); + value_destroy(count(), alloc); + parent()->init_child(position() + 1, dest); + + if (!leaf()) { + for (int i = 0; i <= dest->count(); ++i) { + assert(child(count() + i + 1) != nullptr); + dest->init_child(i, child(count() + i + 1)); + clear_child(count() + i + 1); + } + } + } + + template + void btree_node

::merge(btree_node *src, allocator_type *alloc) { + assert(parent() == src->parent()); + assert(position() + 1 == src->position()); + + // Move the delimiting value to the left node. + value_init(count(), alloc, parent()->slot(position())); + + // Move the values from the right to the left node. + src->uninitialized_move_n(src->count(), 0, count() + 1, this, alloc); + + // Destroy the now-empty entries in the right node. + src->value_destroy_n(0, src->count(), alloc); + + if (!leaf()) { + // Move the child pointers from the right to the left node. + for (int i = 0; i <= src->count(); ++i) { + init_child(count() + i + 1, src->child(i)); + src->clear_child(i); + } + } + + // Fixup the counts on the src and dest nodes. + set_count((field_type)(1 + count() + src->count())); + src->set_count(0); + + // Remove the value on the parent node. + parent()->remove_value(position(), alloc); + } + + template + void btree_node

::swap(btree_node *x, allocator_type *alloc) { + using std::swap; + assert(leaf() == x->leaf()); + + // Determine which is the smaller/larger node. + btree_node *smaller = this, *larger = x; + if (smaller->count() > larger->count()) { + swap(smaller, larger); + } + + // Swap the values. + for (slot_type *a = smaller->slot(0), *b = larger->slot(0), + *end = a + smaller->count(); + a != end; ++a, ++b) { + params_type::swap(alloc, a, b); + } + + // Move values that can't be swapped. + const size_type to_move = larger->count() - smaller->count(); + larger->uninitialized_move_n(to_move, smaller->count(), smaller->count(), + smaller, alloc); + larger->value_destroy_n(smaller->count(), to_move, alloc); + + if (!leaf()) { + // Swap the child pointers. + std::swap_ranges(&smaller->mutable_child(0), + &smaller->mutable_child(smaller->count() + 1), + &larger->mutable_child(0)); + // Update swapped children's parent pointers. + int i = 0; + for (; i <= smaller->count(); ++i) { + smaller->child(i)->set_parent(smaller); + larger->child(i)->set_parent(larger); + } + // Move the child pointers that couldn't be swapped. + for (; i <= larger->count(); ++i) { + smaller->init_child(i, larger->child(i)); + larger->clear_child(i); + } + } + + // Swap the counts. + swap(mutable_count(), x->mutable_count()); + } + + //// + // btree_iterator methods + template + void btree_iterator::increment_slow() { + if (node->leaf()) { + assert(position >= node->count()); + btree_iterator save(*this); + while (position == node->count() && !node->is_root()) { + assert(node->parent()->child(node->position()) == node); + position = node->position(); + node = node->parent(); + } + if (position == node->count()) { + *this = save; + } + } else { + assert(position < node->count()); + node = node->child(position + 1); + while (!node->leaf()) { + node = node->child(0); + } + position = 0; + } + } + + template + void btree_iterator::decrement_slow() { + if (node->leaf()) { + assert(position <= -1); + btree_iterator save(*this); + while (position < 0 && !node->is_root()) { + assert(node->parent()->child(node->position()) == node); + position = node->position() - 1; + node = node->parent(); + } + if (position < 0) { + *this = save; + } + } else { + assert(position >= 0); + node = node->child(position); + while (!node->leaf()) { + node = node->child(node->count()); + } + position = node->count() - 1; + } + } + + //// + // btree methods + template + template + void btree

::copy_or_move_values_in_order(Btree *x) { + static_assert(std::is_same::value || + std::is_same::value, + "Btree type must be same or const."); + assert(empty()); + + // We can avoid key comparisons because we know the order of the + // values is the same order we'll store them in. + auto iter = x->begin(); + if (iter == x->end()) return; + insert_multi(maybe_move_from_iterator(iter)); + ++iter; + for (; iter != x->end(); ++iter) { + // If the btree is not empty, we can just insert the new value at the end + // of the tree. + internal_emplace(end(), maybe_move_from_iterator(iter)); + } + } + + template + constexpr bool btree

::static_assert_validation() { + static_assert(std::is_nothrow_copy_constructible::value, + "Key comparison must be nothrow copy constructible"); + static_assert(std::is_nothrow_copy_constructible::value, + "Allocator must be nothrow copy constructible"); + static_assert(type_traits_internal::is_trivially_copyable::value, + "iterator not trivially copyable."); + + // Note: We assert that kTargetValues, which is computed from + // Params::kTargetNodeSize, must fit the node_type::field_type. + static_assert( + kNodeValues < (1 << (8 * sizeof(typename node_type::field_type))), + "target node size too large"); + + // Verify that key_compare returns an phmap::{weak,strong}_ordering or bool. + using compare_result_type = + phmap::invoke_result_t; + static_assert( + std::is_same::value || + std::is_convertible::value, + "key comparison function must return phmap::{weak,strong}_ordering or " + "bool."); + + // Test the assumption made in setting kNodeValueSpace. + static_assert(node_type::MinimumOverhead() >= sizeof(void *) + 4, + "node space assumption incorrect"); + + return true; + } + + template + btree

::btree(const key_compare &comp, const allocator_type &alloc) + : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {} + + template + btree

::btree(const btree &x) : btree(x.key_comp(), x.allocator()) { + copy_or_move_values_in_order(&x); + } + + template + template + auto btree

::insert_unique(const key_type &key, Args &&... args) + -> std::pair { + if (empty()) { + mutable_root() = rightmost_ = new_leaf_root_node(1); + } + + auto res = internal_locate(key); + iterator &iter = res.value; + + if (res.HasMatch()) { + if (res.IsEq()) { + // The key already exists in the tree, do nothing. + return {iter, false}; + } + } else { + iterator last = internal_last(iter); + if (last.node && !compare_keys(key, last.key())) { + // The key already exists in the tree, do nothing. + return {last, false}; + } + } + return {internal_emplace(iter, std::forward(args)...), true}; + } + + template + template + inline auto btree

::insert_hint_unique(iterator position, const key_type &key, + Args &&... args) + -> std::pair { + if (!empty()) { + if (position == end() || compare_keys(key, position.key())) { + iterator prev = position; + if (position == begin() || compare_keys((--prev).key(), key)) { + // prev.key() < key < position.key() + return {internal_emplace(position, std::forward(args)...), true}; + } + } else if (compare_keys(position.key(), key)) { + ++position; + if (position == end() || compare_keys(key, position.key())) { + // {original `position`}.key() < key < {current `position`}.key() + return {internal_emplace(position, std::forward(args)...), true}; + } + } else { + // position.key() == key + return {position, false}; + } + } + return insert_unique(key, std::forward(args)...); + } + + template + template + void btree

::insert_iterator_unique(InputIterator b, InputIterator e) { + for (; b != e; ++b) { + insert_hint_unique(end(), params_type::key(*b), *b); + } + } + + template + template + auto btree

::insert_multi(const key_type &key, ValueType &&v) -> iterator { + if (empty()) { + mutable_root() = rightmost_ = new_leaf_root_node(1); + } + + iterator iter = internal_upper_bound(key); + if (iter.node == nullptr) { + iter = end(); + } + return internal_emplace(iter, std::forward(v)); + } + + template + template + auto btree

::insert_hint_multi(iterator position, ValueType &&v) -> iterator { + if (!empty()) { + const key_type &key = params_type::key(v); + if (position == end() || !compare_keys(position.key(), key)) { + iterator prev = position; + if (position == begin() || !compare_keys(key, (--prev).key())) { + // prev.key() <= key <= position.key() + return internal_emplace(position, std::forward(v)); + } + } else { + iterator next = position; + ++next; + if (next == end() || !compare_keys(next.key(), key)) { + // position.key() < key <= next.key() + return internal_emplace(next, std::forward(v)); + } + } + } + return insert_multi(std::forward(v)); + } + + template + template + void btree

::insert_iterator_multi(InputIterator b, InputIterator e) { + for (; b != e; ++b) { + insert_hint_multi(end(), *b); + } + } + + template + auto btree

::operator=(const btree &x) -> btree & { + if (this != &x) { + clear(); + + *mutable_key_comp() = x.key_comp(); + if (phmap::allocator_traits< + allocator_type>::propagate_on_container_copy_assignment::value) { + *mutable_allocator() = x.allocator(); + } + + copy_or_move_values_in_order(&x); + } + return *this; + } + + template + auto btree

::operator=(btree &&x) noexcept -> btree & { + if (this != &x) { + clear(); + + using std::swap; + if (phmap::allocator_traits< + allocator_type>::propagate_on_container_copy_assignment::value) { + // Note: `root_` also contains the allocator and the key comparator. + swap(root_, x.root_); + swap(rightmost_, x.rightmost_); + swap(size_, x.size_); + } else { + if (allocator() == x.allocator()) { + swap(mutable_root(), x.mutable_root()); + swap(*mutable_key_comp(), *x.mutable_key_comp()); + swap(rightmost_, x.rightmost_); + swap(size_, x.size_); + } else { + // We aren't allowed to propagate the allocator and the allocator is + // different so we can't take over its memory. We must move each element + // individually. We need both `x` and `this` to have `x`s key comparator + // while moving the values so we can't swap the key comparators. + *mutable_key_comp() = x.key_comp(); + copy_or_move_values_in_order(&x); + } + } + } + return *this; + } + + template + auto btree

::erase(iterator iter) -> iterator { + bool internal_delete = false; + if (!iter.node->leaf()) { + // Deletion of a value on an internal node. First, move the largest value + // from our left child here, then delete that position (in remove_value() + // below). We can get to the largest value from our left child by + // decrementing iter. + iterator internal_iter(iter); + --iter; + assert(iter.node->leaf()); + params_type::move(mutable_allocator(), iter.node->slot(iter.position), + internal_iter.node->slot(internal_iter.position)); + internal_delete = true; + } + + // Delete the key from the leaf. + iter.node->remove_value(iter.position, mutable_allocator()); + --size_; + + // We want to return the next value after the one we just erased. If we + // erased from an internal node (internal_delete == true), then the next + // value is ++(++iter). If we erased from a leaf node (internal_delete == + // false) then the next value is ++iter. Note that ++iter may point to an + // internal node and the value in the internal node may move to a leaf node + // (iter.node) when rebalancing is performed at the leaf level. + + iterator res = rebalance_after_delete(iter); + + // If we erased from an internal node, advance the iterator. + if (internal_delete) { + ++res; + } + return res; + } + + template + auto btree

::rebalance_after_delete(iterator iter) -> iterator { + // Merge/rebalance as we walk back up the tree. + iterator res(iter); + bool first_iteration = true; + for (;;) { + if (iter.node == root()) { + try_shrink(); + if (empty()) { + return end(); + } + break; + } + if (iter.node->count() >= kMinNodeValues) { + break; + } + bool merged = try_merge_or_rebalance(&iter); + // On the first iteration, we should update `res` with `iter` because `res` + // may have been invalidated. + if (first_iteration) { + res = iter; + first_iteration = false; + } + if (!merged) { + break; + } + iter.position = iter.node->position(); + iter.node = iter.node->parent(); + } + + // Adjust our return value. If we're pointing at the end of a node, advance + // the iterator. + if (res.position == res.node->count()) { + res.position = res.node->count() - 1; + ++res; + } + + return res; + } + + template + auto btree

::erase(iterator _begin, iterator _end) + -> std::pair { + difference_type count = std::distance(_begin, _end); + assert(count >= 0); + + if (count == 0) { + return {0, _begin}; + } + + if (count == (difference_type)size_) { + clear(); + return {count, this->end()}; + } + + if (_begin.node == _end.node) { + erase_same_node(_begin, _end); + size_ -= count; + return {count, rebalance_after_delete(_begin)}; + } + + const size_type target_size = size_ - count; + while (size_ > target_size) { + if (_begin.node->leaf()) { + const size_type remaining_to_erase = size_ - target_size; + const size_type remaining_in_node = _begin.node->count() - _begin.position; + _begin = erase_from_leaf_node( + _begin, (std::min)(remaining_to_erase, remaining_in_node)); + } else { + _begin = erase(_begin); + } + } + return {count, _begin}; + } + + template + void btree

::erase_same_node(iterator _begin, iterator _end) { + assert(_begin.node == _end.node); + assert(_end.position > _begin.position); + + node_type *node = _begin.node; + size_type to_erase = _end.position - _begin.position; + if (!node->leaf()) { + // Delete all children between _begin and _end. + for (size_type i = 0; i < to_erase; ++i) { + internal_clear(node->child(_begin.position + i + 1)); + } + // Rotate children after _end into new positions. + for (size_type i = _begin.position + to_erase + 1; i <= node->count(); ++i) { + node->set_child(i - to_erase, node->child(i)); + node->clear_child(i); + } + } + node->remove_values_ignore_children(_begin.position, to_erase, + mutable_allocator()); + + // Do not need to update rightmost_, because + // * either _end == this->end(), and therefore node == rightmost_, and still + // exists + // * or _end != this->end(), and therefore rightmost_ hasn't been erased, since + // it wasn't covered in [_begin, _end) + } + + template + auto btree

::erase_from_leaf_node(iterator _begin, size_type to_erase) + -> iterator { + node_type *node = _begin.node; + assert(node->leaf()); + assert(node->count() > _begin.position); + assert(_begin.position + to_erase <= node->count()); + + node->remove_values_ignore_children(_begin.position, to_erase, + mutable_allocator()); + + size_ -= to_erase; + + return rebalance_after_delete(_begin); + } + + template + template + auto btree

::erase_unique(const K &key) -> size_type { + const iterator iter = internal_find(key); + if (iter.node == nullptr) { + // The key doesn't exist in the tree, return nothing done. + return 0; + } + erase(iter); + return 1; + } + + template + template + auto btree

::erase_multi(const K &key) -> size_type { + const iterator _begin = internal_lower_bound(key); + if (_begin.node == nullptr) { + // The key doesn't exist in the tree, return nothing done. + return 0; + } + // Delete all of the keys between _begin and upper_bound(key). + const iterator _end = internal_end(internal_upper_bound(key)); + return erase(_begin, _end).first; + } + + template + void btree

::clear() { + if (!empty()) { + internal_clear(root()); + } + mutable_root() = EmptyNode(); + rightmost_ = EmptyNode(); + size_ = 0; + } + + template + void btree

::swap(btree &x) { + using std::swap; + if (phmap::allocator_traits< + allocator_type>::propagate_on_container_swap::value) { + // Note: `root_` also contains the allocator and the key comparator. + swap(root_, x.root_); + } else { + // It's undefined behavior if the allocators are unequal here. + assert(allocator() == x.allocator()); + swap(mutable_root(), x.mutable_root()); + swap(*mutable_key_comp(), *x.mutable_key_comp()); + } + swap(rightmost_, x.rightmost_); + swap(size_, x.size_); + } + + template + void btree

::verify() const { + assert(root() != nullptr); + assert(leftmost() != nullptr); + assert(rightmost_ != nullptr); + assert(empty() || size() == internal_verify(root(), nullptr, nullptr)); + assert(leftmost() == (++const_iterator(root(), -1)).node); + assert(rightmost_ == (--const_iterator(root(), root()->count())).node); + assert(leftmost()->leaf()); + assert(rightmost_->leaf()); + } + + template + void btree

::rebalance_or_split(iterator *iter) { + node_type *&node = iter->node; + int &insert_position = iter->position; + assert(node->count() == node->max_count()); + assert(kNodeValues == node->max_count()); + + // First try to make room on the node by rebalancing. + node_type *parent = node->parent(); + if (node != root()) { + if (node->position() > 0) { + // Try rebalancing with our left sibling. + node_type *left = parent->child(node->position() - 1); + assert(left->max_count() == kNodeValues); + if (left->count() < kNodeValues) { + // We bias rebalancing based on the position being inserted. If we're + // inserting at the end of the right node then we bias rebalancing to + // fill up the left node. + int to_move = (kNodeValues - left->count()) / + (1 + (insert_position < kNodeValues)); + to_move = (std::max)(1, to_move); + + if (((insert_position - to_move) >= 0) || + ((left->count() + to_move) < kNodeValues)) { + left->rebalance_right_to_left(to_move, node, mutable_allocator()); + + assert(node->max_count() - node->count() == to_move); + insert_position = insert_position - to_move; + if (insert_position < 0) { + insert_position = insert_position + left->count() + 1; + node = left; + } + + assert(node->count() < node->max_count()); + return; + } + } + } + + if (node->position() < parent->count()) { + // Try rebalancing with our right sibling. + node_type *right = parent->child(node->position() + 1); + assert(right->max_count() == kNodeValues); + if (right->count() < kNodeValues) { + // We bias rebalancing based on the position being inserted. If we're + // inserting at the _beginning of the left node then we bias rebalancing + // to fill up the right node. + int to_move = + (kNodeValues - right->count()) / (1 + (insert_position > 0)); + to_move = (std::max)(1, to_move); + + if ((insert_position <= (node->count() - to_move)) || + ((right->count() + to_move) < kNodeValues)) { + node->rebalance_left_to_right(to_move, right, mutable_allocator()); + + if (insert_position > node->count()) { + insert_position = insert_position - node->count() - 1; + node = right; + } + + assert(node->count() < node->max_count()); + return; + } + } + } + + // Rebalancing failed, make sure there is room on the parent node for a new + // value. + assert(parent->max_count() == kNodeValues); + if (parent->count() == kNodeValues) { + iterator parent_iter(node->parent(), node->position()); + rebalance_or_split(&parent_iter); + } + } else { + // Rebalancing not possible because this is the root node. + // Create a new root node and set the current root node as the child of the + // new root. + parent = new_internal_node(parent); + parent->init_child(0, root()); + mutable_root() = parent; + // If the former root was a leaf node, then it's now the rightmost node. + assert(!parent->child(0)->leaf() || parent->child(0) == rightmost_); + } + + // Split the node. + node_type *split_node; + if (node->leaf()) { + split_node = new_leaf_node(parent); + node->split(insert_position, split_node, mutable_allocator()); + if (rightmost_ == node) rightmost_ = split_node; + } else { + split_node = new_internal_node(parent); + node->split(insert_position, split_node, mutable_allocator()); + } + + if (insert_position > node->count()) { + insert_position = insert_position - node->count() - 1; + node = split_node; + } + } + + template + void btree

::merge_nodes(node_type *left, node_type *right) { + left->merge(right, mutable_allocator()); + if (right->leaf()) { + if (rightmost_ == right) rightmost_ = left; + delete_leaf_node(right); + } else { + delete_internal_node(right); + } + } + + template + bool btree

::try_merge_or_rebalance(iterator *iter) { + node_type *parent = iter->node->parent(); + if (iter->node->position() > 0) { + // Try merging with our left sibling. + node_type *left = parent->child(iter->node->position() - 1); + assert(left->max_count() == kNodeValues); + if ((1 + left->count() + iter->node->count()) <= kNodeValues) { + iter->position += 1 + left->count(); + merge_nodes(left, iter->node); + iter->node = left; + return true; + } + } + if (iter->node->position() < parent->count()) { + // Try merging with our right sibling. + node_type *right = parent->child(iter->node->position() + 1); + assert(right->max_count() == kNodeValues); + if ((1 + iter->node->count() + right->count()) <= kNodeValues) { + merge_nodes(iter->node, right); + return true; + } + // Try rebalancing with our right sibling. We don't perform rebalancing if + // we deleted the first element from iter->node and the node is not + // empty. This is a small optimization for the common pattern of deleting + // from the front of the tree. + if ((right->count() > kMinNodeValues) && + ((iter->node->count() == 0) || + (iter->position > 0))) { + int to_move = (right->count() - iter->node->count()) / 2; + to_move = (std::min)(to_move, right->count() - 1); + iter->node->rebalance_right_to_left(to_move, right, mutable_allocator()); + return false; + } + } + if (iter->node->position() > 0) { + // Try rebalancing with our left sibling. We don't perform rebalancing if + // we deleted the last element from iter->node and the node is not + // empty. This is a small optimization for the common pattern of deleting + // from the back of the tree. + node_type *left = parent->child(iter->node->position() - 1); + if ((left->count() > kMinNodeValues) && + ((iter->node->count() == 0) || + (iter->position < iter->node->count()))) { + int to_move = (left->count() - iter->node->count()) / 2; + to_move = (std::min)(to_move, left->count() - 1); + left->rebalance_left_to_right(to_move, iter->node, mutable_allocator()); + iter->position += to_move; + return false; + } + } + return false; + } + + template + void btree

::try_shrink() { + if (root()->count() > 0) { + return; + } + // Deleted the last item on the root node, shrink the height of the tree. + if (root()->leaf()) { + assert(size() == 0); + delete_leaf_node(root()); + mutable_root() = EmptyNode(); + rightmost_ = EmptyNode(); + } else { + node_type *child = root()->child(0); + child->make_root(); + delete_internal_node(root()); + mutable_root() = child; + } + } + + template + template + inline IterType btree

::internal_last(IterType iter) { + assert(iter.node != nullptr); + while (iter.position == iter.node->count()) { + iter.position = iter.node->position(); + iter.node = iter.node->parent(); + if (iter.node->leaf()) { + iter.node = nullptr; + break; + } + } + return iter; + } + + template + template + inline auto btree

::internal_emplace(iterator iter, Args &&... args) + -> iterator { + if (!iter.node->leaf()) { + // We can't insert on an internal node. Instead, we'll insert after the + // previous value which is guaranteed to be on a leaf node. + --iter; + ++iter.position; + } + const int max_count = iter.node->max_count(); + if (iter.node->count() == max_count) { + // Make room in the leaf for the new item. + if (max_count < kNodeValues) { + // Insertion into the root where the root is smaller than the full node + // size. Simply grow the size of the root node. + assert(iter.node == root()); + iter.node = + new_leaf_root_node((std::min)(kNodeValues, 2 * max_count)); + iter.node->swap(root(), mutable_allocator()); + delete_leaf_node(root()); + mutable_root() = iter.node; + rightmost_ = iter.node; + } else { + rebalance_or_split(&iter); + } + } + iter.node->emplace_value(iter.position, mutable_allocator(), + std::forward(args)...); + ++size_; + return iter; + } + + template + template + inline auto btree

::internal_locate(const K &key) const + -> SearchResult { + return internal_locate_impl(key, is_key_compare_to()); + } + + template + template + inline auto btree

::internal_locate_impl( + const K &key, std::false_type /* IsCompareTo */) const + -> SearchResult { + iterator iter(const_cast(root()), 0); + for (;;) { + iter.position = iter.node->lower_bound(key, key_comp()).value; + // NOTE: we don't need to walk all the way down the tree if the keys are + // equal, but determining equality would require doing an extra comparison + // on each node on the way down, and we will need to go all the way to the + // leaf node in the expected case. + if (iter.node->leaf()) { + break; + } + iter.node = iter.node->child(iter.position); + } + return {iter}; + } + + template + template + inline auto btree

::internal_locate_impl( + const K &key, std::true_type /* IsCompareTo */) const + -> SearchResult { + iterator iter(const_cast(root()), 0); + for (;;) { + SearchResult res = iter.node->lower_bound(key, key_comp()); + iter.position = res.value; + if (res.match == MatchKind::kEq) { + return {iter, MatchKind::kEq}; + } + if (iter.node->leaf()) { + break; + } + iter.node = iter.node->child(iter.position); + } + return {iter, MatchKind::kNe}; + } + + template + template + auto btree

::internal_lower_bound(const K &key) const -> iterator { + iterator iter(const_cast(root()), 0); + for (;;) { + iter.position = iter.node->lower_bound(key, key_comp()).value; + if (iter.node->leaf()) { + break; + } + iter.node = iter.node->child(iter.position); + } + return internal_last(iter); + } + + template + template + auto btree

::internal_upper_bound(const K &key) const -> iterator { + iterator iter(const_cast(root()), 0); + for (;;) { + iter.position = iter.node->upper_bound(key, key_comp()); + if (iter.node->leaf()) { + break; + } + iter.node = iter.node->child(iter.position); + } + return internal_last(iter); + } + + template + template + auto btree

::internal_find(const K &key) const -> iterator { + auto res = internal_locate(key); + if (res.HasMatch()) { + if (res.IsEq()) { + return res.value; + } + } else { + const iterator iter = internal_last(res.value); + if (iter.node != nullptr && !compare_keys(key, iter.key())) { + return iter; + } + } + return {nullptr, 0}; + } + + template + void btree

::internal_clear(node_type *node) { + if (!node->leaf()) { + for (int i = 0; i <= node->count(); ++i) { + internal_clear(node->child(i)); + } + delete_internal_node(node); + } else { + delete_leaf_node(node); + } + } + + template + int btree

::internal_verify( + const node_type *node, const key_type *lo, const key_type *hi) const { + assert(node->count() > 0); + assert(node->count() <= node->max_count()); + if (lo) { + assert(!compare_keys(node->key(0), *lo)); + } + if (hi) { + assert(!compare_keys(*hi, node->key(node->count() - 1))); + } + for (int i = 1; i < node->count(); ++i) { + assert(!compare_keys(node->key(i), node->key(i - 1))); + } + int count = node->count(); + if (!node->leaf()) { + for (int i = 0; i <= node->count(); ++i) { + assert(node->child(i) != nullptr); + assert(node->child(i)->parent() == node); + assert(node->child(i)->position() == i); + count += internal_verify( + node->child(i), + (i == 0) ? lo : &node->key(i - 1), + (i == node->count()) ? hi : &node->key(i)); + } + } + return count; + } + + // A common base class for btree_set, btree_map, btree_multiset, and btree_multimap. + // --------------------------------------------------------------------------------- + template + class btree_container { + using params_type = typename Tree::params_type; + + protected: + // Alias used for heterogeneous lookup functions. + // `key_arg` evaluates to `K` when the functors are transparent and to + // `key_type` otherwise. It permits template argument deduction on `K` for the + // transparent case. + template + using key_arg = + typename KeyArg::value>:: + template type; + + public: + using key_type = typename Tree::key_type; + using value_type = typename Tree::value_type; + using size_type = typename Tree::size_type; + using difference_type = typename Tree::difference_type; + using key_compare = typename Tree::key_compare; + using value_compare = typename Tree::value_compare; + using allocator_type = typename Tree::allocator_type; + using reference = typename Tree::reference; + using const_reference = typename Tree::const_reference; + using pointer = typename Tree::pointer; + using const_pointer = typename Tree::const_pointer; + using iterator = typename Tree::iterator; + using const_iterator = typename Tree::const_iterator; + using reverse_iterator = typename Tree::reverse_iterator; + using const_reverse_iterator = typename Tree::const_reverse_iterator; + using node_type = typename Tree::node_handle_type; + + // Constructors/assignments. + btree_container() : tree_(key_compare(), allocator_type()) {} + explicit btree_container(const key_compare &comp, + const allocator_type &alloc = allocator_type()) + : tree_(comp, alloc) {} + btree_container(const btree_container &x) = default; + btree_container(btree_container &&x) noexcept = default; + btree_container &operator=(const btree_container &x) = default; + btree_container &operator=(btree_container &&x) noexcept( + std::is_nothrow_move_assignable::value) = default; + + // Iterator routines. + iterator begin() { return tree_.begin(); } + const_iterator begin() const { return tree_.begin(); } + const_iterator cbegin() const { return tree_.begin(); } + iterator end() { return tree_.end(); } + const_iterator end() const { return tree_.end(); } + const_iterator cend() const { return tree_.end(); } + reverse_iterator rbegin() { return tree_.rbegin(); } + const_reverse_iterator rbegin() const { return tree_.rbegin(); } + const_reverse_iterator crbegin() const { return tree_.rbegin(); } + reverse_iterator rend() { return tree_.rend(); } + const_reverse_iterator rend() const { return tree_.rend(); } + const_reverse_iterator crend() const { return tree_.rend(); } + + // Lookup routines. + template + iterator find(const key_arg &key) { + return tree_.find(key); + } + template + const_iterator find(const key_arg &key) const { return tree_.find(key); } + + template + bool contains(const key_arg &key) const { return find(key) != end(); } + + template + iterator lower_bound(const key_arg &key) { return tree_.lower_bound(key); } + + template + const_iterator lower_bound(const key_arg &key) const { return tree_.lower_bound(key); } + + template + iterator upper_bound(const key_arg &key) { return tree_.upper_bound(key); } + + template + const_iterator upper_bound(const key_arg &key) const { return tree_.upper_bound(key); } + + template + std::pair equal_range(const key_arg &key) { return tree_.equal_range(key); } + + template + std::pair equal_range( + const key_arg &key) const { + return tree_.equal_range(key); + } + + iterator erase(const_iterator iter) { return tree_.erase(iterator(iter)); } + iterator erase(iterator iter) { return tree_.erase(iter); } + iterator erase(const_iterator first, const_iterator last) { + return tree_.erase(iterator(first), iterator(last)).second; + } + + node_type extract(iterator position) { + // Use Move instead of Transfer, because the rebalancing code expects to + // have a valid object to scribble metadata bits on top of. + auto node = CommonAccess::Move(get_allocator(), position.slot()); + erase(position); + return node; + } + + node_type extract(const_iterator position) { + return extract(iterator(position)); + } + + public: + void clear() { tree_.clear(); } + void swap(btree_container &x) { tree_.swap(x.tree_); } + void verify() const { tree_.verify(); } + + size_type size() const { return tree_.size(); } + size_type max_size() const { return tree_.max_size(); } + bool empty() const { return tree_.empty(); } + + friend bool operator==(const btree_container &x, const btree_container &y) { + if (x.size() != y.size()) return false; + return std::equal(x.begin(), x.end(), y.begin()); + } + + friend bool operator!=(const btree_container &x, const btree_container &y) { return !(x == y); } + + friend bool operator<(const btree_container &x, const btree_container &y) { + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); + } + + friend bool operator>(const btree_container &x, const btree_container &y) { return y < x; } + + friend bool operator<=(const btree_container &x, const btree_container &y) { return !(y < x); } + + friend bool operator>=(const btree_container &x, const btree_container &y) { return !(x < y); } + + // The allocator used by the btree. + allocator_type get_allocator() const { return tree_.get_allocator(); } + + // The key comparator used by the btree. + key_compare key_comp() const { return tree_.key_comp(); } + value_compare value_comp() const { return tree_.value_comp(); } + + // Support absl::Hash. + template + friend State AbslHashValue(State h, const btree_container &b) { + for (const auto &v : b) { + h = State::combine(std::move(h), v); + } + return State::combine(std::move(h), b.size()); + } + + protected: + Tree tree_; + }; + + // A common base class for btree_set and btree_map. + // ----------------------------------------------- + template + class btree_set_container : public btree_container { + using super_type = btree_container; + using params_type = typename Tree::params_type; + using init_type = typename params_type::init_type; + using is_key_compare_to = typename params_type::is_key_compare_to; + friend class BtreeNodePeer; + + protected: + template + using key_arg = typename super_type::template key_arg; + + public: + using key_type = typename Tree::key_type; + using value_type = typename Tree::value_type; + using size_type = typename Tree::size_type; + using key_compare = typename Tree::key_compare; + using allocator_type = typename Tree::allocator_type; + using iterator = typename Tree::iterator; + using const_iterator = typename Tree::const_iterator; + using node_type = typename super_type::node_type; + using insert_return_type = InsertReturnType; + using super_type::super_type; + btree_set_container() {} + + template + btree_set_container(InputIterator b, InputIterator e, + const key_compare &comp = key_compare(), + const allocator_type &alloc = allocator_type()) + : super_type(comp, alloc) { + insert(b, e); + } + + btree_set_container(std::initializer_list init, + const key_compare &comp = key_compare(), + const allocator_type &alloc = allocator_type()) + : btree_set_container(init.begin(), init.end(), comp, alloc) {} + + // Lookup routines. + template + size_type count(const key_arg &key) const { + return this->tree_.count_unique(key); + } + + // Insertion routines. + std::pair insert(const value_type &x) { + return this->tree_.insert_unique(params_type::key(x), x); + } + std::pair insert(value_type &&x) { + return this->tree_.insert_unique(params_type::key(x), std::move(x)); + } + template + std::pair emplace(Args &&... args) { + init_type v(std::forward(args)...); + return this->tree_.insert_unique(params_type::key(v), std::move(v)); + } + iterator insert(const_iterator position, const value_type &x) { + return this->tree_ + .insert_hint_unique(iterator(position), params_type::key(x), x) + .first; + } + iterator insert(const_iterator position, value_type &&x) { + return this->tree_ + .insert_hint_unique(iterator(position), params_type::key(x), + std::move(x)) + .first; + } + + template + iterator emplace_hint(const_iterator position, Args &&... args) { + init_type v(std::forward(args)...); + return this->tree_ + .insert_hint_unique(iterator(position), params_type::key(v), + std::move(v)) + .first; + } + + template + void insert(InputIterator b, InputIterator e) { + this->tree_.insert_iterator_unique(b, e); + } + + void insert(std::initializer_list init) { + this->tree_.insert_iterator_unique(init.begin(), init.end()); + } + + insert_return_type insert(node_type &&node) { + if (!node) return {this->end(), false, node_type()}; + std::pair res = + this->tree_.insert_unique(params_type::key(CommonAccess::GetSlot(node)), + CommonAccess::GetSlot(node)); + if (res.second) { + CommonAccess::Destroy(&node); + return {res.first, true, node_type()}; + } else { + return {res.first, false, std::move(node)}; + } + } + + iterator insert(const_iterator hint, node_type &&node) { + if (!node) return this->end(); + std::pair res = this->tree_.insert_hint_unique( + iterator(hint), params_type::key(CommonAccess::GetSlot(node)), + CommonAccess::GetSlot(node)); + if (res.second) CommonAccess::Destroy(&node); + return res.first; + } + + template + size_type erase(const key_arg &key) { return this->tree_.erase_unique(key); } + using super_type::erase; + + template + node_type extract(const key_arg &key) { + auto it = this->find(key); + return it == this->end() ? node_type() : extract(it); + } + + using super_type::extract; + + // Merge routines. + // Moves elements from `src` into `this`. If the element already exists in + // `this`, it is left unmodified in `src`. + template < + typename T, + typename phmap::enable_if_t< + phmap::conjunction< + std::is_same, + std::is_same, + std::is_same>::value, + int> = 0> + void merge(btree_container &src) { // NOLINT + for (auto src_it = src.begin(); src_it != src.end();) { + if (insert(std::move(*src_it)).second) { + src_it = src.erase(src_it); + } else { + ++src_it; + } + } + } + + template < + typename T, + typename phmap::enable_if_t< + phmap::conjunction< + std::is_same, + std::is_same, + std::is_same>::value, + int> = 0> + void merge(btree_container &&src) { + merge(src); + } + }; + + // Base class for btree_map. + // ------------------------- + template + class btree_map_container : public btree_set_container { + using super_type = btree_set_container; + using params_type = typename Tree::params_type; + + protected: + template + using key_arg = typename super_type::template key_arg; + + public: + using key_type = typename Tree::key_type; + using mapped_type = typename params_type::mapped_type; + using value_type = typename Tree::value_type; + using key_compare = typename Tree::key_compare; + using allocator_type = typename Tree::allocator_type; + using iterator = typename Tree::iterator; + using const_iterator = typename Tree::const_iterator; + + // Inherit constructors. + using super_type::super_type; + btree_map_container() {} + + // Insertion routines. + template + std::pair try_emplace(const key_type &k, Args &&... args) { + return this->tree_.insert_unique( + k, std::piecewise_construct, std::forward_as_tuple(k), + std::forward_as_tuple(std::forward(args)...)); + } + template + std::pair try_emplace(key_type &&k, Args &&... args) { + // Note: `key_ref` exists to avoid a ClangTidy warning about moving from `k` + // and then using `k` unsequenced. This is safe because the move is into a + // forwarding reference and insert_unique guarantees that `key` is never + // referenced after consuming `args`. + const key_type& key_ref = k; + return this->tree_.insert_unique( + key_ref, std::piecewise_construct, std::forward_as_tuple(std::move(k)), + std::forward_as_tuple(std::forward(args)...)); + } + template + iterator try_emplace(const_iterator hint, const key_type &k, + Args &&... args) { + return this->tree_ + .insert_hint_unique(iterator(hint), k, std::piecewise_construct, + std::forward_as_tuple(k), + std::forward_as_tuple(std::forward(args)...)) + .first; + } + template + iterator try_emplace(const_iterator hint, key_type &&k, Args &&... args) { + // Note: `key_ref` exists to avoid a ClangTidy warning about moving from `k` + // and then using `k` unsequenced. This is safe because the move is into a + // forwarding reference and insert_hint_unique guarantees that `key` is + // never referenced after consuming `args`. + const key_type& key_ref = k; + return this->tree_ + .insert_hint_unique(iterator(hint), key_ref, std::piecewise_construct, + std::forward_as_tuple(std::move(k)), + std::forward_as_tuple(std::forward(args)...)) + .first; + } + mapped_type &operator[](const key_type &k) { + return try_emplace(k).first->second; + } + mapped_type &operator[](key_type &&k) { + return try_emplace(std::move(k)).first->second; + } + + template + mapped_type &at(const key_arg &key) { + auto it = this->find(key); + if (it == this->end()) + base_internal::ThrowStdOutOfRange("phmap::btree_map::at"); + return it->second; + } + template + const mapped_type &at(const key_arg &key) const { + auto it = this->find(key); + if (it == this->end()) + base_internal::ThrowStdOutOfRange("phmap::btree_map::at"); + return it->second; + } + }; + + // A common base class for btree_multiset and btree_multimap. + template + class btree_multiset_container : public btree_container { + using super_type = btree_container; + using params_type = typename Tree::params_type; + using init_type = typename params_type::init_type; + using is_key_compare_to = typename params_type::is_key_compare_to; + + template + using key_arg = typename super_type::template key_arg; + + public: + using key_type = typename Tree::key_type; + using value_type = typename Tree::value_type; + using size_type = typename Tree::size_type; + using key_compare = typename Tree::key_compare; + using allocator_type = typename Tree::allocator_type; + using iterator = typename Tree::iterator; + using const_iterator = typename Tree::const_iterator; + using node_type = typename super_type::node_type; + + // Inherit constructors. + using super_type::super_type; + btree_multiset_container() {} + + // Range constructor. + template + btree_multiset_container(InputIterator b, InputIterator e, + const key_compare &comp = key_compare(), + const allocator_type &alloc = allocator_type()) + : super_type(comp, alloc) { + insert(b, e); + } + + // Initializer list constructor. + btree_multiset_container(std::initializer_list init, + const key_compare &comp = key_compare(), + const allocator_type &alloc = allocator_type()) + : btree_multiset_container(init.begin(), init.end(), comp, alloc) {} + + // Lookup routines. + template + size_type count(const key_arg &key) const { + return this->tree_.count_multi(key); + } + + // Insertion routines. + iterator insert(const value_type &x) { return this->tree_.insert_multi(x); } + iterator insert(value_type &&x) { + return this->tree_.insert_multi(std::move(x)); + } + iterator insert(const_iterator position, const value_type &x) { + return this->tree_.insert_hint_multi(iterator(position), x); + } + iterator insert(const_iterator position, value_type &&x) { + return this->tree_.insert_hint_multi(iterator(position), std::move(x)); + } + template + void insert(InputIterator b, InputIterator e) { + this->tree_.insert_iterator_multi(b, e); + } + void insert(std::initializer_list init) { + this->tree_.insert_iterator_multi(init.begin(), init.end()); + } + template + iterator emplace(Args &&... args) { + return this->tree_.insert_multi(init_type(std::forward(args)...)); + } + template + iterator emplace_hint(const_iterator position, Args &&... args) { + return this->tree_.insert_hint_multi( + iterator(position), init_type(std::forward(args)...)); + } + iterator insert(node_type &&node) { + if (!node) return this->end(); + iterator res = + this->tree_.insert_multi(params_type::key(CommonAccess::GetSlot(node)), + CommonAccess::GetSlot(node)); + CommonAccess::Destroy(&node); + return res; + } + iterator insert(const_iterator hint, node_type &&node) { + if (!node) return this->end(); + iterator res = this->tree_.insert_hint_multi( + iterator(hint), + std::move(params_type::element(CommonAccess::GetSlot(node)))); + CommonAccess::Destroy(&node); + return res; + } + + // Deletion routines. + template + size_type erase(const key_arg &key) { + return this->tree_.erase_multi(key); + } + using super_type::erase; + + // Node extraction routines. + template + node_type extract(const key_arg &key) { + auto it = this->find(key); + return it == this->end() ? node_type() : extract(it); + } + using super_type::extract; + + // Merge routines. + // Moves all elements from `src` into `this`. + template < + typename T, + typename phmap::enable_if_t< + phmap::conjunction< + std::is_same, + std::is_same, + std::is_same>::value, + int> = 0> + void merge(btree_container &src) { // NOLINT + insert(std::make_move_iterator(src.begin()), + std::make_move_iterator(src.end())); + src.clear(); + } + + template < + typename T, + typename phmap::enable_if_t< + phmap::conjunction< + std::is_same, + std::is_same, + std::is_same>::value, + int> = 0> + void merge(btree_container &&src) { + merge(src); + } + }; + + // A base class for btree_multimap. + template + class btree_multimap_container : public btree_multiset_container { + using super_type = btree_multiset_container; + using params_type = typename Tree::params_type; + + public: + using mapped_type = typename params_type::mapped_type; + + // Inherit constructors. + using super_type::super_type; + btree_multimap_container() {} + }; + +} // namespace priv + + + + // ---------------------------------------------------------------------- + // btree_set - default values in phmap_fwd_decl.h + // ---------------------------------------------------------------------- + template + class btree_set : public priv::btree_set_container< + priv::btree>> + { + using Base = typename btree_set::btree_set_container; + + public: + btree_set() {} + using Base::Base; + using Base::begin; + using Base::cbegin; + using Base::end; + using Base::cend; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::emplace; + using Base::emplace_hint; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::get_allocator; + using Base::key_comp; + using Base::value_comp; + }; + + // Swaps the contents of two `phmap::btree_set` containers. + // ------------------------------------------------------- + template + void swap(btree_set &x, btree_set &y) { + return x.swap(y); + } + + // Erases all elements that satisfy the predicate pred from the container. + // ---------------------------------------------------------------------- + template + void erase_if(btree_set &set, Pred pred) { + for (auto it = set.begin(); it != set.end();) { + if (pred(*it)) { + it = set.erase(it); + } else { + ++it; + } + } + } + + // ---------------------------------------------------------------------- + // btree_multiset - default values in phmap_fwd_decl.h + // ---------------------------------------------------------------------- + template + class btree_multiset : public priv::btree_multiset_container< + priv::btree>> + { + using Base = typename btree_multiset::btree_multiset_container; + + public: + btree_multiset() {} + using Base::Base; + using Base::begin; + using Base::cbegin; + using Base::end; + using Base::cend; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::emplace; + using Base::emplace_hint; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::get_allocator; + using Base::key_comp; + using Base::value_comp; + }; + + // Swaps the contents of two `phmap::btree_multiset` containers. + // ------------------------------------------------------------ + template + void swap(btree_multiset &x, btree_multiset &y) { + return x.swap(y); + } + + // Erases all elements that satisfy the predicate pred from the container. + // ---------------------------------------------------------------------- + template + void erase_if(btree_multiset &set, Pred pred) { + for (auto it = set.begin(); it != set.end();) { + if (pred(*it)) { + it = set.erase(it); + } else { + ++it; + } + } + } + + + // ---------------------------------------------------------------------- + // btree_map - default values in phmap_fwd_decl.h + // ---------------------------------------------------------------------- + template + class btree_map : public priv::btree_map_container< + priv::btree>> + { + using Base = typename btree_map::btree_map_container; + + public: + btree_map() {} + using Base::Base; + using Base::begin; + using Base::cbegin; + using Base::end; + using Base::cend; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::emplace; + using Base::emplace_hint; + using Base::try_emplace; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::at; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::operator[]; + using Base::get_allocator; + using Base::key_comp; + using Base::value_comp; + }; + + // Swaps the contents of two `phmap::btree_map` containers. + // ------------------------------------------------------- + template + void swap(btree_map &x, btree_map &y) { + return x.swap(y); + } + + // ---------------------------------------------------------------------- + template + void erase_if(btree_map &map, Pred pred) { + for (auto it = map.begin(); it != map.end();) { + if (pred(*it)) { + it = map.erase(it); + } else { + ++it; + } + } + } + + // ---------------------------------------------------------------------- + // btree_multimap - default values in phmap_fwd_decl.h + // ---------------------------------------------------------------------- + template + class btree_multimap : public priv::btree_multimap_container< + priv::btree>> + { + using Base = typename btree_multimap::btree_multimap_container; + + public: + btree_multimap() {} + using Base::Base; + using Base::begin; + using Base::cbegin; + using Base::end; + using Base::cend; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::emplace; + using Base::emplace_hint; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::get_allocator; + using Base::key_comp; + using Base::value_comp; + }; + + // Swaps the contents of two `phmap::btree_multimap` containers. + // ------------------------------------------------------------ + template + void swap(btree_multimap &x, btree_multimap &y) { + return x.swap(y); + } + + // Erases all elements that satisfy the predicate pred from the container. + // ---------------------------------------------------------------------- + template + void erase_if(btree_multimap &map, Pred pred) { + for (auto it = map.begin(); it != map.end();) { + if (pred(*it)) { + it = map.erase(it); + } else { + ++it; + } + } + } + + +} // namespace btree + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + + +#endif // PHMAP_BTREE_BTREE_CONTAINER_H_ diff --git a/extern/phmap/parallel_hashmap/conanfile.py b/extern/phmap/parallel_hashmap/conanfile.py new file mode 100644 index 0000000..c046377 --- /dev/null +++ b/extern/phmap/parallel_hashmap/conanfile.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from conans import ConanFile, tools +import os + +class SparseppConan(ConanFile): + name = "parallel_hashmap" + version = "1.27" + description = "A header-only, very fast and memory-friendly hash map" + + # Indicates License type of the packaged library + license = "https://github.com/greg7mdp/parallel-hashmap/blob/master/LICENSE" + + # Packages the license for the conanfile.py + exports = ["LICENSE"] + + # Custom attributes for Bincrafters recipe conventions + source_subfolder = "source_subfolder" + + def source(self): + source_url = "https://github.com/greg7mdp/parallel-hashmap" + tools.get("{0}/archive/{1}.tar.gz".format(source_url, self.version)) + extracted_dir = self.name + "-" + self.version + + #Rename to "source_folder" is a convention to simplify later steps + os.rename(extracted_dir, self.source_subfolder) + + + def package(self): + include_folder = os.path.join(self.source_subfolder, "parallel_hashmap") + self.copy(pattern="LICENSE") + self.copy(pattern="*", dst="include/parallel_hashmap", src=include_folder) + + def package_id(self): + self.info.header_only() diff --git a/extern/phmap/parallel_hashmap/meminfo.h b/extern/phmap/parallel_hashmap/meminfo.h new file mode 100644 index 0000000..872f3c6 --- /dev/null +++ b/extern/phmap/parallel_hashmap/meminfo.h @@ -0,0 +1,195 @@ +#if !defined(spp_memory_h_guard) +#define spp_memory_h_guard + +#include +#include +#include + +#if defined(_WIN32) || defined( __CYGWIN__) + #define SPP_WIN +#endif + +#ifdef SPP_WIN + #include + #include + #undef min + #undef max +#elif defined(__linux__) + #include + #include +#elif defined(__FreeBSD__) + #include + #include + #include + #include + #include + #include +#endif + +namespace spp +{ + uint64_t GetSystemMemory(); + uint64_t GetTotalMemoryUsed(); + uint64_t GetProcessMemoryUsed(); + uint64_t GetPhysicalMemory(); + + uint64_t GetSystemMemory() + { +#ifdef SPP_WIN + MEMORYSTATUSEX memInfo; + memInfo.dwLength = sizeof(MEMORYSTATUSEX); + GlobalMemoryStatusEx(&memInfo); + return static_cast(memInfo.ullTotalPageFile); +#elif defined(__linux__) + struct sysinfo memInfo; + sysinfo (&memInfo); + auto totalVirtualMem = memInfo.totalram; + + totalVirtualMem += memInfo.totalswap; + totalVirtualMem *= memInfo.mem_unit; + return static_cast(totalVirtualMem); +#elif defined(__FreeBSD__) + kvm_t *kd; + u_int pageCnt; + size_t pageCntLen = sizeof(pageCnt); + u_int pageSize; + struct kvm_swap kswap; + uint64_t totalVirtualMem; + + pageSize = static_cast(getpagesize()); + + sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0); + totalVirtualMem = pageCnt * pageSize; + + kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); + kvm_getswapinfo(kd, &kswap, 1, 0); + kvm_close(kd); + totalVirtualMem += kswap.ksw_total * pageSize; + + return totalVirtualMem; +#else + return 0; +#endif + } + + uint64_t GetTotalMemoryUsed() + { +#ifdef SPP_WIN + MEMORYSTATUSEX memInfo; + memInfo.dwLength = sizeof(MEMORYSTATUSEX); + GlobalMemoryStatusEx(&memInfo); + return static_cast(memInfo.ullTotalPageFile - memInfo.ullAvailPageFile); +#elif defined(__linux__) + struct sysinfo memInfo; + sysinfo(&memInfo); + auto virtualMemUsed = memInfo.totalram - memInfo.freeram; + + virtualMemUsed += memInfo.totalswap - memInfo.freeswap; + virtualMemUsed *= memInfo.mem_unit; + + return static_cast(virtualMemUsed); +#elif defined(__FreeBSD__) + kvm_t *kd; + u_int pageSize; + u_int pageCnt, freeCnt; + size_t pageCntLen = sizeof(pageCnt); + size_t freeCntLen = sizeof(freeCnt); + struct kvm_swap kswap; + uint64_t virtualMemUsed; + + pageSize = static_cast(getpagesize()); + + sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0); + sysctlbyname("vm.stats.vm.v_free_count", &freeCnt, &freeCntLen, NULL, 0); + virtualMemUsed = (pageCnt - freeCnt) * pageSize; + + kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); + kvm_getswapinfo(kd, &kswap, 1, 0); + kvm_close(kd); + virtualMemUsed += kswap.ksw_used * pageSize; + + return virtualMemUsed; +#else + return 0; +#endif + } + + uint64_t GetProcessMemoryUsed() + { +#ifdef SPP_WIN + PROCESS_MEMORY_COUNTERS_EX pmc; + GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast(&pmc), sizeof(pmc)); + return static_cast(pmc.PrivateUsage); +#elif defined(__linux__) + auto parseLine = + [](char* line)->int + { + auto i = strlen(line); + + while(*line < '0' || *line > '9') + { + line++; + } + + line[i-3] = '\0'; + i = atoi(line); + return i; + }; + + auto file = fopen("/proc/self/status", "r"); + auto result = -1; + char line[128]; + + while(fgets(line, 128, file) != nullptr) + { + if(strncmp(line, "VmSize:", 7) == 0) + { + result = parseLine(line); + break; + } + } + + fclose(file); + return static_cast(result) * 1024; +#elif defined(__FreeBSD__) + struct kinfo_proc info; + size_t infoLen = sizeof(info); + int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() }; + + sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &infoLen, NULL, 0); + return static_cast(info.ki_rssize * getpagesize()); +#else + return 0; +#endif + } + + uint64_t GetPhysicalMemory() + { +#ifdef SPP_WIN + MEMORYSTATUSEX memInfo; + memInfo.dwLength = sizeof(MEMORYSTATUSEX); + GlobalMemoryStatusEx(&memInfo); + return static_cast(memInfo.ullTotalPhys); +#elif defined(__linux__) + struct sysinfo memInfo; + sysinfo(&memInfo); + + auto totalPhysMem = memInfo.totalram; + + totalPhysMem *= memInfo.mem_unit; + return static_cast(totalPhysMem); +#elif defined(__FreeBSD__) + u_long physMem; + size_t physMemLen = sizeof(physMem); + int mib[] = { CTL_HW, HW_PHYSMEM }; + + sysctl(mib, sizeof(mib) / sizeof(*mib), &physMem, &physMemLen, NULL, 0); + return physMem; +#else + return 0; +#endif + } + +} + +#endif // spp_memory_h_guard diff --git a/extern/phmap/parallel_hashmap/phmap.h b/extern/phmap/parallel_hashmap/phmap.h new file mode 100644 index 0000000..f8de239 --- /dev/null +++ b/extern/phmap/parallel_hashmap/phmap.h @@ -0,0 +1,4812 @@ +#if !defined(phmap_h_guard_) +#define phmap_h_guard_ + +// --------------------------------------------------------------------------- +// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp) +// with modifications. +// +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// --------------------------------------------------------------------------- + +#ifdef _MSC_VER + #pragma warning(push) + + #pragma warning(disable : 4127) // conditional expression is constant + #pragma warning(disable : 4324) // structure was padded due to alignment specifier + #pragma warning(disable : 4514) // unreferenced inline function has been removed + #pragma warning(disable : 4623) // default constructor was implicitly defined as deleted + #pragma warning(disable : 4625) // copy constructor was implicitly defined as deleted + #pragma warning(disable : 4626) // assignment operator was implicitly defined as deleted + #pragma warning(disable : 4710) // function not inlined + #pragma warning(disable : 4711) // selected for automatic inline expansion + #pragma warning(disable : 4820) // '6' bytes padding added after data member + #pragma warning(disable : 4868) // compiler may not enforce left-to-right evaluation order in braced initializer list + #pragma warning(disable : 5027) // move assignment operator was implicitly defined as deleted + #pragma warning(disable : 5045) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phmap_fwd_decl.h" +#include "phmap_utils.h" +#include "phmap_base.h" + +#if PHMAP_HAVE_STD_STRING_VIEW + #include +#endif + +namespace phmap { + +namespace priv { + +// -------------------------------------------------------------------------- +template +class probe_seq +{ +public: + probe_seq(size_t hashval, size_t mask) { + assert(((mask + 1) & mask) == 0 && "not a mask"); + mask_ = mask; + offset_ = hashval & mask_; + } + size_t offset() const { return offset_; } + size_t offset(size_t i) const { return (offset_ + i) & mask_; } + + void next() { + index_ += Width; + offset_ += index_; + offset_ &= mask_; + } + // 0-based probe index. The i-th probe in the probe sequence. + size_t getindex() const { return index_; } + +private: + size_t mask_; + size_t offset_; + size_t index_ = 0; +}; + +// -------------------------------------------------------------------------- +template +struct RequireUsableKey +{ + template + std::pair< + decltype(std::declval()(std::declval())), + decltype(std::declval()(std::declval(), + std::declval()))>* + operator()(const PassedKey&, const Args&...) const; +}; + +// -------------------------------------------------------------------------- +template +struct IsDecomposable : std::false_type {}; + +template +struct IsDecomposable< + phmap::void_t(), + std::declval()...))>, + Policy, Hash, Eq, Ts...> : std::true_type {}; + +// TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it. +// -------------------------------------------------------------------------- +template +constexpr bool IsNoThrowSwappable() { + using std::swap; + return noexcept(swap(std::declval(), std::declval())); +} + +// -------------------------------------------------------------------------- +template +int TrailingZeros(T x) { + PHMAP_IF_CONSTEXPR(sizeof(T) == 8) + return base_internal::CountTrailingZerosNonZero64(static_cast(x)); + else + return base_internal::CountTrailingZerosNonZero32(static_cast(x)); +} + +// -------------------------------------------------------------------------- +template +int LeadingZeros(T x) { + PHMAP_IF_CONSTEXPR(sizeof(T) == 8) + return base_internal::CountLeadingZeros64(static_cast(x)); + else + return base_internal::CountLeadingZeros32(static_cast(x)); +} + +// -------------------------------------------------------------------------- +// An abstraction over a bitmask. It provides an easy way to iterate through the +// indexes of the set bits of a bitmask. When Shift=0 (platforms with SSE), +// this is a true bitmask. On non-SSE, platforms the arithematic used to +// emulate the SSE behavior works in bytes (Shift=3) and leaves each bytes as +// either 0x00 or 0x80. +// +// For example: +// for (int i : BitMask(0x5)) -> yields 0, 2 +// for (int i : BitMask(0x0000000080800000)) -> yields 2, 3 +// -------------------------------------------------------------------------- +template +class BitMask +{ + static_assert(std::is_unsigned::value, ""); + static_assert(Shift == 0 || Shift == 3, ""); + +public: + // These are useful for unit tests (gunit). + using value_type = int; + using iterator = BitMask; + using const_iterator = BitMask; + + explicit BitMask(T mask) : mask_(mask) {} + BitMask& operator++() { + mask_ &= (mask_ - 1); + return *this; + } + explicit operator bool() const { return mask_ != 0; } + int operator*() const { return LowestBitSet(); } + int LowestBitSet() const { + return priv::TrailingZeros(mask_) >> Shift; + } + int HighestBitSet() const { + return (sizeof(T) * CHAR_BIT - priv::LeadingZeros(mask_) - + 1) >> + Shift; + } + + BitMask begin() const { return *this; } + BitMask end() const { return BitMask(0); } + + int TrailingZeros() const { + return priv::TrailingZeros(mask_) >> Shift; + } + + int LeadingZeros() const { + constexpr int total_significant_bits = SignificantBits << Shift; + constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits; + return priv::LeadingZeros(mask_ << extra_bits) >> Shift; + } + +private: + friend bool operator==(const BitMask& a, const BitMask& b) { + return a.mask_ == b.mask_; + } + friend bool operator!=(const BitMask& a, const BitMask& b) { + return a.mask_ != b.mask_; + } + + T mask_; +}; + +// -------------------------------------------------------------------------- +using ctrl_t = signed char; +using h2_t = uint8_t; + +// -------------------------------------------------------------------------- +// The values here are selected for maximum performance. See the static asserts +// below for details. +// -------------------------------------------------------------------------- +enum Ctrl : ctrl_t +{ + kEmpty = -128, // 0b10000000 + kDeleted = -2, // 0b11111110 + kSentinel = -1, // 0b11111111 +}; + +static_assert( + kEmpty & kDeleted & kSentinel & 0x80, + "Special markers need to have the MSB to make checking for them efficient"); +static_assert(kEmpty < kSentinel && kDeleted < kSentinel, + "kEmpty and kDeleted must be smaller than kSentinel to make the " + "SIMD test of IsEmptyOrDeleted() efficient"); +static_assert(kSentinel == -1, + "kSentinel must be -1 to elide loading it from memory into SIMD " + "registers (pcmpeqd xmm, xmm)"); +static_assert(kEmpty == -128, + "kEmpty must be -128 to make the SIMD check for its " + "existence efficient (psignb xmm, xmm)"); +static_assert(~kEmpty & ~kDeleted & kSentinel & 0x7F, + "kEmpty and kDeleted must share an unset bit that is not shared " + "by kSentinel to make the scalar test for MatchEmptyOrDeleted() " + "efficient"); +static_assert(kDeleted == -2, + "kDeleted must be -2 to make the implementation of " + "ConvertSpecialToEmptyAndFullToDeleted efficient"); + +// -------------------------------------------------------------------------- +// A single block of empty control bytes for tables without any slots allocated. +// This enables removing a branch in the hot path of find(). +// -------------------------------------------------------------------------- +inline ctrl_t* EmptyGroup() { + alignas(16) static constexpr ctrl_t empty_group[] = { + kSentinel, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, + kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty}; + return const_cast(empty_group); +} + +// -------------------------------------------------------------------------- +inline size_t HashSeed(const ctrl_t* ctrl) { + // The low bits of the pointer have little or no entropy because of + // alignment. We shift the pointer to try to use higher entropy bits. A + // good number seems to be 12 bits, because that aligns with page size. + return reinterpret_cast(ctrl) >> 12; +} + +#ifdef PHMAP_NON_DETERMINISTIC + +inline size_t H1(size_t hashval, const ctrl_t* ctrl) { + // use ctrl_ pointer to add entropy to ensure + // non-deterministic iteration order. + return (hashval >> 7) ^ HashSeed(ctrl); +} + +#else + +inline size_t H1(size_t hashval, const ctrl_t* ) { + return (hashval >> 7); +} + +#endif + + +inline ctrl_t H2(size_t hashval) { return (ctrl_t)(hashval & 0x7F); } + +inline bool IsEmpty(ctrl_t c) { return c == kEmpty; } +inline bool IsFull(ctrl_t c) { return c >= 0; } +inline bool IsDeleted(ctrl_t c) { return c == kDeleted; } +inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; } + +#if PHMAP_HAVE_SSE2 + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable : 4365) // conversion from 'int' to 'T', signed/unsigned mismatch +#endif + +// -------------------------------------------------------------------------- +// https://github.com/abseil/abseil-cpp/issues/209 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853 +// _mm_cmpgt_epi8 is broken under GCC with -funsigned-char +// Work around this by using the portable implementation of Group +// when using -funsigned-char under GCC. +// -------------------------------------------------------------------------- +inline __m128i _mm_cmpgt_epi8_fixed(__m128i a, __m128i b) { +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Woverflow" + + if (std::is_unsigned::value) { + const __m128i mask = _mm_set1_epi8(static_cast(0x80)); + const __m128i diff = _mm_subs_epi8(b, a); + return _mm_cmpeq_epi8(_mm_and_si128(diff, mask), mask); + } + + #pragma GCC diagnostic pop +#endif + return _mm_cmpgt_epi8(a, b); +} + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +struct GroupSse2Impl +{ + enum { kWidth = 16 }; // the number of slots per group + + explicit GroupSse2Impl(const ctrl_t* pos) { + ctrl = _mm_loadu_si128(reinterpret_cast(pos)); + } + + // Returns a bitmask representing the positions of slots that match hash. + // ---------------------------------------------------------------------- + BitMask Match(h2_t hash) const { + auto match = _mm_set1_epi8((char)hash); + return BitMask( + _mm_movemask_epi8(_mm_cmpeq_epi8(match, ctrl))); + } + + // Returns a bitmask representing the positions of empty slots. + // ------------------------------------------------------------ + BitMask MatchEmpty() const { +#if PHMAP_HAVE_SSSE3 + // This only works because kEmpty is -128. + return BitMask( + _mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl))); +#else + return Match(static_cast(kEmpty)); +#endif + } + + // Returns a bitmask representing the positions of empty or deleted slots. + // ----------------------------------------------------------------------- + BitMask MatchEmptyOrDeleted() const { + auto special = _mm_set1_epi8(kSentinel); + return BitMask( + _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))); + } + + // Returns the number of trailing empty or deleted elements in the group. + // ---------------------------------------------------------------------- + uint32_t CountLeadingEmptyOrDeleted() const { + auto special = _mm_set1_epi8(kSentinel); + return TrailingZeros( + _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1); + } + + // ---------------------------------------------------------------------- + void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const { + auto msbs = _mm_set1_epi8(static_cast(-128)); + auto x126 = _mm_set1_epi8(126); +#if PHMAP_HAVE_SSSE3 + auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs); +#else + auto zero = _mm_setzero_si128(); + auto special_mask = _mm_cmpgt_epi8_fixed(zero, ctrl); + auto res = _mm_or_si128(msbs, _mm_andnot_si128(special_mask, x126)); +#endif + _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), res); + } + + __m128i ctrl; +}; + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif // PHMAP_HAVE_SSE2 + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +struct GroupPortableImpl +{ + enum { kWidth = 8 }; + + explicit GroupPortableImpl(const ctrl_t* pos) + : ctrl(little_endian::Load64(pos)) {} + + BitMask Match(h2_t hash) const { + // For the technique, see: + // http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord + // (Determine if a word has a byte equal to n). + // + // Caveat: there are false positives but: + // - they only occur if there is a real match + // - they never occur on kEmpty, kDeleted, kSentinel + // - they will be handled gracefully by subsequent checks in code + // + // Example: + // v = 0x1716151413121110 + // hash = 0x12 + // retval = (v - lsbs) & ~v & msbs = 0x0000000080800000 + constexpr uint64_t msbs = 0x8080808080808080ULL; + constexpr uint64_t lsbs = 0x0101010101010101ULL; + auto x = ctrl ^ (lsbs * hash); + return BitMask((x - lsbs) & ~x & msbs); + } + + BitMask MatchEmpty() const { + constexpr uint64_t msbs = 0x8080808080808080ULL; + return BitMask((ctrl & (~ctrl << 6)) & msbs); + } + + BitMask MatchEmptyOrDeleted() const { + constexpr uint64_t msbs = 0x8080808080808080ULL; + return BitMask((ctrl & (~ctrl << 7)) & msbs); + } + + uint32_t CountLeadingEmptyOrDeleted() const { + constexpr uint64_t gaps = 0x00FEFEFEFEFEFEFEULL; + return (uint32_t)((TrailingZeros(((~ctrl & (ctrl >> 7)) | gaps) + 1) + 7) >> 3); + } + + void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const { + constexpr uint64_t msbs = 0x8080808080808080ULL; + constexpr uint64_t lsbs = 0x0101010101010101ULL; + auto x = ctrl & msbs; + auto res = (~x + (x >> 7)) & ~lsbs; + little_endian::Store64(dst, res); + } + + uint64_t ctrl; +}; + +#if PHMAP_HAVE_SSE2 + using Group = GroupSse2Impl; +#else + using Group = GroupPortableImpl; +#endif + +template +class raw_hash_set; + +inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } + +// -------------------------------------------------------------------------- +// PRECONDITION: +// IsValidCapacity(capacity) +// ctrl[capacity] == kSentinel +// ctrl[i] != kSentinel for all i < capacity +// Applies mapping for every byte in ctrl: +// DELETED -> EMPTY +// EMPTY -> EMPTY +// FULL -> DELETED +// -------------------------------------------------------------------------- +inline void ConvertDeletedToEmptyAndFullToDeleted( + ctrl_t* ctrl, size_t capacity) +{ + assert(ctrl[capacity] == kSentinel); + assert(IsValidCapacity(capacity)); + for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) { + Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos); + } + // Copy the cloned ctrl bytes. + std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth); + ctrl[capacity] = kSentinel; +} + +// -------------------------------------------------------------------------- +// Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1. +// -------------------------------------------------------------------------- +inline size_t NormalizeCapacity(size_t n) +{ + return n ? ~size_t{} >> LeadingZeros(n) : 1; +} + +// -------------------------------------------------------------------------- +// We use 7/8th as maximum load factor. +// For 16-wide groups, that gives an average of two empty slots per group. +// -------------------------------------------------------------------------- +inline size_t CapacityToGrowth(size_t capacity) +{ + assert(IsValidCapacity(capacity)); + // `capacity*7/8` + PHMAP_IF_CONSTEXPR (Group::kWidth == 8) { + if (capacity == 7) + { + // x-x/8 does not work when x==7. + return 6; + } + } + return capacity - capacity / 8; +} + +// -------------------------------------------------------------------------- +// From desired "growth" to a lowerbound of the necessary capacity. +// Might not be a valid one and required NormalizeCapacity(). +// -------------------------------------------------------------------------- +inline size_t GrowthToLowerboundCapacity(size_t growth) +{ + // `growth*8/7` + PHMAP_IF_CONSTEXPR (Group::kWidth == 8) { + if (growth == 7) + { + // x+(x-1)/7 does not work when x==7. + return 8; + } + } + return growth + static_cast((static_cast(growth) - 1) / 7); +} + +namespace hashtable_debug_internal { + +// If it is a map, call get<0>(). +using std::get; +template +auto GetKey(const typename T::value_type& pair, int) -> decltype(get<0>(pair)) { + return get<0>(pair); +} + +// If it is not a map, return the value directly. +template +const typename T::key_type& GetKey(const typename T::key_type& key, char) { + return key; +} + +// -------------------------------------------------------------------------- +// Containers should specialize this to provide debug information for that +// container. +// -------------------------------------------------------------------------- +template +struct HashtableDebugAccess +{ + // Returns the number of probes required to find `key` in `c`. The "number of + // probes" is a concept that can vary by container. Implementations should + // return 0 when `key` was found in the minimum number of operations and + // should increment the result for each non-trivial operation required to find + // `key`. + // + // The default implementation uses the bucket api from the standard and thus + // works for `std::unordered_*` containers. + // -------------------------------------------------------------------------- + static size_t GetNumProbes(const Container& c, + const typename Container::key_type& key) { + if (!c.bucket_count()) return {}; + size_t num_probes = 0; + size_t bucket = c.bucket(key); + for (auto it = c.begin(bucket), e = c.end(bucket);; ++it, ++num_probes) { + if (it == e) return num_probes; + if (c.key_eq()(key, GetKey(*it, 0))) return num_probes; + } + } +}; + +} // namespace hashtable_debug_internal + +// ---------------------------------------------------------------------------- +// I N F O Z S T U B S +// ---------------------------------------------------------------------------- +struct HashtablezInfo +{ + void PrepareForSampling() {} +}; + +inline void RecordRehashSlow(HashtablezInfo*, size_t ) {} + +static inline void RecordInsertSlow(HashtablezInfo* , size_t, size_t ) {} + +static inline void RecordEraseSlow(HashtablezInfo*) {} + +static inline HashtablezInfo* SampleSlow(int64_t*) { return nullptr; } +static inline void UnsampleSlow(HashtablezInfo* ) {} + +class HashtablezInfoHandle +{ +public: + inline void RecordStorageChanged(size_t , size_t ) {} + inline void RecordRehash(size_t ) {} + inline void RecordInsert(size_t , size_t ) {} + inline void RecordErase() {} + friend inline void swap(HashtablezInfoHandle& , + HashtablezInfoHandle& ) noexcept {} +}; + +static inline HashtablezInfoHandle Sample() { return HashtablezInfoHandle(); } + +class HashtablezSampler +{ +public: + // Returns a global Sampler. + static HashtablezSampler& Global() { static HashtablezSampler hzs; return hzs; } + HashtablezInfo* Register() { static HashtablezInfo info; return &info; } + void Unregister(HashtablezInfo* ) {} + + using DisposeCallback = void (*)(const HashtablezInfo&); + DisposeCallback SetDisposeCallback(DisposeCallback ) { return nullptr; } + int64_t Iterate(const std::function& ) { return 0; } +}; + +static inline void SetHashtablezEnabled(bool ) {} +static inline void SetHashtablezSampleParameter(int32_t ) {} +static inline void SetHashtablezMaxSamples(int32_t ) {} + + +namespace memory_internal { + +// Constructs T into uninitialized storage pointed by `ptr` using the args +// specified in the tuple. +// ---------------------------------------------------------------------------- +template +void ConstructFromTupleImpl(Alloc* alloc, T* ptr, Tuple&& t, + phmap::index_sequence) { + phmap::allocator_traits::construct( + *alloc, ptr, std::get(std::forward(t))...); +} + +template +struct WithConstructedImplF { + template + decltype(std::declval()(std::declval())) operator()( + Args&&... args) const { + return std::forward(f)(T(std::forward(args)...)); + } + F&& f; +}; + +template +decltype(std::declval()(std::declval())) WithConstructedImpl( + Tuple&& t, phmap::index_sequence, F&& f) { + return WithConstructedImplF{std::forward(f)}( + std::get(std::forward(t))...); +} + +template +auto TupleRefImpl(T&& t, phmap::index_sequence) + -> decltype(std::forward_as_tuple(std::get(std::forward(t))...)) { + return std::forward_as_tuple(std::get(std::forward(t))...); +} + +// Returns a tuple of references to the elements of the input tuple. T must be a +// tuple. +// ---------------------------------------------------------------------------- +template +auto TupleRef(T&& t) -> decltype( + TupleRefImpl(std::forward(t), + phmap::make_index_sequence< + std::tuple_size::type>::value>())) { + return TupleRefImpl( + std::forward(t), + phmap::make_index_sequence< + std::tuple_size::type>::value>()); +} + +template +decltype(std::declval()(std::declval(), std::piecewise_construct, + std::declval>(), std::declval())) +DecomposePairImpl(F&& f, std::pair, V> p) { + const auto& key = std::get<0>(p.first); + return std::forward(f)(key, std::piecewise_construct, std::move(p.first), + std::move(p.second)); +} + +} // namespace memory_internal + + +// ---------------------------------------------------------------------------- +// R A W _ H A S H _ S E T +// ---------------------------------------------------------------------------- +// An open-addressing +// hashtable with quadratic probing. +// +// This is a low level hashtable on top of which different interfaces can be +// implemented, like flat_hash_set, node_hash_set, string_hash_set, etc. +// +// The table interface is similar to that of std::unordered_set. Notable +// differences are that most member functions support heterogeneous keys when +// BOTH the hash and eq functions are marked as transparent. They do so by +// providing a typedef called `is_transparent`. +// +// When heterogeneous lookup is enabled, functions that take key_type act as if +// they have an overload set like: +// +// iterator find(const key_type& key); +// template +// iterator find(const K& key); +// +// size_type erase(const key_type& key); +// template +// size_type erase(const K& key); +// +// std::pair equal_range(const key_type& key); +// template +// std::pair equal_range(const K& key); +// +// When heterogeneous lookup is disabled, only the explicit `key_type` overloads +// exist. +// +// find() also supports passing the hash explicitly: +// +// iterator find(const key_type& key, size_t hash); +// template +// iterator find(const U& key, size_t hash); +// +// In addition the pointer to element and iterator stability guarantees are +// weaker: all iterators and pointers are invalidated after a new element is +// inserted. +// +// IMPLEMENTATION DETAILS +// +// The table stores elements inline in a slot array. In addition to the slot +// array the table maintains some control state per slot. The extra state is one +// byte per slot and stores empty or deleted marks, or alternatively 7 bits from +// the hash of an occupied slot. The table is split into logical groups of +// slots, like so: +// +// Group 1 Group 2 Group 3 +// +---------------+---------------+---------------+ +// | | | | | | | | | | | | | | | | | | | | | | | | | +// +---------------+---------------+---------------+ +// +// On lookup the hash is split into two parts: +// - H2: 7 bits (those stored in the control bytes) +// - H1: the rest of the bits +// The groups are probed using H1. For each group the slots are matched to H2 in +// parallel. Because H2 is 7 bits (128 states) and the number of slots per group +// is low (8 or 16) in almost all cases a match in H2 is also a lookup hit. +// +// On insert, once the right group is found (as in lookup), its slots are +// filled in order. +// +// On erase a slot is cleared. In case the group did not have any empty slots +// before the erase, the erased slot is marked as deleted. +// +// Groups without empty slots (but maybe with deleted slots) extend the probe +// sequence. The probing algorithm is quadratic. Given N the number of groups, +// the probing function for the i'th probe is: +// +// P(0) = H1 % N +// +// P(i) = (P(i - 1) + i) % N +// +// This probing function guarantees that after N probes, all the groups of the +// table will be probed exactly once. +// ---------------------------------------------------------------------------- +template +class raw_hash_set +{ + using PolicyTraits = hash_policy_traits; + using KeyArgImpl = + KeyArg::value && IsTransparent::value>; + +public: + using init_type = typename PolicyTraits::init_type; + using key_type = typename PolicyTraits::key_type; + // TODO(sbenza): Hide slot_type as it is an implementation detail. Needs user + // code fixes! + using slot_type = typename PolicyTraits::slot_type; + using allocator_type = Alloc; + using size_type = size_t; + using difference_type = ptrdiff_t; + using hasher = Hash; + using key_equal = Eq; + using policy_type = Policy; + using value_type = typename PolicyTraits::value_type; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = typename phmap::allocator_traits< + allocator_type>::template rebind_traits::pointer; + using const_pointer = typename phmap::allocator_traits< + allocator_type>::template rebind_traits::const_pointer; + + // Alias used for heterogeneous lookup functions. + // `key_arg` evaluates to `K` when the functors are transparent and to + // `key_type` otherwise. It permits template argument deduction on `K` for the + // transparent case. + template + using key_arg = typename KeyArgImpl::template type; + +private: + // Give an early error when key_type is not hashable/eq. + auto KeyTypeCanBeHashed(const Hash& h, const key_type& k) -> decltype(h(k)); + auto KeyTypeCanBeEq(const Eq& eq, const key_type& k) -> decltype(eq(k, k)); + + using Layout = phmap::priv::Layout; + + static Layout MakeLayout(size_t capacity) { + assert(IsValidCapacity(capacity)); + return Layout(capacity + Group::kWidth + 1, capacity); + } + + using AllocTraits = phmap::allocator_traits; + using SlotAlloc = typename phmap::allocator_traits< + allocator_type>::template rebind_alloc; + using SlotAllocTraits = typename phmap::allocator_traits< + allocator_type>::template rebind_traits; + + static_assert(std::is_lvalue_reference::value, + "Policy::element() must return a reference"); + + template + struct SameAsElementReference + : std::is_same::type>::type, + typename std::remove_cv< + typename std::remove_reference::type>::type> {}; + + // An enabler for insert(T&&): T must be convertible to init_type or be the + // same as [cv] value_type [ref]. + // Note: we separate SameAsElementReference into its own type to avoid using + // reference unless we need to. MSVC doesn't seem to like it in some + // cases. + template + using RequiresInsertable = typename std::enable_if< + phmap::disjunction, + SameAsElementReference>::value, + int>::type; + + // RequiresNotInit is a workaround for gcc prior to 7.1. + // See https://godbolt.org/g/Y4xsUh. + template + using RequiresNotInit = + typename std::enable_if::value, int>::type; + + template + using IsDecomposable = IsDecomposable; + +public: + static_assert(std::is_same::value, + "Allocators with custom pointer types are not supported"); + static_assert(std::is_same::value, + "Allocators with custom pointer types are not supported"); + + class iterator + { + friend class raw_hash_set; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = typename raw_hash_set::value_type; + using reference = + phmap::conditional_t; + using pointer = phmap::remove_reference_t*; + using difference_type = typename raw_hash_set::difference_type; + + iterator() {} + + // PRECONDITION: not an end() iterator. + reference operator*() const { return PolicyTraits::element(slot_); } + + // PRECONDITION: not an end() iterator. + pointer operator->() const { return &operator*(); } + + // PRECONDITION: not an end() iterator. + iterator& operator++() { + ++ctrl_; + ++slot_; + skip_empty_or_deleted(); + return *this; + } + // PRECONDITION: not an end() iterator. + iterator operator++(int) { + auto tmp = *this; + ++*this; + return tmp; + } + +#if PHMAP_BIDIRECTIONAL + // PRECONDITION: not a begin() iterator. + iterator& operator--() { + assert(ctrl_); + do { + --ctrl_; + --slot_; + } while (IsEmptyOrDeleted(*ctrl_)); + return *this; + } + + // PRECONDITION: not a begin() iterator. + iterator operator--(int) { + auto tmp = *this; + --*this; + return tmp; + } +#endif + + friend bool operator==(const iterator& a, const iterator& b) { + return a.ctrl_ == b.ctrl_; + } + friend bool operator!=(const iterator& a, const iterator& b) { + return !(a == b); + } + + private: + iterator(ctrl_t* ctrl) : ctrl_(ctrl) {} // for end() + iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {} + + void skip_empty_or_deleted() { + while (IsEmptyOrDeleted(*ctrl_)) { + // ctrl is not necessarily aligned to Group::kWidth. It is also likely + // to read past the space for ctrl bytes and into slots. This is ok + // because ctrl has sizeof() == 1 and slot has sizeof() >= 1 so there + // is no way to read outside the combined slot array. + uint32_t shift = Group{ctrl_}.CountLeadingEmptyOrDeleted(); + ctrl_ += shift; + slot_ += shift; + } + } + + ctrl_t* ctrl_ = nullptr; + // To avoid uninitialized member warnings, put slot_ in an anonymous union. + // The member is not initialized on singleton and end iterators. + union { + slot_type* slot_; + }; + }; + + class const_iterator + { + friend class raw_hash_set; + + public: + using iterator_category = typename iterator::iterator_category; + using value_type = typename raw_hash_set::value_type; + using reference = typename raw_hash_set::const_reference; + using pointer = typename raw_hash_set::const_pointer; + using difference_type = typename raw_hash_set::difference_type; + + const_iterator() {} + // Implicit construction from iterator. + const_iterator(iterator i) : inner_(std::move(i)) {} + + reference operator*() const { return *inner_; } + pointer operator->() const { return inner_.operator->(); } + + const_iterator& operator++() { + ++inner_; + return *this; + } + const_iterator operator++(int) { return inner_++; } + + friend bool operator==(const const_iterator& a, const const_iterator& b) { + return a.inner_ == b.inner_; + } + friend bool operator!=(const const_iterator& a, const const_iterator& b) { + return !(a == b); + } + + private: + const_iterator(const ctrl_t* ctrl, const slot_type* slot) + : inner_(const_cast(ctrl), const_cast(slot)) {} + + iterator inner_; + }; + + using node_type = node_handle, Alloc>; + using insert_return_type = InsertReturnType; + + raw_hash_set() noexcept( + std::is_nothrow_default_constructible::value&& + std::is_nothrow_default_constructible::value&& + std::is_nothrow_default_constructible::value) {} + + explicit raw_hash_set(size_t bucket_cnt, const hasher& hashfn = hasher(), + const key_equal& eq = key_equal(), + const allocator_type& alloc = allocator_type()) + : ctrl_(EmptyGroup()), settings_(0, hashfn, eq, alloc) { + if (bucket_cnt) { + size_t new_capacity = NormalizeCapacity(bucket_cnt); + reset_growth_left(new_capacity); + initialize_slots(new_capacity); + capacity_ = new_capacity; + } + } + + raw_hash_set(size_t bucket_cnt, const hasher& hashfn, + const allocator_type& alloc) + : raw_hash_set(bucket_cnt, hashfn, key_equal(), alloc) {} + + raw_hash_set(size_t bucket_cnt, const allocator_type& alloc) + : raw_hash_set(bucket_cnt, hasher(), key_equal(), alloc) {} + + explicit raw_hash_set(const allocator_type& alloc) + : raw_hash_set(0, hasher(), key_equal(), alloc) {} + + template + raw_hash_set(InputIter first, InputIter last, size_t bucket_cnt = 0, + const hasher& hashfn = hasher(), const key_equal& eq = key_equal(), + const allocator_type& alloc = allocator_type()) + : raw_hash_set(bucket_cnt, hashfn, eq, alloc) { + insert(first, last); + } + + template + raw_hash_set(InputIter first, InputIter last, size_t bucket_cnt, + const hasher& hashfn, const allocator_type& alloc) + : raw_hash_set(first, last, bucket_cnt, hashfn, key_equal(), alloc) {} + + template + raw_hash_set(InputIter first, InputIter last, size_t bucket_cnt, + const allocator_type& alloc) + : raw_hash_set(first, last, bucket_cnt, hasher(), key_equal(), alloc) {} + + template + raw_hash_set(InputIter first, InputIter last, const allocator_type& alloc) + : raw_hash_set(first, last, 0, hasher(), key_equal(), alloc) {} + + // Instead of accepting std::initializer_list as the first + // argument like std::unordered_set does, we have two overloads + // that accept std::initializer_list and std::initializer_list. + // This is advantageous for performance. + // + // // Turns {"abc", "def"} into std::initializer_list, then + // // copies the strings into the set. + // std::unordered_set s = {"abc", "def"}; + // + // // Turns {"abc", "def"} into std::initializer_list, then + // // copies the strings into the set. + // phmap::flat_hash_set s = {"abc", "def"}; + // + // The same trick is used in insert(). + // + // The enabler is necessary to prevent this constructor from triggering where + // the copy constructor is meant to be called. + // + // phmap::flat_hash_set a, b{a}; + // + // RequiresNotInit is a workaround for gcc prior to 7.1. + template = 0, RequiresInsertable = 0> + raw_hash_set(std::initializer_list init, size_t bucket_cnt = 0, + const hasher& hashfn = hasher(), const key_equal& eq = key_equal(), + const allocator_type& alloc = allocator_type()) + : raw_hash_set(init.begin(), init.end(), bucket_cnt, hashfn, eq, alloc) {} + + raw_hash_set(std::initializer_list init, size_t bucket_cnt = 0, + const hasher& hashfn = hasher(), const key_equal& eq = key_equal(), + const allocator_type& alloc = allocator_type()) + : raw_hash_set(init.begin(), init.end(), bucket_cnt, hashfn, eq, alloc) {} + + template = 0, RequiresInsertable = 0> + raw_hash_set(std::initializer_list init, size_t bucket_cnt, + const hasher& hashfn, const allocator_type& alloc) + : raw_hash_set(init, bucket_cnt, hashfn, key_equal(), alloc) {} + + raw_hash_set(std::initializer_list init, size_t bucket_cnt, + const hasher& hashfn, const allocator_type& alloc) + : raw_hash_set(init, bucket_cnt, hashfn, key_equal(), alloc) {} + + template = 0, RequiresInsertable = 0> + raw_hash_set(std::initializer_list init, size_t bucket_cnt, + const allocator_type& alloc) + : raw_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {} + + raw_hash_set(std::initializer_list init, size_t bucket_cnt, + const allocator_type& alloc) + : raw_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {} + + template = 0, RequiresInsertable = 0> + raw_hash_set(std::initializer_list init, const allocator_type& alloc) + : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {} + + raw_hash_set(std::initializer_list init, + const allocator_type& alloc) + : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {} + + raw_hash_set(const raw_hash_set& that) + : raw_hash_set(that, AllocTraits::select_on_container_copy_construction( + that.alloc_ref())) {} + + raw_hash_set(const raw_hash_set& that, const allocator_type& a) + : raw_hash_set(0, that.hash_ref(), that.eq_ref(), a) { + reserve(that.size()); + // Because the table is guaranteed to be empty, we can do something faster + // than a full `insert`. + for (const auto& v : that) { + const size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, v); + auto target = find_first_non_full(hashval); + set_ctrl(target.offset, H2(hashval)); + emplace_at(target.offset, v); + infoz_.RecordInsert(hashval, target.probe_length); + } + size_ = that.size(); + growth_left() -= that.size(); + } + + raw_hash_set(raw_hash_set&& that) noexcept( + std::is_nothrow_copy_constructible::value&& + std::is_nothrow_copy_constructible::value&& + std::is_nothrow_copy_constructible::value) + : ctrl_(phmap::exchange(that.ctrl_, EmptyGroup())), + slots_(phmap::exchange(that.slots_, nullptr)), + size_(phmap::exchange(that.size_, 0)), + capacity_(phmap::exchange(that.capacity_, 0)), + infoz_(phmap::exchange(that.infoz_, HashtablezInfoHandle())), + // Hash, equality and allocator are copied instead of moved because + // `that` must be left valid. If Hash is std::function, moving it + // would create a nullptr functor that cannot be called. + settings_(that.settings_) { + // growth_left was copied above, reset the one from `that`. + that.growth_left() = 0; + } + + raw_hash_set(raw_hash_set&& that, const allocator_type& a) + : ctrl_(EmptyGroup()), + slots_(nullptr), + size_(0), + capacity_(0), + settings_(0, that.hash_ref(), that.eq_ref(), a) { + if (a == that.alloc_ref()) { + std::swap(ctrl_, that.ctrl_); + std::swap(slots_, that.slots_); + std::swap(size_, that.size_); + std::swap(capacity_, that.capacity_); + std::swap(growth_left(), that.growth_left()); + std::swap(infoz_, that.infoz_); + } else { + reserve(that.size()); + // Note: this will copy elements of dense_set and unordered_set instead of + // moving them. This can be fixed if it ever becomes an issue. + for (auto& elem : that) insert(std::move(elem)); + } + } + + raw_hash_set& operator=(const raw_hash_set& that) { + raw_hash_set tmp(that, + AllocTraits::propagate_on_container_copy_assignment::value + ? that.alloc_ref() + : alloc_ref()); + swap(tmp); + return *this; + } + + raw_hash_set& operator=(raw_hash_set&& that) noexcept( + phmap::allocator_traits::is_always_equal::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_assignable::value) { + // TODO(sbenza): We should only use the operations from the noexcept clause + // to make sure we actually adhere to that contract. + return move_assign( + std::move(that), + typename AllocTraits::propagate_on_container_move_assignment()); + } + + ~raw_hash_set() { destroy_slots(); } + + iterator begin() { + auto it = iterator_at(0); + it.skip_empty_or_deleted(); + return it; + } + iterator end() + { +#if PHMAP_BIDIRECTIONAL + return iterator_at(capacity_); +#else + return {ctrl_ + capacity_}; +#endif + } + + const_iterator begin() const { + return const_cast(this)->begin(); + } + const_iterator end() const { return const_cast(this)->end(); } + const_iterator cbegin() const { return begin(); } + const_iterator cend() const { return end(); } + + bool empty() const { return !size(); } + size_t size() const { return size_; } + size_t capacity() const { return capacity_; } + size_t max_size() const { return (std::numeric_limits::max)(); } + + PHMAP_ATTRIBUTE_REINITIALIZES void clear() { + // Iterating over this container is O(bucket_count()). When bucket_count() + // is much greater than size(), iteration becomes prohibitively expensive. + // For clear() it is more important to reuse the allocated array when the + // container is small because allocation takes comparatively long time + // compared to destruction of the elements of the container. So we pick the + // largest bucket_count() threshold for which iteration is still fast and + // past that we simply deallocate the array. + if (empty()) + return; + if (capacity_ > 127) { + destroy_slots(); + } else if (capacity_) { + for (size_t i = 0; i != capacity_; ++i) { + if (IsFull(ctrl_[i])) { + PolicyTraits::destroy(&alloc_ref(), slots_ + i); + } + } + size_ = 0; + reset_ctrl(capacity_); + reset_growth_left(capacity_); + } + assert(empty()); + infoz_.RecordStorageChanged(0, capacity_); + } + + // This overload kicks in when the argument is an rvalue of insertable and + // decomposable type other than init_type. + // + // flat_hash_map m; + // m.insert(std::make_pair("abc", 42)); + template = 0, + typename std::enable_if::value, int>::type = 0, + T* = nullptr> + std::pair insert(T&& value) { + return emplace(std::forward(value)); + } + + // This overload kicks in when the argument is a bitfield or an lvalue of + // insertable and decomposable type. + // + // union { int n : 1; }; + // flat_hash_set s; + // s.insert(n); + // + // flat_hash_set s; + // const char* p = "hello"; + // s.insert(p); + // + // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace + // RequiresInsertable with RequiresInsertable. + // We are hitting this bug: https://godbolt.org/g/1Vht4f. + template = 0, + typename std::enable_if::value, int>::type = 0> + std::pair insert(const T& value) { + return emplace(value); + } + + // This overload kicks in when the argument is an rvalue of init_type. Its + // purpose is to handle brace-init-list arguments. + // + // flat_hash_set s; + // s.insert({"abc", 42}); + std::pair insert(init_type&& value) { + return emplace(std::move(value)); + } + + template = 0, + typename std::enable_if::value, int>::type = 0, + T* = nullptr> + iterator insert(const_iterator, T&& value) { + return insert(std::forward(value)).first; + } + + // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace + // RequiresInsertable with RequiresInsertable. + // We are hitting this bug: https://godbolt.org/g/1Vht4f. + template = 0, + typename std::enable_if::value, int>::type = 0> + iterator insert(const_iterator, const T& value) { + return insert(value).first; + } + + iterator insert(const_iterator, init_type&& value) { + return insert(std::move(value)).first; + } + + template + using IsRandomAccess = std::is_same::iterator_category, + std::random_access_iterator_tag>; + + + template + struct has_difference_operator + { + private: + using yes = std::true_type; + using no = std::false_type; + + template static auto test(int) -> decltype(std::declval() - std::declval() == 1, yes()); + template static no test(...); + + public: + static constexpr bool value = std::is_same(0)), yes>::value; + }; + + template ::value, int> = 0> + void insert(InputIt first, InputIt last) { + this->reserve(this->size() + (last - first)); + for (; first != last; ++first) + emplace(*first); + } + + template ::value, int> = 0> + void insert(InputIt first, InputIt last) { + for (; first != last; ++first) + emplace(*first); + } + + template = 0, RequiresInsertable = 0> + void insert(std::initializer_list ilist) { + insert(ilist.begin(), ilist.end()); + } + + void insert(std::initializer_list ilist) { + insert(ilist.begin(), ilist.end()); + } + + insert_return_type insert(node_type&& node) { + if (!node) return {end(), false, node_type()}; + const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node)); + auto res = PolicyTraits::apply( + InsertSlot{*this, std::move(*CommonAccess::GetSlot(node))}, + elem); + if (res.second) { + CommonAccess::Reset(&node); + return {res.first, true, node_type()}; + } else { + return {res.first, false, std::move(node)}; + } + } + + insert_return_type insert(node_type&& node, size_t hashval) { + if (!node) return {end(), false, node_type()}; + const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node)); + auto res = PolicyTraits::apply( + InsertSlotWithHash{*this, std::move(*CommonAccess::GetSlot(node)), hashval}, + elem); + if (res.second) { + CommonAccess::Reset(&node); + return {res.first, true, node_type()}; + } else { + return {res.first, false, std::move(node)}; + } + } + + iterator insert(const_iterator, node_type&& node) { + return insert(std::move(node)).first; + } + + // This overload kicks in if we can deduce the key from args. This enables us + // to avoid constructing value_type if an entry with the same key already + // exists. + // + // For example: + // + // flat_hash_map m = {{"abc", "def"}}; + // // Creates no std::string copies and makes no heap allocations. + // m.emplace("abc", "xyz"); + template ::value, int>::type = 0> + std::pair emplace(Args&&... args) { + return PolicyTraits::apply(EmplaceDecomposable{*this}, + std::forward(args)...); + } + + template ::value, int>::type = 0> + std::pair emplace_with_hash(size_t hashval, Args&&... args) { + return PolicyTraits::apply(EmplaceDecomposableHashval{*this, hashval}, std::forward(args)...); + } + + // This overload kicks in if we cannot deduce the key from args. It constructs + // value_type unconditionally and then either moves it into the table or + // destroys. + template ::value, int>::type = 0> + std::pair emplace(Args&&... args) { + typename std::aligned_storage::type + raw; + slot_type* slot = reinterpret_cast(&raw); + + PolicyTraits::construct(&alloc_ref(), slot, std::forward(args)...); + const auto& elem = PolicyTraits::element(slot); + return PolicyTraits::apply(InsertSlot{*this, std::move(*slot)}, elem); + } + + template ::value, int>::type = 0> + std::pair emplace_with_hash(size_t hashval, Args&&... args) { + typename std::aligned_storage::type raw; + slot_type* slot = reinterpret_cast(&raw); + + PolicyTraits::construct(&alloc_ref(), slot, std::forward(args)...); + const auto& elem = PolicyTraits::element(slot); + return PolicyTraits::apply(InsertSlotWithHash{*this, std::move(*slot), hashval}, elem); + } + + template + iterator emplace_hint(const_iterator, Args&&... args) { + return emplace(std::forward(args)...).first; + } + + template + iterator emplace_hint_with_hash(size_t hashval, const_iterator, Args&&... args) { + return emplace_with_hash(hashval, std::forward(args)...).first; + } + + // Extension API: support for lazy emplace. + // + // Looks up key in the table. If found, returns the iterator to the element. + // Otherwise calls f with one argument of type raw_hash_set::constructor. f + // MUST call raw_hash_set::constructor with arguments as if a + // raw_hash_set::value_type is constructed, otherwise the behavior is + // undefined. + // + // For example: + // + // std::unordered_set s; + // // Makes ArenaStr even if "abc" is in the map. + // s.insert(ArenaString(&arena, "abc")); + // + // flat_hash_set s; + // // Makes ArenaStr only if "abc" is not in the map. + // s.lazy_emplace("abc", [&](const constructor& ctor) { + // ctor(&arena, "abc"); + // }); + // + // WARNING: This API is currently experimental. If there is a way to implement + // the same thing with the rest of the API, prefer that. + class constructor + { + friend class raw_hash_set; + + public: + template + void operator()(Args&&... args) const { + assert(*slot_); + PolicyTraits::construct(alloc_, *slot_, std::forward(args)...); + *slot_ = nullptr; + } + + private: + constructor(allocator_type* a, slot_type** slot) : alloc_(a), slot_(slot) {} + + allocator_type* alloc_; + slot_type** slot_; + }; + + template + iterator lazy_emplace(const key_arg& key, F&& f) { + auto res = find_or_prepare_insert(key); + if (res.second) { + lazy_emplace_at(res.first, std::forward(f)); + } + return iterator_at(res.first); + } + + template + iterator lazy_emplace_with_hash(const key_arg& key, size_t &hashval, F&& f) { + auto res = find_or_prepare_insert(key, hashval); + if (res.second) { + lazy_emplace_at(res.first, std::forward(f)); + } + return iterator_at(res.first); + } + + template + void lazy_emplace_at(size_t& idx, F&& f) { + slot_type* slot = slots_ + idx; + std::forward(f)(constructor(&alloc_ref(), &slot)); + assert(!slot); + } + + + // Extension API: support for heterogeneous keys. + // + // std::unordered_set s; + // // Turns "abc" into std::string. + // s.erase("abc"); + // + // flat_hash_set s; + // // Uses "abc" directly without copying it into std::string. + // s.erase("abc"); + template + size_type erase(const key_arg& key) { + auto it = find(key); + if (it == end()) return 0; + _erase(it); + return 1; + } + + + iterator erase(const_iterator cit) { return erase(cit.inner_); } + + // Erases the element pointed to by `it`. Unlike `std::unordered_set::erase`, + // this method returns void to reduce algorithmic complexity to O(1). In + // order to erase while iterating across a map, use the following idiom (which + // also works for standard containers): + // + // for (auto it = m.begin(), end = m.end(); it != end;) { + // if () { + // m._erase(it++); + // } else { + // ++it; + // } + // } + void _erase(iterator it) { + assert(it != end()); + PolicyTraits::destroy(&alloc_ref(), it.slot_); + erase_meta_only(it); + } + void _erase(const_iterator cit) { _erase(cit.inner_); } + + // This overload is necessary because otherwise erase(const K&) would be + // a better match if non-const iterator is passed as an argument. + iterator erase(iterator it) { + auto res = it; + ++res; + _erase(it); + return res; + } + + iterator erase(const_iterator first, const_iterator last) { + while (first != last) { + _erase(first++); + } + return last.inner_; + } + + // Moves elements from `src` into `this`. + // If the element already exists in `this`, it is left unmodified in `src`. + template + void merge(raw_hash_set& src) { // NOLINT + assert(this != &src); + for (auto it = src.begin(), e = src.end(); it != e; ++it) { + if (PolicyTraits::apply(InsertSlot{*this, std::move(*it.slot_)}, + PolicyTraits::element(it.slot_)) + .second) { + src.erase_meta_only(it); + } + } + } + + template + void merge(raw_hash_set&& src) { + merge(src); + } + + node_type extract(const_iterator position) { + auto node = + CommonAccess::Make(alloc_ref(), position.inner_.slot_); + erase_meta_only(position); + return node; + } + + template < + class K = key_type, + typename std::enable_if::value, int>::type = 0> + node_type extract(const key_arg& key) { + auto it = find(key); + return it == end() ? node_type() : extract(const_iterator{it}); + } + + void swap(raw_hash_set& that) noexcept( + IsNoThrowSwappable() && IsNoThrowSwappable() && + (!AllocTraits::propagate_on_container_swap::value || + IsNoThrowSwappable())) { + using std::swap; + swap(ctrl_, that.ctrl_); + swap(slots_, that.slots_); + swap(size_, that.size_); + swap(capacity_, that.capacity_); + swap(growth_left(), that.growth_left()); + swap(hash_ref(), that.hash_ref()); + swap(eq_ref(), that.eq_ref()); + swap(infoz_, that.infoz_); + if (AllocTraits::propagate_on_container_swap::value) { + swap(alloc_ref(), that.alloc_ref()); + } else { + // If the allocators do not compare equal it is officially undefined + // behavior. We choose to do nothing. + } + } + +#if !defined(PHMAP_NON_DETERMINISTIC) + template + bool phmap_dump(OutputArchive&) const; + + template + bool phmap_load(InputArchive&); +#endif + + void rehash(size_t n) { + if (n == 0 && capacity_ == 0) return; + if (n == 0 && size_ == 0) { + destroy_slots(); + infoz_.RecordStorageChanged(0, 0); + return; + } + // bitor is a faster way of doing `max` here. We will round up to the next + // power-of-2-minus-1, so bitor is good enough. + auto m = NormalizeCapacity((std::max)(n, size())); + // n == 0 unconditionally rehashes as per the standard. + if (n == 0 || m > capacity_) { + resize(m); + } + } + + void reserve(size_t n) { rehash(GrowthToLowerboundCapacity(n)); } + + // Extension API: support for heterogeneous keys. + // + // std::unordered_set s; + // // Turns "abc" into std::string. + // s.count("abc"); + // + // ch_set s; + // // Uses "abc" directly without copying it into std::string. + // s.count("abc"); + template + size_t count(const key_arg& key) const { + return find(key) == end() ? size_t(0) : size_t(1); + } + + // Issues CPU prefetch instructions for the memory needed to find or insert + // a key. Like all lookup functions, this support heterogeneous keys. + // + // NOTE: This is a very low level operation and should not be used without + // specific benchmarks indicating its importance. + void prefetch_hash(size_t hashval) const { + (void)hashval; +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) + auto seq = probe(hashval); + _mm_prefetch((const char *)(ctrl_ + seq.offset()), _MM_HINT_NTA); + _mm_prefetch((const char *)(slots_ + seq.offset()), _MM_HINT_NTA); +#elif defined(__GNUC__) + auto seq = probe(hashval); + __builtin_prefetch(static_cast(ctrl_ + seq.offset())); + __builtin_prefetch(static_cast(slots_ + seq.offset())); +#endif // __GNUC__ + } + + template + void prefetch(const key_arg& key) const { + prefetch_hash(this->hash(key)); + } + + // The API of find() has two extensions. + // + // 1. The hash can be passed by the user. It must be equal to the hash of the + // key. + // + // 2. The type of the key argument doesn't have to be key_type. This is so + // called heterogeneous key support. + template + iterator find(const key_arg& key, size_t hashval) { + size_t offset; + if (find_impl(key, hashval, offset)) + return iterator_at(offset); + else + return end(); + } + + template + pointer find_ptr(const key_arg& key, size_t hashval) { + size_t offset; + if (find_impl(key, hashval, offset)) + return &PolicyTraits::element(slots_ + offset); + else + return nullptr; + } + + template + iterator find(const key_arg& key) { + return find(key, this->hash(key)); + } + + template + const_iterator find(const key_arg& key, size_t hashval) const { + return const_cast(this)->find(key, hashval); + } + template + const_iterator find(const key_arg& key) const { + return find(key, this->hash(key)); + } + + template + bool contains(const key_arg& key) const { + return find(key) != end(); + } + + template + bool contains(const key_arg& key, size_t hashval) const { + return find(key, hashval) != end(); + } + + template + std::pair equal_range(const key_arg& key) { + auto it = find(key); + if (it != end()) return {it, std::next(it)}; + return {it, it}; + } + template + std::pair equal_range( + const key_arg& key) const { + auto it = find(key); + if (it != end()) return {it, std::next(it)}; + return {it, it}; + } + + size_t bucket_count() const { return capacity_; } + float load_factor() const { + return capacity_ ? static_cast(size()) / capacity_ : 0.0; + } + float max_load_factor() const { return 1.0f; } + void max_load_factor(float) { + // Does nothing. + } + + hasher hash_function() const { return hash_ref(); } // warning: doesn't match internal hash - use hash() member function + key_equal key_eq() const { return eq_ref(); } + allocator_type get_allocator() const { return alloc_ref(); } + + friend bool operator==(const raw_hash_set& a, const raw_hash_set& b) { + if (a.size() != b.size()) return false; + const raw_hash_set* outer = &a; + const raw_hash_set* inner = &b; + if (outer->capacity() > inner->capacity()) + std::swap(outer, inner); + for (const value_type& elem : *outer) + if (!inner->has_element(elem)) return false; + return true; + } + + friend bool operator!=(const raw_hash_set& a, const raw_hash_set& b) { + return !(a == b); + } + + friend void swap(raw_hash_set& a, + raw_hash_set& b) noexcept(noexcept(a.swap(b))) { + a.swap(b); + } + + template + size_t hash(const K& key) const { + return HashElement{hash_ref()}(key); + } + +private: + template + friend struct phmap::priv::hashtable_debug_internal::HashtableDebugAccess; + + template + bool find_impl(const key_arg& key, size_t hashval, size_t& offset) { + auto seq = probe(hashval); + while (true) { + Group g{ ctrl_ + seq.offset() }; + for (int i : g.Match((h2_t)H2(hashval))) { + offset = seq.offset((size_t)i); + if (PHMAP_PREDICT_TRUE(PolicyTraits::apply( + EqualElement{key, eq_ref()}, + PolicyTraits::element(slots_ + offset)))) + return true; + } + if (PHMAP_PREDICT_TRUE(g.MatchEmpty())) + return false; + seq.next(); + } + } + + struct FindElement + { + template + const_iterator operator()(const K& key, Args&&...) const { + return s.find(key); + } + const raw_hash_set& s; + }; + + struct HashElement + { + template + size_t operator()(const K& key, Args&&...) const { + return phmap_mix()(h(key)); + } + const hasher& h; + }; + + template + struct EqualElement + { + template + bool operator()(const K2& lhs, Args&&...) const { + return eq(lhs, rhs); + } + const K1& rhs; + const key_equal& eq; + }; + + template + std::pair emplace_decomposable(const K& key, size_t hashval, + Args&&... args) + { + auto res = find_or_prepare_insert(key, hashval); + if (res.second) { + emplace_at(res.first, std::forward(args)...); + } + return {iterator_at(res.first), res.second}; + } + + struct EmplaceDecomposable + { + template + std::pair operator()(const K& key, Args&&... args) const { + return s.emplace_decomposable(key, s.hash(key), std::forward(args)...); + } + raw_hash_set& s; + }; + + struct EmplaceDecomposableHashval { + template + std::pair operator()(const K& key, Args&&... args) const { + return s.emplace_decomposable(key, hashval, std::forward(args)...); + } + raw_hash_set& s; + size_t hashval; + }; + + template + struct InsertSlot + { + template + std::pair operator()(const K& key, Args&&...) && { + auto res = s.find_or_prepare_insert(key); + if (res.second) { + PolicyTraits::transfer(&s.alloc_ref(), s.slots_ + res.first, &slot); + } else if (do_destroy) { + PolicyTraits::destroy(&s.alloc_ref(), &slot); + } + return {s.iterator_at(res.first), res.second}; + } + raw_hash_set& s; + // Constructed slot. Either moved into place or destroyed. + slot_type&& slot; + }; + + template + struct InsertSlotWithHash + { + template + std::pair operator()(const K& key, Args&&...) && { + auto res = s.find_or_prepare_insert(key, hashval); + if (res.second) { + PolicyTraits::transfer(&s.alloc_ref(), s.slots_ + res.first, &slot); + } else if (do_destroy) { + PolicyTraits::destroy(&s.alloc_ref(), &slot); + } + return {s.iterator_at(res.first), res.second}; + } + raw_hash_set& s; + // Constructed slot. Either moved into place or destroyed. + slot_type&& slot; + size_t &hashval; + }; + + // "erases" the object from the container, except that it doesn't actually + // destroy the object. It only updates all the metadata of the class. + // This can be used in conjunction with Policy::transfer to move the object to + // another place. + void erase_meta_only(const_iterator it) { + assert(IsFull(*it.inner_.ctrl_) && "erasing a dangling iterator"); + --size_; + const size_t index = (size_t)(it.inner_.ctrl_ - ctrl_); + const size_t index_before = (index - Group::kWidth) & capacity_; + const auto empty_after = Group(it.inner_.ctrl_).MatchEmpty(); + const auto empty_before = Group(ctrl_ + index_before).MatchEmpty(); + + // We count how many consecutive non empties we have to the right and to the + // left of `it`. If the sum is >= kWidth then there is at least one probe + // window that might have seen a full group. + bool was_never_full = + empty_before && empty_after && + static_cast(empty_after.TrailingZeros() + + empty_before.LeadingZeros()) < Group::kWidth; + + set_ctrl(index, was_never_full ? kEmpty : kDeleted); + growth_left() += was_never_full; + infoz_.RecordErase(); + } + + void initialize_slots(size_t new_capacity) { + assert(new_capacity); + if (std::is_same>::value && + slots_ == nullptr) { + infoz_ = Sample(); + } + + auto layout = MakeLayout(new_capacity); + char* mem = static_cast( + Allocate(&alloc_ref(), layout.AllocSize())); + ctrl_ = reinterpret_cast(layout.template Pointer<0>(mem)); + slots_ = layout.template Pointer<1>(mem); + reset_ctrl(new_capacity); + reset_growth_left(new_capacity); + infoz_.RecordStorageChanged(size_, new_capacity); + } + + void destroy_slots() { + if (!capacity_) return; + for (size_t i = 0; i != capacity_; ++i) { + if (IsFull(ctrl_[i])) { + PolicyTraits::destroy(&alloc_ref(), slots_ + i); + } + } + auto layout = MakeLayout(capacity_); + // Unpoison before returning the memory to the allocator. + SanitizerUnpoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_); + Deallocate(&alloc_ref(), ctrl_, layout.AllocSize()); + ctrl_ = EmptyGroup(); + slots_ = nullptr; + size_ = 0; + capacity_ = 0; + growth_left() = 0; + } + + void resize(size_t new_capacity) { + assert(IsValidCapacity(new_capacity)); + auto* old_ctrl = ctrl_; + auto* old_slots = slots_; + const size_t old_capacity = capacity_; + initialize_slots(new_capacity); + capacity_ = new_capacity; + + for (size_t i = 0; i != old_capacity; ++i) { + if (IsFull(old_ctrl[i])) { + size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, + PolicyTraits::element(old_slots + i)); + auto target = find_first_non_full(hashval); + size_t new_i = target.offset; + set_ctrl(new_i, H2(hashval)); + PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, old_slots + i); + } + } + if (old_capacity) { + SanitizerUnpoisonMemoryRegion(old_slots, + sizeof(slot_type) * old_capacity); + auto layout = MakeLayout(old_capacity); + Deallocate(&alloc_ref(), old_ctrl, + layout.AllocSize()); + } + } + + void drop_deletes_without_resize() PHMAP_ATTRIBUTE_NOINLINE { + assert(IsValidCapacity(capacity_)); + assert(!is_small()); + // Algorithm: + // - mark all DELETED slots as EMPTY + // - mark all FULL slots as DELETED + // - for each slot marked as DELETED + // hash = Hash(element) + // target = find_first_non_full(hash) + // if target is in the same group + // mark slot as FULL + // else if target is EMPTY + // transfer element to target + // mark slot as EMPTY + // mark target as FULL + // else if target is DELETED + // swap current element with target element + // mark target as FULL + // repeat procedure for current slot with moved from element (target) + ConvertDeletedToEmptyAndFullToDeleted(ctrl_, capacity_); + typename std::aligned_storage::type + raw; + slot_type* slot = reinterpret_cast(&raw); + for (size_t i = 0; i != capacity_; ++i) { + if (!IsDeleted(ctrl_[i])) continue; + size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, + PolicyTraits::element(slots_ + i)); + auto target = find_first_non_full(hashval); + size_t new_i = target.offset; + + // Verify if the old and new i fall within the same group wrt the hashval. + // If they do, we don't need to move the object as it falls already in the + // best probe we can. + const auto probe_index = [&](size_t pos) { + return ((pos - probe(hashval).offset()) & capacity_) / Group::kWidth; + }; + + // Element doesn't move. + if (PHMAP_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) { + set_ctrl(i, H2(hashval)); + continue; + } + if (IsEmpty(ctrl_[new_i])) { + // Transfer element to the empty spot. + // set_ctrl poisons/unpoisons the slots so we have to call it at the + // right time. + set_ctrl(new_i, H2(hashval)); + PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slots_ + i); + set_ctrl(i, kEmpty); + } else { + assert(IsDeleted(ctrl_[new_i])); + set_ctrl(new_i, H2(hashval)); + // Until we are done rehashing, DELETED marks previously FULL slots. + // Swap i and new_i elements. + PolicyTraits::transfer(&alloc_ref(), slot, slots_ + i); + PolicyTraits::transfer(&alloc_ref(), slots_ + i, slots_ + new_i); + PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slot); + --i; // repeat + } + } + reset_growth_left(capacity_); + } + + void rehash_and_grow_if_necessary() { + if (capacity_ == 0) { + resize(1); + } else if (size() <= CapacityToGrowth(capacity()) / 2) { + // Squash DELETED without growing if there is enough capacity. + drop_deletes_without_resize(); + } else { + // Otherwise grow the container. + resize(capacity_ * 2 + 1); + } + } + + bool has_element(const value_type& elem, size_t hashval) const { + auto seq = probe(hashval); + while (true) { + Group g{ctrl_ + seq.offset()}; + for (int i : g.Match((h2_t)H2(hashval))) { + if (PHMAP_PREDICT_TRUE(PolicyTraits::element(slots_ + seq.offset((size_t)i)) == + elem)) + return true; + } + if (PHMAP_PREDICT_TRUE(g.MatchEmpty())) return false; + seq.next(); + assert(seq.getindex() < capacity_ && "full table!"); + } + return false; + } + + bool has_element(const value_type& elem) const { + size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, elem); + return has_element(elem, hashval); + } + + // Probes the raw_hash_set with the probe sequence for hash and returns the + // pointer to the first empty or deleted slot. + // NOTE: this function must work with tables having both kEmpty and kDelete + // in one group. Such tables appears during drop_deletes_without_resize. + // + // This function is very useful when insertions happen and: + // - the input is already a set + // - there are enough slots + // - the element with the hash is not in the table + struct FindInfo + { + size_t offset; + size_t probe_length; + }; + FindInfo find_first_non_full(size_t hashval) { + auto seq = probe(hashval); + while (true) { + Group g{ctrl_ + seq.offset()}; + auto mask = g.MatchEmptyOrDeleted(); + if (mask) { + return {seq.offset((size_t)mask.LowestBitSet()), seq.getindex()}; + } + assert(seq.getindex() < capacity_ && "full table!"); + seq.next(); + } + } + + // TODO(alkis): Optimize this assuming *this and that don't overlap. + raw_hash_set& move_assign(raw_hash_set&& that, std::true_type) { + raw_hash_set tmp(std::move(that)); + swap(tmp); + return *this; + } + raw_hash_set& move_assign(raw_hash_set&& that, std::false_type) { + raw_hash_set tmp(std::move(that), alloc_ref()); + swap(tmp); + return *this; + } + +protected: + template + std::pair find_or_prepare_insert(const K& key, size_t hashval) { + auto seq = probe(hashval); + while (true) { + Group g{ctrl_ + seq.offset()}; + for (int i : g.Match((h2_t)H2(hashval))) { + if (PHMAP_PREDICT_TRUE(PolicyTraits::apply( + EqualElement{key, eq_ref()}, + PolicyTraits::element(slots_ + seq.offset((size_t)i))))) + return {seq.offset((size_t)i), false}; + } + if (PHMAP_PREDICT_TRUE(g.MatchEmpty())) break; + seq.next(); + } + return {prepare_insert(hashval), true}; + } + + template + std::pair find_or_prepare_insert(const K& key) { + return find_or_prepare_insert(key, this->hash(key)); + } + + size_t prepare_insert(size_t hashval) PHMAP_ATTRIBUTE_NOINLINE { + auto target = find_first_non_full(hashval); + if (PHMAP_PREDICT_FALSE(growth_left() == 0 && + !IsDeleted(ctrl_[target.offset]))) { + rehash_and_grow_if_necessary(); + target = find_first_non_full(hashval); + } + ++size_; + growth_left() -= IsEmpty(ctrl_[target.offset]); + set_ctrl(target.offset, H2(hashval)); + infoz_.RecordInsert(hashval, target.probe_length); + return target.offset; + } + + // Constructs the value in the space pointed by the iterator. This only works + // after an unsuccessful find_or_prepare_insert() and before any other + // modifications happen in the raw_hash_set. + // + // PRECONDITION: i is an index returned from find_or_prepare_insert(k), where + // k is the key decomposed from `forward(args)...`, and the bool + // returned by find_or_prepare_insert(k) was true. + // POSTCONDITION: *m.iterator_at(i) == value_type(forward(args)...). + template + void emplace_at(size_t i, Args&&... args) { + PolicyTraits::construct(&alloc_ref(), slots_ + i, + std::forward(args)...); + + assert(PolicyTraits::apply(FindElement{*this}, *iterator_at(i)) == + iterator_at(i) && + "constructed value does not match the lookup key"); + } + + iterator iterator_at(size_t i) { return {ctrl_ + i, slots_ + i}; } + const_iterator iterator_at(size_t i) const { return {ctrl_ + i, slots_ + i}; } + +private: + friend struct RawHashSetTestOnlyAccess; + + probe_seq probe(size_t hashval) const { + return probe_seq(H1(hashval, ctrl_), capacity_); + } + + // Reset all ctrl bytes back to kEmpty, except the sentinel. + void reset_ctrl(size_t capacity) { + std::memset(ctrl_, kEmpty, capacity + Group::kWidth); + ctrl_[capacity] = kSentinel; + SanitizerPoisonMemoryRegion(slots_, sizeof(slot_type) * capacity); + } + + void reset_growth_left(size_t capacity) { + growth_left() = CapacityToGrowth(capacity) - size_; + } + + // Sets the control byte, and if `i < Group::kWidth`, set the cloned byte at + // the end too. + void set_ctrl(size_t i, ctrl_t h) { + assert(i < capacity_); + + if (IsFull(h)) { + SanitizerUnpoisonObject(slots_ + i); + } else { + SanitizerPoisonObject(slots_ + i); + } + + ctrl_[i] = h; + ctrl_[((i - Group::kWidth) & capacity_) + 1 + + ((Group::kWidth - 1) & capacity_)] = h; + } + + size_t& growth_left() { return settings_.template get<0>(); } + + template class RefSet, + class M, class P, class H, class E, class A> + friend class parallel_hash_set; + + template class RefSet, + class M, class P, class H, class E, class A> + friend class parallel_hash_map; + + // The representation of the object has two modes: + // - small: For capacities < kWidth-1 + // - large: For the rest. + // + // Differences: + // - In small mode we are able to use the whole capacity. The extra control + // bytes give us at least one "empty" control byte to stop the iteration. + // This is important to make 1 a valid capacity. + // + // - In small mode only the first `capacity()` control bytes after the + // sentinel are valid. The rest contain dummy kEmpty values that do not + // represent a real slot. This is important to take into account on + // find_first_non_full(), where we never try ShouldInsertBackwards() for + // small tables. + bool is_small() const { return capacity_ < Group::kWidth - 1; } + + hasher& hash_ref() { return settings_.template get<1>(); } + const hasher& hash_ref() const { return settings_.template get<1>(); } + key_equal& eq_ref() { return settings_.template get<2>(); } + const key_equal& eq_ref() const { return settings_.template get<2>(); } + allocator_type& alloc_ref() { return settings_.template get<3>(); } + const allocator_type& alloc_ref() const { + return settings_.template get<3>(); + } + + // TODO(alkis): Investigate removing some of these fields: + // - ctrl/slots can be derived from each other + // - size can be moved into the slot array + ctrl_t* ctrl_ = EmptyGroup(); // [(capacity + 1) * ctrl_t] + slot_type* slots_ = nullptr; // [capacity * slot_type] + size_t size_ = 0; // number of full slots + size_t capacity_ = 0; // total number of slots + HashtablezInfoHandle infoz_; + phmap::priv::CompressedTuple + settings_{0, hasher{}, key_equal{}, allocator_type{}}; +}; + + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +template +class raw_hash_map : public raw_hash_set +{ + // P is Policy. It's passed as a template argument to support maps that have + // incomplete types as values, as in unordered_map. + // MappedReference<> may be a non-reference type. + template + using MappedReference = decltype(P::value( + std::addressof(std::declval()))); + + // MappedConstReference<> may be a non-reference type. + template + using MappedConstReference = decltype(P::value( + std::addressof(std::declval()))); + + using KeyArgImpl = + KeyArg::value && IsTransparent::value>; + + using Base = raw_hash_set; + +public: + using key_type = typename Policy::key_type; + using mapped_type = typename Policy::mapped_type; + template + using key_arg = typename KeyArgImpl::template type; + + static_assert(!std::is_reference::value, ""); + // TODO(alkis): remove this assertion and verify that reference mapped_type is + // supported. + static_assert(!std::is_reference::value, ""); + + using iterator = typename raw_hash_map::raw_hash_set::iterator; + using const_iterator = typename raw_hash_map::raw_hash_set::const_iterator; + + raw_hash_map() {} + using Base::raw_hash_set; // use raw_hash_set constructor + + // The last two template parameters ensure that both arguments are rvalues + // (lvalue arguments are handled by the overloads below). This is necessary + // for supporting bitfield arguments. + // + // union { int n : 1; }; + // flat_hash_map m; + // m.insert_or_assign(n, n); + template + std::pair insert_or_assign(key_arg&& k, V&& v) { + return insert_or_assign_impl(std::forward(k), std::forward(v)); + } + + template + std::pair insert_or_assign(key_arg&& k, const V& v) { + return insert_or_assign_impl(std::forward(k), v); + } + + template + std::pair insert_or_assign(const key_arg& k, V&& v) { + return insert_or_assign_impl(k, std::forward(v)); + } + + template + std::pair insert_or_assign(const key_arg& k, const V& v) { + return insert_or_assign_impl(k, v); + } + + template + iterator insert_or_assign(const_iterator, key_arg&& k, V&& v) { + return insert_or_assign(std::forward(k), std::forward(v)).first; + } + + template + iterator insert_or_assign(const_iterator, key_arg&& k, const V& v) { + return insert_or_assign(std::forward(k), v).first; + } + + template + iterator insert_or_assign(const_iterator, const key_arg& k, V&& v) { + return insert_or_assign(k, std::forward(v)).first; + } + + template + iterator insert_or_assign(const_iterator, const key_arg& k, const V& v) { + return insert_or_assign(k, v).first; + } + + template ::value, int>::type = 0, + K* = nullptr> + std::pair try_emplace(key_arg&& k, Args&&... args) { + return try_emplace_impl(std::forward(k), std::forward(args)...); + } + + template ::value, int>::type = 0> + std::pair try_emplace(const key_arg& k, Args&&... args) { + return try_emplace_impl(k, std::forward(args)...); + } + + template + iterator try_emplace(const_iterator, key_arg&& k, Args&&... args) { + return try_emplace(std::forward(k), std::forward(args)...).first; + } + + template + iterator try_emplace(const_iterator, const key_arg& k, Args&&... args) { + return try_emplace(k, std::forward(args)...).first; + } + + template + MappedReference

at(const key_arg& key) { + auto it = this->find(key); + if (it == this->end()) + phmap::base_internal::ThrowStdOutOfRange("phmap at(): lookup non-existent key"); + return Policy::value(&*it); + } + + template + MappedConstReference

at(const key_arg& key) const { + auto it = this->find(key); + if (it == this->end()) + phmap::base_internal::ThrowStdOutOfRange("phmap at(): lookup non-existent key"); + return Policy::value(&*it); + } + + template + MappedReference

operator[](key_arg&& key) { + return Policy::value(&*try_emplace(std::forward(key)).first); + } + + template + MappedReference

operator[](const key_arg& key) { + return Policy::value(&*try_emplace(key).first); + } + +private: + template + std::pair insert_or_assign_impl(K&& k, V&& v) { + auto res = this->find_or_prepare_insert(k); + if (res.second) + this->emplace_at(res.first, std::forward(k), std::forward(v)); + else + Policy::value(&*this->iterator_at(res.first)) = std::forward(v); + return {this->iterator_at(res.first), res.second}; + } + + template + std::pair try_emplace_impl(K&& k, Args&&... args) { + auto res = this->find_or_prepare_insert(k); + if (res.second) + this->emplace_at(res.first, std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)); + return {this->iterator_at(res.first), res.second}; + } +}; + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// Returns "random" seed. +inline size_t RandomSeed() +{ +#if PHMAP_HAVE_THREAD_LOCAL + static thread_local size_t counter = 0; + size_t value = ++counter; +#else // PHMAP_HAVE_THREAD_LOCAL + static std::atomic counter(0); + size_t value = counter.fetch_add(1, std::memory_order_relaxed); +#endif // PHMAP_HAVE_THREAD_LOCAL + return value ^ static_cast(reinterpret_cast(&counter)); +} + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +template class RefSet, + class Mtx_, + class Policy, class Hash, class Eq, class Alloc> +class parallel_hash_set +{ + using PolicyTraits = hash_policy_traits; + using KeyArgImpl = + KeyArg::value && IsTransparent::value>; + + static_assert(N <= 12, "N = 12 means 4096 hash tables!"); + constexpr static size_t num_tables = 1 << N; + constexpr static size_t mask = num_tables - 1; + +public: + using EmbeddedSet = RefSet; + using EmbeddedIterator= typename EmbeddedSet::iterator; + using EmbeddedConstIterator= typename EmbeddedSet::const_iterator; + using constructor = typename EmbeddedSet::constructor; + using init_type = typename PolicyTraits::init_type; + using key_type = typename PolicyTraits::key_type; + using slot_type = typename PolicyTraits::slot_type; + using allocator_type = Alloc; + using size_type = size_t; + using difference_type = ptrdiff_t; + using hasher = Hash; + using key_equal = Eq; + using policy_type = Policy; + using value_type = typename PolicyTraits::value_type; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = typename phmap::allocator_traits< + allocator_type>::template rebind_traits::pointer; + using const_pointer = typename phmap::allocator_traits< + allocator_type>::template rebind_traits::const_pointer; + + // Alias used for heterogeneous lookup functions. + // `key_arg` evaluates to `K` when the functors are transparent and to + // `key_type` otherwise. It permits template argument deduction on `K` for the + // transparent case. + // -------------------------------------------------------------------- + template + using key_arg = typename KeyArgImpl::template type; + +protected: + using Lockable = phmap::LockableImpl; + + // -------------------------------------------------------------------- + struct Inner : public Lockable + { + bool operator==(const Inner& o) const + { + typename Lockable::SharedLocks l(const_cast(*this), const_cast(o)); + return set_ == o.set_; + } + + EmbeddedSet set_; + }; + +private: + // Give an early error when key_type is not hashable/eq. + // -------------------------------------------------------------------- + auto KeyTypeCanBeHashed(const Hash& h, const key_type& k) -> decltype(h(k)); + auto KeyTypeCanBeEq(const Eq& eq, const key_type& k) -> decltype(eq(k, k)); + + using AllocTraits = phmap::allocator_traits; + + static_assert(std::is_lvalue_reference::value, + "Policy::element() must return a reference"); + + template + struct SameAsElementReference : std::is_same< + typename std::remove_cv::type>::type, + typename std::remove_cv::type>::type> {}; + + // An enabler for insert(T&&): T must be convertible to init_type or be the + // same as [cv] value_type [ref]. + // Note: we separate SameAsElementReference into its own type to avoid using + // reference unless we need to. MSVC doesn't seem to like it in some + // cases. + // -------------------------------------------------------------------- + template + using RequiresInsertable = typename std::enable_if< + phmap::disjunction, + SameAsElementReference>::value, + int>::type; + + // RequiresNotInit is a workaround for gcc prior to 7.1. + // See https://godbolt.org/g/Y4xsUh. + template + using RequiresNotInit = + typename std::enable_if::value, int>::type; + + template + using IsDecomposable = IsDecomposable; + +public: + static_assert(std::is_same::value, + "Allocators with custom pointer types are not supported"); + static_assert(std::is_same::value, + "Allocators with custom pointer types are not supported"); + + // --------------------- i t e r a t o r ------------------------------ + class iterator + { + friend class parallel_hash_set; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = typename parallel_hash_set::value_type; + using reference = + phmap::conditional_t; + using pointer = phmap::remove_reference_t*; + using difference_type = typename parallel_hash_set::difference_type; + using Inner = typename parallel_hash_set::Inner; + using EmbeddedSet = typename parallel_hash_set::EmbeddedSet; + using EmbeddedIterator = typename EmbeddedSet::iterator; + + iterator() {} + + reference operator*() const { return *it_; } + pointer operator->() const { return &operator*(); } + + iterator& operator++() { + assert(inner_); // null inner means we are already at the end + ++it_; + skip_empty(); + return *this; + } + + iterator operator++(int) { + assert(inner_); // null inner means we are already at the end + auto tmp = *this; + ++*this; + return tmp; + } + + friend bool operator==(const iterator& a, const iterator& b) { + return a.inner_ == b.inner_ && (!a.inner_ || a.it_ == b.it_); + } + + friend bool operator!=(const iterator& a, const iterator& b) { + return !(a == b); + } + + private: + iterator(Inner *inner, Inner *inner_end, const EmbeddedIterator& it) : + inner_(inner), inner_end_(inner_end), it_(it) { // for begin() and end() + if (inner) + it_end_ = inner->set_.end(); + } + + void skip_empty() { + while (it_ == it_end_) { + ++inner_; + if (inner_ == inner_end_) { + inner_ = nullptr; // marks end() + break; + } + else { + it_ = inner_->set_.begin(); + it_end_ = inner_->set_.end(); + } + } + } + + Inner *inner_ = nullptr; + Inner *inner_end_ = nullptr; + EmbeddedIterator it_, it_end_; + }; + + // --------------------- c o n s t i t e r a t o r ----------------- + class const_iterator + { + friend class parallel_hash_set; + + public: + using iterator_category = typename iterator::iterator_category; + using value_type = typename parallel_hash_set::value_type; + using reference = typename parallel_hash_set::const_reference; + using pointer = typename parallel_hash_set::const_pointer; + using difference_type = typename parallel_hash_set::difference_type; + using Inner = typename parallel_hash_set::Inner; + + const_iterator() {} + // Implicit construction from iterator. + const_iterator(iterator i) : iter_(std::move(i)) {} + + reference operator*() const { return *(iter_); } + pointer operator->() const { return iter_.operator->(); } + + const_iterator& operator++() { + ++iter_; + return *this; + } + const_iterator operator++(int) { return iter_++; } + + friend bool operator==(const const_iterator& a, const const_iterator& b) { + return a.iter_ == b.iter_; + } + friend bool operator!=(const const_iterator& a, const const_iterator& b) { + return !(a == b); + } + + private: + const_iterator(const Inner *inner, const Inner *inner_end, const EmbeddedIterator& it) + : iter_(const_cast(inner), + const_cast(inner_end), + const_cast(it)) {} + + iterator iter_; + }; + + using node_type = node_handle, Alloc>; + using insert_return_type = InsertReturnType; + + // ------------------------- c o n s t r u c t o r s ------------------ + + parallel_hash_set() noexcept( + std::is_nothrow_default_constructible::value&& + std::is_nothrow_default_constructible::value&& + std::is_nothrow_default_constructible::value) {} + + explicit parallel_hash_set(size_t bucket_cnt, + const hasher& hash_param = hasher(), + const key_equal& eq = key_equal(), + const allocator_type& alloc = allocator_type()) { + for (auto& inner : sets_) + inner.set_ = EmbeddedSet(bucket_cnt / N, hash_param, eq, alloc); + } + + parallel_hash_set(size_t bucket_cnt, + const hasher& hash_param, + const allocator_type& alloc) + : parallel_hash_set(bucket_cnt, hash_param, key_equal(), alloc) {} + + parallel_hash_set(size_t bucket_cnt, const allocator_type& alloc) + : parallel_hash_set(bucket_cnt, hasher(), key_equal(), alloc) {} + + explicit parallel_hash_set(const allocator_type& alloc) + : parallel_hash_set(0, hasher(), key_equal(), alloc) {} + + template + parallel_hash_set(InputIter first, InputIter last, size_t bucket_cnt = 0, + const hasher& hash_param = hasher(), const key_equal& eq = key_equal(), + const allocator_type& alloc = allocator_type()) + : parallel_hash_set(bucket_cnt, hash_param, eq, alloc) { + insert(first, last); + } + + template + parallel_hash_set(InputIter first, InputIter last, size_t bucket_cnt, + const hasher& hash_param, const allocator_type& alloc) + : parallel_hash_set(first, last, bucket_cnt, hash_param, key_equal(), alloc) {} + + template + parallel_hash_set(InputIter first, InputIter last, size_t bucket_cnt, + const allocator_type& alloc) + : parallel_hash_set(first, last, bucket_cnt, hasher(), key_equal(), alloc) {} + + template + parallel_hash_set(InputIter first, InputIter last, const allocator_type& alloc) + : parallel_hash_set(first, last, 0, hasher(), key_equal(), alloc) {} + + // Instead of accepting std::initializer_list as the first + // argument like std::unordered_set does, we have two overloads + // that accept std::initializer_list and std::initializer_list. + // This is advantageous for performance. + // + // // Turns {"abc", "def"} into std::initializer_list, then copies + // // the strings into the set. + // std::unordered_set s = {"abc", "def"}; + // + // // Turns {"abc", "def"} into std::initializer_list, then + // // copies the strings into the set. + // phmap::flat_hash_set s = {"abc", "def"}; + // + // The same trick is used in insert(). + // + // The enabler is necessary to prevent this constructor from triggering where + // the copy constructor is meant to be called. + // + // phmap::flat_hash_set a, b{a}; + // + // RequiresNotInit is a workaround for gcc prior to 7.1. + // -------------------------------------------------------------------- + template = 0, RequiresInsertable = 0> + parallel_hash_set(std::initializer_list init, size_t bucket_cnt = 0, + const hasher& hash_param = hasher(), const key_equal& eq = key_equal(), + const allocator_type& alloc = allocator_type()) + : parallel_hash_set(init.begin(), init.end(), bucket_cnt, hash_param, eq, alloc) {} + + parallel_hash_set(std::initializer_list init, size_t bucket_cnt = 0, + const hasher& hash_param = hasher(), const key_equal& eq = key_equal(), + const allocator_type& alloc = allocator_type()) + : parallel_hash_set(init.begin(), init.end(), bucket_cnt, hash_param, eq, alloc) {} + + template = 0, RequiresInsertable = 0> + parallel_hash_set(std::initializer_list init, size_t bucket_cnt, + const hasher& hash_param, const allocator_type& alloc) + : parallel_hash_set(init, bucket_cnt, hash_param, key_equal(), alloc) {} + + parallel_hash_set(std::initializer_list init, size_t bucket_cnt, + const hasher& hash_param, const allocator_type& alloc) + : parallel_hash_set(init, bucket_cnt, hash_param, key_equal(), alloc) {} + + template = 0, RequiresInsertable = 0> + parallel_hash_set(std::initializer_list init, size_t bucket_cnt, + const allocator_type& alloc) + : parallel_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {} + + parallel_hash_set(std::initializer_list init, size_t bucket_cnt, + const allocator_type& alloc) + : parallel_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {} + + template = 0, RequiresInsertable = 0> + parallel_hash_set(std::initializer_list init, const allocator_type& alloc) + : parallel_hash_set(init, 0, hasher(), key_equal(), alloc) {} + + parallel_hash_set(std::initializer_list init, + const allocator_type& alloc) + : parallel_hash_set(init, 0, hasher(), key_equal(), alloc) {} + + parallel_hash_set(const parallel_hash_set& that) + : parallel_hash_set(that, AllocTraits::select_on_container_copy_construction( + that.alloc_ref())) {} + + parallel_hash_set(const parallel_hash_set& that, const allocator_type& a) + : parallel_hash_set(0, that.hash_ref(), that.eq_ref(), a) { + for (size_t i=0; i::value&& + std::is_nothrow_copy_constructible::value&& + std::is_nothrow_copy_constructible::value) + : parallel_hash_set(std::move(that), that.alloc_ref()) { + } + + parallel_hash_set(parallel_hash_set&& that, const allocator_type& a) + { + for (size_t i=0; i::is_always_equal::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value) { + for (size_t i=0; i(this)->begin(); } + const_iterator end() const { return const_cast(this)->end(); } + const_iterator cbegin() const { return begin(); } + const_iterator cend() const { return end(); } + + bool empty() const { return !size(); } + + size_t size() const { + size_t sz = 0; + for (const auto& inner : sets_) + sz += inner.set_.size(); + return sz; + } + + size_t capacity() const { + size_t c = 0; + for (const auto& inner : sets_) + c += inner.set_.capacity(); + return c; + } + + size_t max_size() const { return (std::numeric_limits::max)(); } + + PHMAP_ATTRIBUTE_REINITIALIZES void clear() { + for (auto& inner : sets_) + { + typename Lockable::UniqueLock m(inner); + inner.set_.clear(); + } + } + + // extension - clears only soecified submap + // ---------------------------------------- + void clear(std::size_t submap_index) { + Inner& inner = sets_[submap_index]; + typename Lockable::UniqueLock m(inner); + inner.set_.clear(); + } + + // This overload kicks in when the argument is an rvalue of insertable and + // decomposable type other than init_type. + // + // flat_hash_map m; + // m.insert(std::make_pair("abc", 42)); + // -------------------------------------------------------------------- + template = 0, + typename std::enable_if::value, int>::type = 0, + T* = nullptr> + std::pair insert(T&& value) { + return emplace(std::forward(value)); + } + + // This overload kicks in when the argument is a bitfield or an lvalue of + // insertable and decomposable type. + // + // union { int n : 1; }; + // flat_hash_set s; + // s.insert(n); + // + // flat_hash_set s; + // const char* p = "hello"; + // s.insert(p); + // + // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace + // RequiresInsertable with RequiresInsertable. + // We are hitting this bug: https://godbolt.org/g/1Vht4f. + // -------------------------------------------------------------------- + template < + class T, RequiresInsertable = 0, + typename std::enable_if::value, int>::type = 0> + std::pair insert(const T& value) { + return emplace(value); + } + + // This overload kicks in when the argument is an rvalue of init_type. Its + // purpose is to handle brace-init-list arguments. + // + // flat_hash_set> s; + // s.insert({"abc", 42}); + // -------------------------------------------------------------------- + std::pair insert(init_type&& value) { + return emplace(std::move(value)); + } + + template = 0, + typename std::enable_if::value, int>::type = 0, + T* = nullptr> + iterator insert(const_iterator, T&& value) { + return insert(std::forward(value)).first; + } + + // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace + // RequiresInsertable with RequiresInsertable. + // We are hitting this bug: https://godbolt.org/g/1Vht4f. + // -------------------------------------------------------------------- + template < + class T, RequiresInsertable = 0, + typename std::enable_if::value, int>::type = 0> + iterator insert(const_iterator, const T& value) { + return insert(value).first; + } + + iterator insert(const_iterator, init_type&& value) { + return insert(std::move(value)).first; + } + + template + void insert(InputIt first, InputIt last) { + for (; first != last; ++first) insert(*first); + } + + template = 0, RequiresInsertable = 0> + void insert(std::initializer_list ilist) { + insert(ilist.begin(), ilist.end()); + } + + void insert(std::initializer_list ilist) { + insert(ilist.begin(), ilist.end()); + } + + insert_return_type insert(node_type&& node) { + if (!node) + return {end(), false, node_type()}; + auto& key = node.key(); + size_t hashval = this->hash(key); + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + + typename Lockable::UniqueLock m(inner); + auto res = set.insert(std::move(node), hashval); + return { make_iterator(&inner, res.position), + res.inserted, + res.inserted ? node_type() : std::move(res.node) }; + } + + iterator insert(const_iterator, node_type&& node) { + return insert(std::move(node)).first; + } + + struct ReturnKey_ + { + template + Key operator()(Key&& k, const Args&...) const { + return std::forward(k); + } + }; + + // -------------------------------------------------------------------- + // phmap expension: emplace_with_hash + // ---------------------------------- + // same as emplace, but hashval is provided + // -------------------------------------------------------------------- + template + std::pair emplace_decomposable_with_hash(const K& key, size_t hashval, Args&&... args) + { + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + typename Lockable::UniqueLock m(inner); + return make_rv(&inner, set.emplace_decomposable(key, hashval, std::forward(args)...)); + } + + struct EmplaceDecomposableHashval + { + template + std::pair operator()(const K& key, Args&&... args) const { + return s.emplace_decomposable_with_hash(key, hashval, std::forward(args)...); + } + parallel_hash_set& s; + size_t hashval; + }; + + // This overload kicks in if we can deduce the key from args. This enables us + // to avoid constructing value_type if an entry with the same key already + // exists. + // + // For example: + // + // flat_hash_map m = {{"abc", "def"}}; + // // Creates no std::string copies and makes no heap allocations. + // m.emplace("abc", "xyz"); + // -------------------------------------------------------------------- + template ::value, int>::type = 0> + std::pair emplace_with_hash(size_t hashval, Args&&... args) { + return PolicyTraits::apply(EmplaceDecomposableHashval{*this, hashval}, + std::forward(args)...); + } + + // This overload kicks in if we cannot deduce the key from args. It constructs + // value_type unconditionally and then either moves it into the table or + // destroys. + // -------------------------------------------------------------------- + template ::value, int>::type = 0> + std::pair emplace_with_hash(size_t hashval, Args&&... args) { + typename std::aligned_storage::type raw; + slot_type* slot = reinterpret_cast(&raw); + + PolicyTraits::construct(&alloc_ref(), slot, std::forward(args)...); + const auto& elem = PolicyTraits::element(slot); + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + typename Lockable::UniqueLock m(inner); + typename EmbeddedSet::template InsertSlotWithHash f { + inner, std::move(*slot), hashval}; + return make_rv(PolicyTraits::apply(f, elem)); + } + + template + iterator emplace_hint_with_hash(size_t hashval, const_iterator, Args&&... args) { + return emplace_with_hash(hashval, std::forward(args)...).first; + } + + template + iterator lazy_emplace_with_hash(size_t hashval, const key_arg& key, F&& f) { + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + typename Lockable::UniqueLock m(inner); + return make_iterator(&inner, set.lazy_emplace_with_hash(key, hashval, std::forward(f))); + } + + // -------------------------------------------------------------------- + // end of phmap expension + // -------------------------------------------------------------------- + + template + std::pair emplace_decomposable(const K& key, Args&&... args) + { + size_t hashval = this->hash(key); + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + typename Lockable::UniqueLock m(inner); + return make_rv(&inner, set.emplace_decomposable(key, hashval, std::forward(args)...)); + } + + struct EmplaceDecomposable + { + template + std::pair operator()(const K& key, Args&&... args) const { + return s.emplace_decomposable(key, std::forward(args)...); + } + parallel_hash_set& s; + }; + + // This overload kicks in if we can deduce the key from args. This enables us + // to avoid constructing value_type if an entry with the same key already + // exists. + // + // For example: + // + // flat_hash_map m = {{"abc", "def"}}; + // // Creates no std::string copies and makes no heap allocations. + // m.emplace("abc", "xyz"); + // -------------------------------------------------------------------- + template ::value, int>::type = 0> + std::pair emplace(Args&&... args) { + return PolicyTraits::apply(EmplaceDecomposable{*this}, + std::forward(args)...); + } + + // This overload kicks in if we cannot deduce the key from args. It constructs + // value_type unconditionally and then either moves it into the table or + // destroys. + // -------------------------------------------------------------------- + template ::value, int>::type = 0> + std::pair emplace(Args&&... args) { + typename std::aligned_storage::type raw; + slot_type* slot = reinterpret_cast(&raw); + size_t hashval = this->hash(PolicyTraits::key(slot)); + + PolicyTraits::construct(&alloc_ref(), slot, std::forward(args)...); + const auto& elem = PolicyTraits::element(slot); + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + typename Lockable::UniqueLock m(inner); + typename EmbeddedSet::template InsertSlotWithHash f { + inner, std::move(*slot), hashval}; + return make_rv(PolicyTraits::apply(f, elem)); + } + + template + iterator emplace_hint(const_iterator, Args&&... args) { + return emplace(std::forward(args)...).first; + } + + iterator make_iterator(Inner* inner, const EmbeddedIterator it) + { + if (it == inner->set_.end()) + return iterator(); + return iterator(inner, &sets_[0] + num_tables, it); + } + + std::pair make_rv(Inner* inner, + const std::pair& res) + { + return {iterator(inner, &sets_[0] + num_tables, res.first), res.second}; + } + + template + iterator lazy_emplace(const key_arg& key, F&& f) { + auto hashval = this->hash(key); + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + typename Lockable::UniqueLock m(inner); + return make_iterator(&inner, set.lazy_emplace_with_hash(key, hashval, std::forward(f))); + } + + template + bool lazy_emplace_l(const key_arg& key, FExists&& fExists, FEmplace&& fEmplace) { + typename Lockable::UniqueLock m; + auto res = this->find_or_prepare_insert(key, m); + Inner* inner = std::get<0>(res); + if (std::get<2>(res)) + inner->set_.lazy_emplace_at(std::get<1>(res), std::forward(fEmplace)); + else { + auto it = this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))); + std::forward(fExists)(Policy::value(&*it)); + } + return std::get<2>(res); + } + + // Extension API: support iterating over all values + // + // flat_hash_set s; + // s.insert(...); + // s.for_each([](auto const & key) { + // // Safely iterates over all the keys + // }); + template + void for_each(F&& fCallback) const { + for (auto const& inner : sets_) { + typename Lockable::SharedLock m(const_cast(inner)); + std::for_each(inner.set_.begin(), inner.set_.end(), fCallback); + } + } + + // this version allows to modify the values + void for_each_m(std::function && fCallback) { + for (auto& inner : sets_) { + typename Lockable::UniqueLock m(const_cast(inner)); + std::for_each(inner.set_.begin(), inner.set_.end(), fCallback); + } + } + + // Extension API: support for heterogeneous keys. + // + // std::unordered_set s; + // // Turns "abc" into std::string. + // s.erase("abc"); + // + // flat_hash_set s; + // // Uses "abc" directly without copying it into std::string. + // s.erase("abc"); + // -------------------------------------------------------------------- + template + size_type erase(const key_arg& key) { + auto hashval = this->hash(key); + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + typename Lockable::UpgradeLock m(inner); + auto it = set.find(key, hashval); + if (it == set.end()) + return 0; + + typename Lockable::UpgradeToUnique unique(m); + set._erase(it); + return 1; + } + + // -------------------------------------------------------------------- + iterator erase(const_iterator cit) { return erase(cit.iter_); } + + // Erases the element pointed to by `it`. Unlike `std::unordered_set::erase`, + // this method returns void to reduce algorithmic complexity to O(1). In + // order to erase while iterating across a map, use the following idiom (which + // also works for standard containers): + // + // for (auto it = m.begin(), end = m.end(); it != end;) { + // if () { + // m._erase(it++); + // } else { + // ++it; + // } + // } + // -------------------------------------------------------------------- + void _erase(iterator it) { + assert(it.inner_ != nullptr); + it.inner_->set_._erase(it.it_); + } + void _erase(const_iterator cit) { _erase(cit.iter_); } + + // This overload is necessary because otherwise erase(const K&) would be + // a better match if non-const iterator is passed as an argument. + // -------------------------------------------------------------------- + iterator erase(iterator it) { _erase(it++); return it; } + + iterator erase(const_iterator first, const_iterator last) { + while (first != last) { + _erase(first++); + } + return last.iter_; + } + + // Moves elements from `src` into `this`. + // If the element already exists in `this`, it is left unmodified in `src`. + // -------------------------------------------------------------------- + template + void merge(parallel_hash_set& src) { // NOLINT + assert(this != &src); + if (this != &src) + { + for (size_t i=0; i + void merge(parallel_hash_set&& src) { + merge(src); + } + + node_type extract(const_iterator position) { + return position.iter_.inner_->set_.extract(EmbeddedConstIterator(position.iter_.it_)); + } + + template < + class K = key_type, + typename std::enable_if::value, int>::type = 0> + node_type extract(const key_arg& key) { + auto it = find(key); + return it == end() ? node_type() : extract(const_iterator{it}); + } + + void swap(parallel_hash_set& that) noexcept( + IsNoThrowSwappable() && + (!AllocTraits::propagate_on_container_swap::value || + IsNoThrowSwappable())) { + using std::swap; + for (size_t i=0; i target ? normalized : target); + } + + // Extension API: support for heterogeneous keys. + // + // std::unordered_set s; + // // Turns "abc" into std::string. + // s.count("abc"); + // + // ch_set s; + // // Uses "abc" directly without copying it into std::string. + // s.count("abc"); + // -------------------------------------------------------------------- + template + size_t count(const key_arg& key) const { + return find(key) == end() ? 0 : 1; + } + + // Issues CPU prefetch instructions for the memory needed to find or insert + // a key. Like all lookup functions, this support heterogeneous keys. + // + // NOTE: This is a very low level operation and should not be used without + // specific benchmarks indicating its importance. + // -------------------------------------------------------------------- + void prefetch_hash(size_t hashval) const { + const Inner& inner = sets_[subidx(hashval)]; + const auto& set = inner.set_; + typename Lockable::SharedLock m(const_cast(inner)); + set.prefetch_hash(hashval); + } + + template + void prefetch(const key_arg& key) const { + prefetch_hash(this->hash(key)); + } + + // The API of find() has two extensions. + // + // 1. The hash can be passed by the user. It must be equal to the hash of the + // key. + // + // 2. The type of the key argument doesn't have to be key_type. This is so + // called heterogeneous key support. + // -------------------------------------------------------------------- + template + iterator find(const key_arg& key, size_t hashval) { + typename Lockable::SharedLock m; + return find(key, hashval, m); + } + + template + iterator find(const key_arg& key) { + return find(key, this->hash(key)); + } + + template + const_iterator find(const key_arg& key, size_t hashval) const { + return const_cast(this)->find(key, hashval); + } + + template + const_iterator find(const key_arg& key) const { + return find(key, this->hash(key)); + } + + template + bool contains(const key_arg& key) const { + return find(key) != end(); + } + + template + bool contains(const key_arg& key, size_t hashval) const { + return find(key, hashval) != end(); + } + + template + std::pair equal_range(const key_arg& key) { + auto it = find(key); + if (it != end()) return {it, std::next(it)}; + return {it, it}; + } + + template + std::pair equal_range( + const key_arg& key) const { + auto it = find(key); + if (it != end()) return {it, std::next(it)}; + return {it, it}; + } + + size_t bucket_count() const { + size_t sz = 0; + for (const auto& inner : sets_) + { + typename Lockable::SharedLock m(const_cast(inner)); + sz += inner.set_.bucket_count(); + } + return sz; + } + + float load_factor() const { + size_t _capacity = bucket_count(); + return _capacity ? static_cast(static_cast(size()) / _capacity) : 0; + } + + float max_load_factor() const { return 1.0f; } + void max_load_factor(float) { + // Does nothing. + } + + hasher hash_function() const { return hash_ref(); } // warning: doesn't match internal hash - use hash() member function + key_equal key_eq() const { return eq_ref(); } + allocator_type get_allocator() const { return alloc_ref(); } + + friend bool operator==(const parallel_hash_set& a, const parallel_hash_set& b) { + return std::equal(a.sets_.begin(), a.sets_.end(), b.sets_.begin()); + } + + friend bool operator!=(const parallel_hash_set& a, const parallel_hash_set& b) { + return !(a == b); + } + + friend void swap(parallel_hash_set& a, + parallel_hash_set& b) noexcept(noexcept(a.swap(b))) { + a.swap(b); + } + + template + size_t hash(const K& key) const { + return HashElement{hash_ref()}(key); + } + +#if !defined(PHMAP_NON_DETERMINISTIC) + template + bool phmap_dump(OutputArchive& ar) const; + + template + bool phmap_load(InputArchive& ar); +#endif + +private: + template + friend struct phmap::priv::hashtable_debug_internal::HashtableDebugAccess; + + struct FindElement + { + template + const_iterator operator()(const K& key, Args&&...) const { + return s.find(key); + } + const parallel_hash_set& s; + }; + + struct HashElement + { + template + size_t operator()(const K& key, Args&&...) const { + return phmap_mix()(h(key)); + } + const hasher& h; + }; + + template + struct EqualElement + { + template + bool operator()(const K2& lhs, Args&&...) const { + return eq(lhs, rhs); + } + const K1& rhs; + const key_equal& eq; + }; + + // "erases" the object from the container, except that it doesn't actually + // destroy the object. It only updates all the metadata of the class. + // This can be used in conjunction with Policy::transfer to move the object to + // another place. + // -------------------------------------------------------------------- + void erase_meta_only(const_iterator cit) { + auto &it = cit.iter_; + assert(it.set_ != nullptr); + it.set_.erase_meta_only(const_iterator(it.it_)); + } + + void drop_deletes_without_resize() PHMAP_ATTRIBUTE_NOINLINE { + for (auto& inner : sets_) + { + typename Lockable::UniqueLock m(inner); + inner.set_.drop_deletes_without_resize(); + } + } + + bool has_element(const value_type& elem) const { + size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, elem); + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + typename Lockable::SharedLock m(const_cast(inner)); + return set.has_element(elem, hashval); + } + + // TODO(alkis): Optimize this assuming *this and that don't overlap. + // -------------------------------------------------------------------- + parallel_hash_set& move_assign(parallel_hash_set&& that, std::true_type) { + parallel_hash_set tmp(std::move(that)); + swap(tmp); + return *this; + } + + parallel_hash_set& move_assign(parallel_hash_set&& that, std::false_type) { + parallel_hash_set tmp(std::move(that), alloc_ref()); + swap(tmp); + return *this; + } + +protected: + template + pointer find_ptr(const key_arg& key, size_t hashval, L& mutexlock) + { + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + mutexlock = std::move(L(inner)); + return set.find_ptr(key, hashval); + } + + template + iterator find(const key_arg& key, size_t hashval, L& mutexlock) { + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + mutexlock = std::move(L(inner)); + return make_iterator(&inner, set.find(key, hashval)); + } + + template + std::tuple + find_or_prepare_insert_with_hash(size_t hashval, const K& key, typename Lockable::UniqueLock &mutexlock) { + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + mutexlock = std::move(typename Lockable::UniqueLock(inner)); + auto p = set.find_or_prepare_insert(key, hashval); // std::pair + return std::make_tuple(&inner, p.first, p.second); + } + + template + std::tuple + find_or_prepare_insert(const K& key, typename Lockable::UniqueLock &mutexlock) { + return find_or_prepare_insert_with_hash(this->hash(key), key, mutexlock); + } + + iterator iterator_at(Inner *inner, + const EmbeddedIterator& it) { + return {inner, &sets_[0] + num_tables, it}; + } + const_iterator iterator_at(Inner *inner, + const EmbeddedIterator& it) const { + return {inner, &sets_[0] + num_tables, it}; + } + + static size_t subidx(size_t hashval) { + return ((hashval >> 8) ^ (hashval >> 16) ^ (hashval >> 24)) & mask; + } + + static size_t subcnt() { + return num_tables; + } + +private: + friend struct RawHashSetTestOnlyAccess; + + size_t growth_left() { + size_t sz = 0; + for (const auto& set : sets_) + sz += set.growth_left(); + return sz; + } + + hasher& hash_ref() { return sets_[0].set_.hash_ref(); } + const hasher& hash_ref() const { return sets_[0].set_.hash_ref(); } + key_equal& eq_ref() { return sets_[0].set_.eq_ref(); } + const key_equal& eq_ref() const { return sets_[0].set_.eq_ref(); } + allocator_type& alloc_ref() { return sets_[0].set_.alloc_ref(); } + const allocator_type& alloc_ref() const { + return sets_[0].set_.alloc_ref(); + } + +protected: // protected in case users want to derive fromm this + std::array sets_; +}; + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +template class RefSet, + class Mtx_, + class Policy, class Hash, class Eq, class Alloc> +class parallel_hash_map : public parallel_hash_set +{ + // P is Policy. It's passed as a template argument to support maps that have + // incomplete types as values, as in unordered_map. + // MappedReference<> may be a non-reference type. + template + using MappedReference = decltype(P::value( + std::addressof(std::declval()))); + + // MappedConstReference<> may be a non-reference type. + template + using MappedConstReference = decltype(P::value( + std::addressof(std::declval()))); + + using KeyArgImpl = + KeyArg::value && IsTransparent::value>; + + using Base = typename parallel_hash_map::parallel_hash_set; + using Lockable = phmap::LockableImpl; + +public: + using key_type = typename Policy::key_type; + using mapped_type = typename Policy::mapped_type; + template + using key_arg = typename KeyArgImpl::template type; + + static_assert(!std::is_reference::value, ""); + // TODO(alkis): remove this assertion and verify that reference mapped_type is + // supported. + static_assert(!std::is_reference::value, ""); + + using iterator = typename parallel_hash_map::parallel_hash_set::iterator; + using const_iterator = typename parallel_hash_map::parallel_hash_set::const_iterator; + + parallel_hash_map() {} + +#ifdef __INTEL_COMPILER + using Base::parallel_hash_set; +#else + using parallel_hash_map::parallel_hash_set::parallel_hash_set; +#endif + + // The last two template parameters ensure that both arguments are rvalues + // (lvalue arguments are handled by the overloads below). This is necessary + // for supporting bitfield arguments. + // + // union { int n : 1; }; + // flat_hash_map m; + // m.insert_or_assign(n, n); + template + std::pair insert_or_assign(key_arg&& k, V&& v) { + return insert_or_assign_impl(std::forward(k), std::forward(v)); + } + + template + std::pair insert_or_assign(key_arg&& k, const V& v) { + return insert_or_assign_impl(std::forward(k), v); + } + + template + std::pair insert_or_assign(const key_arg& k, V&& v) { + return insert_or_assign_impl(k, std::forward(v)); + } + + template + std::pair insert_or_assign(const key_arg& k, const V& v) { + return insert_or_assign_impl(k, v); + } + + template + iterator insert_or_assign(const_iterator, key_arg&& k, V&& v) { + return insert_or_assign(std::forward(k), std::forward(v)).first; + } + + template + iterator insert_or_assign(const_iterator, key_arg&& k, const V& v) { + return insert_or_assign(std::forward(k), v).first; + } + + template + iterator insert_or_assign(const_iterator, const key_arg& k, V&& v) { + return insert_or_assign(k, std::forward(v)).first; + } + + template + iterator insert_or_assign(const_iterator, const key_arg& k, const V& v) { + return insert_or_assign(k, v).first; + } + + template ::value, int>::type = 0, + K* = nullptr> + std::pair try_emplace(key_arg&& k, Args&&... args) { + return try_emplace_impl(std::forward(k), std::forward(args)...); + } + + template ::value, int>::type = 0> + std::pair try_emplace(const key_arg& k, Args&&... args) { + return try_emplace_impl(k, std::forward(args)...); + } + + template + iterator try_emplace(const_iterator, key_arg&& k, Args&&... args) { + return try_emplace(std::forward(k), std::forward(args)...).first; + } + + template + iterator try_emplace(const_iterator, const key_arg& k, Args&&... args) { + return try_emplace(k, std::forward(args)...).first; + } + + template + MappedReference

at(const key_arg& key) { + auto it = this->find(key); + if (it == this->end()) + phmap::base_internal::ThrowStdOutOfRange("phmap at(): lookup non-existent key"); + return Policy::value(&*it); + } + + template + MappedConstReference

at(const key_arg& key) const { + auto it = this->find(key); + if (it == this->end()) + phmap::base_internal::ThrowStdOutOfRange("phmap at(): lookup non-existent key"); + return Policy::value(&*it); + } + + // ----------- phmap extensions -------------------------- + + template ::value, int>::type = 0, + K* = nullptr> + std::pair try_emplace_with_hash(size_t hashval, key_arg&& k, Args&&... args) { + return try_emplace_impl_with_hash(hashval, std::forward(k), std::forward(args)...); + } + + template ::value, int>::type = 0> + std::pair try_emplace_with_hash(size_t hashval, const key_arg& k, Args&&... args) { + return try_emplace_impl_with_hash(hashval, k, std::forward(args)...); + } + + template + iterator try_emplace_with_hash(size_t hashval, const_iterator, key_arg&& k, Args&&... args) { + return try_emplace_with_hash(hashval, std::forward(k), std::forward(args)...).first; + } + + template + iterator try_emplace_with_hash(size_t hashval, const_iterator, const key_arg& k, Args&&... args) { + return try_emplace_with_hash(hashval, k, std::forward(args)...).first; + } + + // if map contains key, lambda is called with the mapped value (under read lock protection), + // and if_contains returns true. This is a const API and lambda should not modify the value + // ----------------------------------------------------------------------------------------- + template + bool if_contains(const key_arg& key, F&& f) const { + return const_cast(this)->template + modify_if_impl(key, std::forward(f)); + } + + // if map contains key, lambda is called with the mapped value without read lock protection, + // and if_contains_unsafe returns true. This is a const API and lambda should not modify the value + // This should be used only if we know that no other thread may be mutating the map at the time. + // ----------------------------------------------------------------------------------------- + template + bool if_contains_unsafe(const key_arg& key, F&& f) const { + return const_cast(this)->template + modify_if_impl::DoNothing>(key, std::forward(f)); + } + + // if map contains key, lambda is called with the mapped value (under write lock protection), + // and modify_if returns true. This is a non-const API and lambda is allowed to modify the mapped value + // ---------------------------------------------------------------------------------------------------- + template + bool modify_if(const key_arg& key, F&& f) { + return modify_if_impl(key, std::forward(f)); + } + + + // if map contains key, lambda is called with the mapped value (under write lock protection). + // If the lambda returns true, the key is subsequently erased from the map (the write lock + // is only released after erase). + // returns true if key was erased, false otherwise. + // ---------------------------------------------------------------------------------------------------- + template + bool erase_if(const key_arg& key, F&& f) { + return erase_if_impl(key, std::forward(f)); + } + + // if map does not contains key, it is inserted and the mapped value is value-constructed + // with the provided arguments (if any), as with try_emplace. + // if map already contains key, then the lambda is called with the mapped value (under + // write lock protection) and can update the mapped value. + // returns true if key was not already present, false otherwise. + // --------------------------------------------------------------------------------------- + template + bool try_emplace_l(K&& k, F&& f, Args&&... args) { + typename Lockable::UniqueLock m; + auto res = this->find_or_prepare_insert(k, m); + typename Base::Inner *inner = std::get<0>(res); + if (std::get<2>(res)) + inner->set_.emplace_at(std::get<1>(res), std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)); + else { + auto it = this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))); + std::forward(f)(Policy::value(&*it)); + } + return std::get<2>(res); + } + + // ----------- end of phmap extensions -------------------------- + + template + MappedReference

operator[](key_arg&& key) { + return Policy::value(&*try_emplace(std::forward(key)).first); + } + + template + MappedReference

operator[](const key_arg& key) { + return Policy::value(&*try_emplace(key).first); + } + +private: + template + bool modify_if_impl(const key_arg& key, F&& f) { +#if __cplusplus >= 201703L + static_assert(std::is_invocable::value); +#endif + L m; + auto ptr = this->template find_ptr(key, this->hash(key), m); + if (ptr == nullptr) + return false; + std::forward(f)(Policy::value(ptr)); + return true; + } + + template + bool erase_if_impl(const key_arg& key, F&& f) { +#if __cplusplus >= 201703L + static_assert(std::is_invocable::value); +#endif + L m; + auto it = this->template find(key, this->hash(key), m); + if (it == this->end()) return false; + if (std::forward(f)(Policy::value(&*it))) + { + this->erase(it); + return true; + } + return false; + } + + + template + std::pair insert_or_assign_impl(K&& k, V&& v) { + typename Lockable::UniqueLock m; + auto res = this->find_or_prepare_insert(k, m); + typename Base::Inner *inner = std::get<0>(res); + if (std::get<2>(res)) + inner->set_.emplace_at(std::get<1>(res), std::forward(k), std::forward(v)); + else + Policy::value(&*inner->set_.iterator_at(std::get<1>(res))) = std::forward(v); + return {this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))), + std::get<2>(res)}; + } + + template + std::pair try_emplace_impl(K&& k, Args&&... args) { + typename Lockable::UniqueLock m; + auto res = this->find_or_prepare_insert(k, m); + typename Base::Inner *inner = std::get<0>(res); + if (std::get<2>(res)) + inner->set_.emplace_at(std::get<1>(res), std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)); + return {this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))), + std::get<2>(res)}; + } + + template + std::pair try_emplace_impl_with_hash(size_t hashval, K&& k, Args&&... args) { + typename Lockable::UniqueLock m; + auto res = this->find_or_prepare_insert_with_hash(hashval, k, m); + typename Base::Inner *inner = std::get<0>(res); + if (std::get<2>(res)) + inner->set_.emplace_at(std::get<1>(res), std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)); + return {this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))), + std::get<2>(res)}; + } + + +}; + + +// Constructs T into uninitialized storage pointed by `ptr` using the args +// specified in the tuple. +// ---------------------------------------------------------------------------- +template +void ConstructFromTuple(Alloc* alloc, T* ptr, Tuple&& t) { + memory_internal::ConstructFromTupleImpl( + alloc, ptr, std::forward(t), + phmap::make_index_sequence< + std::tuple_size::type>::value>()); +} + +// Constructs T using the args specified in the tuple and calls F with the +// constructed value. +// ---------------------------------------------------------------------------- +template +decltype(std::declval()(std::declval())) WithConstructed( + Tuple&& t, F&& f) { + return memory_internal::WithConstructedImpl( + std::forward(t), + phmap::make_index_sequence< + std::tuple_size::type>::value>(), + std::forward(f)); +} + +// ---------------------------------------------------------------------------- +// Given arguments of an std::pair's consructor, PairArgs() returns a pair of +// tuples with references to the passed arguments. The tuples contain +// constructor arguments for the first and the second elements of the pair. +// +// The following two snippets are equivalent. +// +// 1. std::pair p(args...); +// +// 2. auto a = PairArgs(args...); +// std::pair p(std::piecewise_construct, +// std::move(p.first), std::move(p.second)); +// ---------------------------------------------------------------------------- +inline std::pair, std::tuple<>> PairArgs() { return {}; } + +template +std::pair, std::tuple> PairArgs(F&& f, S&& s) { + return {std::piecewise_construct, std::forward_as_tuple(std::forward(f)), + std::forward_as_tuple(std::forward(s))}; +} + +template +std::pair, std::tuple> PairArgs( + const std::pair& p) { + return PairArgs(p.first, p.second); +} + +template +std::pair, std::tuple> PairArgs(std::pair&& p) { + return PairArgs(std::forward(p.first), std::forward(p.second)); +} + +template +auto PairArgs(std::piecewise_construct_t, F&& f, S&& s) + -> decltype(std::make_pair(memory_internal::TupleRef(std::forward(f)), + memory_internal::TupleRef(std::forward(s)))) { + return std::make_pair(memory_internal::TupleRef(std::forward(f)), + memory_internal::TupleRef(std::forward(s))); +} + +// A helper function for implementing apply() in map policies. +// ---------------------------------------------------------------------------- +template +auto DecomposePair(F&& f, Args&&... args) + -> decltype(memory_internal::DecomposePairImpl( + std::forward(f), PairArgs(std::forward(args)...))) { + return memory_internal::DecomposePairImpl( + std::forward(f), PairArgs(std::forward(args)...)); +} + +// A helper function for implementing apply() in set policies. +// ---------------------------------------------------------------------------- +template +decltype(std::declval()(std::declval(), std::declval())) +DecomposeValue(F&& f, Arg&& arg) { + const auto& key = arg; + return std::forward(f)(key, std::forward(arg)); +} + + +// -------------------------------------------------------------------------- +// Policy: a policy defines how to perform different operations on +// the slots of the hashtable (see hash_policy_traits.h for the full interface +// of policy). +// +// Hash: a (possibly polymorphic) functor that hashes keys of the hashtable. The +// functor should accept a key and return size_t as hash. For best performance +// it is important that the hash function provides high entropy across all bits +// of the hash. +// +// Eq: a (possibly polymorphic) functor that compares two keys for equality. It +// should accept two (of possibly different type) keys and return a bool: true +// if they are equal, false if they are not. If two keys compare equal, then +// their hash values as defined by Hash MUST be equal. +// +// Allocator: an Allocator [https://devdocs.io/cpp/concept/allocator] with which +// the storage of the hashtable will be allocated and the elements will be +// constructed and destroyed. +// -------------------------------------------------------------------------- +template +struct FlatHashSetPolicy +{ + using slot_type = T; + using key_type = T; + using init_type = T; + using constant_iterators = std::true_type; + + template + static void construct(Allocator* alloc, slot_type* slot, Args&&... args) { + phmap::allocator_traits::construct(*alloc, slot, + std::forward(args)...); + } + + template + static void destroy(Allocator* alloc, slot_type* slot) { + phmap::allocator_traits::destroy(*alloc, slot); + } + + template + static void transfer(Allocator* alloc, slot_type* new_slot, + slot_type* old_slot) { + construct(alloc, new_slot, std::move(*old_slot)); + destroy(alloc, old_slot); + } + + static T& element(slot_type* slot) { return *slot; } + + template + static decltype(phmap::priv::DecomposeValue( + std::declval(), std::declval()...)) + apply(F&& f, Args&&... args) { + return phmap::priv::DecomposeValue( + std::forward(f), std::forward(args)...); + } + + static size_t space_used(const T*) { return 0; } +}; + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +template +struct FlatHashMapPolicy +{ + using slot_policy = priv::map_slot_policy; + using slot_type = typename slot_policy::slot_type; + using key_type = K; + using mapped_type = V; + using init_type = std::pair; + + template + static void construct(Allocator* alloc, slot_type* slot, Args&&... args) { + slot_policy::construct(alloc, slot, std::forward(args)...); + } + + template + static void destroy(Allocator* alloc, slot_type* slot) { + slot_policy::destroy(alloc, slot); + } + + template + static void transfer(Allocator* alloc, slot_type* new_slot, + slot_type* old_slot) { + slot_policy::transfer(alloc, new_slot, old_slot); + } + + template + static decltype(phmap::priv::DecomposePair( + std::declval(), std::declval()...)) + apply(F&& f, Args&&... args) { + return phmap::priv::DecomposePair(std::forward(f), + std::forward(args)...); + } + + static size_t space_used(const slot_type*) { return 0; } + + static std::pair& element(slot_type* slot) { return slot->value; } + + static V& value(std::pair* kv) { return kv->second; } + static const V& value(const std::pair* kv) { return kv->second; } +}; + +template +struct node_hash_policy { + static_assert(std::is_lvalue_reference::value, ""); + + using slot_type = typename std::remove_cv< + typename std::remove_reference::type>::type*; + + template + static void construct(Alloc* alloc, slot_type* slot, Args&&... args) { + *slot = Policy::new_element(alloc, std::forward(args)...); + } + + template + static void destroy(Alloc* alloc, slot_type* slot) { + Policy::delete_element(alloc, *slot); + } + + template + static void transfer(Alloc*, slot_type* new_slot, slot_type* old_slot) { + *new_slot = *old_slot; + } + + static size_t space_used(const slot_type* slot) { + if (slot == nullptr) return Policy::element_space_used(nullptr); + return Policy::element_space_used(*slot); + } + + static Reference element(slot_type* slot) { return **slot; } + + template + static auto value(T* elem) -> decltype(P::value(elem)) { + return P::value(elem); + } + + template + static auto apply(Ts&&... ts) -> decltype(P::apply(std::forward(ts)...)) { + return P::apply(std::forward(ts)...); + } +}; + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +template +struct NodeHashSetPolicy + : phmap::priv::node_hash_policy> +{ + using key_type = T; + using init_type = T; + using constant_iterators = std::true_type; + + template + static T* new_element(Allocator* alloc, Args&&... args) { + using ValueAlloc = + typename phmap::allocator_traits::template rebind_alloc; + ValueAlloc value_alloc(*alloc); + T* res = phmap::allocator_traits::allocate(value_alloc, 1); + phmap::allocator_traits::construct(value_alloc, res, + std::forward(args)...); + return res; + } + + template + static void delete_element(Allocator* alloc, T* elem) { + using ValueAlloc = + typename phmap::allocator_traits::template rebind_alloc; + ValueAlloc value_alloc(*alloc); + phmap::allocator_traits::destroy(value_alloc, elem); + phmap::allocator_traits::deallocate(value_alloc, elem, 1); + } + + template + static decltype(phmap::priv::DecomposeValue( + std::declval(), std::declval()...)) + apply(F&& f, Args&&... args) { + return phmap::priv::DecomposeValue( + std::forward(f), std::forward(args)...); + } + + static size_t element_space_used(const T*) { return sizeof(T); } +}; + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +template +class NodeHashMapPolicy + : public phmap::priv::node_hash_policy< + std::pair&, NodeHashMapPolicy> +{ + using value_type = std::pair; + +public: + using key_type = Key; + using mapped_type = Value; + using init_type = std::pair; + + template + static value_type* new_element(Allocator* alloc, Args&&... args) { + using PairAlloc = typename phmap::allocator_traits< + Allocator>::template rebind_alloc; + PairAlloc pair_alloc(*alloc); + value_type* res = + phmap::allocator_traits::allocate(pair_alloc, 1); + phmap::allocator_traits::construct(pair_alloc, res, + std::forward(args)...); + return res; + } + + template + static void delete_element(Allocator* alloc, value_type* pair) { + using PairAlloc = typename phmap::allocator_traits< + Allocator>::template rebind_alloc; + PairAlloc pair_alloc(*alloc); + phmap::allocator_traits::destroy(pair_alloc, pair); + phmap::allocator_traits::deallocate(pair_alloc, pair, 1); + } + + template + static decltype(phmap::priv::DecomposePair( + std::declval(), std::declval()...)) + apply(F&& f, Args&&... args) { + return phmap::priv::DecomposePair(std::forward(f), + std::forward(args)...); + } + + static size_t element_space_used(const value_type*) { + return sizeof(value_type); + } + + static Value& value(value_type* elem) { return elem->second; } + static const Value& value(const value_type* elem) { return elem->second; } +}; + + +// -------------------------------------------------------------------------- +// hash_default +// -------------------------------------------------------------------------- + +#if PHMAP_HAVE_STD_STRING_VIEW + +// support char16_t wchar_t .... +template +struct StringHashT +{ + using is_transparent = void; + + size_t operator()(std::basic_string_view v) const { + std::string_view bv{reinterpret_cast(v.data()), v.size() * sizeof(CharT)}; + return std::hash()(bv); + } +}; + +// Supports heterogeneous lookup for basic_string-like elements. +template +struct StringHashEqT +{ + using Hash = StringHashT; + + struct Eq { + using is_transparent = void; + + bool operator()(std::basic_string_view lhs, std::basic_string_view rhs) const { + return lhs == rhs; + } + }; +}; + +template <> +struct HashEq : StringHashEqT {}; + +template <> +struct HashEq : StringHashEqT {}; + +// char16_t +template <> +struct HashEq : StringHashEqT {}; + +template <> +struct HashEq : StringHashEqT {}; + +// wchar_t +template <> +struct HashEq : StringHashEqT {}; + +template <> +struct HashEq : StringHashEqT {}; + +#endif + +// Supports heterogeneous lookup for pointers and smart pointers. +// ------------------------------------------------------------- +template +struct HashEq +{ + struct Hash { + using is_transparent = void; + template + size_t operator()(const U& ptr) const { + return phmap::Hash{}(HashEq::ToPtr(ptr)); + } + }; + + struct Eq { + using is_transparent = void; + template + bool operator()(const A& a, const B& b) const { + return HashEq::ToPtr(a) == HashEq::ToPtr(b); + } + }; + +private: + static const T* ToPtr(const T* ptr) { return ptr; } + + template + static const T* ToPtr(const std::unique_ptr& ptr) { + return ptr.get(); + } + + template + static const T* ToPtr(const std::shared_ptr& ptr) { + return ptr.get(); + } +}; + +template +struct HashEq> : HashEq {}; + +template +struct HashEq> : HashEq {}; + +namespace hashtable_debug_internal { + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +template +struct HashtableDebugAccess> +{ + using Traits = typename Set::PolicyTraits; + using Slot = typename Traits::slot_type; + + static size_t GetNumProbes(const Set& set, + const typename Set::key_type& key) { + size_t num_probes = 0; + size_t hashval = set.hash(key); + auto seq = set.probe(hashval); + while (true) { + priv::Group g{set.ctrl_ + seq.offset()}; + for (int i : g.Match(priv::H2(hashval))) { + if (Traits::apply( + typename Set::template EqualElement{ + key, set.eq_ref()}, + Traits::element(set.slots_ + seq.offset((size_t)i)))) + return num_probes; + ++num_probes; + } + if (g.MatchEmpty()) return num_probes; + seq.next(); + ++num_probes; + } + } + + static size_t AllocatedByteSize(const Set& c) { + size_t capacity = c.capacity_; + if (capacity == 0) return 0; + auto layout = Set::MakeLayout(capacity); + size_t m = layout.AllocSize(); + + size_t per_slot = Traits::space_used(static_cast(nullptr)); + if (per_slot != ~size_t{}) { + m += per_slot * c.size(); + } else { + for (size_t i = 0; i != capacity; ++i) { + if (priv::IsFull(c.ctrl_[i])) { + m += Traits::space_used(c.slots_ + i); + } + } + } + return m; + } + + static size_t LowerBoundAllocatedByteSize(size_t size) { + size_t capacity = GrowthToLowerboundCapacity(size); + if (capacity == 0) return 0; + auto layout = Set::MakeLayout(NormalizeCapacity(capacity)); + size_t m = layout.AllocSize(); + size_t per_slot = Traits::space_used(static_cast(nullptr)); + if (per_slot != ~size_t{}) { + m += per_slot * size; + } + return m; + } +}; + +} // namespace hashtable_debug_internal +} // namespace priv + +// ----------------------------------------------------------------------------- +// phmap::flat_hash_set +// ----------------------------------------------------------------------------- +// An `phmap::flat_hash_set` is an unordered associative container which has +// been optimized for both speed and memory footprint in most common use cases. +// Its interface is similar to that of `std::unordered_set` with the +// following notable differences: +// +// * Supports heterogeneous lookup, through `find()`, `operator[]()` and +// `insert()`, provided that the set is provided a compatible heterogeneous +// hashing function and equality operator. +// * Invalidates any references and pointers to elements within the table after +// `rehash()`. +// * Contains a `capacity()` member function indicating the number of element +// slots (open, deleted, and empty) within the hash set. +// * Returns `void` from the `_erase(iterator)` overload. +// ----------------------------------------------------------------------------- +template // default values in phmap_fwd_decl.h +class flat_hash_set + : public phmap::priv::raw_hash_set< + phmap::priv::FlatHashSetPolicy, Hash, Eq, Alloc> +{ + using Base = typename flat_hash_set::raw_hash_set; + +public: + flat_hash_set() {} +#ifdef __INTEL_COMPILER + using Base::raw_hash_set; +#else + using Base::Base; +#endif + using Base::begin; + using Base::cbegin; + using Base::cend; + using Base::end; + using Base::capacity; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; // may shrink - To avoid shrinking `erase(begin(), end())` + using Base::erase; + using Base::insert; + using Base::emplace; + using Base::emplace_hint; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::rehash; + using Base::reserve; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::bucket_count; + using Base::load_factor; + using Base::max_load_factor; + using Base::get_allocator; + using Base::hash_function; + using Base::hash; + using Base::key_eq; +}; + +// ----------------------------------------------------------------------------- +// phmap::flat_hash_map +// ----------------------------------------------------------------------------- +// +// An `phmap::flat_hash_map` is an unordered associative container which +// has been optimized for both speed and memory footprint in most common use +// cases. Its interface is similar to that of `std::unordered_map` with +// the following notable differences: +// +// * Supports heterogeneous lookup, through `find()`, `operator[]()` and +// `insert()`, provided that the map is provided a compatible heterogeneous +// hashing function and equality operator. +// * Invalidates any references and pointers to elements within the table after +// `rehash()`. +// * Contains a `capacity()` member function indicating the number of element +// slots (open, deleted, and empty) within the hash map. +// * Returns `void` from the `_erase(iterator)` overload. +// ----------------------------------------------------------------------------- +template // default values in phmap_fwd_decl.h +class flat_hash_map : public phmap::priv::raw_hash_map< + phmap::priv::FlatHashMapPolicy, + Hash, Eq, Alloc> { + using Base = typename flat_hash_map::raw_hash_map; + +public: + flat_hash_map() {} +#ifdef __INTEL_COMPILER + using Base::raw_hash_map; +#else + using Base::Base; +#endif + using Base::begin; + using Base::cbegin; + using Base::cend; + using Base::end; + using Base::capacity; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::insert_or_assign; + using Base::emplace; + using Base::emplace_hint; + using Base::try_emplace; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::rehash; + using Base::reserve; + using Base::at; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::operator[]; + using Base::bucket_count; + using Base::load_factor; + using Base::max_load_factor; + using Base::get_allocator; + using Base::hash_function; + using Base::hash; + using Base::key_eq; +}; + +// ----------------------------------------------------------------------------- +// phmap::node_hash_set +// ----------------------------------------------------------------------------- +// An `phmap::node_hash_set` is an unordered associative container which +// has been optimized for both speed and memory footprint in most common use +// cases. Its interface is similar to that of `std::unordered_set` with the +// following notable differences: +// +// * Supports heterogeneous lookup, through `find()`, `operator[]()` and +// `insert()`, provided that the map is provided a compatible heterogeneous +// hashing function and equality operator. +// * Contains a `capacity()` member function indicating the number of element +// slots (open, deleted, and empty) within the hash set. +// * Returns `void` from the `erase(iterator)` overload. +// ----------------------------------------------------------------------------- +template // default values in phmap_fwd_decl.h +class node_hash_set + : public phmap::priv::raw_hash_set< + phmap::priv::NodeHashSetPolicy, Hash, Eq, Alloc> +{ + using Base = typename node_hash_set::raw_hash_set; + +public: + node_hash_set() {} +#ifdef __INTEL_COMPILER + using Base::raw_hash_set; +#else + using Base::Base; +#endif + using Base::begin; + using Base::cbegin; + using Base::cend; + using Base::end; + using Base::capacity; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::emplace; + using Base::emplace_hint; + using Base::emplace_with_hash; + using Base::emplace_hint_with_hash; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::rehash; + using Base::reserve; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::bucket_count; + using Base::load_factor; + using Base::max_load_factor; + using Base::get_allocator; + using Base::hash_function; + using Base::hash; + using Base::key_eq; + typename Base::hasher hash_funct() { return this->hash_function(); } + void resize(typename Base::size_type hint) { this->rehash(hint); } +}; + +// ----------------------------------------------------------------------------- +// phmap::node_hash_map +// ----------------------------------------------------------------------------- +// +// An `phmap::node_hash_map` is an unordered associative container which +// has been optimized for both speed and memory footprint in most common use +// cases. Its interface is similar to that of `std::unordered_map` with +// the following notable differences: +// +// * Supports heterogeneous lookup, through `find()`, `operator[]()` and +// `insert()`, provided that the map is provided a compatible heterogeneous +// hashing function and equality operator. +// * Contains a `capacity()` member function indicating the number of element +// slots (open, deleted, and empty) within the hash map. +// * Returns `void` from the `erase(iterator)` overload. +// ----------------------------------------------------------------------------- +template // default values in phmap_fwd_decl.h +class node_hash_map + : public phmap::priv::raw_hash_map< + phmap::priv::NodeHashMapPolicy, Hash, Eq, + Alloc> +{ + using Base = typename node_hash_map::raw_hash_map; + +public: + node_hash_map() {} +#ifdef __INTEL_COMPILER + using Base::raw_hash_map; +#else + using Base::Base; +#endif + using Base::begin; + using Base::cbegin; + using Base::cend; + using Base::end; + using Base::capacity; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::insert_or_assign; + using Base::emplace; + using Base::emplace_hint; + using Base::try_emplace; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::rehash; + using Base::reserve; + using Base::at; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::operator[]; + using Base::bucket_count; + using Base::load_factor; + using Base::max_load_factor; + using Base::get_allocator; + using Base::hash_function; + using Base::hash; + using Base::key_eq; + typename Base::hasher hash_funct() { return this->hash_function(); } + void resize(typename Base::size_type hint) { this->rehash(hint); } +}; + +// ----------------------------------------------------------------------------- +// phmap::parallel_flat_hash_set +// ----------------------------------------------------------------------------- +template // default values in phmap_fwd_decl.h +class parallel_flat_hash_set + : public phmap::priv::parallel_hash_set< + N, phmap::priv::raw_hash_set, Mtx_, + phmap::priv::FlatHashSetPolicy, + Hash, Eq, Alloc> +{ + using Base = typename parallel_flat_hash_set::parallel_hash_set; + +public: + parallel_flat_hash_set() {} +#ifdef __INTEL_COMPILER + using Base::parallel_hash_set; +#else + using Base::Base; +#endif + using Base::hash; + using Base::subidx; + using Base::subcnt; + using Base::begin; + using Base::cbegin; + using Base::cend; + using Base::end; + using Base::capacity; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::emplace; + using Base::emplace_hint; + using Base::emplace_with_hash; + using Base::emplace_hint_with_hash; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::rehash; + using Base::reserve; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::bucket_count; + using Base::load_factor; + using Base::max_load_factor; + using Base::get_allocator; + using Base::hash_function; + using Base::key_eq; +}; + +// ----------------------------------------------------------------------------- +// phmap::parallel_flat_hash_map - default values in phmap_fwd_decl.h +// ----------------------------------------------------------------------------- +template +class parallel_flat_hash_map : public phmap::priv::parallel_hash_map< + N, phmap::priv::raw_hash_set, Mtx_, + phmap::priv::FlatHashMapPolicy, + Hash, Eq, Alloc> +{ + using Base = typename parallel_flat_hash_map::parallel_hash_map; + +public: + parallel_flat_hash_map() {} +#ifdef __INTEL_COMPILER + using Base::parallel_hash_map; +#else + using Base::Base; +#endif + using Base::hash; + using Base::subidx; + using Base::subcnt; + using Base::begin; + using Base::cbegin; + using Base::cend; + using Base::end; + using Base::capacity; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::insert_or_assign; + using Base::emplace; + using Base::emplace_hint; + using Base::try_emplace; + using Base::emplace_with_hash; + using Base::emplace_hint_with_hash; + using Base::try_emplace_with_hash; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::rehash; + using Base::reserve; + using Base::at; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::operator[]; + using Base::bucket_count; + using Base::load_factor; + using Base::max_load_factor; + using Base::get_allocator; + using Base::hash_function; + using Base::key_eq; +}; + +// ----------------------------------------------------------------------------- +// phmap::parallel_node_hash_set +// ----------------------------------------------------------------------------- +template +class parallel_node_hash_set + : public phmap::priv::parallel_hash_set< + N, phmap::priv::raw_hash_set, Mtx_, + phmap::priv::NodeHashSetPolicy, Hash, Eq, Alloc> +{ + using Base = typename parallel_node_hash_set::parallel_hash_set; + +public: + parallel_node_hash_set() {} +#ifdef __INTEL_COMPILER + using Base::parallel_hash_set; +#else + using Base::Base; +#endif + using Base::hash; + using Base::subidx; + using Base::subcnt; + using Base::begin; + using Base::cbegin; + using Base::cend; + using Base::end; + using Base::capacity; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::emplace; + using Base::emplace_hint; + using Base::emplace_with_hash; + using Base::emplace_hint_with_hash; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::rehash; + using Base::reserve; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::bucket_count; + using Base::load_factor; + using Base::max_load_factor; + using Base::get_allocator; + using Base::hash_function; + using Base::key_eq; + typename Base::hasher hash_funct() { return this->hash_function(); } + void resize(typename Base::size_type hint) { this->rehash(hint); } +}; + +// ----------------------------------------------------------------------------- +// phmap::parallel_node_hash_map +// ----------------------------------------------------------------------------- +template +class parallel_node_hash_map + : public phmap::priv::parallel_hash_map< + N, phmap::priv::raw_hash_set, Mtx_, + phmap::priv::NodeHashMapPolicy, Hash, Eq, + Alloc> +{ + using Base = typename parallel_node_hash_map::parallel_hash_map; + +public: + parallel_node_hash_map() {} +#ifdef __INTEL_COMPILER + using Base::parallel_hash_map; +#else + using Base::Base; +#endif + using Base::hash; + using Base::subidx; + using Base::subcnt; + using Base::begin; + using Base::cbegin; + using Base::cend; + using Base::end; + using Base::capacity; + using Base::empty; + using Base::max_size; + using Base::size; + using Base::clear; + using Base::erase; + using Base::insert; + using Base::insert_or_assign; + using Base::emplace; + using Base::emplace_hint; + using Base::try_emplace; + using Base::emplace_with_hash; + using Base::emplace_hint_with_hash; + using Base::try_emplace_with_hash; + using Base::extract; + using Base::merge; + using Base::swap; + using Base::rehash; + using Base::reserve; + using Base::at; + using Base::contains; + using Base::count; + using Base::equal_range; + using Base::find; + using Base::operator[]; + using Base::bucket_count; + using Base::load_factor; + using Base::max_load_factor; + using Base::get_allocator; + using Base::hash_function; + using Base::key_eq; + typename Base::hasher hash_funct() { return this->hash_function(); } + void resize(typename Base::size_type hint) { this->rehash(hint); } +}; + +} // namespace phmap + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + + +#endif // phmap_h_guard_ diff --git a/extern/phmap/parallel_hashmap/phmap_base.h b/extern/phmap/parallel_hashmap/phmap_base.h new file mode 100644 index 0000000..6b9ea9e --- /dev/null +++ b/extern/phmap/parallel_hashmap/phmap_base.h @@ -0,0 +1,5171 @@ +#if !defined(phmap_base_h_guard_) +#define phmap_base_h_guard_ + +// --------------------------------------------------------------------------- +// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp) +// with modifications. +// +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// --------------------------------------------------------------------------- + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for std::lock + +#include "phmap_config.h" + +#ifdef PHMAP_HAVE_SHARED_MUTEX + #include // after "phmap_config.h" +#endif + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable : 4514) // unreferenced inline function has been removed + #pragma warning(disable : 4582) // constructor is not implicitly called + #pragma warning(disable : 4625) // copy constructor was implicitly defined as deleted + #pragma warning(disable : 4626) // assignment operator was implicitly defined as deleted + #pragma warning(disable : 4710) // function not inlined + #pragma warning(disable : 4711) // selected for automatic inline expansion + #pragma warning(disable : 4820) // '6' bytes padding added after data member +#endif // _MSC_VER + +namespace phmap { + +template using Allocator = typename std::allocator; + +template using Pair = typename std::pair; + +template +struct EqualTo +{ + inline bool operator()(const T& a, const T& b) const + { + return std::equal_to()(a, b); + } +}; + +template +struct Less +{ + inline bool operator()(const T& a, const T& b) const + { + return std::less()(a, b); + } +}; + +namespace type_traits_internal { + +template +struct VoidTImpl { + using type = void; +}; + +// This trick to retrieve a default alignment is necessary for our +// implementation of aligned_storage_t to be consistent with any implementation +// of std::aligned_storage. +// --------------------------------------------------------------------------- +template > +struct default_alignment_of_aligned_storage; + +template +struct default_alignment_of_aligned_storage> { + static constexpr size_t value = Align; +}; + +// NOTE: The `is_detected` family of templates here differ from the library +// fundamentals specification in that for library fundamentals, `Op` is +// evaluated as soon as the type `is_detected` undergoes +// substitution, regardless of whether or not the `::value` is accessed. That +// is inconsistent with all other standard traits and prevents lazy evaluation +// in larger contexts (such as if the `is_detected` check is a trailing argument +// of a `conjunction`. This implementation opts to instead be lazy in the same +// way that the standard traits are (this "defect" of the detection idiom +// specifications has been reported). +// --------------------------------------------------------------------------- + +template class Op, class... Args> +struct is_detected_impl { + using type = std::false_type; +}; + +template