commit 133700160ab19a50d90b8a72fcf42f4092262915 Author: dsc Date: Wed Oct 7 12:36:04 2020 +0200 Feather, a free Monero desktop wallet Co-Authored-By: tobtoht diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..01a8d7c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +* +!contrib/Qt5.15_LinuxPatch.json +!utils/pubkeys/* \ No newline at end of file diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..41c83cc --- /dev/null +++ b/.drone.yml @@ -0,0 +1,160 @@ +--- +kind: pipeline +type: docker +name: linux-release + +steps: + - name: build + image: feather:linux + volumes: + - name: ccache_linux_release + path: /root/.ccache + - name: files_linux_release + path: /files + commands: + - git config --global url."http://gitea:3000/tor/".insteadOf https://git.torproject.org/ + - git config --global url."http://gitea:3000/".insteadOf https://github.com/ + - git submodule update --init --depth 50 contrib/tor + - git submodule update --init --depth 50 contrib/torsocks + - git submodule update --init --depth 120 monero + - git submodule update --init --depth 120 --recursive monero + - make -j8 release-static + environment: + OPENSSL_ROOT_DIR: /usr/local/openssl/ + CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off + - name: deploy + image: feather:linux + volumes: + - name: ccache_linux_release + path: /root/.ccache + - name: files_linux_release + path: /files + commands: + - export FN="feather-`git rev-parse --short HEAD`.zip" + - export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH" + - mkdir -p "$TARGET_DIR" + - echo "writing to $TARGET_DIR/$FN" + - strip -s build/bin/feather + - zip -j "$TARGET_DIR/$FN" build/feather.log build/bin/feather + - echo "[*] written to https://build.featherwallet.org/files/linux-release/$DRONE_SOURCE_BRANCH/$FN" + +volumes: +- name: ccache_linux_release + host: + path: /var/drone/ccache_linux_release/ +- name: files_linux_release + host: + path: /mnt/storage1/feather_files/files/linux-release/ + +--- + +kind: pipeline +type: docker +name: linux-release-appimage + +steps: + - name: build + image: feather:appimage + commands: + - export FN="feather-`git rev-parse --short HEAD`.zip" + - export BRANCH="$DRONE_SOURCE_BRANCH" + - bash ./contrib/build-appimage.sh + - name: deploy + image: feather:appimage + volumes: + - name: files_linux_appimage + path: /files + commands: + - export FN="feather-`git rev-parse --short HEAD`.AppImage" + - export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH" + - mkdir -p "$TARGET_DIR" + - echo "writing to $TARGET_DIR/$FN" + - mv "Feather-1.0-x86_64.AppImage" "$TARGET_DIR/$FN" + - echo "[*] written to https://build.featherwallet.org/files/linux-release-appimage/$DRONE_SOURCE_BRANCH/$FN" + +volumes: + - name: files_linux_appimage + host: + path: /mnt/storage1/feather_files/files/linux-release-appimage/ + +--- + +kind: pipeline +type: docker +name: windows-mxe-release + +steps: + - name: build + image: feather:win + volumes: + - name: ccache_win_release + path: /root/.ccache + - name: files_win_release + path: /files + commands: + - git config --global url."http://gitea:3000/tor/".insteadOf https://git.torproject.org/ + - git config --global url."http://gitea:3000/".insteadOf https://github.com/ + - git submodule update --init --depth 50 contrib/tor + - git submodule update --init --depth 50 contrib/torsocks + - git submodule update --init --depth 120 monero + - git submodule update --init --depth 120 --recursive monero + - PATH=/mxe/usr/bin/:$PATH make -j8 windows-mxe-release + environment: + CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off + - name: deploy + image: feather:win + volumes: + - name: ccache_win_release + path: /root/.ccache + - name: files_win_release + path: /files + commands: + - export FN="feather-`git rev-parse --short HEAD`.zip" + - export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH" + - mkdir -p "$TARGET_DIR" + - echo "writing to $TARGET_DIR/$FN" + - zip -j "$TARGET_DIR/$FN" build/feather.log build/bin/feather.exe + - echo "[*] written to https://build.featherwallet.org/files/windows-mxe-release/$DRONE_SOURCE_BRANCH/$FN" + +volumes: +- name: ccache_win_release + host: + path: /var/drone/ccache_win_release/ +- name: files_win_release + host: + path: /mnt/storage1/feather_files/files/windows-mxe-release/ + +--- + +kind: pipeline +type: docker +name: mac-release + +steps: + - name: build + image: feather:mac + volumes: + - name: files_mac_release + path: /files + commands: + - mkdir -p build + - scp -P22 utils/build_macos.sh administrator@steve.jobs.xmr.pm:build_macos.sh + - ssh administrator@steve.jobs.xmr.pm "chmod +x build_macos.sh && PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin ~/build_macos.sh $DRONE_COMMIT_SHA" + - scp -P22 administrator@steve.jobs.xmr.pm:feather.zip build/feather.zip + - name: deploy + image: feather:mac + volumes: + - name: files_mac_release + path: /files + commands: + - export FN="feather-`git rev-parse --short HEAD`.zip" + - export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH" + - mkdir -p "$TARGET_DIR" + - echo "writing to $TARGET_DIR/$FN" + - mv build/feather.zip "$TARGET_DIR/$FN" + - echo "[*] written to https://build.featherwallet.org/files/mac-release/$DRONE_SOURCE_BRANCH/$FN" + +volumes: +- name: files_mac_release + host: + path: /mnt/storage1/feather_files/files/mac-release/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a00d97 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +.DS_Store +lib/* +cmake-build-debug/* +.idea +*.user +*.stash +build/* +CMakeCache.txt +CMakeFiles +cmake_install.cmake +feather_autogen/ +feather.cbp +src/tor/* +!src/tor/.gitkeep +src/config-feather.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4053728 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "monero"] + path = monero + url = https://git.wownero.com/feather/monero.git +[submodule "contrib/torsocks"] + path = contrib/torsocks + url = https://git.torproject.org/torsocks.git +[submodule "contrib/tor"] + path = contrib/tor + url = https://git.torproject.org/tor.git diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 0000000..35efd02 --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,101 @@ +# Buildbot builds + +The docker build bins can be found here: https://build.featherwallet.org/files/ + +## Docker static builds + +Static builds via Docker are done in 3 steps: + +1. Cloning this repository (+submodules) +2. Creating a base Docker image +3. Using the base image to compile a build + +### Windows + +The docker image for Windows static compiles uses Ubuntu 18.04 and installs [mxe](https://mxe.cc) from [our git](https://git.wownero.com/feather/mxe/src/branch/feather-patch), +which comes with: OpenSSL 1.1.1g, Qt 5.15.0 (OpenGL via mesa). For more information, check the Dockerfile: `Dockerfile_windows`. + +#### 1. Clone + +```bash +git clone --recursive https://git.wownero.com/feather/feather.git +cd feather +``` + +#### 2. Base image + +Warning: Building the MXE base image takes up to a hour, so go watch a movie. + +```bash +docker build -f Dockerfile_windows --tag feather:win --build-arg THREADS=8 . +``` + +Note: You only need to build the base image once. + +#### 3. Build + +```bash +docker run --rm -it -v /tmp/ccache:/root/.ccache -v /root/feather:/feather -w /feather feather:win /bin/bash -c 'PATH=/mxe/usr/bin/:$PATH make windows-mxe-release -j8' +``` + +Replace `PATH_TO_FEATHER` with the absolute path to Feather locally. + +The resulting binary can be found in `build/bin/feather.exe`. + +### Linux + +The docker image for Linux static compiles uses Ubuntu 18.04 and compiles the required libraries statically so that +the resulting Feather binary is static. It comes with OpenSSL 1.1.1g, Qt 5.15.0 (OpenGL disabled). For more information, +check the Dockerfile: `Dockerfile`. + +#### 1. Clone + +```bash +git clone --recursive https://git.wownero.com/feather/feather.git +cd feather +``` + +#### 2. Base image + +Warning: Building the base image takes a while, go prepare some dinner. + +```bash +docker build --tag feather:linux --build-arg THREADS=8 . +``` + +Note: You only need to build the base image once. + +#### 3. Build + +```bash +docker run --env OPENSSL_ROOT_DIR=/usr/local/openssl/ --rm -it -v /tmp/ccache:/root/.ccache -v PATH_TO_FEATHER:/feather -w /feather feather:linux sh -c 'make release-static -j8' +``` + +Replace `PATH_TO_FEATHER` with the absolute path to Feather locally. + +The resulting binary can be found in `build/bin/feather`. + +## macOS + +For MacOS it's easiest to leverage [brew](https://brew.sh) to install the required dependencies. + +```bash +HOMEBREW_OPTFLAGS="-march=core2" HOMEBREW_OPTIMIZATION_LEVEL="O0" \ + brew install boost zmq openssl libpgm miniupnpc libsodium expat libunwind-headers protobuf libgcrypt qrencode ccache cmake pkgconfig git +``` + +Clone the repository. + +```bash +git clone --recursive https://git.wownero.com/feather/feather.git +``` + +Get the latest LTS from here: https://www.qt.io/offline-installers and install. + +Build Feather. + +```bash +CMAKE_PREFIX_PATH=~/Qt5.15.1/5.15.1/clang_64 make mac-release +``` + +The resulting Mac OS application can be found `build/bin/feather.app`. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9fe9733 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,349 @@ +cmake_minimum_required(VERSION 3.13) +project(feather) + +message(STATUS "Initiating compile using CMake ${CMAKE_VERSION}") + +set(THREADS_PREFER_PTHREAD_FLAG ON) +set(VERSION_MAJOR "0") +set(VERSION_MINOR "1") +set(VERSION_REVISION "0") +set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}") + +option(FETCH_DEPS "Download dependencies if they are not found" ON) +option(XMRTO "Include Xmr.To module" ON) +option(BUILD_TOR "Build Tor" OFF) +option(STATIC "Link libraries statically, requires static Qt") +option(USE_DEVICE_TREZOR "Trezor support compilation" OFF) +option(DONATE_BEG "Prompt donation window every once in a while" ON) +list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake") +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) +include(CheckLinkerFlag) +include(FetchContent) +include(FindCcache) +include(CheckIncludeFile) +include(CheckSymbolExists) + +if(DEBUG) + set(CMAKE_VERBOSE_MAKEFILE ON) +endif() + +set(MONERO_HEAD "a1404e92cb439ba0f120e7c4a579ed0b9a0372a4") +set(BUILD_GUI_DEPS ON) +set(ARCH "x86-64") +set(BUILD_64 ON) +set(INSTALL_VENDORED_LIBUNBOUND ${STATIC}) +set(USE_SINGLE_BUILDDIR ON) + +check_include_file(sys/prctl.h HAVE_SYS_PRCTL_H) +check_symbol_exists(prctl "sys/prctl.h" HAVE_PRCTL) + +if(STATIC) + message(STATUS "Initiating static build, turning on manual submodules") + set(MANUAL_SUBMODULES 1) + + # monero-project/unbound:monero has a fix for static builds, however, it's not merged in Monero yet, because + # it breaks their buildbot, since that still uses openssl 1.1.0 and we use openssl 1.1.1g. We need to + # manually set the unbound submodule the right commit that has the fix. + # This only works with -DMANUAL_SUBMODULES=1 + message(STATUS "applying unbound static build fix contrib/unbound_static.patch") + execute_process(COMMAND bash -c "git -C ${CMAKE_SOURCE_DIR}/monero/external/unbound apply ${CMAKE_SOURCE_DIR}/contrib/unbound_static.patch") + + set(Boost_USE_STATIC_LIBS ON) + set(Boost_USE_STATIC_RUNTIME ON) + add_definitions(-DMONERO_GUI_STATIC) +endif() + +function (add_c_flag_if_supported flag var) + string(REPLACE "-" "_" supported ${flag}_c) + check_c_compiler_flag(${flag} ${supported}) + if(${${supported}}) + set(${var} "${${var}} ${flag}" PARENT_SCOPE) + endif() +endfunction() + +function (add_cxx_flag_if_supported flag var) + string(REPLACE "-" "_" supported ${flag}_cxx) + check_cxx_compiler_flag(${flag} ${supported}) + if(${${supported}}) + set(${var} "${${var}} ${flag}" PARENT_SCOPE) + endif() +endfunction() + +function (add_linker_flag_if_supported flag var) + string(REPLACE "-" "_" supported ${flag}_ld) + string(REPLACE "," "_" supported ${flag}_ld) + check_linker_flag(${flag} ${supported}) + if(${${supported}}) + set(${var} "${${var}} ${flag}" PARENT_SCOPE) + endif() +endfunction() + +find_package(Git) +if(GIT_FOUND) + execute_process(COMMAND git rev-parse "HEAD" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/monero OUTPUT_VARIABLE _MONERO_HEAD OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT _MONERO_HEAD STREQUAL MONERO_HEAD) + message(FATAL_ERROR "[submodule] Monero HEAD was at ${_MONERO_HEAD} but should be at ${MONERO_HEAD}") + else() + message(STATUS "[submodule] Monero HEAD @ ${MONERO_HEAD}") + endif() +endif() + +add_subdirectory(monero) +set_property(TARGET wallet_merged PROPERTY FOLDER "monero") +get_directory_property(ARCH_WIDTH DIRECTORY "monero" DEFINITION ARCH_WIDTH) +get_directory_property(UNBOUND_LIBRARY DIRECTORY "monero" DEFINITION UNBOUND_LIBRARY) + +include(CMakePackageConfigHelpers) +include(VersionMonero) +include(VersionFeather) + +include_directories(${EASYLOGGING_INCLUDE}) +link_directories(${EASYLOGGING_LIBRARY_DIRS}) + +# OpenSSL +if(APPLE AND NOT OPENSSL_ROOT_DIR) + execute_process(COMMAND brew --prefix openssl OUTPUT_VARIABLE OPENSSL_ROOT_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +find_package(OpenSSL REQUIRED) +message(STATUS "OpenSSL: Version ${OPENSSL_VERSION}") +message(STATUS "OpenSSL: include dir at ${OPENSSL_INCLUDE_DIR}") +message(STATUS "OpenSSL: libraries at ${OPENSSL_LIBRARIES} ${OPENSSL_SSL_LIBRARIES}") + +# Sodium +find_library(SODIUM_LIBRARY sodium) +message(STATUS "libsodium: libraries at ${SODIUM_LIBRARY}") + +# HIDApi +set(HIDAPI_FOUND OFF) + +# QrEncode +find_package(QREncode REQUIRED) + +# Tevador 14 word Monero seed +find_package(monero-seed CONFIG) +if(NOT monero-seed_FOUND) + if(FETCH_DEPS) + FetchContent_Declare(monero-seed + GIT_REPOSITORY https://git.wownero.com/feather/monero-seed.git) + FetchContent_GetProperties(monero-seed) + if(NOT monero-seed_POPULATED) + message(STATUS "Fetching monero-seed") + FetchContent_Populate(monero-seed) + add_subdirectory(${monero-seed_SOURCE_DIR} ${monero-seed_BINARY_DIR}) + endif() + add_library(monero-seed::monero-seed ALIAS monero-seed) + else() + message(FATAL_ERROR "monero-seed was not installed and fetching deps is disabled") + endif() +endif() + +# Boost +if(DEBUG) + set(Boost_DEBUG ON) +endif() +if(APPLE AND NOT BOOST_ROOT) + execute_process(COMMAND brew --prefix boost OUTPUT_VARIABLE BOOST_ROOT OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +find_package(Boost 1.58 REQUIRED COMPONENTS + system + filesystem + thread + date_time + chrono + regex + serialization + program_options + locale) + +if(UNIX AND NOT APPLE) + find_package(X11 REQUIRED) + message(STATUS "X11_FOUND = ${X11_FOUND}") + message(STATUS "X11_INCLUDE_DIR = ${X11_INCLUDE_DIR}") + message(STATUS "X11_LIBRARIES = ${X11_LIBRARIES}") + include_directories(${X11_INCLUDE_DIR}) + link_directories(${X11_LIBRARIES}) + if(STATIC) + find_library(XCB_LIBRARY xcb) + message(STATUS "Found xcb library: ${XCB_LIBRARY}") + endif() +endif() + +# Tor/torsocks +set(TOR_TAG "tor-0.4.3.5") +set(TOR_DIR "${CMAKE_SOURCE_DIR}/contrib/tor") +if(UNIX AND NOT APPLE) + set(TOR_LIB "libtorsocks.so") +elseif(APPLE) + set(TOR_LIB "libtorsocks.dylib") +endif() +if("$ENV{DRONE}" STREQUAL "true" AND STATIC AND BUILD_TOR) + message(STATUS "We are inside a static compile with Drone CI") + if(MINGW) + execute_process(COMMAND bash -c "cp /mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe ${CMAKE_SOURCE_DIR}/src/tor/tor.exe") + elseif(UNIX AND NOT APPLE) + execute_process(COMMAND bash -c "cp /usr/local/tor/bin/tor ${CMAKE_SOURCE_DIR}/src/tor/tor") + execute_process(COMMAND bash -c "cp /usr/local/torsocks/lib/torsocks/* ${CMAKE_SOURCE_DIR}/src/tor/") + endif() +else() + if(BUILD_TOR) + if(UNIX OR APPLE) + execute_process(COMMAND bash -c "ls -al src/tor/${TOR_LIB} 2>/dev/null" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE TOR_FOUND OUTPUT_STRIP_TRAILING_WHITESPACE) + if(TOR_FOUND) + message(STATUS "${TOR_LIB} found, skipping Tor build") + else() + message(STATUS "${TOR_LIB} not found, building Tor") + execute_process(COMMAND bash -c "bash build_tor.sh ${TOR_TAG} ${CMAKE_SOURCE_DIR} 'ON'" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/contrib) + endif() + endif() + else() + message(STATUS "Skipping Tor build because -DBUILD_TOR=OFF") + endif() +endif() + +if(MINGW) + string(REGEX MATCH "^[^/]:/[^/]*" msys2_install_path "${CMAKE_C_COMPILER}") + message(STATUS "MSYS location: ${msys2_install_path}") + set(CMAKE_INCLUDE_PATH "${msys2_install_path}/mingw${ARCH_WIDTH}/include") + # This is necessary because otherwise CMake will make Boost libraries -lfoo + # rather than a full path. Unfortunately, this makes the shared libraries get + # linked due to a bug in CMake which misses putting -static flags around the + # -lfoo arguments. + set(DEFLIB ${msys2_install_path}/mingw${ARCH_WIDTH}/lib) + list(REMOVE_ITEM CMAKE_C_IMPLICIT_LINK_DIRECTORIES ${DEFLIB}) + list(REMOVE_ITEM CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES ${DEFLIB}) +endif() + +message(STATUS "Using Boost include dir at ${Boost_INCLUDE_DIRS}") +message(STATUS "Using Boost libraries at ${Boost_LIBRARIES}") + +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) +if(MINGW) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj") + set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32;bcrypt) + if(DEPENDS) + set(ICU_LIBRARIES icuio icui18n icuuc icudata icutu iconv) + else() + set(ICU_LIBRARIES icuio icuin icuuc icudt icutu iconv) + endif() +elseif(APPLE) + set(EXTRA_LIBRARIES "-framework AppKit") +elseif(OPENBSD) + set(EXTRA_LIBRARIES "") +elseif(FREEBSD) + set(EXTRA_LIBRARIES execinfo) +elseif(DRAGONFLY) + find_library(COMPAT compat) + set(EXTRA_LIBRARIES execinfo ${COMPAT}) +elseif(CMAKE_SYSTEM_NAME MATCHES "(SunOS|Solaris)") + set(EXTRA_LIBRARIES socket nsl resolv) +elseif(NOT MSVC AND NOT DEPENDS) + find_library(RT rt) + set(EXTRA_LIBRARIES ${RT}) +endif() + +list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS}) + +if(APPLE) + include_directories(SYSTEM /usr/include/malloc) + if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) + endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default -std=c++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -DGTEST_HAS_TR1_TUPLE=0") +endif() + +if (APPLE AND NOT IOS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default -std=c++11") +endif() + +if(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -DGTEST_HAS_TR1_TUPLE=0") +endif() + +# warnings +# @TODO: enable these 2 for migration to Qt 6 +#add_c_flag_if_supported(-Werror C_SECURITY_FLAGS) +#add_cxx_flag_if_supported(-Werror CXX_SECURITY_FLAGS) +add_c_flag_if_supported(-Wformat C_SECURITY_FLAGS) +add_cxx_flag_if_supported(-Wformat CXX_SECURITY_FLAGS) +add_c_flag_if_supported(-Wformat-security C_SECURITY_FLAGS) +add_cxx_flag_if_supported(-Wformat-security CXX_SECURITY_FLAGS) + +# -fstack-protector +if (NOT OPENBSD AND NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1))) + add_c_flag_if_supported(-fstack-protector C_SECURITY_FLAGS) + add_cxx_flag_if_supported(-fstack-protector CXX_SECURITY_FLAGS) + add_c_flag_if_supported(-fstack-protector-strong C_SECURITY_FLAGS) + add_cxx_flag_if_supported(-fstack-protector-strong CXX_SECURITY_FLAGS) +endif() + +# New in GCC 8.2 +if (NOT OPENBSD AND NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1))) + add_c_flag_if_supported(-fcf-protection=full C_SECURITY_FLAGS) + add_cxx_flag_if_supported(-fcf-protection=full CXX_SECURITY_FLAGS) +endif() +if (NOT WIN32 AND NOT OPENBSD) + add_c_flag_if_supported(-fstack-clash-protection C_SECURITY_FLAGS) + add_cxx_flag_if_supported(-fstack-clash-protection CXX_SECURITY_FLAGS) +endif() + +# Removed in GCC 9.1 (or before ?), but still accepted, so spams the output +if (NOT (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1)) + add_c_flag_if_supported(-mmitigate-rop C_SECURITY_FLAGS) + add_cxx_flag_if_supported(-mmitigate-rop CXX_SECURITY_FLAGS) +endif() + +# linker +if (APPLE) + add_linker_flag_if_supported(-Wl,-bind_at_load LD_SECURITY_FLAGS) + add_linker_flag_if_supported(-Wl,-dead_strip LD_SECURITY_FLAGS) + add_linker_flag_if_supported(-Wl,-dead_strip_dylibs LD_SECURITY_FLAGS) +endif() +if (NOT APPLE AND NOT (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "GNU")) + # Windows binaries die on startup with PIE when compiled with GCC + add_linker_flag_if_supported(-pie LD_SECURITY_FLAGS) +endif() +add_linker_flag_if_supported(-Wl,-z,relro LD_SECURITY_FLAGS) +add_linker_flag_if_supported(-Wl,-z,now LD_SECURITY_FLAGS) +add_linker_flag_if_supported(-Wl,-z,noexecstack noexecstack_SUPPORTED) +if (noexecstack_SUPPORTED) + set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecstack") +endif() +add_linker_flag_if_supported(-Wl,-z,noexecheap noexecheap_SUPPORTED) +if (noexecheap_SUPPORTED) + set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecheap") +endif() + +# some windows linker bits +if (WIN32) + add_linker_flag_if_supported(-Wl,--dynamicbase LD_SECURITY_FLAGS) + add_linker_flag_if_supported(-Wl,--nxcompat LD_SECURITY_FLAGS) + add_linker_flag_if_supported(-Wl,--high-entropy-va LD_SECURITY_FLAGS) +endif() + +if(STATIC) + add_linker_flag_if_supported(-static-libgcc STATIC_FLAGS) + add_linker_flag_if_supported(-static-libstdc++ STATIC_FLAGS) + if(MINGW) + add_linker_flag_if_supported(-static STATIC_FLAGS) + endif() +endif() + +# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that +# is fixed in the code (Issue #847), force compiler to be conservative. +add_c_flag_if_supported(-fno-strict-aliasing C_SECURITY_FLAGS) +add_cxx_flag_if_supported(-fno-strict-aliasing CXX_SECURITY_FLAGS) + +add_c_flag_if_supported(-fPIC C_SECURITY_FLAGS) +add_cxx_flag_if_supported(-fPIC CXX_SECURITY_FLAGS) + +message(STATUS "Using C security hardening flags: ${C_SECURITY_FLAGS}") +message(STATUS "Using C++ security hardening flags: ${CXX_SECURITY_FLAGS}") +message(STATUS "Using linker security hardening flags: ${LD_SECURITY_FLAGS}") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 ${C_SECURITY_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${CXX_SECURITY_FLAGS}") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS} ${STATIC_FLAGS}") + +add_subdirectory(src) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7e3728f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,307 @@ +FROM ubuntu:18.04 + +ARG THREADS=1 + +RUN apt clean && apt update +RUN apt install -y gnupg + +COPY utils/pubkeys/kitware.asc /kitware.asc +RUN cat /kitware.asc | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null +RUN apt install -y automake git pkg-config python wget python3.6-distutils software-properties-common +RUN apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' && apt update + +ARG DEBIAN_FRONTEND=noninteractive +ENV TZ=Europe/Amsterdam +RUN apt install -y build-essential nano vim aptitude ccache libusb-1.0-0-dev tzdata + +RUN apt install -y xutils-dev && \ + git clone -b xorgproto-2020.1 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xorgproto && \ + cd xorgproto && \ + git reset --hard c62e8203402cafafa5ba0357b6d1c019156c9f36 && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b xcb-proto-1.13 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xcbproto && \ + cd xcbproto && \ + git reset --hard 94228cde97d9aecfda04a8e699d462ba2b89e3a0 && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN apt install -y libtool-bin && \ + git clone -b libXau-1.0.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxau && \ + cd libxau && \ + git reset --hard d9443b2c57b512cfb250b35707378654d86c7dea && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN apt install -y libpthread-stubs0-dev && \ + git clone -b 1.13.1 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb && \ + cd libxcb && \ + git reset --hard 8287ebd7b752c33b0cabc4982606fe4831106f7e && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b 0.4.0 --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-util.git && \ + cd libxcb-util && \ + git reset --hard acf790d7752f36e450d476ad79807d4012ec863b && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b xtrans-1.3.5 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxtrans.git && \ + cd libxtrans && \ + git reset --hard 7cbad9fe2e61cd9d5caeaf361826a6f4bd320f03 && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b 0.4.0 --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-image.git && \ + cd libxcb-image && \ + git reset --hard d882052fb2ce439c6483fce944ba8f16f7294639 && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b 0.4.0 --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-keysyms.git && \ + cd libxcb-keysyms && \ + git reset --hard 0e51ee5570a6a80bdf98770b975dfe8a57f4eeb1 && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b 0.3.9 --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-render-util.git && \ + cd libxcb-render-util && \ + git reset --hard 0317caf63de532fd7a0493ed6afa871a67253747 && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b 0.4.1 --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-wm.git && \ + cd libxcb-wm && \ + git reset --hard 24eb17df2e1245885e72c9d4bbb0a0f69f0700f2 && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b libX11-1.6.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libx11 && \ + cd libx11 && \ + git reset --hard db7cca17ad7807e92a928da9d4c68a00f4836da2 && \ + ACLOCAL='aclocal -I /usr/local/share/aclocal/' CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b libXext-1.3.4 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxext && \ + cd libxext && \ + git reset --hard ebb167f34a3514783966775fb12573c4ed209625 && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN apt install -y libpthread-stubs0-dev && \ + git clone -b libXinerama-1.1.4 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxinerama.git && \ + cd libxinerama && \ + git reset --hard c3ab2361f13154921df2992f9eacc1ea1b3f946b && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b v1.2.11 --depth 1 https://github.com/madler/zlib && \ + cd zlib && \ + git reset --hard cacf7f1d4e3d44d871b605da3b647f07d718623f && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --static && \ + make -j$THREADS && \ + make -j$THREADS install && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --static --prefix=/usr/local/zlib && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b VER-2-10-2 --depth 1 https://git.sv.nongnu.org/r/freetype/freetype2.git && \ + cd freetype2 && \ + git reset --hard 132f19b779828b194b3fede187cee719785db4d8 && \ + ./autogen.sh && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --with-zlib=no && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b R_2_2_9 --depth 1 https://github.com/libexpat/libexpat && \ + cd libexpat/expat && \ + git reset --hard a7bc26b69768f7fb24f0c7976fae24b157b85b13 && \ + ./buildconf.sh && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN apt install -y autopoint gettext gperf libpng-dev && \ + git clone -b 2.13.92 --depth 1 https://gitlab.freedesktop.org/fontconfig/fontconfig && \ + cd fontconfig && \ + git reset --hard b1df1101a643ae16cdfa1d83b939de2497b1bf27 && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static --sysconfdir=/etc --localstatedir=/var && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b release-64-2 --depth 1 https://github.com/unicode-org/icu && \ + cd icu/icu4c/source && \ + git reset --hard e2d85306162d3a0691b070b4f0a73e4012433444 && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-tests --disable-samples && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN apt install -y wget && \ + wget https://dl.bintray.com/boostorg/release/1.73.0/source/boost_1_73_0.tar.gz && \ + echo "9995e192e68528793755692917f9eb6422f3052a53c5e13ba278a228af6c7acf boost_1_73_0.tar.gz" > hashsum.txt && \ + sha256sum -c hashsum.txt && \ + tar -xvzf boost_1_73_0.tar.gz && \ + cd boost_1_73_0 && \ + ./bootstrap.sh && \ + ./b2 --with-atomic --with-system --with-filesystem --with-thread --with-date_time --with-chrono --with-regex --with-serialization --with-program_options --with-locale variant=release link=static runtime-link=static cflags='-fPIC' cxxflags='-fPIC' install -a --prefix=/usr + +RUN wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz && \ + echo "ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46 openssl-1.1.1g.tar.gz" > hashsum.txt && \ + sha256sum -c hashsum.txt && \ + tar -xzf openssl-1.1.1g.tar.gz && \ + cd openssl-1.1.1g && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./config no-asm no-shared no-zlib-dynamic --prefix=/usr/local/openssl && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN wget https://download.qt.io/archive/qt/5.15/5.15.0/single/qt-everywhere-src-5.15.0.tar.xz && \ + echo "22b63d7a7a45183865cc4141124f12b673e7a17b1fe2b91e433f6547c5d548c3 qt-everywhere-src-5.15.0.tar.xz" > hashsum.txt && \ + sha256sum -c hashsum.txt && \ + tar -xf qt-everywhere-src-5.15.0.tar.xz + +COPY contrib/Qt5.15_LinuxPatch.json /qt-everywhere-src-5.15.0/qtbase/src/gui/configure.json +RUN apt install -y libgl1-mesa-dev libglib2.0-dev libxkbcommon-dev libxkbcommon-x11-dev + +RUN cd /qt-everywhere-src-5.15.0 && \ + sed -ri s/\(Libs:.*\)/\\1\ -lexpat/ /usr/local/lib/pkgconfig/fontconfig.pc && \ + sed -ri s/\(Libs:.*\)/\\1\ -lz/ /usr/local/lib/pkgconfig/freetype2.pc && \ + sed -ri s/\(Libs:.*\)/\\1\ -lXau/ /usr/local/lib/pkgconfig/xcb.pc && \ + OPENSSL_LIBS="-lssl -lcrypto -lpthread -ldl" \ + ./configure --prefix=/usr -platform linux-g++-64 -opensource -confirm-license -release -static -no-avx \ + -no-opengl -qpa xcb -openssl-linked -I /usr/local/openssl/include -L /usr/local/openssl/lib -system-freetype -fontconfig -glib \ + -no-dbus -no-sql-sqlite -no-use-gold-linker -no-kms \ + -qt-harfbuzz -qt-libjpeg -qt-libpng -qt-pcre -qt-zlib \ + -skip qt3d -skip qtandroidextras -skip qtcanvas3d -skip qtcharts -skip qtconnectivity -skip qtdatavis3d \ + -skip qtdoc -skip qtquickcontrols -skip qtquickcontrols2 -skip qtspeech -skip qtgamepad \ + -skip qtlocation -skip qtmacextras -skip qtnetworkauth -skip qtpurchasing -optimize-size \ + -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qttools \ + -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebview \ + -skip qtwinextras -skip qtx11extras -skip gamepad -skip serialbus -skip location -skip webengine \ + -skip qtdeclarative -skip qtmultimedia \ + -no-feature-cups -no-feature-ftp -no-feature-pdf -no-feature-animation \ + -nomake examples -nomake tests -nomake tools + +RUN cd /qt-everywhere-src-5.15.0 && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN cd qt-everywhere-src-5.15.0/qttools/src/linguist/lrelease && \ + qmake && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN apt install -y libudev-dev && \ + git clone -b v1.0.23 --depth 1 https://github.com/libusb/libusb && \ + cd libusb && \ + git reset --hard e782eeb2514266f6738e242cdcb18e3ae1ed06fa && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b hidapi-0.9.0 --depth 1 https://github.com/libusb/hidapi && \ + cd hidapi && \ + git reset --hard 7da5cc91fc0d2dbe4df4f08cd31f6ca1a262418f && \ + ./bootstrap && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN apt install -y libsodium-dev && \ + git clone -b v4.3.2 --depth 1 https://github.com/zeromq/libzmq && \ + cd libzmq && \ + git reset --hard a84ffa12b2eb3569ced199660bac5ad128bff1f0 && \ + ./autogen.sh && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-libunwind --with-libsodium && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b libgpg-error-1.38 --depth 1 git://git.gnupg.org/libgpg-error.git && \ + cd libgpg-error && \ + git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 && \ + ./autogen.sh && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-doc --disable-tests && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b libgcrypt-1.8.5 --depth 1 git://git.gnupg.org/libgcrypt.git && \ + cd libgcrypt && \ + git reset --hard 56606331bc2a80536db9fc11ad53695126007298 && \ + ./autogen.sh && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-doc && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b v3.10.0 --depth 1 https://github.com/protocolbuffers/protobuf && \ + cd protobuf && \ + git reset --hard 6d4e7fd7966c989e38024a8ea693db83758944f1 && \ + ./autogen.sh && \ + CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --enable-static --disable-shared && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN apt install -y zip cmake && git clone -b v4.0.2 --depth 1 https://github.com/fukuchi/libqrencode.git && \ + cd libqrencode && \ + git reset --hard 59ee597f913fcfda7a010a6e106fbee2595f68e4 && \ + cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=/usr . && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN apt install -y libmbedtls-dev && git clone -b release-2.1.12-stable --depth 1 https://github.com/libevent/libevent.git && \ + cd libevent && \ + mkdir build && cd build && \ + cmake -DEVENT_LIBRARY_STATIC=ON -DOPENSSL_ROOT_DIR=/usr/local/openssl -DCMAKE_INSTALL_PREFIX=/usr/local/libevent .. && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone -b tor-0.4.3.5 --depth 1 https://git.torproject.org/tor.git && \ + cd tor && \ + bash autogen.sh && \ + LDFLAGS="-L/usr/local/openssl/lib/" LIBS="-lssl -lcrypto -lpthread -ldl" CPPFLAGS="-I/usr/local/openssl/include/" ./configure \ + --enable-static-zlib \ + --enable-static-openssl \ + --enable-static-libevent \ + --disable-system-torrc \ + --with-libevent-dir=/usr/local/libevent \ + --with-openssl-dir=/usr/local/openssl/ \ + --with-zlib-dir=/usr/local/zlib \ + --disable-system-torrc \ + --disable-tool-name-check \ + --disable-systemd \ + --disable-lzma \ + --disable-unittests \ + --disable-zstd \ + --disable-seccomp \ + --disable-asciidoc \ + --disable-manpage \ + --disable-html-manual \ + --disable-system-torrc \ + --prefix=/usr/local/tor && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone https://git.torproject.org/torsocks.git && \ + cd torsocks && \ + bash autogen.sh && \ + ./configure --prefix=/usr/local/torsocks && \ + make -j$THREADS && \ + make -j$THREADS install + +RUN git clone https://git.wownero.com/feather/monero-seed.git && \ + cd monero-seed && \ + cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && \ + make -Cbuild -j$THREADS && \ + make -Cbuild install diff --git a/Dockerfile_appimage b/Dockerfile_appimage new file mode 100644 index 0000000..da34c82 --- /dev/null +++ b/Dockerfile_appimage @@ -0,0 +1,18 @@ +FROM ubuntu:20.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt clean && apt update +RUN apt install -y golang git build-essential wget curl ngrep unzip file squashfs-tools desktop-file-utils patchelf libxkbcommon-x11-dev + +RUN go get github.com/probonopd/go-appimage/src/appimagetool +RUN go build -trimpath -ldflags="-s -w" github.com/probonopd/go-appimage/src/appimagetool +RUN chmod +x appimagetool + +RUN cd /usr/bin && \ + wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh -O uploadtool && \ + chmod +x uploadtool + +RUN cd / && \ + wget -c https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-x86_64 && \ + chmod +x runtime-x86_64 \ No newline at end of file diff --git a/Dockerfile_macos b/Dockerfile_macos new file mode 100644 index 0000000..f94f367 --- /dev/null +++ b/Dockerfile_macos @@ -0,0 +1,13 @@ +# this image is used internally for the buildbot +FROM ubuntu:20.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt clean && apt update +RUN apt install -y git build-essential wget curl ngrep unzip file ssh zip + +RUN cat /dev/zero | ssh-keygen -q -N "" + +RUN cat ~/.ssh/id_rsa.pub + +RUN printf "Host *\n StrictHostKeyChecking no" > ~/.ssh/config \ No newline at end of file diff --git a/Dockerfile_windows b/Dockerfile_windows new file mode 100644 index 0000000..759d88c --- /dev/null +++ b/Dockerfile_windows @@ -0,0 +1,74 @@ +FROM ubuntu:18.04 + +ARG THREADS=1 + +RUN apt clean && apt update +ARG DEBIAN_FRONTEND=noninteractive +ENV TZ=Europe/Amsterdam + +RUN apt install -y \ + autoconf \ + automake \ + autopoint \ + aptitude \ + bash \ + build-essential \ + bison \ + bzip2 \ + ccache \ + flex \ + g++ \ + g++-multilib \ + gettext \ + git \ + gperf \ + intltool \ + libc6-dev-i386 \ + libgdk-pixbuf2.0-dev \ + libltdl-dev \ + libssl-dev \ + libtool-bin \ + libxml-parser-perl \ + lzip \ + nano \ + make \ + openssl \ + p7zip-full \ + patch \ + perl \ + python \ + python-mako \ + ruby \ + sed \ + scons \ + software-properties-common \ + unzip \ + tzdata \ + vim \ + wget \ + xz-utils + +RUN git clone -b feather-patch --depth 1 https://git.wownero.com/feather/mxe.git && \ + cd mxe && \ + make -j$THREADS MXE_TARGETS='x86_64-w64-mingw32.static' gcc libqrencode pkgconf libgpg_error libgcrypt cmake libsodium lzma readline libzmq boost qtbase qtsvg qtwebsockets qtimageformats + +# plugins +RUN cd mxe && make -j$THREADS MXE_PLUGIN_DIRS='/mxe/plugins/apps/' MXE_TARGETS='x86_64-w64-mingw32.static' tor + +# fix env. +RUN echo "export PATH=\"/mxe/usr/bin/:\$PATH\"" >> "/root/.bashrc" +RUN ln -s /mxe/usr/bin/x86_64-w64-mingw32.static-cmake /usr/local/bin/cmake +RUN ln -s /mxe/usr/bin/x86_64-w64-mingw32.static-windres /usr/local/bin/windres +RUN ln -s /mxe/usr/x86_64-w64-mingw32.static/lib/libsicudt.a /mxe/usr/x86_64-w64-mingw32.static/lib/libicudt.a +RUN ln -s /mxe/usr/x86_64-w64-mingw32.static/lib/libsicuio.a /mxe/usr/x86_64-w64-mingw32.static/lib/libicuio.a +RUN ln -s /mxe/usr/x86_64-w64-mingw32.static/lib/libsicutu.a /mxe/usr/x86_64-w64-mingw32.static/lib/libicutu.a +RUN ln -s /mxe/usr/x86_64-w64-mingw32.static/lib/libsicuuc.a /mxe/usr/x86_64-w64-mingw32.static/lib/libicuuc.a +RUN ln -s /mxe/usr/x86_64-w64-mingw32.static/lib/libsicuin.a /mxe/usr/x86_64-w64-mingw32.static/lib/libicuin.a + +ENV PATH="/mxe/usr/bin/:$PATH" + +RUN git clone https://git.wownero.com/feather/monero-seed.git && \ + cd monero-seed && \ + cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && \ + make -Cbuild -j$THREADS && \ + make -Cbuild install diff --git a/HACKING.md b/HACKING.md new file mode 100644 index 0000000..f644a4c --- /dev/null +++ b/HACKING.md @@ -0,0 +1,104 @@ +# Documentation for developers + +Feather is developed primarily on Linux. It uses Qt 5.15.* and chances are that your +distro's package manager has a lower version. It is therefore recommended that you install +Qt manually using the online installer, which can be found here: https://www.qt.io/download +(under open-source). + +## Jetbrains Clion + +Feather was developed using JetBrains Clion since it integrates nicely +with CMake and comes with a built-in debugger. To pass CMake flags to CLion, +go to `File->Settings->Build->CMake`, set Build Type to `Debug` and set your +preferred CMake options/definitions. + +## Requirements + +### Ubuntu/Debian + +```bash +apt install -y git cmake libqrencode-dev build-essential cmake libboost-all-dev \ +miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev \ +libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev \ +libprotobuf-dev protobuf-compiler libgcrypt20-dev +``` + +## Mac OS + +```bash +brew install boost zmq openssl libpgm miniupnpc libsodium expat libunwind-headers \ +protobuf libgcrypt qrencode ccache cmake pkgconfig git +``` + +## CMake + +After installing Qt you might have a folder called `/home/$user/Qt/`. You need to pass this to CMake +via the `CMAKE_PREFIX_PATH` definition. For me this is: + +``` +-DCMAKE_PREFIX_PATH=/home/dsc/QtNew/5.15.0/gcc_64 +``` + +There are some Monero/Feather related options/definitions that you may pass: + +- `-DXMRTO=OFF` - disable Xmr.To feature +- `-DBUILD_TOR=OFF` - disable embedded Tor +- `-DDONATE_BEG=OFF` - disable the dreaded donate requests + +And: + +``` +-DMANUAL_SUBMODULES=1 +-DUSE_DEVICE_TREZOR=OFF +-DUSE_SINGLE_BUILDDIR=ON +-DDEV_MODE=ON +``` + +If you have OpenSSL installed in a custom location, try: + +``` +-DOPENSSL_INCLUDE_DIR=/usr/local/lib/openssl-1.1.1g/include +-DOPENSSL_SSL_LIBRARY=/usr/local/lib/openssl-1.1.1g/libssl.so.1.1 +-DOPENSSL_CRYPTO_LIBRARY=/usr/local/lib/openssl-1.1.1g/libcrypto.so.1.1 +``` + +I prefer also enabling verbose makefiles, which may be useful in some situations. + +``` +-DCMAKE_VERBOSE_MAKEFILE=ON +``` + +Enable debugging symbols: + +```bash +-DCMAKE_BUILD_TYPE=Debug +``` + +## Feather + +It's best to install Tor locally as a service and start Feather with `--use-local-tor`, this +prevents the child process from starting up and saves time. + +#### Ubuntu/Debian + +```bash +apt install -y tor +sudo service tor start +``` + +#### Mac OS + +```bash +brew install tor +brew services start tor +``` + +To skip the wizards and open a wallet directly use `--wallet-file`: + +```bash +./feather --use-local-tor --wallet-file /home/user/Monero/wallets/bla.keys +``` + +It is recommended that you use `--stagenet` for development. Testnet is also possible, +but you'll have to provide Feather a testnet node of your own. + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b99f64a --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2020, The Monero Project + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..88d2800 --- /dev/null +++ b/Makefile @@ -0,0 +1,70 @@ +# Copyright (c) 2014-2021, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + +CMAKEFLAGS = \ + -DARCH=x86_64 \ + -DBUILD_64=On \ + -DBUILD_TESTS=Off \ + -DXMRTO=ON \ + -DCMAKE_CXX_STANDARD=11 \ + -DCMAKE_VERBOSE_MAKEFILE=On \ + -DINSTALL_VENDORED_LIBUNBOUND=Off \ + -DMANUAL_SUBMODULES=1 \ + -DSTATIC=On \ + -DUSE_DEVICE_TREZOR=Off \ + $(CMAKEFLAGS_EXTRA) + +release-static: CMAKEFLAGS += -DBUILD_TAG="linux-x64" +release-static: CMAKEFLAGS += -DBUILD_TOR=On +release-static: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release +release-static: + cmake -Bbuild $(CMAKEFLAGS) + $(MAKE) -Cbuild + +windows-mxe-release: CMAKEFLAGS += -DBUILD_TAG="win-x64" +windows-mxe-release: CMAKEFLAGS += -DBUILD_TOR=On +windows-mxe-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release +windows-mxe-release: + cmake -Bbuild $(CMAKEFLAGS) + $(MAKE) -Cbuild + +windows-mxe-debug: CMAKEFLAGS += -DBUILD_TAG="win-x64" +windows-mxe-debug: CMAKEFLAGS += -DBUILD_TOR=Off +windows-mxe-debug: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Debug +windows-mxe-debug: + cmake -Bbuild $(CMAKEFLAGS) + $(MAKE) -Cbuild + +mac-release: CMAKEFLAGS += -DSTATIC=Off +mac-release: CMAKEFLAGS += -DBUILD_TAG="mac-x64" +mac-release: CMAKEFLAGS += -DBUILD_TOR=Off +mac-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release +mac-release: + cmake -Bbuild $(CMAKEFLAGS) + $(MAKE) -Cbuild + $(MAKE) -Cbuild deploy \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3618247 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# Feather - a free Monero desktop wallet + +[![Build Status](https://build.featherwallet.org/api/badges/feather/feather/status.svg)](https://build.featherwallet.org/feather/feather) + +Feather is a free, open-source Monero client for Mac OS and Linux platforms written in C++ with the Qt framework. It is created and maintained by [dsc](dsc@xmr.pm) and [tobtoht](thotbot@protonmail.com). + +## Development resources +* Web: [featherwallet.org](https://featherwallet.org) +* Git: [git.wownero.com/feather/feather](https://git.wownero.com/feather/feather) +* IRC: `#feather` on OFTC +* Development builds: [build.featherwallet.org/files](https://build.featherwallet.org/files/) + +Copyright (c) 2020-2021 The Monero Project. + +## Compiling Feather from source + +Feather uses Monero, as such it requires the same dependencies as outlined in [Monero's README](https://github.com/monero-project/monero#compiling-monero-from-source). Additionally, Feather uses: + +- Qt 5.15.0 +- libqrencode +- openpgp + +See [BUILDING.md](https://git.wownero.com/feather/feather/src/branch/master/BUILDING.md) for information on how to compile a build. + +## Supporting the project + +Feather is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially. + +`47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f` + +## Developers + +See [HACKING.md](https://git.wownero.com/feather/feather/src/branch/master/HACKING.md) for useful development resources. + +It is HIGHLY recommended that you join the `#feather` IRC channel on OFTC if you are hacking on Feather. Due to the nature of this open source software project, joining this channel and idling is the best way to stay updated on best practices and new developments. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..250d74d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,16 @@ +# Security Policy + +## Reporting a Vulnerability + +Please do not open an issue to report security issues. + +To report a vulnerability send an email to dev@featherwallet.org + +The following keys may be used to communicate sensitive information to developers: + +| Name | Fingerprint | +|------|-------------| +| dsc | 1BFD 40F9 B0E2 B40D C8C7 FD4A 521F 1E79 91AA 42DC | +| tobtoht | C5AB E5C0 E50F A2B3 F14A B92D 1CAD D27F 41F4 5C3C | + +Public keys can be found in `utils/pubkeys`. diff --git a/cmake/32-bit-toolchain.cmake b/cmake/32-bit-toolchain.cmake new file mode 100644 index 0000000..2d53adf --- /dev/null +++ b/cmake/32-bit-toolchain.cmake @@ -0,0 +1,50 @@ +# Copyright (c) 2014-2019, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (NOT CMAKE_HOST_WIN32) + set (CMAKE_SYSTEM_NAME Windows) +endif() + +set (GCC_PREFIX i686-w64-mingw32) +set (CMAKE_C_COMPILER ${GCC_PREFIX}-gcc) +set (CMAKE_CXX_COMPILER ${GCC_PREFIX}-g++) +set (CMAKE_AR ar CACHE FILEPATH "" FORCE) +set (CMAKE_NM nm CACHE FILEPATH "" FORCE) +set (CMAKE_LINKER ld CACHE FILEPATH "" FORCE) +#set (CMAKE_RANLIB ${GCC_PREFIX}-gcc-ranlib CACHE FILEPATH "" FORCE) +set (CMAKE_RC_COMPILER windres) + +set (CMAKE_FIND_ROOT_PATH "${MSYS2_FOLDER}/mingw32") + +# Ensure cmake doesn't find things in the wrong places +set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # Find programs on host +set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # Find libs in target +set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # Find includes in target + +set (MINGW_FLAG "-m32") +set (USE_LTO_DEFAULT false) diff --git a/cmake/64-bit-toolchain.cmake b/cmake/64-bit-toolchain.cmake new file mode 100644 index 0000000..7c56eef --- /dev/null +++ b/cmake/64-bit-toolchain.cmake @@ -0,0 +1,50 @@ +# Copyright (c) 2014-2019, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (NOT CMAKE_HOST_WIN32) + set (CMAKE_SYSTEM_NAME Windows) +endif() + +set (GCC_PREFIX x86_64-w64-mingw32) +set (CMAKE_C_COMPILER ${GCC_PREFIX}-gcc) +set (CMAKE_CXX_COMPILER ${GCC_PREFIX}-g++) +set (CMAKE_AR ar CACHE FILEPATH "" FORCE) +set (CMAKE_NM nm CACHE FILEPATH "" FORCE) +set (CMAKE_LINKER ld CACHE FILEPATH "" FORCE) +#set (CMAKE_RANLIB ${GCC_PREFIX}-gcc-ranlib CACHE FILEPATH "" FORCE) +set (CMAKE_RC_COMPILER windres) + +set (CMAKE_FIND_ROOT_PATH "${MSYS2_FOLDER}/mingw64") + +# Ensure cmake doesn't find things in the wrong places +set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # Find programs on host +set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # Find libs in target +set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # Find includes in target + +set (MINGW_FLAG "-m64") +set (USE_LTO_DEFAULT false) diff --git a/cmake/CheckLinkerFlag.c b/cmake/CheckLinkerFlag.c new file mode 100644 index 0000000..a0dcc16 --- /dev/null +++ b/cmake/CheckLinkerFlag.c @@ -0,0 +1,14 @@ +#ifdef __CLASSIC_C__ +int main() +{ + int ac; + char* av[]; +#else +int main(int ac, char* av[]) +{ +#endif + if (ac > 1000) { + return *av[0]; + } + return 0; +} diff --git a/cmake/CheckLinkerFlag.cmake b/cmake/CheckLinkerFlag.cmake new file mode 100644 index 0000000..2b507ab --- /dev/null +++ b/cmake/CheckLinkerFlag.cmake @@ -0,0 +1,47 @@ +include(CheckCCompilerFlag) + +macro(CHECK_LINKER_FLAG flag VARIABLE) + if(NOT DEFINED "${VARIABLE}") + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${flag} linker flag") + endif() + + set(_cle_source ${CMAKE_SOURCE_DIR}/cmake/CheckLinkerFlag.c) + + set(saved_CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) + set(CMAKE_C_FLAGS "${flag}") + try_compile(${VARIABLE} + ${CMAKE_BINARY_DIR} + ${_cle_source} + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} ${flag} + CMAKE_FLAGS + OUTPUT_VARIABLE OUTPUT) + unset(_cle_source) + set(CMAKE_C_FLAGS ${saved_CMAKE_C_FLAGS}) + unset(saved_CMAKE_C_FLAGS) + + if ("${OUTPUT}" MATCHES "warning.*ignored") + set(${VARIABLE} 0) + endif() + + if(${VARIABLE}) + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${flag} linker flag - found") + endif() + set(${VARIABLE} 1 CACHE INTERNAL "Have linker flag ${flag}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the ${flag} linker flag is supported " + "passed with the following output:\n" + "${OUTPUT}\n\n") + else() + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${flag} linker flag - not found") + endif() + set(${VARIABLE} "" CACHE INTERNAL "Have linker flag ${flag}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the ${flag} linker flag is supported " + "failed with the following output:\n" + "${OUTPUT}\n\n") + endif() + endif() +endmacro() diff --git a/cmake/CheckTrezor.cmake b/cmake/CheckTrezor.cmake new file mode 100644 index 0000000..54f067d --- /dev/null +++ b/cmake/CheckTrezor.cmake @@ -0,0 +1,5 @@ +OPTION(USE_DEVICE_TREZOR "Trezor support compilation" OFF) +OPTION(USE_DEVICE_TREZOR_LIBUSB "Trezor LibUSB compilation" OFF) +OPTION(USE_DEVICE_TREZOR_UDP_RELEASE "Trezor UdpTransport in release mode" OFF) +OPTION(USE_DEVICE_TREZOR_DEBUG "Trezor Debugging enabled" OFF) +OPTION(TREZOR_DEBUG "Main trezor debugging switch" OFF) diff --git a/cmake/Deploy.cmake b/cmake/Deploy.cmake new file mode 100644 index 0000000..1a1e76b --- /dev/null +++ b/cmake/Deploy.cmake @@ -0,0 +1,28 @@ +if(APPLE OR (WIN32 AND NOT STATIC)) + add_custom_target(deploy) + get_target_property(_qmake_executable Qt5::qmake IMPORTED_LOCATION) + get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY) + + if(APPLE AND NOT IOS) + find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}") + add_custom_command(TARGET deploy + POST_BUILD + COMMAND "${MACDEPLOYQT_EXECUTABLE}" "$/../.." -always-overwrite + COMMENT "Running macdeployqt..." + ) + + # workaround for a Qt bug that requires manually adding libqsvg.dylib to bundle + find_file(_qt_svg_dylib "libqsvg.dylib" PATHS "${CMAKE_PREFIX_PATH}/plugins/imageformats" NO_DEFAULT_PATH) + if(_qt_svg_dylib) + add_custom_command(TARGET deploy + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${_qt_svg_dylib} $/../PlugIns/imageformats/ + COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtGui.framework/Versions/5/QtGui" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $/../PlugIns/imageformats/libqsvg.dylib + COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtWidgets.framework/Versions/5/QtWidgets" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $/../PlugIns/imageformats/libqsvg.dylib + COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtSvg.framework/Versions/5/QtSvg" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $/../PlugIns/imageformats/libqsvg.dylib + COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtCore.framework/Versions/5/QtCore" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $/../PlugIns/imageformats/libqsvg.dylib + COMMENT "Copying libqsvg.dylib, running install_name_tool" + ) + endif() + endif() +endif() \ No newline at end of file diff --git a/cmake/Doxyfile.in b/cmake/Doxyfile.in new file mode 100644 index 0000000..35a4911 --- /dev/null +++ b/cmake/Doxyfile.in @@ -0,0 +1,1803 @@ +# Doxyfile 1.8.1.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = Monero + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @VERSION_STRING@ + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = @CPACK_PACKAGE_DESCRIPTION_SUMMARY@ + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = YES + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../README.md \ + ../contrib/ \ + ../external/ \ + ../include/ \ + ../tests/ \ + ../src/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.cpp \ + *.h \ + *.hpp + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = *.pb.* \ + tinythread.* \ + fast_mutex.* \ + anyoption.* \ + stacktrace.* \ + */simpleini/* \ + ExportWrapper.* \ + WinsockWrapper.* \ + otapicli.* \ + test*.* \ + irrXML.* \ + */chaiscript/* \ + */zmq/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = tinythread + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = YES + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = OT_CRYPTO_USING_OPENSSL \ + OT_CASH_USING_LUCRE + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/cmake/Doxygen.extra.css.in b/cmake/Doxygen.extra.css.in new file mode 100644 index 0000000..022974f --- /dev/null +++ b/cmake/Doxygen.extra.css.in @@ -0,0 +1,14 @@ +/* increase vertical space */ +#titlearea, #nav-path { + display: none; + height: 0px; +} + + +/* uncomment these lines for some extra vertical space */ + +/* +.tablist li { + line-height: 26px; +} +*/ diff --git a/cmake/FindBacktrace.cmake b/cmake/FindBacktrace.cmake new file mode 100644 index 0000000..8137125 --- /dev/null +++ b/cmake/FindBacktrace.cmake @@ -0,0 +1,98 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindBacktrace +# ------------- +# +# Find provider for backtrace(3). +# +# Checks if OS supports backtrace(3) via either libc or custom library. +# This module defines the following variables: +# +# ``Backtrace_HEADER`` +# The header file needed for backtrace(3). Cached. +# Could be forcibly set by user. +# ``Backtrace_INCLUDE_DIRS`` +# The include directories needed to use backtrace(3) header. +# ``Backtrace_LIBRARIES`` +# The libraries (linker flags) needed to use backtrace(3), if any. +# ``Backtrace_FOUND`` +# Is set if and only if backtrace(3) support detected. +# +# The following cache variables are also available to set or use: +# +# ``Backtrace_LIBRARY`` +# The external library providing backtrace, if any. +# ``Backtrace_INCLUDE_DIR`` +# The directory holding the backtrace(3) header. +# +# Typical usage is to generate of header file using configure_file() with the +# contents like the following:: +# +# #cmakedefine01 Backtrace_FOUND +# #if Backtrace_FOUND +# # include <${Backtrace_HEADER}> +# #endif +# +# And then reference that generated header file in actual source. + +include(CMakePushCheckState) +include(CheckSymbolExists) +include(FindPackageHandleStandardArgs) + +# List of variables to be provided to find_package_handle_standard_args() +set(_Backtrace_STD_ARGS Backtrace_INCLUDE_DIR) + +if(Backtrace_HEADER) + set(_Backtrace_HEADER_TRY "${Backtrace_HEADER}") +else(Backtrace_HEADER) + set(_Backtrace_HEADER_TRY "execinfo.h") +endif(Backtrace_HEADER) + +find_path(Backtrace_INCLUDE_DIR "${_Backtrace_HEADER_TRY}") +set(Backtrace_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR}) + +if (NOT DEFINED Backtrace_LIBRARY) + # First, check if we already have backtrace(), e.g., in libc + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_INCLUDES ${Backtrace_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_QUIET ${Backtrace_FIND_QUIETLY}) + check_symbol_exists("backtrace" "${_Backtrace_HEADER_TRY}" _Backtrace_SYM_FOUND) + cmake_pop_check_state() +endif() + +if(_Backtrace_SYM_FOUND) + # Avoid repeating the message() call below each time CMake is run. + if(NOT Backtrace_FIND_QUIETLY AND NOT DEFINED Backtrace_LIBRARY) + message(STATUS "backtrace facility detected in default set of libraries") + endif() + set(Backtrace_LIBRARY "" CACHE FILEPATH "Library providing backtrace(3), empty for default set of libraries") +else() + # Check for external library, for non-glibc systems + if(Backtrace_INCLUDE_DIR) + # OpenBSD has libbacktrace renamed to libexecinfo + find_library(Backtrace_LIBRARY "execinfo") + elseif() # respect user wishes + set(_Backtrace_HEADER_TRY "backtrace.h") + find_path(Backtrace_INCLUDE_DIR ${_Backtrace_HEADER_TRY}) + find_library(Backtrace_LIBRARY "backtrace") + endif() + + # Prepend list with library path as it's more common practice + set(_Backtrace_STD_ARGS Backtrace_LIBRARY ${_Backtrace_STD_ARGS}) +endif() + +message(STATUS "Backtrace_LIBRARY: ${Backtrace_LIBRARY}") +if(Backtrace_LIBRARY STREQUAL "NOTFOUND") + set(Backtrace_LIBRARY "") +endif() +if(Backtrace_LIBRARY STREQUAL "Backtrace_LIBRARY-NOTFOUND") + set(Backtrace_LIBRARY "") +endif() + +set(Backtrace_LIBRARIES ${Backtrace_LIBRARY}) +set(Backtrace_HEADER "${_Backtrace_HEADER_TRY}" CACHE STRING "Header providing backtrace(3) facility") + +find_package_handle_standard_args(Backtrace FOUND_VAR Backtrace_FOUND REQUIRED_VARS ${_Backtrace_STD_ARGS}) +mark_as_advanced(Backtrace_HEADER Backtrace_INCLUDE_DIR Backtrace_LIBRARY) diff --git a/cmake/FindBerkeleyDB.cmake b/cmake/FindBerkeleyDB.cmake new file mode 100644 index 0000000..916d8f9 --- /dev/null +++ b/cmake/FindBerkeleyDB.cmake @@ -0,0 +1,25 @@ +# - Try to find Berkeley DB +# Once done this will define +# +# BERKELEY_DB_FOUND - system has Berkeley DB +# BERKELEY_DB_INCLUDE_DIR - the Berkeley DB include directory +# BERKELEY_DB_LIBRARIES - Link these to use Berkeley DB +# BERKELEY_DB_DEFINITIONS - Compiler switches required for using Berkeley DB + +# Copyright (c) 2006, Alexander Dymo, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +find_path(BERKELEY_DB_INCLUDE_DIR db_cxx.h + /usr/include/db4 + /usr/local/include/db4 +) + +find_library(BERKELEY_DB_LIBRARIES NAMES db_cxx ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Berkeley "Could not find Berkeley DB >= 4.1" BERKELEY_DB_INCLUDE_DIR BERKELEY_DB_LIBRARIES) +# show the BERKELEY_DB_INCLUDE_DIR and BERKELEY_DB_LIBRARIES variables only in the advanced view +mark_as_advanced(BERKELEY_DB_INCLUDE_DIR BERKELEY_DB_LIBRARIES ) + diff --git a/cmake/FindCcache.cmake b/cmake/FindCcache.cmake new file mode 100644 index 0000000..29e2d24 --- /dev/null +++ b/cmake/FindCcache.cmake @@ -0,0 +1,56 @@ +# Copyright (c) 2014-2020, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# - Try to find readline include dirs and libraries +# +# Automatically finds ccache build accelerator, if it's found in PATH. +# +# Usage of this module as follows: +# +# project(monero) +# include(FindCcache) # Include AFTER the project() macro to be able to reach the CMAKE_CXX_COMPILER variable +# +# Properties modified by this module: +# +# GLOBAL PROPERTY RULE_LAUNCH_COMPILE set to ccache, when ccache found +# GLOBAL PROPERTY RULE_LAUNCH_LINK set to ccache, when ccache found + +find_program(CCACHE_FOUND ccache) +if (CCACHE_FOUND) + set(TEMP_CPP_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test-program.cpp") + file(WRITE "${TEMP_CPP_FILE}" "int main() { return 0; }") + execute_process(COMMAND "${CCACHE_FOUND}" "${CMAKE_CXX_COMPILER}" "${TEMP_CPP_FILE}" RESULT_VARIABLE RET) + if (${RET} EQUAL 0) + message("found usable ccache: ${CCACHE_FOUND}") + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}") + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_FOUND}") + else() + message("found ccache ${CCACHE_FOUND}, but is UNUSABLE! Return code: ${RET}") + endif() +else() + message("ccache NOT found!") +endif() diff --git a/cmake/FindGCrypt.cmake b/cmake/FindGCrypt.cmake new file mode 100644 index 0000000..7ce9b9c --- /dev/null +++ b/cmake/FindGCrypt.cmake @@ -0,0 +1,70 @@ +# - Try to find GCrypt +# Once done this will define +# +# GCRYPT_FOUND - system has GCrypt +# GCRYPT_INCLUDE_DIRS - the GCrypt include directory +# GCRYPT_LIBRARIES - Link these to use GCrypt +# GCRYPT_DEFINITIONS - Compiler switches required for using GCrypt +# +#============================================================================= +# Copyright (c) 2009-2011 Andreas Schneider +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# + +if (GCRYPT_LIBRARIES AND GCRYPT_INCLUDE_DIRS) + # in cache already + # set(GCRYPT_FOUND TRUE) +else (GCRYPT_LIBRARIES AND GCRYPT_INCLUDE_DIRS) + + set(_GCRYPT_ROOT_PATHS + "$ENV{PROGRAMFILES}/libgcrypt" + ) + + find_path(GCRYPT_ROOT_DIR + NAMES + include/gcrypt.h + PATHS + ${_GCRYPT_ROOT_PATHS} + ) + mark_as_advanced(ZLIB_ROOT_DIR) + + find_path(GCRYPT_INCLUDE_DIR + NAMES + gcrypt.h + PATHS + /usr/local/include + /opt/local/include + /sw/include + /usr/lib/sfw/include + ${GCRYPT_ROOT_DIR}/include + ) + set(GCRYPT_INCLUDE_DIRS ${GCRYPT_INCLUDE_DIR}) + + find_library(GCRYPT_LIBRARY + NAMES + gcrypt + gcrypt11 + libgcrypt-11 + PATHS + /opt/local/lib + /sw/lib + /usr/sfw/lib/64 + /usr/sfw/lib + ${GCRYPT_ROOT_DIR}/lib + ) + set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY}) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(GCrypt DEFAULT_MSG GCRYPT_LIBRARIES GCRYPT_INCLUDE_DIRS) + + # show the GCRYPT_INCLUDE_DIRS and GCRYPT_LIBRARIES variables only in the advanced view + mark_as_advanced(GCRYPT_INCLUDE_DIRS GCRYPT_LIBRARIES) + +endif (GCRYPT_LIBRARIES AND GCRYPT_INCLUDE_DIRS) \ No newline at end of file diff --git a/cmake/FindHIDAPI.cmake b/cmake/FindHIDAPI.cmake new file mode 100644 index 0000000..e69de29 diff --git a/cmake/FindLibunwind.cmake b/cmake/FindLibunwind.cmake new file mode 100644 index 0000000..af657ca --- /dev/null +++ b/cmake/FindLibunwind.cmake @@ -0,0 +1,41 @@ +# - Try to find libunwind +# Once done this will define +# +# LIBUNWIND_FOUND - system has libunwind +# LIBUNWIND_INCLUDE_DIR - the libunwind include directory +# LIBUNWIND_LIBRARIES - Link these to use libunwind +# LIBUNWIND_DEFINITIONS - Compiler switches required for using libunwind + +# Copyright (c) 2006, Alexander Dymo, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +find_path(LIBUNWIND_INCLUDE_DIR libunwind.h + /usr/include + /usr/local/include +) + +find_library(LIBUNWIND_LIBRARIES NAMES unwind ) +if(NOT LIBUNWIND_LIBRARIES STREQUAL "LIBUNWIND_LIBRARIES-NOTFOUND") + if (CMAKE_COMPILER_IS_GNUCC) + set(LIBUNWIND_LIBRARIES "gcc_eh;${LIBUNWIND_LIBRARIES}") + endif() +endif() + +# some versions of libunwind need liblzma, and we don't use pkg-config +# so we just look whether liblzma is installed, and add it if it is. +# It might not be actually needed, but doesn't hurt if it is not. +# We don't need any headers, just the lib, as it's privately needed. +message(STATUS "looking for liblzma") +find_library(LIBLZMA_LIBRARIES lzma ) +if(NOT LIBLZMA_LIBRARIES STREQUAL "LIBLZMA_LIBRARIES-NOTFOUND") + message(STATUS "liblzma found") + set(LIBUNWIND_LIBRARIES "${LIBUNWIND_LIBRARIES};${LIBLZMA_LIBRARIES}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Libunwind "Could not find libunwind" LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES) +# show the LIBUNWIND_INCLUDE_DIR and LIBUNWIND_LIBRARIES variables only in the advanced view +mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES ) + diff --git a/cmake/FindMiniupnpc.cmake b/cmake/FindMiniupnpc.cmake new file mode 100644 index 0000000..ad2004a --- /dev/null +++ b/cmake/FindMiniupnpc.cmake @@ -0,0 +1,59 @@ +# --------------------------------- FindMiniupnpc Start --------------------------------- +# Locate miniupnp library +# This module defines +# MINIUPNP_FOUND, if false, do not try to link to miniupnp +# MINIUPNP_LIBRARY, the miniupnp variant +# MINIUPNP_INCLUDE_DIR, where to find miniupnpc.h and family) +# MINIUPNPC_VERSION_1_7_OR_HIGHER, set if we detect the version of miniupnpc is 1.7 or higher +# +# Note that the expected include convention is +# #include "miniupnpc.h" +# and not +# #include +# This is because, the miniupnpc location is not standardized and may exist +# in locations other than miniupnpc/ + +if (MINIUPNP_INCLUDE_DIR AND MINIUPNP_LIBRARY) + # Already in cache, be silent + set(MINIUPNP_FIND_QUIETLY TRUE) +endif () + +find_path(MINIUPNP_INCLUDE_DIR miniupnpc.h + HINTS $ENV{MINIUPNP_INCLUDE_DIR} + PATH_SUFFIXES miniupnpc +) + +find_library(MINIUPNP_LIBRARY miniupnpc + HINTS $ENV{MINIUPNP_LIBRARY} +) + +find_library(MINIUPNP_STATIC_LIBRARY libminiupnpc.a + HINTS $ENV{MINIUPNP_STATIC_LIBRARY} +) + +set(MINIUPNP_INCLUDE_DIRS ${MINIUPNP_INCLUDE_DIR}) +set(MINIUPNP_LIBRARIES ${MINIUPNP_LIBRARY}) +set(MINIUPNP_STATIC_LIBRARIES ${MINIUPNP_STATIC_LIBRARY}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + MiniUPnPc DEFAULT_MSG + MINIUPNP_INCLUDE_DIR + MINIUPNP_LIBRARY +) + +IF(MINIUPNPC_FOUND) + file(STRINGS "${MINIUPNP_INCLUDE_DIR}/miniupnpc.h" MINIUPNPC_API_VERSION_STR REGEX "^#define[\t ]+MINIUPNPC_API_VERSION[\t ]+[0-9]+") + if(MINIUPNPC_API_VERSION_STR MATCHES "^#define[\t ]+MINIUPNPC_API_VERSION[\t ]+([0-9]+)") + set(MINIUPNPC_API_VERSION "${CMAKE_MATCH_1}") + if (${MINIUPNPC_API_VERSION} GREATER "10" OR ${MINIUPNPC_API_VERSION} EQUAL "10") + message(STATUS "Found miniupnpc API version " ${MINIUPNPC_API_VERSION}) + set(MINIUPNP_FOUND true) + set(MINIUPNPC_VERSION_1_7_OR_HIGHER true) + endif() + endif() + +ENDIF() + +mark_as_advanced(MINIUPNP_INCLUDE_DIR MINIUPNP_LIBRARY MINIUPNP_STATIC_LIBRARY) +# --------------------------------- FindMiniupnpc End --------------------------------- diff --git a/cmake/FindQREncode.cmake b/cmake/FindQREncode.cmake new file mode 100644 index 0000000..2f93c2b --- /dev/null +++ b/cmake/FindQREncode.cmake @@ -0,0 +1,7 @@ +find_path(QRENCODE_INCLUDE_DIR qrencode.h) +find_library(QRENCODE_LIBRARY qrencode) + +mark_as_advanced(QRENCODE_LIBRARY QRENCODE_INCLUDE_DIR) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(QREncode DEFAULT_MSG QRENCODE_LIBRARY QRENCODE_INCLUDE_DIR) diff --git a/cmake/FindReadline.cmake b/cmake/FindReadline.cmake new file mode 100644 index 0000000..f26911b --- /dev/null +++ b/cmake/FindReadline.cmake @@ -0,0 +1,91 @@ +# - Try to find readline include dirs and libraries +# +# Usage of this module as follows: +# +# find_package(Readline) +# +# Variables used by this module, they can change the default behaviour and need +# to be set before calling find_package: +# +# Readline_ROOT_DIR Set this variable to the root installation of +# readline if the module has problems finding the +# proper installation path. +# +# Variables defined by this module: +# +# READLINE_FOUND System has readline, include and lib dirs found +# GNU_READLINE_FOUND Version of readline found is GNU readline, not libedit! +# LIBEDIT_FOUND Version of readline found is libedit, not GNU readline! +# Readline_INCLUDE_DIR The readline include directories. +# Readline_LIBRARY The readline library. +# GNU_READLINE_LIBRARY The GNU readline library or empty string. +# LIBEDIT_LIBRARY The libedit library or empty string. + +find_path(Readline_ROOT_DIR + NAMES include/readline/readline.h + PATHS /usr/local/opt/readline/ /opt/local/ /usr/local/ /usr/ + NO_DEFAULT_PATH +) + +find_path(Readline_INCLUDE_DIR + NAMES readline/readline.h + PATHS ${Readline_ROOT_DIR}/include + NO_DEFAULT_PATH +) + +find_library(Readline_LIBRARY + NAMES readline + PATHS ${Readline_ROOT_DIR}/lib + NO_DEFAULT_PATH +) + +find_library(Termcap_LIBRARY + NAMES tinfo termcap ncursesw ncurses cursesw curses +) + +if(Readline_INCLUDE_DIR AND Readline_LIBRARY) + set(READLINE_FOUND TRUE) +else(Readline_INCLUDE_DIR AND Readline_LIBRARY) + FIND_LIBRARY(Readline_LIBRARY NAMES readline PATHS Readline_ROOT_DIR) + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY ) + MARK_AS_ADVANCED(Readline_INCLUDE_DIR Readline_LIBRARY) +endif(Readline_INCLUDE_DIR AND Readline_LIBRARY) + +mark_as_advanced( + Readline_ROOT_DIR + Readline_INCLUDE_DIR + Readline_LIBRARY +) + +set(CMAKE_REQUIRED_INCLUDES ${Readline_INCLUDE_DIR}) +set(CMAKE_REQUIRED_LIBRARIES ${Readline_LIBRARY}) + +include(CheckFunctionExists) +check_function_exists(rl_copy_text HAVE_COPY_TEXT) +check_function_exists(rl_filename_completion_function HAVE_COMPLETION_FUNCTION) + +if(NOT HAVE_COMPLETION_FUNCTION) + if (Readline_LIBRARY) + set(CMAKE_REQUIRED_LIBRARIES ${Readline_LIBRARY} ${Termcap_LIBRARY}) + endif(Readline_LIBRARY) + check_function_exists(rl_copy_text HAVE_COPY_TEXT_TC) + check_function_exists(rl_filename_completion_function HAVE_COMPLETION_FUNCTION_TC) + set(HAVE_COMPLETION_FUNCTION ${HAVE_COMPLETION_FUNCTION_TC}) + set(HAVE_COPY_TEXT ${HAVE_COPY_TEXT_TC}) + if(HAVE_COMPLETION_FUNCTION) + set(Readline_LIBRARY ${Readline_LIBRARY} ${Termcap_LIBRARY}) + endif(HAVE_COMPLETION_FUNCTION) +endif(NOT HAVE_COMPLETION_FUNCTION) + +set(LIBEDIT_LIBRARY "") +set(GNU_READLINE_LIBRARY "") + +if(HAVE_COMPLETION_FUNCTION AND HAVE_COPY_TEXT) + set(GNU_READLINE_FOUND TRUE) + set(GNU_READLINE_LIBRARY ${Readline_LIBRARY}) +elseif(READLINE_FOUND AND NOT HAVE_COPY_TEXT) + set(LIBEDIT_FOUND TRUE) + set(LIBEDIT_LIBRARY ${Readline_LIBRARY}) +endif(HAVE_COMPLETION_FUNCTION AND HAVE_COPY_TEXT) + diff --git a/cmake/FindSodium.cmake b/cmake/FindSodium.cmake new file mode 100644 index 0000000..3792815 --- /dev/null +++ b/cmake/FindSodium.cmake @@ -0,0 +1,291 @@ +# Written in 2016 by Henrik Steffen Gaßmann +# +# To the extent possible under law, the author(s) have dedicated all copyright +# and related and neighboring rights to this software to the public domain +# worldwide. This software is distributed without any warranty. +# +# You should have received a copy of the CC0 Public Domain Dedication along with +# this software. If not, see +# +# http://creativecommons.org/publicdomain/zero/1.0/ +# +# ############################################################################## +# Tries to find the local libsodium installation. +# +# On Windows the sodium_DIR environment variable is used as a default hint which +# can be overridden by setting the corresponding cmake variable. +# +# Once done the following variables will be defined: +# +# sodium_FOUND sodium_INCLUDE_DIR sodium_LIBRARY_DEBUG sodium_LIBRARY_RELEASE +# sodium_VERSION_STRING +# +# Furthermore an imported "sodium" target is created. +# + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") + set(_GCC_COMPATIBLE 1) +endif() + +# static library option +if(NOT DEFINED sodium_USE_STATIC_LIBS) + option(sodium_USE_STATIC_LIBS "enable to statically link against sodium" OFF) +endif() +if(NOT (sodium_USE_STATIC_LIBS EQUAL sodium_USE_STATIC_LIBS_LAST)) + unset(sodium_LIBRARY CACHE) + unset(sodium_LIBRARY_DEBUG CACHE) + unset(sodium_LIBRARY_RELEASE CACHE) + unset(sodium_DLL_DEBUG CACHE) + unset(sodium_DLL_RELEASE CACHE) + set(sodium_USE_STATIC_LIBS_LAST + ${sodium_USE_STATIC_LIBS} + CACHE INTERNAL "internal change tracking variable") +endif() + +# ############################################################################## +# UNIX +if(UNIX) + # import pkg-config + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(sodium_PKG QUIET libsodium) + endif() + + if(sodium_USE_STATIC_LIBS) + if(sodium_PKG_STATIC_LIBRARIES) + foreach(_libname ${sodium_PKG_STATIC_LIBRARIES}) + if(NOT _libname MATCHES "^lib.*\\.a$") # ignore strings already ending + # with .a + list(INSERT sodium_PKG_STATIC_LIBRARIES 0 "lib${_libname}.a") + endif() + endforeach() + list(REMOVE_DUPLICATES sodium_PKG_STATIC_LIBRARIES) + else() + # if pkgconfig for libsodium doesn't provide static lib info, then + # override PKG_STATIC here.. + set(sodium_PKG_STATIC_LIBRARIES libsodium.a) + endif() + + set(XPREFIX sodium_PKG_STATIC) + else() + if(sodium_PKG_LIBRARIES STREQUAL "") + set(sodium_PKG_LIBRARIES sodium) + endif() + + set(XPREFIX sodium_PKG) + endif() + + find_path(sodium_INCLUDE_DIR sodium.h HINTS ${${XPREFIX}_INCLUDE_DIRS}) + find_library(sodium_LIBRARY_DEBUG + NAMES ${${XPREFIX}_LIBRARIES} + HINTS ${${XPREFIX}_LIBRARY_DIRS}) + find_library(sodium_LIBRARY_RELEASE + NAMES ${${XPREFIX}_LIBRARIES} + HINTS ${${XPREFIX}_LIBRARY_DIRS}) + + # ############################################################################ + # Windows +elseif(WIN32) + set(sodium_DIR "$ENV{sodium_DIR}" CACHE FILEPATH "sodium install directory") + mark_as_advanced(sodium_DIR) + + find_path(sodium_INCLUDE_DIR sodium.h + HINTS ${sodium_DIR} + PATH_SUFFIXES include) + + if(MSVC) + # detect target architecture + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/arch.c" [=[ + #if defined _M_IX86 + #error ARCH_VALUE x86_32 + #elif defined _M_X64 + #error ARCH_VALUE x86_64 + #endif + #error ARCH_VALUE unknown + ]=]) + try_compile(_UNUSED_VAR "${CMAKE_CURRENT_BINARY_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}/arch.c" + OUTPUT_VARIABLE _COMPILATION_LOG) + string(REGEX + REPLACE ".*ARCH_VALUE ([a-zA-Z0-9_]+).*" + "\\1" + _TARGET_ARCH + "${_COMPILATION_LOG}") + + # construct library path + if(_TARGET_ARCH STREQUAL "x86_32") + string(APPEND _PLATFORM_PATH "Win32") + elseif(_TARGET_ARCH STREQUAL "x86_64") + string(APPEND _PLATFORM_PATH "x64") + else() + message( + FATAL_ERROR + "the ${_TARGET_ARCH} architecture is not supported by Findsodium.cmake." + ) + endif() + string(APPEND _PLATFORM_PATH "/$$CONFIG$$") + + if(MSVC_VERSION LESS 1900) + math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 60") + else() + math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 50") + endif() + string(APPEND _PLATFORM_PATH "/v${_VS_VERSION}") + + if(sodium_USE_STATIC_LIBS) + string(APPEND _PLATFORM_PATH "/static") + else() + string(APPEND _PLATFORM_PATH "/dynamic") + endif() + + string(REPLACE "$$CONFIG$$" + "Debug" + _DEBUG_PATH_SUFFIX + "${_PLATFORM_PATH}") + string(REPLACE "$$CONFIG$$" + "Release" + _RELEASE_PATH_SUFFIX + "${_PLATFORM_PATH}") + + find_library(sodium_LIBRARY_DEBUG libsodium.lib + HINTS ${sodium_DIR} + PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX}) + find_library(sodium_LIBRARY_RELEASE libsodium.lib + HINTS ${sodium_DIR} + PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX}) + if(NOT sodium_USE_STATIC_LIBS) + set(CMAKE_FIND_LIBRARY_SUFFIXES_BCK ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll") + find_library(sodium_DLL_DEBUG libsodium + HINTS ${sodium_DIR} + PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX}) + find_library(sodium_DLL_RELEASE libsodium + HINTS ${sodium_DIR} + PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX}) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_BCK}) + endif() + + elseif(_GCC_COMPATIBLE) + if(sodium_USE_STATIC_LIBS) + find_library(sodium_LIBRARY_DEBUG libsodium.a + HINTS ${sodium_DIR} + PATH_SUFFIXES lib) + find_library(sodium_LIBRARY_RELEASE libsodium.a + HINTS ${sodium_DIR} + PATH_SUFFIXES lib) + else() + find_library(sodium_LIBRARY_DEBUG libsodium.dll.a + HINTS ${sodium_DIR} + PATH_SUFFIXES lib) + find_library(sodium_LIBRARY_RELEASE libsodium.dll.a + HINTS ${sodium_DIR} + PATH_SUFFIXES lib) + + file(GLOB _DLL + LIST_DIRECTORIES false + RELATIVE "${sodium_DIR}/bin" + "${sodium_DIR}/bin/libsodium*.dll") + find_library(sodium_DLL_DEBUG ${_DLL} libsodium + HINTS ${sodium_DIR} + PATH_SUFFIXES bin) + find_library(sodium_DLL_RELEASE ${_DLL} libsodium + HINTS ${sodium_DIR} + PATH_SUFFIXES bin) + endif() + else() + message(FATAL_ERROR "this platform is not supported by FindSodium.cmake") + endif() + + # ############################################################################ + # unsupported +else() + message(FATAL_ERROR "this platform is not supported by FindSodium.cmake") +endif() + +# ############################################################################## +# common stuff + +# extract sodium version +if(sodium_INCLUDE_DIR) + set(_VERSION_HEADER "${sodium_INCLUDE_DIR}/sodium/version.h") + if(EXISTS "${_VERSION_HEADER}") + file(READ "${_VERSION_HEADER}" _VERSION_HEADER_CONTENT) + string(REGEX + REPLACE ".*define[ \t]+SODIUM_VERSION_STRING[^\"]+\"([^\"]+)\".*" + "\\1" + sodium_VERSION_STRING + "${_VERSION_HEADER_CONTENT}") + set(sodium_VERSION_STRING "${sodium_VERSION_STRING}") + endif() +endif() + +# communicate results +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(sodium + REQUIRED_VARS + sodium_LIBRARY_RELEASE + sodium_LIBRARY_DEBUG + sodium_INCLUDE_DIR + VERSION_VAR + sodium_VERSION_STRING) + +# mark file paths as advanced +mark_as_advanced(sodium_INCLUDE_DIR) +mark_as_advanced(sodium_LIBRARY_DEBUG) +mark_as_advanced(sodium_LIBRARY_RELEASE) +if(WIN32) + mark_as_advanced(sodium_DLL_DEBUG) + mark_as_advanced(sodium_DLL_RELEASE) +endif() + +# create imported target +if(sodium_USE_STATIC_LIBS) + set(_LIB_TYPE STATIC) +else() + set(_LIB_TYPE SHARED) +endif() +add_library(sodium ${_LIB_TYPE} IMPORTED) + +set_target_properties(sodium + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + "${sodium_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES + "C") + +if(sodium_USE_STATIC_LIBS) + set_target_properties(sodium + PROPERTIES INTERFACE_COMPILE_DEFINITIONS + "SODIUM_STATIC" + IMPORTED_LOCATION + "${sodium_LIBRARY_RELEASE}" + IMPORTED_LOCATION_DEBUG + "${sodium_LIBRARY_DEBUG}") +else() + if(UNIX) + set_target_properties(sodium + PROPERTIES IMPORTED_LOCATION + "${sodium_LIBRARY_RELEASE}" + IMPORTED_LOCATION_DEBUG + "${sodium_LIBRARY_DEBUG}") + elseif(WIN32) + set_target_properties(sodium + PROPERTIES IMPORTED_IMPLIB + "${sodium_LIBRARY_RELEASE}" + IMPORTED_IMPLIB_DEBUG + "${sodium_LIBRARY_DEBUG}") + if(NOT (sodium_DLL_DEBUG MATCHES ".*-NOTFOUND")) + set_target_properties(sodium + PROPERTIES IMPORTED_LOCATION_DEBUG + "${sodium_DLL_DEBUG}") + endif() + if(NOT (sodium_DLL_RELEASE MATCHES ".*-NOTFOUND")) + set_target_properties(sodium + PROPERTIES IMPORTED_LOCATION_RELWITHDEBINFO + "${sodium_DLL_RELEASE}" + IMPORTED_LOCATION_MINSIZEREL + "${sodium_DLL_RELEASE}" + IMPORTED_LOCATION_RELEASE + "${sodium_DLL_RELEASE}") + endif() + endif() +endif() \ No newline at end of file diff --git a/cmake/FindUnbound.cmake b/cmake/FindUnbound.cmake new file mode 100644 index 0000000..e3eb3d6 --- /dev/null +++ b/cmake/FindUnbound.cmake @@ -0,0 +1,40 @@ +# Copyright (c) 2014-2019, The Monero Project +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +MESSAGE(STATUS "Looking for libunbound") + +FIND_PATH(UNBOUND_INCLUDE_DIR + NAMES unbound.h + PATH_SUFFIXES include/ include/unbound/ + PATHS "${PROJECT_SOURCE_DIR}" + ${UNBOUND_ROOT} + $ENV{UNBOUND_ROOT} + /usr/local/ + /usr/ +) + +find_library(UNBOUND_LIBRARIES unbound) diff --git a/cmake/FindZBar0.cmake b/cmake/FindZBar0.cmake new file mode 100644 index 0000000..efb1009 --- /dev/null +++ b/cmake/FindZBar0.cmake @@ -0,0 +1,22 @@ +# from http://code.google.com/p/low-cost-vision-2012/source/browse/CMakeModules/FindZBar0.cmake?name=2-helium-1&r=d61f248bd5565b3c086bf4769a04bfd98f7079df +# - Try to find ZBar +# This will define +# +# ZBAR_FOUND - +# ZBAR_LIBRARY_DIR - +# ZBAR_INCLUDE_DIR - +# ZBAR_LIBRARIES - +# + +find_package(PkgConfig) +pkg_check_modules(PC_ZBAR QUIET zbar) +set(ZBAR_DEFINITIONS ${PC_ZBAR_CFLAGS_OTHER}) +find_library(ZBAR_LIBRARIES NAMES zbar + HINTS ${PC_ZBAR_LIBDIR} ${PC_ZBAR_LIBRARY_DIRS} ) +find_path(ZBAR_INCLUDE_DIR Decoder.h + HINTS ${PC_ZBAR_INCLUDEDIR} ${PC_ZBAR_INCLUDE_DIRS} + PATH_SUFFIXES zbar ) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ZBAR DEFAULT_MSG ZBAR_LIBRARIES ZBAR_INCLUDE_DIR) +message(STATUS "Found zbar libraries ${ZBAR_LIBRARIES}") + diff --git a/cmake/GenVersion.cmake b/cmake/GenVersion.cmake new file mode 100644 index 0000000..220a03a --- /dev/null +++ b/cmake/GenVersion.cmake @@ -0,0 +1,65 @@ +# Copyright (c) 2014-2019, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +# Check what commit we're on +execute_process(COMMAND "${GIT}" rev-parse --short=9 HEAD RESULT_VARIABLE RET OUTPUT_VARIABLE COMMIT OUTPUT_STRIP_TRAILING_WHITESPACE) +if(RET) + # Something went wrong, set the version tag to -unknown + + message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.") + set(VERSIONTAG "unknown") + set(VERSION_IS_RELEASE "false") + configure_file("monero/src/version.cpp.in" "${TO}") +else() + string(SUBSTRING ${COMMIT} 0 9 COMMIT) + message(STATUS "You are currently on commit ${COMMIT}") + + # Get all the tags + execute_process(COMMAND "${GIT}" rev-list --tags --max-count=1 --abbrev-commit RESULT_VARIABLE RET OUTPUT_VARIABLE TAGGEDCOMMIT OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(NOT TAGGEDCOMMIT) + message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") + set(VERSIONTAG "${COMMIT}") + set(VERSION_IS_RELEASE "false") + else() + message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}") + + # Check if we're building that tagged commit or a different one + if(COMMIT STREQUAL TAGGEDCOMMIT) + message(STATUS "You are building a tagged release") + set(VERSIONTAG "release") + set(VERSION_IS_RELEASE "true") + else() + message(STATUS "You are ahead of or behind a tagged release") + set(VERSIONTAG "${COMMIT}") + set(VERSION_IS_RELEASE "false") + endif() + endif() + configure_file("monero/src/version.cpp.in" "${TO}") +endif() \ No newline at end of file diff --git a/cmake/Version.cmake b/cmake/Version.cmake new file mode 100644 index 0000000..81857ff --- /dev/null +++ b/cmake/Version.cmake @@ -0,0 +1,53 @@ +# Copyright (c) 2014-2017, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +function (write_static_version_header hash) + set(VERSIONTAG "${hash}") + configure_file("${CMAKE_SOURCE_DIR}/monero/src/version.cpp.in" "${CMAKE_BINARY_DIR}/version.cpp") +endfunction () + +find_package(Git QUIET) +if ("$Format:$" STREQUAL "") + # We're in a tarball; use hard-coded variables. + write_static_version_header("release") +elseif (GIT_FOUND OR Git_FOUND) + add_custom_command( + OUTPUT "${CMAKE_BINARY_DIR}/version.cpp" + COMMAND "${CMAKE_COMMAND}" + "-D" "GIT=${GIT_EXECUTABLE}" + "-D" "TO=${CMAKE_BINARY_DIR}/version.cpp" + "-P" "cmake/GenVersion.cmake" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") + +else() + message(STATUS "WARNING: Git was not found!") + write_static_version_header("unknown") +endif () +add_custom_target(genversion ALL + DEPENDS "${CMAKE_BINARY_DIR}/version.cpp") + diff --git a/cmake/VersionFeather.cmake b/cmake/VersionFeather.cmake new file mode 100644 index 0000000..fc12faf --- /dev/null +++ b/cmake/VersionFeather.cmake @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2020, The Monero Project. + +find_package(Git QUIET) + +# Check what commit we're on +execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --short=9 HEAD RESULT_VARIABLE RET OUTPUT_VARIABLE COMMIT OUTPUT_STRIP_TRAILING_WHITESPACE) + +if(RET) + # Something went wrong, set the version tag to -unknown + + message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.") + set(FEATHER_BRANCH "unknown") + configure_file("cmake/config-feather.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/src/config-feather.h") +else() + string(SUBSTRING ${COMMIT} 0 9 COMMIT) + message(STATUS "You are currently on commit ${COMMIT}") + + # Get all the tags + execute_process(COMMAND "${GIT}" rev-list --tags --max-count=1 --abbrev-commit RESULT_VARIABLE RET OUTPUT_VARIABLE TAGGEDCOMMIT OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(NOT TAGGEDCOMMIT) + message(STATUS "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") + set(FEATHER_BRANCH "${COMMIT}") + else() + message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}") + + # Check if we're building that tagged commit or a different one + if(COMMIT STREQUAL TAGGEDCOMMIT) + message(STATUS "You are building a tagged release") + set(FEATHER_BRANCH "release") + else() + message(STATUS "You are ahead of or behind a tagged release") + set(FEATHER_BRANCH "${COMMIT}") + endif() + endif() + + configure_file("cmake/config-feather.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/src/config-feather.h") +endif() diff --git a/cmake/VersionMonero.cmake b/cmake/VersionMonero.cmake new file mode 100644 index 0000000..4600c7c --- /dev/null +++ b/cmake/VersionMonero.cmake @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2020, The Monero Project. + +find_package(Git QUIET) +# Check what commit we're on +execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --short=9 HEAD RESULT_VARIABLE RET OUTPUT_VARIABLE COMMIT OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/monero) + +if(RET) + # Something went wrong, set the version tag to -unknown + + message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.") + set(MONERO_BRANCH "unknown") +else() + string(SUBSTRING ${COMMIT} 0 9 COMMIT) + message(STATUS "You are currently on commit ${COMMIT}") + + # Get all the tags + execute_process(COMMAND "${GIT}" rev-list --tags --max-count=1 --abbrev-commit RESULT_VARIABLE RET OUTPUT_VARIABLE TAGGEDCOMMIT OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(NOT TAGGEDCOMMIT) + message(STATUS "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") + set(MONERO_BRANCH "${COMMIT}") + else() + message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}") + + # Check if we're building that tagged commit or a different one + if(COMMIT STREQUAL TAGGEDCOMMIT) + message(STATUS "You are building a tagged release") + set(MONERO_BRANCH "release") + else() + message(STATUS "You are ahead of or behind a tagged release") + set(MONERO_BRANCH "${COMMIT}") + endif() + endif() +endif() + +# Check latest tagged release +execute_process(COMMAND "${GIT_EXECUTABLE}" describe --abbrev=0 RESULT_VARIABLE RET OUTPUT_VARIABLE TAG OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/monero) + +if(RET) + message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") + set(MONERO_VERSION "unknown") +else () + set(MONERO_VERSION "${TAG}") +endif() + +configure_file("cmake/config-feather.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/src/config-feather.h") \ No newline at end of file diff --git a/cmake/config-feather.h.cmake b/cmake/config-feather.h.cmake new file mode 100644 index 0000000..f2aef1e --- /dev/null +++ b/cmake/config-feather.h.cmake @@ -0,0 +1,10 @@ +#ifndef FEATHER_VERSION_H +#define FEATHER_VERSION_H + +#define FEATHER_VERSION "@VERSION@" +#define FEATHER_BRANCH "@FEATHER_BRANCH@" + +#define MONERO_VERSION "@MONERO_VERSION@" +#define MONERO_BRANCH "@MONERO_BRANCH@" + +#endif //FEATHER_VERSION_H diff --git a/cmake/test-protobuf.cpp b/cmake/test-protobuf.cpp new file mode 100644 index 0000000..0a1ca82 --- /dev/null +++ b/cmake/test-protobuf.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2014-2019, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include +#include +#include +#include "test-protobuf.pb.h" + +int main(int argc, char *argv[]) { + google::protobuf::UnknownFieldSet ufs; + ufs.ClearAndFreeMemory(); + + Success sc; + sc.set_message("test"); + sc.SerializeToOstream(&std::cerr); + return 0; +} diff --git a/cmake/test-protobuf.proto b/cmake/test-protobuf.proto new file mode 100644 index 0000000..5300aea --- /dev/null +++ b/cmake/test-protobuf.proto @@ -0,0 +1,7 @@ +syntax = "proto2"; + +import "google/protobuf/descriptor.proto"; + +message Success { + optional string message = 1; +} diff --git a/cmake/test-static-assert.c b/cmake/test-static-assert.c new file mode 100644 index 0000000..2e6c848 --- /dev/null +++ b/cmake/test-static-assert.c @@ -0,0 +1,34 @@ +// Copyright (c) 2014-2019, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +static_assert(1, "FAIL"); +int main(int argc, char *argv[]) { + return 0; +} diff --git a/cmake/test-static-assert.cpp b/cmake/test-static-assert.cpp new file mode 100644 index 0000000..2e6c848 --- /dev/null +++ b/cmake/test-static-assert.cpp @@ -0,0 +1,34 @@ +// Copyright (c) 2014-2019, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +static_assert(1, "FAIL"); +int main(int argc, char *argv[]) { + return 0; +} diff --git a/contrib/Qt5.15_LinuxPatch.json b/contrib/Qt5.15_LinuxPatch.json new file mode 100644 index 0000000..a19fc10 --- /dev/null +++ b/contrib/Qt5.15_LinuxPatch.json @@ -0,0 +1,2015 @@ +{ + "module": "gui", + "depends": [ + "core-private", + "network" + ], + "testDir": "../../config.tests", + + "commandline": { + "options": { + "accessibility": "boolean", + "angle": "boolean", + "combined-angle-lib": "boolean", + "direct2d": "boolean", + "directfb": "boolean", + "directwrite": "boolean", + "egl": "boolean", + "eglfs": "boolean", + "evdev": "boolean", + "fontconfig": "boolean", + "freetype": { "type": "enum", "values": [ "no", "qt", "system" ] }, + "gbm": "boolean", + "gif": "boolean", + "harfbuzz": { "type": "enum", "values": [ "no", "qt", "system" ] }, + "ico": "boolean", + "imf": { "type": "boolean", "name": "qqnx_imf" }, + "kms": "boolean", + "lgmon": "boolean", + "libinput": "boolean", + "libjpeg": { "type": "enum", "values": [ "no", "qt", "system" ] }, + "libmd4c": { "type": "enum", "values": [ "no", "qt", "system" ] }, + "libpng": { "type": "enum", "values": [ "no", "qt", "system" ] }, + "linuxfb": "boolean", + "mtdev": "boolean", + "opengl": { "type": "optionalString", "values": [ "no", "yes", "desktop", "es2", "dynamic" ] }, + "opengl-es-2": { "type": "void", "name": "opengl", "value": "es2" }, + "opengles3": "boolean", + "openvg": "boolean", + "qpa": { "type": "string", "name": "qpa_default_platform" }, + "qpa-platform-guard": "boolean", + "sm": { "type": "boolean", "name": "sessionmanager" }, + "tslib": "boolean", + "vulkan": "boolean", + "xcb": "boolean", + "bundled-xcb-xinput": "boolean", + "xcb-native-painting": "boolean", + "xcb-xlib": "boolean", + "xkbcommon": "boolean" + } + }, + + "libraries": { + "atspi": { + "label": "atspi", + "sources": [ + { "type": "pkgConfig", "args": "atspi-2" } + ] + }, + "bcm_host": { + "export": "", + "headers": ["bcm_host.h"], + "sources": [ + { "type": "pkgConfig", "args": "bcm_host" }, + { "type": "makeSpec", "spec": "BCM_HOST" } + ] + }, + "dxguid": { + "label": "DirectX GUID", + "sources": [ + "-ldxguid" + ] + }, + "dxgi": { + "label": "DirectX GI", + "headers": "dxgi.h", + "sources": [ + "-ldxgi" + ] + }, + "dxgi1_2": { + "label": "DirectX GI 1.2", + "test": { + "main": [ + "// fails with mingw-w64 5.4.0 - declaration is missing from header", + "IDXGISurface1 *surface;", + "(void) surface;" + ] + }, + "headers": "dxgi1_2.h", + "sources": [ + "-ldxgi" + ] + }, + "d3d9": { + "label": "Direct3D 9", + "headers": "d3d9.h", + "sources": [ + "-ld3d9" + ] + }, + "d3d11": { + "label": "Direct3D 11", + "headers": "d3d11.h", + "sources": [ + "-ld3d11" + ] + }, + "d3d11_1": { + "label": "Direct3D 11.1", + "headers": "d3d11_1.h", + "sources": [ + "-ld3d11" + ] + }, + "d3dcompiler": { + "label": "Direct3D Shader Compiler Library", + "headers": "d3dcompiler.h", + "sources": [ + "-ld3dcompiler" + ] + }, + "d2d1": { + "label": "Direct2D 1", + "headers": [ "d2d1.h", "d2d1helper.h" ], + "sources": [ + "-ld2d1" + ] + }, + "d2d1_1": { + "label": "Direct2D 1.1", + "test": { + "main": [ + "ID2D1Factory1 *d2dFactory;", + "D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory);" + ] + }, + "headers": [ "d2d1_1.h", "d2d1_1helper.h" ], + "sources": [ + "-ld2d1" + ] + }, + "directfb": { + "label": "DirectFB", + "test": { + "tail": [ + "#ifdef __typeof__", + "# error DirectFB headers are unclean and cannot compile", + "#endif" + ] + }, + "headers": "directfb.h", + "sources": [ + { "type": "pkgConfig", "args": "directfb" } + ] + }, + "dwrite": { + "label": "DirectWrite", + "test": { + "main": [ + "IDWriteFactory *factory = 0;", + "DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),", + " (IUnknown **)(&factory));" + ] + }, + "headers": "dwrite.h", + "sources": [ + "-ldwrite" + ] + }, + "dwrite_1": { + "label": "DirectWrite 1", + "headers": "dwrite_1.h", + "sources": [ + "-ldwrite" + ] + }, + "dwrite_2": { + "label": "DirectWrite 2", + "test": { + "main": [ + "IUnknown *factory = 0;", + "(void)(size_t(DWRITE_E_NOCOLOR) + sizeof(IDWriteFontFace2));", + "DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2),", + " &factory);" + ] + }, + "headers": "dwrite_2.h", + "sources": [ + "-ldwrite" + ] + }, + "drm": { + "label": "KMS", + "test": { + "head": [ + "#include ", + "#include ", + "extern \"C\" {" + ], + "tail": [ + "}" + ], + "main": "(void) drmModeGetCrtc(0, 0);" + }, + "headers": [ "xf86drmMode.h", "xf86drm.h" ], + "sources": [ + { "type": "pkgConfig", "args": "libdrm" }, + { "libs": "-ldrm", "condition": "!config.integrity" }, + { "libs": "-ldrm-nvdc -lposix -livfs -lnvll -lnvdc -lnvrm -lnvrm_graphics -lnvos -lnvtegrahv", "condition": "config.integrity" } + ] + }, + "egl": { + "label": "EGL", + "test": { + "main": [ + "EGLint x = 0; EGLDisplay dpy = 0; EGLContext ctx = 0;", + "eglDestroyContext(dpy, ctx);" + ] + }, + "headers": "EGL/egl.h", + "sources": [ + { "type": "pkgConfig", "args": "egl" }, + { "type": "makeSpec", "spec": "EGL" } + ] + }, + "freetype": { + "label": "FreeType", + "test": { + "tail": [ + "#include FT_FREETYPE_H", + "#if ((FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) < 20200)", + "# error This version of freetype is too old.", + "#endif" + ], + "main": [ + "FT_Face face = 0;" + ] + }, + "headers": "ft2build.h", + "sources": [ + { "type": "pkgConfig", "args": "freetype2" }, + { "type": "freetype", "libs": "-lfreetype", "condition": "!config.wasm" }, + { "libs": "-s USE_FREETYPE=1", "condition": "config.wasm" }, + { "libs": "-lfreetype" } + ], + "use": [ + { "lib": "zlib", "condition": "features.system-zlib" } + ] + }, + "fontconfig": { + "label": "Fontconfig", + "test": { + "tail": [ + "#ifndef FC_RGBA_UNKNOWN", + "# error This version of fontconfig is too old, it is missing the FC_RGBA_UNKNOWN define", + "#endif" + ], + "main": [ + "FcPattern *pattern = 0;" + ] + }, + "headers": "fontconfig/fontconfig.h", + "sources": [ + { "type": "pkgConfig", "args": "fontconfig" }, + { "type": "freetype", "libs": "-lfontconfig" } + ], + "use": "freetype" + }, + "gbm": { + "label": "GBM", + "test": { + "head": [ + "#include ", + "#include ", + "extern \"C\" {" + ], + "tail": [ + "}" + ], + "main": "gbm_surface *surface = 0;" + }, + "headers": "gbm.h", + "sources": [ + { "type": "pkgConfig", "args": "gbm" } + ] + }, + "harfbuzz": { + "label": "HarfBuzz", + "test": { + "tail": [ + "#if !HB_VERSION_ATLEAST(1, 6, 0)", + "# error This version of harfbuzz is too old.", + "#endif" + ], + "main": [ + "hb_buffer_t *buffer = hb_buffer_create();", + "const uint16_t string[] = { 'A', 'b', 'c' };", + "hb_buffer_add_utf16(buffer, string, 3, 0, 3);", + "hb_buffer_guess_segment_properties(buffer);", + "hb_buffer_set_flags(buffer, hb_buffer_flags_t(HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES));", + "hb_buffer_destroy(buffer);" + ] + }, + "headers": "harfbuzz/hb.h", + "sources": [ + "-lharfbuzz" + ] + }, + "imf": { + "label": "IMF", + "export": "", + "test": { + "main": "imf_client_init();" + }, + "headers": "imf/imf_client.h", + "sources": [ + "-linput_client" + ] + }, + "lgmon": { + "label": "lgmon", + "test": { + "main": "lgmon_supported(getpid());" + }, + "headers": "lgmon.h", + "sources": [ + "-llgmon" + ] + }, + "libinput": { + "label": "libinput", + "test": { + "main": "libinput_udev_create_context(NULL, NULL, NULL);" + }, + "headers": "libinput.h", + "sources": [ + { "type": "pkgConfig", "args": "libinput" } + ] + }, + "integrityhid": { + "label": "integrityhid", + "test": { + "head": [ + "#include ", + "#include " + ], + "main": [ + "HIDDriver *driver;", + "uintptr_t devicecontext;", + "uint32_t device_id;", + "gh_hid_enum_devices(driver, &device_id, &devicecontext);" + ] + }, + "headers": "device/hiddriver.h", + "sources": [ + { "libs": "-lhiddev -lusbhid -lusb" } + ] + }, + "libjpeg": { + "label": "libjpeg", + "test": { + "head": [ + "#include ", + "#include ", + "extern \"C\" {" + ], + "tail": [ + "}", + "", + "j_compress_ptr cinfo;" + ], + "main": "jpeg_create_compress(cinfo);" + }, + "headers": "jpeglib.h", + "sources": [ + { "type": "pkgConfig", "args": "libjpeg" }, + { "libs": "-llibjpeg", "condition": "config.msvc" }, + "-ljpeg" + ] + }, + "libmd4c": { + "label": "libmd4c", + "test": { + "main": "md_parse(\"hello\", 5, nullptr, nullptr);" + }, + "headers": "md4c.h", + "sources": [ + { "type": "pkgConfig", "args": "md4c" }, + { "libs": "-lmd4c" } + ] + }, + "libpng": { + "label": "libpng", + "test": { + "main": "(void) png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);" + }, + "headers": "png.h", + "sources": [ + { "type": "pkgConfig", "args": "libpng" }, + { "libs": "-llibpng16", "condition": "config.msvc" }, + { "libs": "-llibpng", "condition": "config.msvc" }, + { "libs": "-lpng16", "condition": "!config.msvc" }, + { "libs": "-lpng", "condition": "!config.msvc" }, + { "libs": "-s USE_LIBPNG=1", "condition": "config.wasm" } + ], + "use": [ + { "lib": "zlib", "condition": "features.system-zlib" } + ] + }, + "mtdev": { + "label": "mtdev", + "test": { + "main": [ + "mtdev m;", + "mtdev_open(&m, 0);" + ] + }, + "headers": "mtdev.h", + "sources": [ + { "type": "pkgConfig", "args": "mtdev" } + ] + }, + "opengl": { + "label": "Desktop OpenGL", + "test": { + "head": [ + "#ifdef __APPLE__", + "# include ", + "#else", + "# define GL_GLEXT_PROTOTYPES", + "#endif" + ], + "main": [ + "glBegin(GL_TRIANGLES);", + " glVertex2f(20.0f, 10.0f);", + " glVertex2f(10.0f, 30.0f);", + " glVertex2f(20.0f, 50.0f);", + "glEnd();" + ] + }, + "headers": [ + { + "condition": "!config.darwin", + "headers": "GL/gl.h" + } + ], + "sources": [ + { "type": "pkgConfig", "args": "gl", "condition": "!config.darwin" }, + { "type": "makeSpec", "spec": "OPENGL" } + ] + }, + "opengl_es2": { + "label": "OpenGL ES 2.0", + "test": { + "head": [ + "#ifdef __APPLE__", + "# include ", + "#else", + "# define GL_GLEXT_PROTOTYPES", + "#endif" + ], + "main": [ + "glUniform1f(1, GLfloat(1.0));", + "glClear(GL_COLOR_BUFFER_BIT);" + ] + }, + "headers": [ + { + "condition": "!config.darwin", + "headers": "GLES2/gl2.h" + } + ], + "sources": [ + { "type": "pkgConfig", "args": "glesv2", "condition": "!config.darwin" }, + { "type": "makeSpec", "spec": "OPENGL_ES2" } + ] + }, + "openvg": { + "label": "OpenVG", + "test": { + "main": "VGint i = 2; vgFlush();" + }, + "headers": "VG/openvg.h", + "sources": [ + { "type": "pkgConfig", "args": "vg" }, + { "type": "makeSpec", "spec": "OPENVG" } + ] + }, + "tslib": { + "label": "tslib", + "test": { + "main": "ts_setup(nullptr, 0);" + }, + "headers": "tslib.h", + "sources": [ + "-lts" + ] + }, + "v4l2": { + "label": "V4L2", + "test": { + "head": [ + "#include ", + "extern \"C\" {" + ], + "tail": [ + "}" + ], + "main": [ + "v4l2_format fmt;", + "media_pad *pad = nullptr;", + "media_device *device = media_device_new(\"/dev/media\");", + "v4l2_subdev_set_format(nullptr, nullptr, 0, V4L2_SUBDEV_FORMAT_ACTIVE);" + ] + }, + "headers": [ "mediactl/mediactl.h", "mediactl/v4l2subdev.h" ], + "sources": [ + { "type": "pkgConfig", "args": "libv4l2 libmediactl" }, + "-lmediactl -lv4l2 -lv4l2subdev" + ] + }, + "vulkan": { + "label": "Vulkan", + "test": { + "comment": "Note: Qt does not rely on linking to a Vulkan library directly.", + "tail": [ + "// The pData parameter has changed from uint32_t* to void* at some point.", + "// Ensure the headers have the updated one to prevent compile errors later on.", + "PFN_vkCmdUpdateBuffer cmdUpdBuf;", + "void testUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData)", + "{", + " cmdUpdBuf(commandBuffer, dstBuffer, dstOffset, dataSize, pData);", + "}" + ], + "main": [ + "VkInstanceCreateInfo info;", + "testUpdateBuffer(0, 0, 0, 0, 0);" + ] + }, + "headers": "vulkan/vulkan.h", + "sources": [ + { "type": "pkgConfig", "args": "vulkan" }, + { "type": "makeSpec", "spec": "VULKAN" } + ] + }, + "wayland_server": { + "label": "Wayland Server", + "test": { + "main": "wl_display_create();" + }, + "headers": "wayland-server.h", + "sources": [ + { "type": "pkgConfig", "args": "wayland-server" } + ] + }, + "xlib": { + "label": "XLib", + "test": { + "main": [ + "Display *d = XOpenDisplay(NULL);", + "XCloseDisplay(d);" + ] + }, + "headers": "X11/Xlib.h", + "sources": [ + { "type": "makeSpec", "spec": "X11" } + ] + }, + "x11sm": { + "label": "X11 session management", + "sources": [ + { "type": "pkgConfig", "args": "sm ice" } + ] + }, + "xcb": { + "label": "XCB >= 1.11", + "test": { + "main": [ + "int primaryScreen = 0;", + "(void)xcb_connect(\"\", &primaryScreen);", + "/* XCB_PACKED define was added in libxcb 1.11 */", + "#ifdef XCB_PACKED", + " return 0;", + "#else", + " return -1;", + "#endif" + ] + }, + "headers": "xcb/xcb.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb >= 1.11" }, + "-lxcb" + ] + }, + "xcb_icccm": { + "label": "XCB ICCCM >= 0.3.9", + "headers": "xcb/xcb_icccm.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-icccm >= 0.3.9" }, + "-lxcb-icccm" + ], + "use": "xcb" + }, + "xcb_util": { + "label": "XCB Util >= 0.3.9", + "headers": "xcb/xcb_util.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-util >= 0.3.9" }, + "-lxcb-util" + ], + "use": "xcb" + }, + "xcb_image": { + "label": "XCB Image >= 0.3.9", + "headers": "xcb/xcb_image.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-image >= 0.3.9" }, + "-lxcb-image" + ], + "use": "xcb_shm xcb_util xcb" + }, + "xcb_keysyms": { + "label": "XCB Keysyms >= 0.3.9", + "headers": "xcb/xcb_keysyms.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-keysyms >= 0.3.9" }, + "-lxcb-keysyms" + ], + "use": "xcb" + }, + "xcb_renderutil": { + "label": "XCB Renderutil >= 0.3.9", + "headers": "xcb/xcb_renderutil.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-renderutil >= 0.3.9" }, + "-lxcb-render-util" + ], + "use": "xcb xcb_render" + }, + "xcb_randr": { + "label": "XCB RandR", + "headers": "xcb/randr.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-randr" }, + "-lxcb-randr" + ], + "use": "xcb" + }, + "xcb_shape": { + "label": "XCB Shape", + "headers": "xcb/shape.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-shape" }, + "-lxcb-shape" + ], + "use": "xcb" + }, + "xcb_shm": { + "label": "XCB SHM", + "headers": "xcb/shm.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-shm" }, + "-lxcb-shm" + ], + "use": "xcb" + }, + "xcb_sync": { + "label": "XCB Sync", + "headers": "xcb/sync.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-sync" }, + "-lxcb-sync" + ], + "use": "xcb" + }, + "xcb_xfixes": { + "label": "XCB Xfixes", + "headers": "xcb/xfixes.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-xfixes" }, + "-lxcb-xfixes" + ], + "use": "xcb" + }, + "xcb_xinerama": { + "label": "XCB Xinerama", + "headers": "xcb/xinerama.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-xinerama" }, + "-lxcb-xinerama" + ], + "use": "xcb" + }, + "xcb_xlib": { + "label": "XCB Xlib", + "test": { + "main": "(void) XGetXCBConnection((Display *)0);" + }, + "headers": "X11/Xlib-xcb.h", + "sources": [ + { "type": "pkgConfig", "args": "x11-xcb" }, + "-lX11-xcb" + ], + "use": "xcb xlib" + }, + "xcb_xkb": { + "label": "XCB XKB", + "headers": "xcb/xkb.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-xkb" }, + "-lxcb-xkb" + ], + "use": "xcb" + }, + "xcb_render": { + "label": "XCB XRender", + "headers": "xcb/render.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-render" }, + "-lxcb-render" + ], + "use": "xcb" + }, + "xcb_glx": { + "label": "XCB GLX", + "test": { + "main": [ + "xcb_connection_t *connection = 0;", + "xcb_generic_error_t *error = 0;", + "xcb_glx_query_version_cookie_t xglx_query_cookie = xcb_glx_query_version(", + " connection, XCB_GLX_MAJOR_VERSION, XCB_GLX_MINOR_VERSION);", + "xcb_glx_query_version_reply(connection, xglx_query_cookie, &error);" + ] + }, + "headers": "xcb/glx.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-glx" }, + "-lxcb-glx" + ], + "use": "xcb" + }, + "xcb_xinput": { + "label": "XCB XInput", + "test": { + "main": [ + "xcb_connection_t *connection = 0;", + "xcb_generic_error_t *error = 0;", + "xcb_input_xi_query_version_cookie_t xinput_query_cookie = xcb_input_xi_query_version(", + " connection, XCB_INPUT_MAJOR_VERSION, XCB_INPUT_MINOR_VERSION);", + "xcb_input_xi_query_version_reply(connection, xinput_query_cookie, &error);" + ] + }, + "headers": "xcb/xinput.h", + "sources": [ + { "type": "pkgConfig", "args": "xcb-xinput >= 1.12" }, + "-lxcb-xinput" + ], + "use": "xcb" + }, + "xkbcommon": { + "label": "xkbcommon >= 0.5.0", + "test": { + "main": "xkb_context_new(XKB_CONTEXT_NO_FLAGS);" + }, + "headers": [ "xkbcommon/xkbcommon.h" ], + "sources": [ + { "type": "pkgConfig", "args": "xkbcommon >= 0.5.0" }, + "-lxkbcommon" + ] + }, + "xkbcommon_x11": { + "label": "xkbcommon-x11", + "test": { + "main": "xkb_x11_setup_xkb_extension_flags flag = XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS;" + }, + "headers": [ "xkbcommon/xkbcommon-x11.h" ], + "sources": [ + { "type": "pkgConfig", "args": "xkbcommon-x11" }, + "-lxkbcommon -lxkbcommon-x11" + ] + }, + "xrender": { + "label": "XRender for native painting", + "test": { + "tail": [ + "#if RENDER_MAJOR == 0 && RENDER_MINOR < 5", + "# error Required Xrender version 0.6 not found.", + "#endif" + ], + "main": "XRenderPictFormat *format = 0;" + }, + "headers": "X11/extensions/Xrender.h", + "sources": [ + "-lXrender" + ], + "use": "xlib" + } + }, + + "tests": { + "angle_d3d11_qdtd": { + "label": "D3D11_QUERY_DATA_TIMESTAMP_DISJOINT", + "type": "compile", + "test": { + "include": "d3d11.h", + "main": [ + "D3D11_QUERY_DATA_TIMESTAMP_DISJOINT qdtd;", + "(void) qdtd;" + ] + } + }, + "fxc": { + "label": "Direct3D Shader Compiler", + "type": "fxc", + "log": "value" + }, + "drm_atomic": { + "label": "DRM Atomic API", + "type": "compile", + "test": { + "head": [ + "#include ", + "#include ", + "extern \"C\" {" + ], + "include": [ + "xf86drmMode.h", + "xf86drm.h" + ], + "tail": [ + "}" + ], + "main": "drmModeAtomicReq *request;" + }, + "use": "drm" + }, + "egl-x11": { + "label": "EGL on X11", + "type": "compile", + "test": { + "head": [ + "// Check if EGL is compatible with X. Some EGL implementations, typically on", + "// embedded devices, are not intended to be used together with X. EGL support", + "// has to be disabled in plugins like xcb in this case since the native display,", + "// window and pixmap types will be different than what an X-based platform", + "// plugin would expect." + ], + "include": [ "EGL/egl.h", "X11/Xlib.h" ], + "main": [ + "Display *dpy = EGL_DEFAULT_DISPLAY;", + "EGLNativeDisplayType egldpy = XOpenDisplay(\"\");", + "dpy = egldpy;", + "EGLNativeWindowType w = XCreateWindow(dpy, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);", + "XDestroyWindow(dpy, w);", + "XCloseDisplay(dpy);" + ] + }, + "use": "egl xlib" + }, + "egl-brcm": { + "label": "Broadcom EGL (Raspberry Pi)", + "type": "compile", + "test": { + "include": [ "EGL/egl.h", "bcm_host.h" ], + "main": "vc_dispmanx_display_open(0);" + }, + "use": "egl bcm_host" + }, + "egl-egldevice": { + "label": "EGLDevice", + "type": "compile", + "test": { + "include": [ "EGL/egl.h", "EGL/eglext.h" ], + "main": [ + "EGLDeviceEXT device = 0;", + "EGLStreamKHR stream = 0;", + "EGLOutputLayerEXT layer = 0;", + "(void) EGL_DRM_CRTC_EXT;" + ] + }, + "use": "egl" + }, + "egl-mali": { + "label": "Mali EGL", + "type": "compile", + "test": { + "include": [ "EGL/fbdev_window.h", "EGL/egl.h", "GLES2/gl2.h" ], + "main": "fbdev_window *w = 0;" + }, + "use": "egl" + }, + "egl-mali-2": { + "label": "Mali 2 EGL", + "type": "compile", + "test": { + "include": [ "EGL/egl.h", "GLES2/gl2.h" ], + "main": "mali_native_window *w = 0;" + }, + "use": "egl" + }, + "egl-viv": { + "label": "i.Mx6 EGL", + "type": "compile", + "test": { + "include": [ "EGL/egl.h", "EGL/eglvivante.h" ], + "main": [ + "#ifdef __INTEGRITY", + "fbGetDisplay();", + "#else", + "// Do not rely on fbGetDisplay(), since the signature has changed over time.", + "// Stick to fbGetDisplayByIndex().", + "fbGetDisplayByIndex(0);", + "#endif" + ], + "qmake": [ + "DEFINES += EGL_API_FB=1", + "!integrity: DEFINES += LINUX=1" + ] + }, + "use": "egl" + }, + "egl-openwfd": { + "label": "OpenWFD EGL", + "type": "compile", + "test": { + "include": [ "wfd.h" ], + "main": [ + "wfdEnumerateDevices(nullptr, 0, nullptr);" + ] + }, + "use": "egl" + }, + "egl-rcar": { + "label": "RCAR EGL", + "type": "compile", + "test": { + "include": [ "EGL/egl.h" ], + "tail": [ + "extern \"C\" {", + "extern unsigned long PVRGrfxServerInit(void);", + "}" + ], + "main": [ + "PVRGrfxServerInit();" + ] + }, + "use": "egl opengl_es2" + }, + "evdev": { + "label": "evdev", + "type": "compile", + "test": { + "head": [ + "#if defined(__FreeBSD__)", + "# include ", + "#else", + "# include ", + "# include ", + "#endif", + "enum {", + " e1 = ABS_PRESSURE,", + " e2 = ABS_X,", + " e3 = REL_X,", + " e4 = SYN_REPORT,", + "};" + ], + "main": [ + "input_event buf[32];", + "(void) buf;" + ] + } + }, + "integrityfb": { + "label": "INTEGRITY framebuffer", + "type": "compile", + "test": { + "include": "device/fbdriver.h", + "main": "FBDriver *driver = 0;" + } + }, + "libinput_axis_api": { + "label": "axis API in libinput", + "type": "compile", + "test": { + "include": "libinput.h", + "main": "libinput_event_pointer_has_axis(nullptr, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);" + }, + "use": "libinput" + }, + "linuxfb": { + "label": "LinuxFB", + "type": "compile", + "test": { + "include": [ "linux/fb.h", "sys/kd.h", "sys/ioctl.h" ], + "main": [ + "fb_fix_screeninfo finfo;", + "fb_var_screeninfo vinfo;", + "int fd = 3;", + "ioctl(fd, FBIOGET_FSCREENINFO, &finfo);", + "ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);" + ] + } + }, + "opengles3": { + "label": "OpenGL ES 3.0", + "type": "compile", + "test": { + "head": [ + "#ifdef __APPLE__", + "# include ", + "#else", + "# define GL_GLEXT_PROTOTYPES", + "# include ", + "#endif" + ], + "main": [ + "static GLfloat f[6];", + "glGetStringi(GL_EXTENSIONS, 0);", + "glReadBuffer(GL_COLOR_ATTACHMENT1);", + "glUniformMatrix2x3fv(0, 0, GL_FALSE, f);", + "glMapBufferRange(GL_ARRAY_BUFFER, 0, 0, GL_MAP_READ_BIT);" + ] + }, + "comment": [ + "The library is expected to be the same as in ES 2.0 (libGLESv2).", + "The difference is the header and the presence of the functions in", + "the library." + ], + "use": "opengl_es2" + }, + "opengles31": { + "label": "OpenGL ES 3.1", + "type": "compile", + "test": { + "include": "GLES3/gl31.h", + "main": [ + "glDispatchCompute(1, 1, 1);", + "glProgramUniform1i(0, 0, 0);" + ] + }, + "use": "opengl_es2" + }, + "opengles32": { + "label": "OpenGL ES 3.2", + "type": "compile", + "test": { + "include": "GLES3/gl32.h", + "main": "glFramebufferTexture(GL_TEXTURE_2D, GL_DEPTH_STENCIL_ATTACHMENT, 1, 0);" + }, + "use": "opengl_es2" + }, + "qpa_default_platform": { + "label": "default QPA platform", + "type": "qpaDefaultPlatform", + "log": "value" + }, + "xcb_syslibs": { + "label": "XCB (extensions)", + "type": "compile", + "test": { + "head": [ + "// xkb.h is using a variable called 'explicit', which is a reserved keyword in C++", + "#define explicit dont_use_cxx_explicit" + ], + "tail": "#undef explicit", + "include": [ + "xcb/xcb.h", + "xcb/xcb_util.h", + "xcb/xcb_image.h", + "xcb/xcb_keysyms.h", + "xcb/randr.h", + "xcb/render.h", + "xcb/shape.h", + "xcb/shm.h", + "xcb/sync.h", + "xcb/xfixes.h", + "xcb/xinerama.h", + "xcb/xcb_icccm.h", + "xcb/xcb_renderutil.h", + "xcb/xkb.h" + ], + "main": [ + "int primaryScreen = 0;", + "xcb_connection_t *c = xcb_connect(\"\", &primaryScreen);", + + "/* RENDER */", + "xcb_generic_error_t *error = nullptr;", + "xcb_render_query_pict_formats_cookie_t formatsCookie =", + " xcb_render_query_pict_formats(c);", + "xcb_render_query_pict_formats_reply_t *formatsReply =", + " xcb_render_query_pict_formats_reply(c, formatsCookie, &error);", + + "/* RENDERUTIL: xcb_renderutil.h include won't compile unless version >= 0.3.9 */", + "xcb_render_util_find_standard_format(nullptr, XCB_PICT_STANDARD_ARGB_32);", + + "/* XKB: This takes more arguments in xcb-xkb < 1.11 */", + "xcb_xkb_get_kbd_by_name_replies_key_names_value_list_sizeof(nullptr, 0, 0, 0, 0, 0, 0, 0, 0);" + ] + }, + "use": "xcb_icccm xcb_util xcb_image xcb_keysyms xcb_randr xcb_render xcb_renderutil xcb_shape xcb_shm xcb_sync xcb_xfixes xcb_xinerama xcb_xkb xcb" + }, + "x11prefix": { + "label": "X11 prefix", + "type": "getPkgConfigVariable", + "pkg-config-args": "x11", + "pkg-config-variable": "prefix", + "value": "/usr", + "log": "value" + } + }, + + "features": { + "accessibility-atspi-bridge": { + "label": "ATSPI Bridge", + "condition": "features.accessibility && features.xcb && features.dbus && libs.atspi", + "output": [ "privateFeature", "feature" ] + }, + "angle": { + "label": "ANGLE", + "autoDetect": "features.opengles2 || features.opengl-dynamic", + "condition": "!features.opengl-desktop && features.dxguid && tests.fxc && (features.direct3d9 || (config.winrt && features.direct3d11 && libs.d3dcompiler))", + "output": [ + "publicFeature", + { "type": "define", "name": "QT_OPENGL_ES_2_ANGLE" }, + { "type": "varAssign", "name": "QMAKE_FXC_LOCATION", "value": "tests.fxc.value" } + ] + }, + "angle_d3d11_qdtd": { + "label": "D3D11_QUERY_DATA_TIMESTAMP_DISJOINT", + "condition": "features.angle && tests.angle_d3d11_qdtd", + "output": [ "privateFeature" ] + }, + "combined-angle-lib": { + "label": "Combined ANGLE Library", + "autoDetect": false, + "condition": "features.angle", + "output": [ "publicFeature" ] + }, + "directfb": { + "label": "DirectFB", + "section": "Platform plugins", + "autoDetect": false, + "condition": "libs.directfb", + "output": [ "privateFeature" ] + }, + "directwrite": { + "label": "DirectWrite", + "emitIf": "config.win32", + "condition": "libs.dwrite", + "output": [ "privateFeature" ] + }, + "directwrite1": { + "label": "DirectWrite 1", + "emitIf": "config.win32", + "condition": "libs.dwrite_1", + "output": [ "privateFeature" ] + }, + "directwrite2": { + "label": "DirectWrite 2", + "emitIf": "config.win32", + "condition": "features.directwrite1 && libs.dwrite_2", + "output": [ "privateFeature" ] + }, + "dxguid": { + "label": "DirectX GUID", + "condition": "config.win32 && libs.dxguid", + "output": [ "privateFeature" ] + }, + "direct3d9": { + "label": "Direct 3D 9", + "condition": "config.win32 && !config.winrt && libs.d3d9", + "output": [ "privateFeature" ] + }, + "dxgi": { + "label": "DirectX GI", + "condition": "config.win32 && libs.dxgi", + "output": [ "privateFeature" ] + }, + "dxgi1_2": { + "label": "DirectX GI 1.2", + "condition": "features.dxgi && libs.dxgi1_2", + "output": [ "privateFeature" ] + }, + "direct3d11": { + "label": "Direct 3D 11", + "condition": "features.dxgi && libs.d3d11", + "output": [ "privateFeature" ] + }, + "direct3d11_1": { + "label": "Direct 3D 11.1", + "condition": "features.direct3d11 && features.dxgi1_2 && libs.d3d11_1", + "output": [ "privateFeature" ] + }, + "direct2d": { + "label": "Direct 2D", + "condition": "config.win32 && !config.winrt && features.direct3d11 && libs.d2d1", + "output": [ "privateFeature" ] + }, + "direct2d1_1": { + "label": "Direct 2D 1.1", + "condition": "features.direct2d && libs.d2d1_1", + "output": [ "privateFeature" ] + }, + "evdev": { + "label": "evdev", + "condition": "features.thread && tests.evdev", + "output": [ "privateFeature" ] + }, + "freetype": { + "label": "FreeType", + "purpose": "Supports the FreeType 2 font engine (and its supported font formats).", + "section": "Fonts", + "output": [ "privateFeature", "feature" ] + }, + "system-freetype": { + "label": " Using system FreeType", + "enable": "input.freetype == 'system'", + "disable": "input.freetype == 'qt'", + "autoDetect": "!config.msvc", + "condition": "features.freetype && libs.freetype", + "output": [ "privateFeature" ] + }, + "fontconfig": { + "label": "Fontconfig", + "autoDetect": "!config.darwin", + "condition": "!config.msvc && features.system-freetype && libs.fontconfig", + "output": [ "privateFeature", "feature" ] + }, + "gbm": { + "label": "GBM", + "condition": "libs.gbm", + "output": [ "publicQtConfig" ] + }, + "harfbuzz": { + "label": "HarfBuzz", + "output": [ "privateFeature", "feature" ] + }, + "system-harfbuzz": { + "label": " Using system HarfBuzz", + "enable": "input.harfbuzz == 'system'", + "disable": "input.harfbuzz == 'qt'", + "autoDetect": "!config.darwin && !config.win32", + "condition": "features.harfbuzz && libs.harfbuzz", + "output": [ "privateFeature" ] + }, + "qqnx_imf": { + "label": "IMF", + "emitIf": "config.qnx", + "condition": "libs.imf", + "output": [ "privateFeature" ] + }, + "integrityfb": { + "label": "INTEGRITY framebuffer", + "section": "Platform plugins", + "condition": "config.integrity && tests.integrityfb", + "output": [ "privateFeature" ] + }, + "kms": { + "label": "KMS", + "condition": "libs.drm", + "output": [ "publicQtConfig", "privateFeature" ] + }, + "drm_atomic": { + "label": "DRM Atomic API", + "condition": "libs.drm && tests.drm_atomic", + "output": [ "privateFeature" ] + }, + "libinput": { + "label": "libinput", + "condition": "features.libudev && libs.libinput", + "output": [ "privateFeature" ] + }, + "integrityhid": { + "label": "INTEGRITY HID", + "condition": "config.integrity && libs.integrityhid", + "output": [ "privateFeature" ] + }, + "libinput-axis-api": { + "label": "axis API in libinput", + "condition": "features.libinput && tests.libinput_axis_api", + "output": [ "privateFeature" ] + }, + "lgmon": { + "label": "lgmon", + "emitIf": "config.qnx", + "condition": "libs.lgmon", + "output": [ "privateConfig" ] + }, + "linuxfb": { + "label": "LinuxFB", + "section": "Platform plugins", + "condition": "tests.linuxfb && features.regularexpression", + "output": [ "privateFeature" ] + }, + "vsp2": { + "label": "VSP2", + "condition": "libs.v4l2", + "autoDetect": false, + "output": [ "privateFeature" ] + }, + "vnc": { + "label": "VNC", + "section": "Platform plugins", + "condition": [ + "config.unix && !config.android && !config.darwin && !config.wasm", + "features.regularexpression && features.network" + ], + "output": [ "privateFeature" ] + }, + "mtdev": { + "label": "mtdev", + "condition": "libs.mtdev", + "output": [ "privateFeature" ] + }, + "opengles2": { + "label": "OpenGL ES 2.0", + "enable": "input.opengl == 'es2' || input.angle == 'yes'", + "disable": "input.opengl == 'desktop' || input.opengl == 'dynamic' || input.opengl == 'no'", + "condition": "(config.win32 && !features.opengl-dynamic) || (!config.watchos && !features.opengl-desktop && libs.opengl_es2)", + "output": [ + "publicFeature", + "publicQtConfig", + { "type": "define", "name": "QT_OPENGL_ES" }, + { "type": "define", "name": "QT_OPENGL_ES_2" } + ] + }, + "opengles3": { + "label": "OpenGL ES 3.0", + "condition": "features.opengles2 && !features.angle && tests.opengles3", + "output": [ + "publicFeature", + { "type": "define", "name": "QT_OPENGL_ES_3" } + ] + }, + "opengles31": { + "label": "OpenGL ES 3.1", + "condition": "features.opengles3 && tests.opengles31", + "output": [ + "publicFeature", + { "type": "define", "name": "QT_OPENGL_ES_3_1" } + ] + }, + "opengles32": { + "label": "OpenGL ES 3.2", + "condition": "features.opengles31 && tests.opengles32", + "output": [ + "publicFeature", + { "type": "define", "name": "QT_OPENGL_ES_3_2" } + ] + }, + "opengl-desktop": { + "label": "Desktop OpenGL", + "autoDetect": "!config.win32", + "enable": "input.opengl == 'desktop'", + "disable": "input.opengl == 'es2' || input.opengl == 'dynamic' || input.opengl == 'no'", + "condition": "(config.win32 && !config.winrt && !features.opengles2 && (config.msvc || libs.opengl)) + || (!config.watchos && !config.win32 && !config.wasm && libs.opengl)" + }, + "opengl-dynamic": { + "label": "Dynamic OpenGL", + "disable": "input.angle == 'yes' || input.opengl == 'no' || input.opengl == 'desktop'", + "condition": "config.win32 && !config.winrt", + "output": [ + { "type": "publicFeature", "name": "dynamicgl" }, + { "type": "define", "name": "QT_OPENGL_DYNAMIC" } + ] + }, + "opengl": { + "label": "OpenGL", + "condition": "features.opengl-desktop || features.opengl-dynamic || features.opengles2", + "output": [ "publicFeature", "feature" ] + }, + "vkgen": { + "label": "vkgen", + "condition": "features.xmlstreamreader", + "output": [ "privateFeature" ] + }, + "vulkan": { + "label": "Vulkan", + "condition": "features.vkgen && libs.vulkan", + "output": [ "publicFeature" ] + }, + "openvg": { + "label": "OpenVG", + "condition": "libs.openvg", + "output": [ "publicFeature" ] + }, + "egl": { + "label": "EGL", + "condition": "(features.opengl || features.openvg) && (features.angle || libs.egl) && (features.dlopen || !config.unix || config.integrity)", + "output": [ "privateFeature", "feature" ] + }, + "egl_x11": { + "label": "EGL on X11", + "condition": "features.thread && features.egl && tests.egl-x11", + "output": [ "privateFeature" ] + }, + "eglfs": { + "label": "EGLFS", + "section": "Platform plugins", + "condition": "!config.android && !config.darwin && !config.win32 && !config.wasm && features.egl", + "output": [ "privateFeature" ] + }, + "eglfs_brcm": { + "label": "EGLFS Raspberry Pi", + "condition": "features.eglfs && tests.egl-brcm", + "output": [ "privateFeature" ] + }, + "eglfs_egldevice": { + "label": "EGLFS EGLDevice", + "condition": "features.eglfs && tests.egl-egldevice && features.kms", + "output": [ "privateFeature" ] + }, + "eglfs_gbm": { + "label": "EGLFS GBM", + "condition": "features.eglfs && features.gbm && features.kms", + "output": [ "privateFeature" ] + }, + "eglfs_vsp2": { + "label": "EGLFS VSP2", + "condition": "features.eglfs && features.gbm && features.kms && features.vsp2", + "output": [ "privateFeature" ] + }, + "eglfs_mali": { + "label": "EGLFS Mali", + "condition": "features.eglfs && (tests.egl-mali || tests.egl-mali-2)", + "output": [ "privateFeature" ] + }, + "eglfs_viv": { + "label": "EGLFS i.Mx6", + "condition": "features.eglfs && tests.egl-viv", + "output": [ "privateFeature" ] + }, + "eglfs_rcar": { + "label": "EGLFS RCAR", + "condition": "config.integrity && features.eglfs && tests.egl-rcar", + "output": [ "privateFeature" ] + }, + "eglfs_viv_wl": { + "label": "EGLFS i.Mx6 Wayland", + "condition": "features.eglfs_viv && libs.wayland_server", + "output": [ "privateFeature" ] + }, + "eglfs_openwfd": { + "label": "EGLFS OpenWFD", + "condition": "config.integrity && features.eglfs && tests.egl-openwfd", + "output": [ "privateFeature" ] + }, + "eglfs_x11": { + "label": "EGLFS X11", + "condition": "features.eglfs && features.xcb-xlib && features.egl_x11", + "output": [ "privateFeature" ] + }, + "gif": { + "label": "GIF", + "condition": "features.imageformatplugin", + "output": [ + "privateFeature", + { "type": "define", "negative": true, "name": "QT_NO_IMAGEFORMAT_GIF" } + ] + }, + "ico": { + "label": "ICO", + "condition": "features.imageformatplugin", + "output": [ "privateFeature", "feature" ] + }, + "jpeg": { + "label": "JPEG", + "disable": "input.libjpeg == 'no'", + "condition": "features.imageformatplugin", + "output": [ + "privateFeature", + { "type": "define", "negative": true, "name": "QT_NO_IMAGEFORMAT_JPEG" } + ] + }, + "system-jpeg": { + "label": " Using system libjpeg", + "disable": "input.libjpeg == 'qt'", + "enable": "input.libjpeg == 'system'", + "condition": "features.jpeg && libs.libjpeg", + "output": [ "privateFeature" ] + }, + "png": { + "label": "PNG", + "disable": "input.libpng == 'no'", + "output": [ + "privateFeature", + { "type": "define", "negative": true, "name": "QT_NO_IMAGEFORMAT_PNG" } + ] + }, + "system-png": { + "label": " Using system libpng", + "disable": "input.libpng == 'qt'", + "enable": "input.libpng == 'system'", + "autoDetect": "features.system-zlib", + "condition": "features.png && libs.libpng", + "output": [ "privateFeature" ] + }, + "qpa_default_platform": { + "label": "QPA default platform", + "condition": "features.gui", + "output": [ + { "type": "define", "name": "QT_QPA_DEFAULT_PLATFORM_NAME", "value": "tests.qpa_default_platform.name" }, + { "type": "varAssign", "public": true, "name": "QT_DEFAULT_QPA_PLUGIN", "value": "tests.qpa_default_platform.plugin", + "condition": "!features.shared" } + ] + }, + "sessionmanager": { + "label": "Session Management", + "purpose": "Provides an interface to the windowing system's session management.", + "section": "Kernel", + "output": [ "publicFeature", "feature" ] + }, + "tslib": { + "label": "tslib", + "condition": "libs.tslib", + "output": [ "privateFeature" ] + }, + "tuiotouch": { + "label": "TuioTouch", + "purpose": "Provides the TuioTouch input plugin.", + "condition": "features.network && features.udpsocket", + "output": [ "privateFeature" ] + }, + "xcb": { + "label": "XCB", + "section": "Platform plugins", + "autoDetect": "!config.darwin", + "condition": "features.thread && libs.xcb && tests.xcb_syslibs && features.xkbcommon-x11", + "output": [ "privateFeature" ] + }, + "x11-prefix": { + "label": "X11 prefix", + "emitIf": "features.xcb", + "output": [ { "type": "varAssign", "name": "QMAKE_X11_PREFIX", "value": "tests.x11prefix.value" } ] + }, + "xcb-glx-plugin": { + "label": "GLX Plugin", + "emitIf": "features.xcb", + "condition": "features.xcb-xlib && features.opengl && !features.opengles2", + "output": [ "privateFeature" ] + }, + "xcb-glx": { + "label": " XCB GLX", + "emitIf": "features.xcb && features.xcb-glx-plugin", + "condition": "libs.xcb_glx", + "output": [ "privateFeature" ] + }, + "xcb-egl-plugin": { + "label": "EGL-X11 Plugin", + "emitIf": "features.xcb", + "condition": "features.egl_x11 && features.opengl", + "output": [ "privateFeature" ] + }, + "xcb-native-painting": { + "label": "Native painting (experimental)", + "autoDetect": false, + "emitIf": "features.xcb", + "condition": "features.xcb-xlib && features.fontconfig && libs.xrender", + "output": [ "privateFeature" ] + }, + "xrender": { + "label": "XRender for native painting", + "emitIf": "features.xcb && features.xcb-native-painting", + "condition": "features.xcb-native-painting", + "output": [ "privateFeature" ] + }, + "xcb-xlib": { + "label": "XCB Xlib", + "condition": "features.xlib && libs.xcb_xlib", + "output": [ "privateFeature" ] + }, + "xcb-sm": { + "label": "xcb-sm", + "emitIf": "features.xcb", + "condition": "features.sessionmanager && libs.x11sm", + "output": [ "privateFeature" ] + }, + "system-xcb-xinput": { + "label": "Using system-provided xcb-xinput", + "emitIf": "features.xcb", + "disable": "input.bundled-xcb-xinput == 'yes'", + "enable": "input.bundled-xcb-xinput == 'no'", + "condition": "libs.xcb_xinput", + "output": [ "privateFeature" ] + }, + "xkbcommon": { + "label": "xkbcommon", + "condition": "libs.xkbcommon", + "output": [ "privateFeature" ] + }, + "xkbcommon-x11": { + "label": "xkbcommon-x11", + "condition": "features.xkbcommon && libs.xkbcommon_x11", + "output": [ "privateFeature" ] + }, + "xlib": { + "label": "XLib", + "autoDetect": "!config.darwin || features.xcb", + "condition": "libs.xlib", + "output": [ "privateFeature" ] + }, + "texthtmlparser": { + "label": "HtmlParser", + "purpose": "Provides a parser for HTML.", + "section": "Kernel", + "output": [ "publicFeature", "feature" ] + }, + "textmarkdownreader": { + "label": "MarkdownReader", + "disable": "input.libmd4c == 'no'", + "enable": "input.libmd4c == 'system' || input.libmd4c == 'qt' || input.libmd4c == 'yes'", + "purpose": "Provides a Markdown (CommonMark and GitHub) reader", + "section": "Kernel", + "output": [ "publicFeature" ] + }, + "system-textmarkdownreader": { + "label": " Using system libmd4c", + "disable": "input.libmd4c == 'qt'", + "enable": "input.libmd4c == 'system'", + "section": "Kernel", + "condition": "libs.libmd4c", + "output": [ "publicFeature" ] + }, + "textmarkdownwriter": { + "label": "MarkdownWriter", + "purpose": "Provides a Markdown (CommonMark) writer", + "section": "Kernel", + "output": [ "publicFeature" ] + }, + "textodfwriter": { + "label": "OdfWriter", + "purpose": "Provides an ODF writer.", + "section": "Kernel", + "condition": "features.xmlstreamwriter", + "output": [ "publicFeature", "feature" ] + }, + "cssparser": { + "label": "CssParser", + "purpose": "Provides a parser for Cascading Style Sheets.", + "section": "Kernel", + "output": [ "publicFeature", "feature" ] + }, + "draganddrop": { + "label": "Drag and Drop", + "purpose": "Supports the drag and drop mechansim.", + "section": "Kernel", + "condition": "features.imageformat_xpm", + "output": [ "publicFeature", "feature" ] + }, + "shortcut": { + "label": "QShortcut", + "purpose": "Provides keyboard accelerators and shortcuts.", + "section": "Kernel", + "output": [ "publicFeature", "feature" ] + }, + "action": { + "label": "QAction", + "purpose": "Provides widget actions.", + "section": "Kernel", + "output": [ "publicFeature", "feature" ] + }, + "cursor": { + "label": "QCursor", + "purpose": "Provides mouse cursors.", + "section": "Kernel", + "output": [ "publicFeature", "feature" ] + }, + "clipboard": { + "label": "QClipboard", + "purpose": "Provides cut and paste operations.", + "section": "Kernel", + "condition": "!config.integrity && !config.qnx && !config.rtems", + "output": [ "publicFeature", "feature" ] + }, + "wheelevent": { + "label": "QWheelEvent", + "purpose": "Supports wheel events.", + "section": "Kernel", + "output": [ "publicFeature", "feature" ] + }, + "tabletevent": { + "label": "QTabletEvent", + "purpose": "Supports tablet events.", + "section": "Kernel", + "output": [ "publicFeature", "feature" ] + }, + "im": { + "label": "QInputContext", + "purpose": "Provides complex input methods.", + "section": "Kernel", + "condition": "features.library", + "output": [ "publicFeature", "feature" ] + }, + "highdpiscaling": { + "label": "High DPI Scaling", + "purpose": "Provides automatic scaling of DPI-unaware applications on high-DPI displays.", + "section": "Kernel", + "output": [ "publicFeature", "feature" ] + }, + "validator": { + "label": "QValidator", + "purpose": "Supports validation of input text.", + "section": "Widgets", + "output": [ "publicFeature", "feature" ] + }, + "standarditemmodel": { + "label": "QStandardItemModel", + "purpose": "Provides a generic model for storing custom data.", + "section": "ItemViews", + "condition": "features.itemmodel", + "output": [ "publicFeature", "feature" ] + }, + "imageformatplugin": { + "label": "QImageIOPlugin", + "purpose": "Provides a base for writing a image format plugins.", + "section": "Images", + "output": [ "publicFeature", "feature" ] + }, + "movie": { + "label": "QMovie", + "purpose": "Supports animated images.", + "section": "Images", + "output": [ "publicFeature", "feature" ] + }, + "imageformat_bmp": { + "label": "BMP Image Format", + "purpose": "Supports Microsoft's Bitmap image file format.", + "section": "Images", + "output": [ "publicFeature", "feature" ] + }, + "imageformat_ppm": { + "label": "PPM Image Format", + "purpose": "Supports the Portable Pixmap image file format.", + "section": "Images", + "output": [ "publicFeature", "feature" ] + }, + "imageformat_xbm": { + "label": "XBM Image Format", + "purpose": "Supports the X11 Bitmap image file format.", + "section": "Images", + "output": [ "publicFeature", "feature" ] + }, + "imageformat_xpm": { + "label": "XPM Image Format", + "purpose": "Supports the X11 Pixmap image file format.", + "section": "Images", + "output": [ "publicFeature", "feature" ] + }, + "imageformat_png": { + "label": "PNG Image Format", + "purpose": "Supports the Portable Network Graphics image file format.", + "section": "Images", + "output": [ "publicFeature", "feature" ] + }, + "imageformat_jpeg": { + "label": "JPEG Image Format", + "purpose": "Supports the Joint Photographic Experts Group image file format.", + "section": "Images", + "output": [ "publicFeature", "feature" ] + }, + "image_heuristic_mask": { + "label": "QImage::createHeuristicMask()", + "purpose": "Supports creating a 1-bpp heuristic mask for images.", + "section": "Images", + "output": [ "publicFeature", "feature" ] + }, + "image_text": { + "label": "Image Text", + "purpose": "Supports image file text strings.", + "section": "Images", + "output": [ "publicFeature", "feature" ] + }, + "picture": { + "label": "QPicture", + "purpose": "Supports recording and replaying QPainter commands.", + "section": "Painting", + "output": [ "publicFeature", "feature" ] + }, + "colornames": { + "label": "Color Names", + "purpose": "Supports color names such as \"red\", used by QColor and by some HTML documents.", + "section": "Painting", + "output": [ "publicFeature", "feature" ] + }, + "pdf": { + "label": "QPdf", + "purpose": "Provides a PDF backend for QPainter.", + "section": "Painting", + "condition": "features.temporaryfile", + "output": [ "publicFeature", "feature" ] + }, + "desktopservices": { + "label": "QDesktopServices", + "purpose": "Provides methods for accessing common desktop services.", + "section": "Utilities", + "output": [ "publicFeature", "feature" ] + }, + "systemtrayicon": { + "label": "QSystemTrayIcon", + "purpose": "Provides an icon for an application in the system tray.", + "section": "Utilities", + "condition": "features.temporaryfile", + "output": [ "publicFeature", "feature" ] + }, + "accessibility": { + "label": "Accessibility", + "purpose": "Provides accessibility support.", + "section": "Utilities", + "condition": "features.properties", + "output": [ "publicFeature", "feature" ] + }, + "multiprocess": { + "label": "Multi process", + "purpose": "Provides support for detecting the desktop environment, launching external processes and opening URLs.", + "section": "Utilities", + "condition": "!config.integrity && !config.rtems", + "output": [ "privateFeature" ] + }, + "whatsthis": { + "label": "QWhatsThis", + "purpose": "Supports displaying \"What's this\" help.", + "section": "Widget Support", + "output": [ "publicFeature", "feature" ] + }, + "raster-64bit": { + "label": "QPainter - 64 bit raster", + "purpose": "Internal painting support for 64 bit (16 bpc) rasterization.", + "section": "Painting", + "output": [ "privateFeature" ] + } + }, + + "earlyReport": [ + { + "type": "error", + "condition": "input.xcb != '' && input.xcb != 'no' && input.xkbcommon == 'no'", + "message": "XCB plugin requires xkbcommon and xkbcommon-x11, but -no-xkbcommon was provided." + } + ], + + "report": [ + { + "type": "note", + "condition": "features.xcb && config.darwin", + "message": "XCB support on macOS is minimal and untested. Some features will +not work properly or at all (e.g. OpenGL, desktop services or accessibility), +or may depend on your system and XQuartz setup." + }, + { + "type": "note", + "condition": "features.accessibility && features.xcb && !features.accessibility-atspi-bridge", + "message": "Disabling X11 Accessibility Bridge: D-Bus or AT-SPI is missing." + }, + { + "type": "warning", + "condition": "input.qpa-platform-guard != ''", + "message": "The [-no]-qpa-platform-guard argument is deprecated and has no effect." + }, + { + "type": "warning", + "condition": "features.gui && config.linux && !config.android && !features.xcb && !features.eglfs && !features.directfb && !features.linuxfb", + "message": "No QPA platform plugin enabled! This will +produce a Qt that cannot run GUI applications. +See \"Platform backends\" in the output of --help." + }, + { + "type": "warning", + "condition": "config.win32 && (features.opengles2 || features.opengl-dynamic) && !features.angle", + "message": "Using OpenGL ES 2.0 on Windows without ANGLE. +The build will most likely fail. +Specify -opengl desktop to use regular OpenGL." + }, + { + "type": "warning", + "condition": "config.darwin && features.system-harfbuzz", + "message": "On OS X, AAT is supported only with -qt-harfbuzz." + }, + { + "type": "error", + "condition": "features.gui && !config.watchos && input.opengl != 'no' && !features.opengl-desktop && !features.opengles2 && !features.opengl-dynamic", + "message": "The OpenGL functionality tests failed! +You might need to modify the include and library search paths by editing QMAKE_INCDIR_OPENGL[_ES2], +QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your platform." + }, + { + "type": "warning", + "condition": "!features.accessibility", + "message": "Accessibility disabled. This configuration of Qt is unsupported." + } + ], + + "summary": [ + { + "section": "Qt Gui", + "entries": [ + "accessibility", + "freetype", + "system-freetype", + "harfbuzz", + "system-harfbuzz", + "fontconfig", + { + "section": "Image formats", + "entries": [ + "gif", "ico", "jpeg", "system-jpeg", "png", "system-png" + ] + }, + { + "section": "Text formats", + "entries": [ + "texthtmlparser", "cssparser", "textodfwriter", "textmarkdownreader", "system-textmarkdownreader", "textmarkdownwriter" + ] + }, + "egl", + "openvg", + { + "section": "OpenGL", + "entries": [ + { + "type": "feature", + "args": "angle", + "condition": "config.win32" + }, + { + "type": "feature", + "args": "combined-angle-lib", + "condition": "features.angle" + }, + "opengl-desktop", + { + "type": "feature", + "args": "opengl-dynamic", + "condition": "config.win32" + }, + "opengles2", + "opengles3", + "opengles31", + "opengles32" + ] + }, + "vulkan", + "sessionmanager" + ] + }, + { + "section": "Features used by QPA backends", + "entries": [ + "evdev", + "libinput", + "integrityhid", + "mtdev", + "tslib", + "xkbcommon", + { + "section": "X11 specific", + "entries": [ + "xlib", + "xcb-xlib", + "egl_x11", + "xkbcommon-x11" + ] + } + ] + }, + { + "section": "QPA backends", + "entries": [ + "directfb", "eglfs", + { + "section": "EGLFS details", + "condition": "features.eglfs", + "entries": [ + "eglfs_openwfd", "eglfs_viv", "eglfs_viv_wl", "eglfs_rcar", "eglfs_egldevice", "eglfs_gbm", "eglfs_vsp2", "eglfs_mali", "eglfs_brcm", "eglfs_x11" + ] + }, + "linuxfb", "vnc", + { + "type": "feature", + "condition": "config.integrity", + "args": "integrityfb" + }, + { + "section": "QNX", + "condition": "config.qnx", + "entries": [ + "lgmon", "qqnx_imf" + ] + }, + { + "section": "XCB", + "condition": "features.xcb", + "entries": [ + "system-xcb-xinput", "xcb-native-painting", + { + "section": "GL integrations", + "entries": [ + "xcb-glx-plugin", + "xcb-glx", + "xcb-egl-plugin" + ] + } + ] + }, + { + "section": "Windows", + "condition": "config.win32", + "entries": [ + "direct2d", "directwrite", "directwrite2" + ] + } + ] + } + ] +} diff --git a/contrib/build-appimage.sh b/contrib/build-appimage.sh new file mode 100644 index 0000000..a8d7cf7 --- /dev/null +++ b/contrib/build-appimage.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -e + +function verify_hash() { + local file=$1 expected_hash=$2 + actual_hash=$(sha256sum $file | awk '{print $1}') + if [ "$actual_hash" == "$expected_hash" ]; then + return 0 + else + echo "$file $actual_hash (unexpected hash)" >&2 + rm "$file" + exit 1 + fi +} + +function download_if_not_exist() { + local file_name=$1 url=$2 + if [ ! -e $file_name ] ; then + wget -q -O $file_name "$url" + fi +} + +APPDIR="$PWD/feather.AppDir" +mkdir -p "$APPDIR" +mkdir -p "$APPDIR/usr/share/applications/" +mkdir -p "$APPDIR/usr/bin" + +echo "Downloading dependencies" + +download_if_not_exist "feather.zip" "https://build.featherwallet.org/files/linux-release/$BRANCH/$FN" +unzip -q feather.zip + +cp "$PWD/src/assets/feather.desktop" "$APPDIR/usr/share/applications/feather.desktop" +cp "$PWD/src/assets/images/appicons/64x64.png" "$APPDIR/feather.png" +cp "$PWD/feather" "$APPDIR/usr/bin/feather" + +/appimagetool deploy "$APPDIR/usr/share/applications/feather.desktop" +VERSION=1.0 /appimagetool ./feather.AppDir + diff --git a/contrib/build_tor.sh b/contrib/build_tor.sh new file mode 100755 index 0000000..1af2d32 --- /dev/null +++ b/contrib/build_tor.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +# this file is used by feather's CMake +# arguments: ./build.tor $TAG $ROOT_FEATHER_DIR + +set -ex + +ERR_WIN="This script does not work on Windows" +if [[ "$OSTYPE" == "msys" ]]; then + echo "$ERR_WIN" + exit 1 +elif [[ "$OSTYPE" == "win32" ]]; then + echo "$ERR_WIN" + exit 1 +fi + +TOR_TAG="$1" +ROOT_DIR="$2" +STATIC="$3" +TOR_DIR="$ROOT_DIR/contrib/tor" +TORSOCKS_DIR="$ROOT_DIR/contrib/torsocks" +TARGET_DIR="$ROOT_DIR/src/tor" + +CPU_CORE_COUNT="$(nproc)" + +# +### tor +# + +pushd "$TOR_DIR" + +rm -rf "$TOR_DIR/build" +mkdir -p "$TOR_DIR/build" + +# configure +git -C "$TOR_DIR" fetch +git -C "$TOR_DIR" checkout tor-0.4.3.5 +bash "$TOR_DIR/autogen.sh" + +if [[ "$STATIC" = "ON" ]]; then + # static assumes that openssl has been compiled with: + # CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./config no-asm no-shared no-zlib-dynamic --prefix=/usr/local/openssl --openssldir=/usr/local/openssl + # and libevent with: + # cmake -DEVENT_LIBRARY_STATIC=ON -DOPENSSL_ROOT_DIR=/usr/local/openssl -DCMAKE_INSTALL_PREFIX=/usr/local/libevent + # and zlib with: + # CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --static --prefix=/usr/local/zlib + + LDFLAGS="-L/usr/local/openssl/lib/" LIBS="-lssl -lcrypto -lpthread -ldl" CPPFLAGS="-I/usr/local/openssl/include/" ./configure \ + --enable-static-zlib \ + --enable-static-openssl \ + --enable-static-libevent \ + --disable-system-torrc \ + --with-libevent-dir=/usr/local/libevent \ + --with-openssl-dir=/usr/local/openssl/ \ + --with-zlib-dir=/usr/local/zlib \ + --disable-system-torrc \ + --disable-tool-name-check \ + --disable-systemd \ + --disable-lzma \ + --disable-unittests \ + --disable-zstd \ + --disable-seccomp \ + --disable-asciidoc \ + --disable-manpage \ + --disable-html-manual \ + --disable-system-torrc \ + --prefix="$TOR_DIR/build" +else + bash "$TOR_DIR/configure" \ + --disable-tool-name-check \ + --disable-systemd \ + --disable-lzma \ + --disable-unittests \ + --disable-zstd \ + --disable-asciidoc \ + --disable-manpage \ + --disable-html-manual \ + --prefix="$TOR_DIR/build" +fi + +# build +make -j "$CPU_CORE_COUNT" +make install -j "$CPU_CORE_COUNT" + +# copy to lib/tor +cp "$TOR_DIR/build/bin/tor" "$TARGET_DIR" +cp "$TOR_DIR/build/etc/tor/torrc.sample"* "$TARGET_DIR" + +# +### torsocks +# + +pushd "$TORSOCKS_DIR" +mkdir -p "$TORSOCKS_DIR/build" + +# configure +bash "$TORSOCKS_DIR/autogen.sh" +bash "$TORSOCKS_DIR/configure" --prefix="$TORSOCKS_DIR/build" + +# build +make -j "$CPU_CORE_COUNT" +make install -j "$CPU_CORE_COUNT" + +# copy to lib/torsocks +cp "$TORSOCKS_DIR/build/lib/torsocks/"* "$TARGET_DIR" +cp "$TORSOCKS_DIR/build/bin/"* "$TARGET_DIR" +cp "$TORSOCKS_DIR/build/etc/tor/"* "$TARGET_DIR" + +# +### verify installation +# + +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + for fn in "$TARGET_DIR/libtorsocks.so" "$TARGET_DIR/tor"; do + if [[ ! -f "$fn" ]]; then + echo "[*] Failed to install tor or torsocks: no such file $fn" + exit 1 + fi; done +elif [[ "$OSTYPE" == "darwin"* ]]; then + for fn in "$TARGET_DIR/libtorsocks.dylib" "$TARGET_DIR/tor"; do + if [[ ! -f "$fn" ]]; then + echo "[*] Failed to install tor or torsocks: no such file $fn" + exit 1 + fi; done +fi + +echo "[*] Compiled tor/torsocks into $TARGET_DIR" diff --git a/contrib/tor b/contrib/tor new file mode 160000 index 0000000..e687707 --- /dev/null +++ b/contrib/tor @@ -0,0 +1 @@ +Subproject commit e68770719ef4d3d3b83398715b1e10391ab6a1b4 diff --git a/contrib/torsocks b/contrib/torsocks new file mode 160000 index 0000000..4c00ec8 --- /dev/null +++ b/contrib/torsocks @@ -0,0 +1 @@ +Subproject commit 4c00ec8773fd63fa48ef49e1ccf2adac598427be diff --git a/contrib/torsocks_macos.patch b/contrib/torsocks_macos.patch new file mode 100644 index 0000000..648c65d --- /dev/null +++ b/contrib/torsocks_macos.patch @@ -0,0 +1,53 @@ +From fc5eafeb2886605d4de1546846f06a12a18c87ef Mon Sep 17 00:00:00 2001 +From: "J.W" +Date: Mon, 22 Apr 2019 05:19:32 +0100 +Subject: [PATCH 1/2] Fix macros for accept4(2) + +Both accept(2) and accept4(2) exist on linux but accept4(2) does not +exist on macos 10.11.6 (and maybe other distros). +--- + src/lib/torsocks.c | 9 ++++++++- + src/lib/torsocks.h | 4 +++- + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/src/lib/torsocks.c b/src/lib/torsocks.c +index 16f2da0..9527513 100644 +--- a/src/lib/torsocks.c ++++ b/src/lib/torsocks.c +@@ -234,9 +234,16 @@ static void init_libc_symbols(void) + tsocks_libc_socket = dlsym(libc_ptr, LIBC_SOCKET_NAME_STR); + tsocks_libc_syscall = dlsym(libc_ptr, LIBC_SYSCALL_NAME_STR); + tsocks_libc_execve = dlsym(libc_ptr, LIBC_EXECVE_NAME_STR); ++ tsocks_libc_accept = dlsym(libc_ptr, LIBC_ACCEPT_NAME_STR); ++#if (defined(__linux__)) + tsocks_libc_accept4 = dlsym(libc_ptr, LIBC_ACCEPT4_NAME_STR); ++#endif ++ + if (!tsocks_libc_connect || !tsocks_libc_close || !tsocks_libc_socket || +- !tsocks_libc_syscall || !tsocks_libc_execve || ! tsocks_libc_accept4) { ++#if (defined(__linux__)) ++ !tsocks_libc_accept4 || ++#endif ++ !tsocks_libc_syscall || !tsocks_libc_execve || ! tsocks_libc_accept) { + ERR("Unable to lookup symbols in " LIBC_NAME "(%s)", dlerror()); + goto error; + } +diff --git a/src/lib/torsocks.h b/src/lib/torsocks.h +index 33da526..bf9109d 100644 +--- a/src/lib/torsocks.h ++++ b/src/lib/torsocks.h +@@ -30,8 +30,10 @@ + * libc call outside of torsocks can be used. These are declared for each + * symbol torsocks hijacked. + */ ++#define TSOCKS_LIBC_FUNC(name) \ ++ tsocks_libc_##name + #define TSOCKS_LIBC_DECL(name, type, sig) \ +- type (*tsocks_libc_##name)(sig); ++ type (*TSOCKS_LIBC_FUNC(name))(sig); + #define TSOCKS_DECL(name, type, sig) \ + extern type tsocks_##name(sig); + +-- +2.21.0 + diff --git a/contrib/unbound_static.patch b/contrib/unbound_static.patch new file mode 100644 index 0000000..a680fd5 --- /dev/null +++ b/contrib/unbound_static.patch @@ -0,0 +1,18 @@ +diff --git a/configure_checks.cmake b/configure_checks.cmake +index c31b3f33..50b3305d 100644 +--- a/configure_checks.cmake ++++ b/configure_checks.cmake +@@ -202,10 +202,10 @@ check_symbol_exists(NID_X9_62_prime256v1 "openssl/evp.h" HAVE_DECL_NID_X9_62_PRI + check_symbol_exists(sk_SSL_COMP_pop_free "openssl/ssl.h" HAVE_DECL_SK_SSL_COMP_POP_FREE) + check_symbol_exists(SSL_COMP_get_compression_methods "openssl/ssl.h" HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS) + +-check_function_exists(EVP_MD_CTX_new HAVE_EVP_MD_CTX_NEW) ++set(HAVE_EVP_MD_CTX_NEW 1) + check_function_exists(EVP_sha1 HAVE_EVP_SHA1) +-check_function_exists(EVP_sha256 HAVE_EVP_SHA256) +-check_function_exists(EVP_sha512 HAVE_EVP_SHA512) ++set(HAVE_EVP_SHA256 1) ++set(HAVE_EVP_SHA512 1) + check_function_exists(FIPS_mode HAVE_FIPS_MODE) + check_function_exists(HMAC_Update HAVE_HMAC_UPDATE) + check_function_exists(OPENSSL_config HAVE_OPENSSL_CONFIG) diff --git a/monero b/monero new file mode 160000 index 0000000..a1404e9 --- /dev/null +++ b/monero @@ -0,0 +1 @@ +Subproject commit a1404e92cb439ba0f120e7c4a579ed0b9a0372a4 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..19021c3 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,216 @@ +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +# pthread +find_package(Threads REQUIRED) + +find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets) + +add_subdirectory(libwalletqt) +add_subdirectory(model) +add_subdirectory(utils) +add_subdirectory(openpgp) + +qt5_add_resources(RESOURCES assets.qrc) + +# Compile source files (.h/.cpp) +file(GLOB SOURCE_FILES + "*.h" + "*.cpp" + "utils/*.h" + "utils/*.cpp" + "libwalletqt/*.h" + "libwalletqt/*.cpp" + "daemon/*.h" + "daemon/*.cpp" + "model/*.h" + "model/*.cpp" + "qt/*.h" + "qt/*.cpp" + "ui/qdarkstyle/style.qrc" + "ui/BreezeStyleSheets/breeze.qrc" + "widgets/*.h" + "widgets/*.cpp" + "wizard/*.h" + "wizard/*.cpp" + "wallet/*.h" + "wallet/*.cpp" + "qrcode/*.h" + "qrcode/*.cpp" + "dialog/*.h" + "dialog/*.cpp" + ) + +if(APPLE AND BUILD_TOR) + set(ASSETS_OS "assets_macos_tor.qrc") +elseif(UNIX AND NOT APPLE AND BUILD_TOR) + set(ASSETS_OS "assets_linux_tor.qrc") +elseif(MINGW AND BUILD_TOR) + set(ASSETS_OS "assets_windows_tor.qrc") +else() + message(STATUS "Building without embedded Tor") +endif() + +set(EXECUTABLE_FLAG) +if(MINGW) + set(EXECUTABLE_FLAG WIN32) + + set(ICON ${PROJECT_SOURCE_DIR}/src/assets/images/appicons/appicon.ico) + set(ICON_RC ${CMAKE_CURRENT_BINARY_DIR}/icon.rc) + set(ICON_RES ${CMAKE_CURRENT_BINARY_DIR}/icon.o) + file(WRITE ${ICON_RC} "IDI_ICON1 ICON DISCARDABLE \"${ICON}\"") + add_custom_command(OUTPUT ${ICON_RES} COMMAND windres ${ICON_RC} ${ICON_RES} MAIN_DEPENDENCY ${ICON_RC}) + list(APPEND RESOURCES ${ICON_RES}) +endif() + +# mac os bundle +if(APPLE) + set(ICON ${PROJECT_SOURCE_DIR}/src/assets/images/appicons/appicon.icns) + set_source_files_properties(${ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") + list(APPEND RESOURCES ${ICON}) +endif() + +add_executable(feather ${EXECUTABLE_FLAG} main.cpp + ${SOURCE_FILES} + ${RESOURCES} + ${ASSETS_OS} + ) + +# mac os bundle +set_target_properties(feather PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/utils/Info.plist" +) + +set_property(TARGET feather PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + +target_include_directories(feather PUBLIC ${OPENGL_INCLUDE_DIR}) +target_include_directories(feather PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) + +file(GLOB_RECURSE SRC_SOURCES *.cpp) +file(GLOB_RECURSE SRC_HEADERS *.h) + +target_include_directories(feather PUBLIC + ${CMAKE_BINARY_DIR}/src/feather_autogen/include + ${CMAKE_SOURCE_DIR}/monero/include + ${CMAKE_SOURCE_DIR}/monero/src + ${CMAKE_SOURCE_DIR}/monero/external/easylogging++ + ${CMAKE_SOURCE_DIR}/monero/contrib/epee/include + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/daemon + ${CMAKE_CURRENT_SOURCE_DIR}/libwalletqt + ${CMAKE_CURRENT_SOURCE_DIR}/model + ${CMAKE_CURRENT_SOURCE_DIR}/utils + ${CMAKE_CURRENT_SOURCE_DIR}/tor + ${CMAKE_CURRENT_SOURCE_DIR}/qrcode + ${X11_INCLUDE_DIR} + ${Boost_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIR} + ${Qt5Core_INCLUDE_DIRS} + ${Qt5Widgets_INCLUDE_DIRS} + ${Qt5Gui_INCLUDE_DIRS} + ${Qt5Network_INCLUDE_DIRS} + ${Qt5Svg_INCLUDE_DIRS} + ${Qt5Xml_INCLUDE_DIRS} + ${Qt5WebSockets_INCLUDE_DIRS} + ) + +if(DONATE_BEG) + target_compile_definitions(feather PRIVATE DONATE_BEG=1) +endif() + +if(BUILD_TOR) + target_compile_definitions(feather PRIVATE BUILD_TOR=1) +endif() + +if(XMRTO) + target_compile_definitions(feather PRIVATE XMRTO=1) +endif() + +if(HAVE_SYS_PRCTL_H) + target_compile_definitions(feather PRIVATE HAVE_SYS_PRCTL_H=1) +endif() + +if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_definitions(feather PRIVATE QT_NO_DEBUG=1) +endif() + +target_compile_definitions(feather + PUBLIC + ${Qt5Core_DEFINITIONS} + ${Qt5Widgets_DEFINITIONS} + ${Qt5Gui_DEFINITIONS} + ${Qt5Network_DEFINITIONS} + ${Qt5Svg_DEFINITIONS} + ${Qt5Xml_DEFINITIONS} + ${Qt5WebSockets_DEFINITIONS} + ) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") + +if(UNIX AND NOT APPLE) + # https://stackoverflow.com/questions/57766620/cmake-add-library-doesnt-initialize-static-global-variable + # so that contrib/monero-seed/src/gf_elem.cpp properly initializes. A better solution is welcome. + target_link_libraries(feather -Wl,--whole-archive monero-seed::monero-seed -Wl,--no-whole-archive) +else() + target_link_libraries(feather monero-seed::monero-seed) +endif() + +target_link_libraries(feather + wallet_merged + ${LMDB_LIBRARY} + epee + ${UNBOUND_LIBRARY} + ${SODIUM_LIBRARY} + easylogging + blockchain_db + randomx + hardforks + ${Boost_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${CMAKE_DL_LIBS} + ${EXTRA_LIBRARIES} + Qt5::Core + Qt5::Widgets + Qt5::Gui + Qt5::Network + Qt5::Svg + Qt5::Xml + Qt5::WebSockets + ${ICU_LIBRARIES} + openpgp + Threads::Threads + ${QRENCODE_LIBRARY} + ) + +if(NOT APPLE) + target_link_libraries(feather + Qt5::QSvgIconPlugin + Qt5::QSvgPlugin + ) +endif() + +if(STATIC) + target_link_libraries(feather + Qt5::QSvgIconPlugin + Qt5::QSvgPlugin) + if(UNIX AND NOT APPLE) + target_link_libraries(feather + Qt5::QXcbIntegrationPlugin) + endif() +endif() + +if(X11_FOUND) + target_link_libraries(feather ${X11_LIBRARIES}) +endif() + +if(APPLE) + include(Deploy) +endif() + +install(TARGETS feather + DESTINATION ${CMAKE_INSTALL_PREFIX} + ) diff --git a/src/appcontext.cpp b/src/appcontext.cpp new file mode 100644 index 0000000..60b196a --- /dev/null +++ b/src/appcontext.cpp @@ -0,0 +1,768 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include +#include +#include + +#include "appcontext.h" +#include "utils/tails.h" +#include "utils/whonix.h" +#include "utils/utils.h" +#include "utils/prices.h" +#include "utils/networktype.h" +#include "utils/wsclient.h" + +// libwalletqt +#include "libwalletqt/WalletManager.h" +#include "libwalletqt/Wallet.h" +#include "libwalletqt/TransactionHistory.h" +#include "libwalletqt/SubaddressAccount.h" +#include "libwalletqt/Subaddress.h" +#include "libwalletqt/Coins.h" +#include "model/TransactionHistoryModel.h" +#include "model/SubaddressAccountModel.h" +#include "model/SubaddressModel.h" +#include "utils/keysfiles.h" +#include "utils/networktype.h" +#include "utils/config.h" + + +Prices *AppContext::prices = nullptr; +WalletKeysFilesModel *AppContext::wallets = nullptr; +TxFiatHistory *AppContext::txFiatHistory = nullptr; +double AppContext::balance = 0; +QMap AppContext::txDescriptionCache; + +AppContext::AppContext(QCommandLineParser *cmdargs) { + this->network = new QNetworkAccessManager(); + this->networkClearnet = new QNetworkAccessManager(); + this->cmdargs = cmdargs; + +#if defined(Q_OS_MAC) + this->isTorSocks = qgetenv("DYLD_INSERT_LIBRARIES").indexOf("libtorsocks") >= 0; +#elif defined(Q_OS_LINUX) + this->isTorSocks = qgetenv("LD_PRELOAD").indexOf("libtorsocks") >= 0; +#elif defined(Q_OS_WIN) + this->isTorSocks = false; +#endif + + this->isTails = TailsOS::detect(); + this->isWhonix = WhonixOS::detect(); + + //Paths + this->configRoot = QDir::homePath(); + if (isTails) { // #if defined(PORTABLE) + QString portablePath = []{ + QString appImagePath = qgetenv("APPIMAGE"); + if (appImagePath.isEmpty()) { + qDebug() << "Not an appimage, using currentPath()"; + return QDir::currentPath() + "/.feather"; + } + + QFileInfo appImageDir(appImagePath); + return appImageDir.absoluteDir().path() + "/.feather"; + }(); + + + if (QDir().mkpath(portablePath)) { + this->configRoot = portablePath; + } else { + qCritical() << "Unable to create portable directory: " << portablePath; + } + } + + this->accountName = Utils::getUnixAccountName(); + this->homeDir = QDir::homePath(); + +#if defined(Q_OS_LINUX) or defined(Q_OS_MAC) + this->defaultWalletDir = QString("%1/Monero/wallets").arg(this->configRoot); + this->defaultWalletDirRoot = QString("%1/Monero").arg(this->configRoot); +#elif defined(Q_OS_WIN) + // @TODO +#endif + + // Create ~/Monero/wallets if it does not exist yet + if (!QDir().mkpath(defaultWalletDir)) + qCritical() << "Unable to create dir: " << defaultWalletDir; + + this->configDirectory = QString("%1/.config/feather/").arg(this->configRoot); +#if defined(Q_OS_UNIX) + if(!this->configDirectory.endsWith('/')) + this->configDirectory = QString("%1/").arg(this->configDirectory); +#endif + this->sorry(); + + // Config + createConfigDirectory(this->configDirectory); + + if(this->cmdargs->isSet("stagenet")) + this->networkType = NetworkType::STAGENET; + else if(this->cmdargs->isSet("testnet")) + this->networkType = NetworkType::TESTNET; + else + this->networkType = NetworkType::MAINNET; + +// auto nodeSourceUInt = config()->get(Config::nodeSource).toUInt(); +// AppContext::nodeSource = static_cast(nodeSourceUInt); + this->nodes = new Nodes(this, this->networkClearnet); + connect(this, &AppContext::nodeSourceChanged, this->nodes, &Nodes::onNodeSourceChanged); + connect(this, &AppContext::setCustomNodes, this->nodes, &Nodes::setCustomNodes); + connect(this, &AppContext::walletClosing, this->nodes, &Nodes::onWalletClosing); + + // Tor & socks proxy + this->ws = new WSClient(this, m_wsUrl); + connect(this->ws, &WSClient::WSMessage, this, &AppContext::onWSMessage); + + // timers + m_storeTimer->setSingleShot(true); + connect(this->m_storeTimer, &QTimer::timeout, [this](){ + if (!this->currentWallet) + return; + qDebug() << "Storing wallet"; + this->currentWallet->store(); + }); + + // restore height lookup + this->initRestoreHeights(); + + // price history lookup + auto genesis_timestamp = this->restoreHeights[NetworkType::Type::MAINNET]->data.firstKey(); + AppContext::txFiatHistory = new TxFiatHistory(genesis_timestamp, this->configDirectory); + connect(this->ws, &WSClient::connectionEstablished, AppContext::txFiatHistory, &TxFiatHistory::onUpdateDatabase); + connect(AppContext::txFiatHistory, &TxFiatHistory::requestYear, [=](unsigned int year){ + QByteArray data = QString(R"({"cmd": "txFiatHistory", "data": {"year": %1}})").arg(year).toUtf8(); + this->ws->sendMsg(data); + }); + connect(AppContext::txFiatHistory, &TxFiatHistory::requestYearMonth, [=](unsigned int year, unsigned int month) { + QByteArray data = QString(R"({"cmd": "txFiatHistory", "data": {"year": %1, "month": %2}})").arg(year).arg(month).toUtf8(); + this->ws->sendMsg(data); + }); + + // fiat/crypto lookup + AppContext::prices = new Prices(); + + // xmr.to +#if defined(XMRTO) + this->XMRTo = new XmrTo(this); +#endif + + this->walletManager = WalletManager::instance(); + QString logPath = QString("%1/daemon.log").arg(configDirectory); + Monero::Utils::onStartup(); + Monero::Wallet::init("", "feather", logPath.toStdString(), true); + + bool logLevelFromEnv; + int logLevel = qEnvironmentVariableIntValue("MONERO_LOG_LEVEL", &logLevelFromEnv); + if(this->cmdargs->isSet("quiet")) + this->walletManager->setLogLevel(-1); + else if (logLevelFromEnv && logLevel >= 0 && logLevel <= Monero::WalletManagerFactory::LogLevel_Max) + Monero::WalletManagerFactory::setLogLevel(logLevel); + + connect(this, &AppContext::createTransactionError, this, &AppContext::onCreateTransactionError); + + // libwallet connects + connect(this->walletManager, &WalletManager::walletOpened, this, &AppContext::onWalletOpened); +} + +void AppContext::initTor() { + this->tor = new Tor(this); + this->tor->start(); + + if (!(isTails || isWhonix)) { + auto networkProxy = new QNetworkProxy(QNetworkProxy::Socks5Proxy, Tor::torHost, Tor::torPort); + this->network->setProxy(*networkProxy); + if (m_wsUrl.host().endsWith(".onion")) + this->ws->webSocket.setProxy(*networkProxy); + } + +} + +void AppContext::initWS() { + this->ws->start(); +} + +void AppContext::onCancelTransaction(PendingTransaction *tx, const QString &address) { + // tx cancelled by user + double amount = tx->amount() / AppContext::cdiv; + emit createTransactionCancelled(address, amount); + this->currentWallet->disposeTransaction(tx); +} + +void AppContext::onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) const { + if(this->currentWallet == nullptr){ + qCritical() << "Cannot create transaction; no wallet loaded"; + return; + } + + if (churn) { + address = this->currentWallet->address(0, 0); // primary address + } + + qCritical() << "Creating transaction"; + this->currentWallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority); +} + +void AppContext::onCreateTransaction(XmrToOrder *order) { + // tx creation via xmr.to + const QString description = QString("XmrTo order %1").arg(order->uuid); + this->onCreateTransaction(order->receiving_subaddress, order->incoming_amount_total, description, false); +} + +void AppContext::onCreateTransaction(const QString &address, const double amount, const QString &description, bool all) { + // tx creation + this->tmpTxDescription = description; + + if(this->currentWallet == nullptr) { + emit createTransactionError("Cannot create transaction; no wallet loaded"); + return; + } + + if (!all && amount <= 0) { + emit createTransactionError("Cannot send nothing"); + return; + } + + auto balance = this->currentWallet->balance() / AppContext::cdiv; + auto unlocked_balance = this->currentWallet->unlockedBalance() / AppContext::cdiv; + if(!all && amount > unlocked_balance) { + emit createTransactionError("Not enough money to spend"); + return; + } else if(unlocked_balance == 0) { + emit createTransactionError("No money to spend"); + return; + } + + auto amount_num = static_cast(amount * AppContext::cdiv); + qDebug() << "creating tx"; + if(all || amount == balance) + this->currentWallet->createTransactionAllAsync(address, "", this->tx_mixin, this->tx_priority); + else + this->currentWallet->createTransactionAsync(address, "", amount_num, this->tx_mixin, this->tx_priority); + + emit initiateTransaction(); +} + +void AppContext::onCreateTransactionError(const QString &msg) { + this->tmpTxDescription = ""; + emit endTransaction(); +} + +void AppContext::walletClose(bool emitClosedSignal) { + this->nodes->stopTimer(); + if(this->currentWallet == nullptr) return; + emit walletClosing(); + //ctx->currentWallet->store(); @TODO: uncomment to store on wallet close + this->currentWallet->disconnect(); + this->walletManager->closeWallet(); + if(this->currentWallet != nullptr) + this->currentWallet = nullptr; + if(emitClosedSignal) + emit walletClosed(); +} + +void AppContext::onOpenWallet(const QString &path, const QString &password){ + if(this->currentWallet != nullptr){ + emit walletOpenedError("There is an active wallet opened."); + return; + } + + if(!Utils::fileExists(path)) { + emit walletOpenedError(QString("Wallet not found: %1").arg(path)); + return; + } + + config()->set(Config::firstRun, false); + + this->walletPath = path; + this->walletManager->openWalletAsync(path, password, this->networkType, 1); +} + +void AppContext::onPreferredFiatCurrencyChanged(const QString &symbol) { + if(this->currentWallet) { + auto *model = this->currentWallet->transactionHistoryModel(); + if(model != nullptr) { + model->preferredFiatSign = AppContext::prices->fiat[symbol]; + model->preferredFiatSymbol = symbol; + } + } +} + +void AppContext::onWalletOpened(Wallet *wallet) { + auto state = wallet->status(); + if (state != Wallet::Status_Ok) { + auto errMsg = wallet->errorString(); + if(errMsg == QString("basic_string::_M_replace_aux") || errMsg == QString("std::bad_alloc")) { + qCritical() << errMsg; + this->walletManager->clearWalletCache(this->walletPath); + errMsg = QString("%1\n\nAttempted to clean wallet cache. Please restart Feather.").arg(errMsg); + this->walletClose(false); + emit walletOpenedError(errMsg); + } else if(errMsg.contains("wallet cannot be opened as")) { + this->walletClose(false); + emit walletOpenedError(errMsg); + } else if(errMsg.contains("is opened by another wallet program")) { + this->walletClose(false); + emit walletOpenedError(errMsg); + } else { + this->walletClose(false); + emit walletOpenPasswordNeeded(this->walletPassword.isEmpty()); + } + return; + } + + this->currentWallet = wallet; + this->walletPath = this->currentWallet->path() + ".keys"; + config()->set(Config::walletPath, this->walletPath); + + connect(this->currentWallet, &Wallet::moneySpent, this, &AppContext::onMoneySpent); + connect(this->currentWallet, &Wallet::moneyReceived, this, &AppContext::onMoneyReceived); + connect(this->currentWallet, &Wallet::unconfirmedMoneyReceived, this, &AppContext::onUnconfirmedMoneyReceived); + connect(this->currentWallet, &Wallet::newBlock, this, &AppContext::onWalletNewBlock); + connect(this->currentWallet, &Wallet::updated, this, &AppContext::onWalletUpdate); + connect(this->currentWallet, &Wallet::refreshed, this, &AppContext::onWalletRefreshed); + connect(this->currentWallet, &Wallet::transactionCommitted, this, &AppContext::onTransactionCommitted); + connect(this->currentWallet, &Wallet::heightRefreshed, this, &AppContext::onHeightRefreshed); + connect(this->currentWallet, &Wallet::transactionCreated, this, &AppContext::onTransactionCreated); + connect(this->currentWallet, &Wallet::connectionStatusChanged, this, &AppContext::onConnectionStatusChanged); + + this->nodes->connectToNode(); + + emit walletOpened(); + this->updateBalance(); + +#ifdef DONATE_BEG + this->donateBeg(); +#endif + + // force trigger preferredFiat signal for history model + this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString()); +} + +void AppContext::onWSMessage(const QJsonObject &msg) { + QString cmd = msg.value("cmd").toString(); + + if(cmd == "blockheights") { + auto heights = msg.value("data").toObject(); + auto mainnet = heights.value("mainnet").toInt(); + auto stagenet = heights.value("stagenet").toInt(); + auto changed = false; + + if(!this->heights.contains("mainnet")) { + this->heights["mainnet"] = (unsigned int) mainnet; + changed = true; + } + else { + if (mainnet > this->heights["mainnet"]) { + this->heights["mainnet"] = (unsigned int) mainnet; + changed = true; + } + } + if(!this->heights.contains("stagenet")) { + this->heights["stagenet"] = (unsigned int) stagenet; + changed = true; + } + else { + if (stagenet > this->heights["stagenet"]) { + this->heights["stagenet"] = (unsigned int) stagenet; + changed = true; + } + } + + if(changed) + emit blockHeightWSUpdated(this->heights); + } + + else if(cmd == "nodes") { + this->onWSNodes(msg.value("data").toArray()); + } + + else if(cmd == "crypto_rates") { + QJsonArray crypto_rates = msg.value("data").toArray(); + AppContext::prices->cryptoPricesReceived(crypto_rates); + } + + else if(cmd == "fiat_rates") { + QJsonObject fiat_rates = msg.value("data").toObject(); + AppContext::prices->fiatPricesReceived(fiat_rates); + } +#if defined(XMRTO) + else if(cmd == "xmrto_rates") { + auto xmr_rates = msg.value("data").toObject(); + this->XMRTo->onRatesReceived(xmr_rates); + } +#endif + else if(cmd == "reddit") { + QJsonArray reddit_data = msg.value("data").toArray(); + this->onWSReddit(reddit_data); + } + + else if(cmd == "ccs") { + auto ccs_data = msg.value("data").toArray(); + this->onWSCCS(ccs_data); + } + + else if(cmd == "txFiatHistory") { + auto txFiatHistory_data = msg.value("data").toObject(); + AppContext::txFiatHistory->onWSData(txFiatHistory_data); + } +} + +void AppContext::onWSNodes(const QJsonArray &nodes) { + QList> l; + for (auto &&entry: nodes) { + auto obj = entry.toObject(); + auto nettype = obj.value("nettype"); + auto type = obj.value("type"); + + // filter remote node network types + if(nettype == "mainnet" && this->networkType != NetworkType::MAINNET) + continue; + if(nettype == "stagenet" && this->networkType != NetworkType::STAGENET) + continue; + if(nettype == "testnet" && this->networkType != NetworkType::TESTNET) + continue; + + if(type == "clearnet" && (this->isTails || this->isWhonix || this->isTorSocks)) + continue; + if(type == "tor" && (!(this->isTails || this->isWhonix || this->isTorSocks))) + continue; + + auto node = new FeatherNode( + obj.value("address").toString(), + (unsigned int)obj.value("height").toInt(), + obj.value("online").toBool()); + QSharedPointer r = QSharedPointer(node); + l.append(r); + } + this->nodes->onWSNodesReceived(l); +} + +void AppContext::onWSReddit(const QJsonArray& reddit_data) { + QList> l; + + for (auto &&entry: reddit_data) { + auto obj = entry.toObject(); + auto redditPost = new RedditPost( + obj.value("title").toString(), + obj.value("author").toString(), + obj.value("url").toString(), + obj.value("comments").toInt()); + QSharedPointer r = QSharedPointer(redditPost); + l.append(r); + } + + emit redditUpdated(l); +} + +void AppContext::onWSCCS(const QJsonArray &ccs_data) { + QList> l; + + + QStringList fonts = {"state", "address", "author", "date", + "title", "target_amount", "raised_amount", + "percentage_funded", "contributions"}; + + for (auto &&entry: ccs_data) { + auto obj = entry.toObject(); + auto c = QSharedPointer(new CCSEntry()); + + if (obj.value("state").toString() != "FUNDING-REQUIRED") + continue; + + c->state = obj.value("state").toString(); + c->address = obj.value("address").toString(); + c->author = obj.value("author").toString(); + c->date = obj.value("date").toString(); + c->title = obj.value("title").toString(); + c->url = obj.value("url").toString(); + c->target_amount = obj.value("target_amount").toDouble(); + c->raised_amount = obj.value("raised_amount").toDouble(); + c->percentage_funded = obj.value("percentage_funded").toDouble(); + c->contributions = obj.value("contributions").toInt(); + l.append(c); + } + + if(l.count() == 0) + emit ccsEmpty(); + + emit ccsUpdated(l); +} + +void AppContext::createConfigDirectory(const QString &dir) { + if(!Utils::dirExists(dir)) { + qDebug() << QString("Creating directory: %1").arg(dir); + if(!QDir().mkpath(dir)) + throw std::runtime_error("Could not create directory " + dir.toStdString()); + } + + QString config_dir_tor = QString("%1%2").arg(dir).arg("tor"); + if(!Utils::dirExists(config_dir_tor)) { + qDebug() << QString("Creating directory: %1").arg(config_dir_tor); + if (!QDir().mkpath(config_dir_tor)) + throw std::runtime_error("Could not create directory " + config_dir_tor.toStdString()); + } + + QString config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data"); + if(!Utils::dirExists(config_dir_tordata)) { + qDebug() << QString("Creating directory: %1").arg(config_dir_tordata); + if (!QDir().mkpath(config_dir_tordata)) + throw std::runtime_error("Could not create directory " + config_dir_tordata.toStdString()); + } + + QString config_dir_torsocks = QString("%1%2").arg(dir).arg("torsocks"); + if(!Utils::dirExists(config_dir_torsocks)) { + qDebug() << QString("Creating directory: %1").arg(config_dir_torsocks); + if (!QDir().mkpath(config_dir_torsocks)) + throw std::runtime_error("Could not create directory " + config_dir_torsocks.toStdString()); + } +} + +void AppContext::createWallet(FeatherSeed seed, const QString &path, const QString &password) { + if(Utils::fileExists(path)) { + auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path); + qCritical() << err; + emit walletCreatedError(err); + return; + } + + this->currentWallet = seed.writeWallet(this->walletManager, this->networkType, path, password, this->kdfRounds); + if(this->currentWallet == nullptr) { + emit walletCreatedError("Failed to write wallet"); + return; + } + + this->currentWallet->setPassword(password); + this->currentWallet->store(); + this->walletPassword = password; + emit walletCreated(this->currentWallet); +} + +void AppContext::initRestoreHeights() { + restoreHeights[NetworkType::TESTNET] = new RestoreHeightLookup(NetworkType::TESTNET); + restoreHeights[NetworkType::STAGENET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_monero_stagenet.txt", NetworkType::STAGENET); + restoreHeights[NetworkType::MAINNET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_monero_mainnet.txt", NetworkType::MAINNET); +} + +void AppContext::onSetRestoreHeight(unsigned int height){ + auto seed = this->currentWallet->getCacheAttribute("feather.seed"); + if(!seed.isEmpty()) { + const auto msg = "This wallet has a 14 word mnemonic seed which has the restore height embedded."; + emit setRestoreHeightError(msg); + return; + } + + this->currentWallet->setWalletCreationHeight(height); + this->currentWallet->setPassword(this->walletPassword); // trigger .keys write + + // nuke wallet cache + const auto fn = this->currentWallet->path(); + this->walletManager->clearWalletCache(fn); + + emit customRestoreHeightSet(height); +} + +void AppContext::onOpenAliasResolve(const QString &openAlias) { + // @TODO: calling this freezes for about 1-2 seconds :/ + const auto result = this->walletManager->resolveOpenAlias(openAlias); + const auto spl = result.split("|"); + auto msg = QString(""); + if(spl.count() != 2) { + msg = "Internal error"; + emit openAliasResolveError(msg); + return; + } + + const auto &status = spl.at(0); + const auto &address = spl.at(1); + const auto valid = this->walletManager->addressValid(address, this->networkType); + if(status == "false"){ + if(valid){ + msg = "Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed"; + emit openAliasResolveError(msg); + return; + } else { + msg = "No valid address found at this OpenAlias address, but the DNSSEC signatures could not be verified, so this may be spoofed"; + emit openAliasResolveError(msg); + return; + } + } else if(status != "true") { + msg = "Internal error"; + emit openAliasResolveError(msg); + return; + } + + if(valid){ + emit openAliasResolved(address, openAlias); + return; + } + + msg = QString("Address validation error."); + if(!address.isEmpty()) + msg += QString(" Perhaps it is of the wrong network type." + "\n\nOpenAlias: %1\nAddress: %2").arg(openAlias).arg(address); + emit openAliasResolveError(msg); +} + +void AppContext::donateBeg() { + if(this->networkType != NetworkType::Type::MAINNET) + return; + + auto donationCounter = config()->get(Config::donateBeg).toInt(); + if(donationCounter == -1) + return; // previously donated + + donationCounter += 1; + if (donationCounter % m_donationBoundary == 0) + emit donationNag(); + config()->set(Config::donateBeg, donationCounter); +} + +void AppContext::sorry() { + auto msg = "Unable to start Feather, error code 0xd34db33f. If this problem " + "persists, please contact Technical Support."; + QStringList paths = {"C:\\ProgramData\\ryo", this->homeDir + "/.ryo"}; + for(const QString &ryo: paths) + if(Utils::dirExists(ryo)) + throw std::runtime_error(msg); +} + +AppContext::~AppContext() { + this->walletClose(false); +} + +// ############################################## LIBWALLET QT ######################################################### + +void AppContext::onMoneySpent(const QString &txId, quint64 amount) { + auto amount_num = amount / AppContext::cdiv; + qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num); +} + +void AppContext::onMoneyReceived(const QString &txId, quint64 amount) { + // Incoming tx included in a block. + auto amount_num = amount / AppContext::cdiv; + qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num); +} + +void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount) { + // Incoming transaction in pool + auto amount_num = amount / AppContext::cdiv; + qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num); + + if(this->currentWallet->synchronized()) { + auto notify = QString("%1 XMR (pending)").arg(amount_num); + Utils::desktopNotify("Payment received", notify, 5000); + } +} + +void AppContext::onWalletUpdate() { + if (this->currentWallet->synchronized()) { + this->refreshModels(); + } + + this->updateBalance(); + this->storeWallet(); +} + +void AppContext::onWalletRefreshed() { + if (!this->refreshed) { + refreshModels(); + this->refreshed = true; + this->storeWallet(); + } + + this->currentWallet->refreshHeightAsync(); +} + +void AppContext::onWalletNewBlock(quint64 blockheight, quint64 targetHeight) { + this->syncStatusUpdated(blockheight, targetHeight); + + if (this->currentWallet->synchronized()) { + this->currentWallet->coins()->refreshUnlocked(); + this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount()); + // Todo: only refresh tx confirmations + } +} + +void AppContext::onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) { + qDebug() << Q_FUNC_INFO << walletHeight << daemonHeight << targetHeight; + + if (!this->currentWallet->connected()) + return; + + if (daemonHeight < targetHeight) { + emit blockchainSync(daemonHeight, targetHeight); + } + else { + this->syncStatusUpdated(walletHeight, daemonHeight); + } +} + +void AppContext::onTransactionCreated(PendingTransaction *tx, const QString &address, const QString &paymentId, quint32 mixin) { + if(address == this->featherDonationAddress) + this->featherDonationSending = true; + + // tx created, but not sent yet. ask user to verify first. + emit createTransactionSuccess(tx, address, mixin); + emit endTransaction(); +} + +void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid){ + this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount()); + this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount()); + this->storeWallet(); + emit transactionCommitted(status, tx, txid); + + // this tx was a donation to Feather, stop our nagging + if(this->featherDonationSending) { + this->featherDonationSending = false; + config()->set(Config::donateBeg, -1); + } +} + +void AppContext::onConnectionStatusChanged(int status) { + +} + +void AppContext::storeWallet() { + if (m_storeTimer->isActive()) + return; + + m_storeTimer->start(60000); +} + +void AppContext::updateBalance() { + if(!this->currentWallet) + throw std::runtime_error("this should not happen, ever"); + + AppContext::balance = this->currentWallet->balance() / AppContext::cdiv; + auto balance_str = QString::number(balance); + + double unlocked = this->currentWallet->unlockedBalance() / AppContext::cdiv; + auto unlocked_str = QString::number(unlocked); + + emit balanceUpdated(balance, unlocked, balance_str, unlocked_str); +} + +void AppContext::syncStatusUpdated(quint64 height, quint64 target) { + if (height < (target - 1)) { + emit refreshSync(height, target); + } + else { + this->updateBalance(); + emit synchronized(); + } +} + +void AppContext::refreshModels() { + if (!this->currentWallet) + return; + + this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount()); + this->currentWallet->subaddress()->refresh(this->currentWallet->currentSubaddressAccount()); + this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount()); + // Todo: set timer for refreshes +} diff --git a/src/appcontext.h b/src/appcontext.h new file mode 100644 index 0000000..fe8ccf1 --- /dev/null +++ b/src/appcontext.h @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_APPCONTEXT_H +#define FEATHER_APPCONTEXT_H + +#include +#include +#include +#include + +#include "utils/tails.h" +#include "utils/prices.h" +#include "utils/networking.h" +#include "utils/tor.h" +#include "utils/xmrto.h" +#include "utils/wsclient.h" +#include "utils/txfiathistory.h" +#include "widgets/RedditPost.h" +#include "widgets/CCSEntry.h" +#include "utils/seeds.h" +#include "utils/nodes.h" + +#include "libwalletqt/WalletManager.h" +#include "utils/keysfiles.h" +#include "PendingTransaction.h" + +#define SUBADDRESS_LOOKAHEAD_MINOR 200 + + +class AppContext : public QObject +{ +Q_OBJECT + +public: + explicit AppContext(QCommandLineParser *cmdargs); + ~AppContext(); + bool isTails = false; + bool isWhonix = false; + bool isDebug = false; + const QString featherDonationAddress = "47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f"; + const int featherDonationAmount = 50; // euro + bool featherDonationSending = false; + + QCommandLineParser *cmdargs; + + QString coinName = "monero"; + bool isTorSocks = false; + QString homeDir; + QString accountName; + QString configRoot; + QString configDirectory; + QString defaultWalletDir; + QString defaultWalletDirRoot; + QString tmpTxDescription; + + QString walletPath; + QString walletPassword = ""; + NetworkType::Type networkType; + + QString applicationPath; + + static void createConfigDirectory(const QString &dir) ; + + QMap heights; + QMap restoreHeights; + const unsigned int kdfRounds = 1; + PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low; + quint32 tx_mixin = static_cast(10); + static constexpr const double cdiv = 1e12; + + QNetworkAccessManager *network; + QNetworkAccessManager *networkClearnet; + QNetworkProxy *networkProxy; + + Tor *tor; + WSClient *ws; + XmrTo *XMRTo; + Nodes *nodes; + static Prices *prices; + static WalletKeysFilesModel *wallets; + static double balance; + static QMap txDescriptionCache; + static TxFiatHistory *txFiatHistory; + + // libwalletqt + unsigned int blockHeight = 0; + bool refreshed = false; + WalletManager *walletManager; + Wallet *currentWallet = nullptr; + void createWallet(FeatherSeed seed, const QString &path, const QString &password); + void syncStatusUpdated(quint64 height, quint64 target); + void updateBalance(); + void initTor(); + void initRestoreHeights(); + void initWS(); + void donateBeg(); + void walletClose(bool emitClosedSignal = true); + void storeWallet(); + void refreshModels(); + +public slots: + void onOpenWallet(const QString& path, const QString &password); + void onCreateTransaction(const QString &address, const double amount, const QString &description, bool all); + void onCreateTransaction(XmrToOrder *order); + void onCancelTransaction(PendingTransaction *tx, const QString &address); + void onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) const; + void onCreateTransactionError(const QString &msg); + void onOpenAliasResolve(const QString &openAlias); + void onSetRestoreHeight(unsigned int height); + void onPreferredFiatCurrencyChanged(const QString &symbol); + +private slots: + void onWSNodes(const QJsonArray &nodes); + void onWSMessage(const QJsonObject& msg); + void onWSCCS(const QJsonArray &ccs_data); + void onWSReddit(const QJsonArray& reddit_data); + + void onMoneySpent(const QString &txId, quint64 amount); + void onMoneyReceived(const QString &txId, quint64 amount); + void onUnconfirmedMoneyReceived(const QString &txId, quint64 amount); + void onWalletUpdate(); + void onWalletRefreshed(); + void onWalletOpened(Wallet *wallet); + void onWalletNewBlock(quint64 blockheight, quint64 targetHeight); + void onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight); + void onTransactionCreated(PendingTransaction *tx, const QString &address, const QString &paymentId, quint32 mixin); + void onTransactionCommitted(bool status, PendingTransaction *t, const QStringList& txid); + void onConnectionStatusChanged(int status); + +signals: + void balanceUpdated(double balance, double unlocked, QString balance_str, QString unlocked_str); + void blockchainSync(int height, int target); + void refreshSync(int height, int target); + void synchronized(); + void blockHeightWSUpdated(QMap heights); + void walletSynchronized(); + void walletOpened(); + void walletClosed(); + void walletCreatedError(const QString &msg); + void walletCreated(Wallet *wallet); + void walletOpenedError(QString msg); + void walletOpenPasswordNeeded(bool invalidPassword); + void transactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid); + void createTransactionError(QString message); + void createTransactionCancelled(QString address, double amount); + void createTransactionSuccess(PendingTransaction *tx, const QString &address, const quint32 &mixin); + void redditUpdated(QList> &posts); + void nodesUpdated(QList> &nodes); + void ccsUpdated(QList> &entries); + void nodeSourceChanged(NodeSource nodeSource); + void setCustomNodes(QList nodes); + void ccsEmpty(); + void openAliasResolveError(const QString &msg); + void openAliasResolved(const QString &address, const QString &openAlias); + void setRestoreHeightError(const QString &msg); + void customRestoreHeightSet(unsigned int height); + void closeApplication(); + void donationNag(); + void initiateTransaction(); + void endTransaction(); + void walletClosing(); + +private: + void sorry(); + const unsigned int m_donationBoundary = 15; + UtilsNetworking *m_utilsNetworkingNodes; + QTimer *m_storeTimer = new QTimer(this); + QUrl m_wsUrl = QUrl(QStringLiteral("ws://6wku2m4zrv6j666crlo7lzofv6ud6enzllyhou3ijeigpukymi37caad.onion/ws")); +}; + +#endif //FEATHER_APPCONTEXT_H diff --git a/src/assets.qrc b/src/assets.qrc new file mode 100644 index 0000000..2fa1f64 --- /dev/null +++ b/src/assets.qrc @@ -0,0 +1,100 @@ + + + assets/about.txt + assets/ack.txt + assets/contributors.txt + assets/feather.desktop + assets/images/appicons/32x32.png + assets/images/appicons/48x48.png + assets/images/appicons/64x64.png + assets/images/appicons/96x96.png + assets/images/appicons/128x128.png + assets/images/appicons/256x256.png + assets/images/arrow.svg + assets/images/bitcoin.png + assets/images/camera_dark.png + assets/images/camera_white.png + assets/images/clock1.png + assets/images/clock2.png + assets/images/clock3.png + assets/images/clock4.png + assets/images/clock5.png + assets/images/coins.png + assets/images/coldcard.png + assets/images/coldcard_unpaired.png + assets/images/confirmed.png + assets/images/confirmed.svg + assets/images/connect.svg + assets/images/copy.png + assets/images/cutexmrfox.png + assets/images/edit.png + assets/images/exchange.png + assets/images/expired.png + assets/images/eye1.png + assets/images/feather.png + assets/images/file.png + assets/images/ghost.png + assets/images/history.png + assets/images/info.png + assets/images/key.png + assets/images/ledger.png + assets/images/ledger_unpaired.png + assets/images/lightning.png + assets/images/lock.png + assets/images/lock.svg + assets/images/microphone.png + assets/images/network.png + assets/images/offline_tx.png + assets/images/person.svg + assets/images/photos/1.png + assets/images/preferences.png + assets/images/preferences.svg + assets/images/qrcode.png + assets/images/qrcode_white.png + assets/images/revealer_c.png + assets/images/revealer.png + assets/images/seal.png + assets/images/seed.png + assets/images/speaker.png + assets/images/status_connected_fork.png + assets/images/status_connected.png + assets/images/status_connected_proxy_fork.png + assets/images/status_connected_proxy.png + assets/images/status_connected_proxy.svg + assets/images/status_connected.svg + assets/images/status_disconnected.png + assets/images/status_disconnected.svg + assets/images/status_lagging_fork.png + assets/images/status_lagging.png + assets/images/status_lagging.svg + assets/images/status_waiting.png + assets/images/status_waiting.svg + assets/images/tab_addresses.png + assets/images/tab_coins.png + assets/images/tab_console.png + assets/images/tab_contacts.png + assets/images/tab_history.png + assets/images/tab_home.png + assets/images/tab_party.png + assets/images/tab_receive.png + assets/images/tab_send.png + assets/images/terminal.png + assets/images/tor_logo_disabled.png + assets/images/tor_logo.png + assets/images/trezor.png + assets/images/trezor_unpaired.png + assets/images/unconfirmed.png + assets/images/unlock.png + assets/images/unlock.svg + assets/images/unpaid.png + assets/images/update.png + assets/images/warning.png + assets/images/xmrto_big.png + assets/images/xmrto.png + assets/images/zoom.png + assets/mnemonic_25_english.txt + assets/restore_heights_monero_mainnet.txt + assets/restore_heights_monero_stagenet.txt + assets/user_agents.txt + + diff --git a/src/assets/about.txt b/src/assets/about.txt new file mode 100644 index 0000000..ac20d39 --- /dev/null +++ b/src/assets/about.txt @@ -0,0 +1,33 @@ +Feather () + +https://featherwallet.org + +Created by dsc , tobtoht , and contributors. + +Copyright (c) 2020-, The Monero Project + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be + used to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/assets/ack.txt b/src/assets/ack.txt new file mode 100644 index 0000000..bb21a5b --- /dev/null +++ b/src/assets/ack.txt @@ -0,0 +1,10 @@ +Feather uses monero-seed written by Tevador, for 14 word mnemonic seeds. + +Initial CMake support for the Monero GUI was coded by TheCharlatan/xiphon. + +The wallet UI is heavily inspired by Electrum. We would like to recognize Thomas Voegtlin for his pioneering work on Bitcoin. + +Huge thanks to nioc, fluffypony, wowario, thrmo for help during development. + +Some more shoutouts for people for hosting nodes and/or having good ideas: +dnale0r, dEBRUYNE, binaryFate, lza_menace, jwinterm, kico, wowario diff --git a/src/assets/contributors.txt b/src/assets/contributors.txt new file mode 100644 index 0000000..251d72c --- /dev/null +++ b/src/assets/contributors.txt @@ -0,0 +1,5 @@ +dsc +tobtoht +selsta +Diego Salazar +Matt Smith \ No newline at end of file diff --git a/src/assets/feather.desktop b/src/assets/feather.desktop new file mode 100644 index 0000000..56a851c --- /dev/null +++ b/src/assets/feather.desktop @@ -0,0 +1,14 @@ +[Desktop Entry] +Comment=Lightweight Monero Wallet +Exec=feather +GenericName[en_US]=Monero Wallet +GenericName=Monero Wallet +Icon=feather +Name[en_US]=Feather +Name=Feather +Categories=Finance;Network; +StartupNotify=false +StartupWMClass=feather +Terminal=false +Type=Application +MimeType=x-scheme-handler/monero; diff --git a/src/assets/images/appicons/128x128.png b/src/assets/images/appicons/128x128.png new file mode 100644 index 0000000..496896c Binary files /dev/null and b/src/assets/images/appicons/128x128.png differ diff --git a/src/assets/images/appicons/256x256.png b/src/assets/images/appicons/256x256.png new file mode 100644 index 0000000..bbc3ddc Binary files /dev/null and b/src/assets/images/appicons/256x256.png differ diff --git a/src/assets/images/appicons/32x32.png b/src/assets/images/appicons/32x32.png new file mode 100644 index 0000000..260435f Binary files /dev/null and b/src/assets/images/appicons/32x32.png differ diff --git a/src/assets/images/appicons/48x48.png b/src/assets/images/appicons/48x48.png new file mode 100644 index 0000000..c28af77 Binary files /dev/null and b/src/assets/images/appicons/48x48.png differ diff --git a/src/assets/images/appicons/64x64.png b/src/assets/images/appicons/64x64.png new file mode 100644 index 0000000..d81babe Binary files /dev/null and b/src/assets/images/appicons/64x64.png differ diff --git a/src/assets/images/appicons/64x64.png~ b/src/assets/images/appicons/64x64.png~ new file mode 100755 index 0000000..c504f89 Binary files /dev/null and b/src/assets/images/appicons/64x64.png~ differ diff --git a/src/assets/images/appicons/96x96.png b/src/assets/images/appicons/96x96.png new file mode 100644 index 0000000..3b3bbbd Binary files /dev/null and b/src/assets/images/appicons/96x96.png differ diff --git a/src/assets/images/appicons/appicon.icns b/src/assets/images/appicons/appicon.icns new file mode 100755 index 0000000..d0df4da Binary files /dev/null and b/src/assets/images/appicons/appicon.icns differ diff --git a/src/assets/images/appicons/appicon.ico b/src/assets/images/appicons/appicon.ico new file mode 100644 index 0000000..a2092a8 Binary files /dev/null and b/src/assets/images/appicons/appicon.ico differ diff --git a/src/assets/images/appicons/monero.png b/src/assets/images/appicons/monero.png new file mode 100755 index 0000000..15d5dcf Binary files /dev/null and b/src/assets/images/appicons/monero.png differ diff --git a/src/assets/images/appicons/monero_grey.png b/src/assets/images/appicons/monero_grey.png new file mode 100755 index 0000000..5006367 Binary files /dev/null and b/src/assets/images/appicons/monero_grey.png differ diff --git a/src/assets/images/arrow.svg b/src/assets/images/arrow.svg new file mode 100644 index 0000000..54d6e0b --- /dev/null +++ b/src/assets/images/arrow.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/assets/images/bitcoin.png b/src/assets/images/bitcoin.png new file mode 100644 index 0000000..a597e86 Binary files /dev/null and b/src/assets/images/bitcoin.png differ diff --git a/src/assets/images/camera_dark.png b/src/assets/images/camera_dark.png new file mode 100644 index 0000000..c2b73f7 Binary files /dev/null and b/src/assets/images/camera_dark.png differ diff --git a/src/assets/images/camera_white.png b/src/assets/images/camera_white.png new file mode 100644 index 0000000..1a07a6f Binary files /dev/null and b/src/assets/images/camera_white.png differ diff --git a/src/assets/images/clock1.png b/src/assets/images/clock1.png new file mode 100644 index 0000000..4e6b04d Binary files /dev/null and b/src/assets/images/clock1.png differ diff --git a/src/assets/images/clock2.png b/src/assets/images/clock2.png new file mode 100644 index 0000000..ac47a29 Binary files /dev/null and b/src/assets/images/clock2.png differ diff --git a/src/assets/images/clock3.png b/src/assets/images/clock3.png new file mode 100644 index 0000000..daa4a9f Binary files /dev/null and b/src/assets/images/clock3.png differ diff --git a/src/assets/images/clock4.png b/src/assets/images/clock4.png new file mode 100644 index 0000000..4139354 Binary files /dev/null and b/src/assets/images/clock4.png differ diff --git a/src/assets/images/clock5.png b/src/assets/images/clock5.png new file mode 100644 index 0000000..64e1f74 Binary files /dev/null and b/src/assets/images/clock5.png differ diff --git a/src/assets/images/coins.png b/src/assets/images/coins.png new file mode 100644 index 0000000..1d6fb8f Binary files /dev/null and b/src/assets/images/coins.png differ diff --git a/src/assets/images/coldcard.png b/src/assets/images/coldcard.png new file mode 100644 index 0000000..74104d7 Binary files /dev/null and b/src/assets/images/coldcard.png differ diff --git a/src/assets/images/coldcard_unpaired.png b/src/assets/images/coldcard_unpaired.png new file mode 100644 index 0000000..2560407 Binary files /dev/null and b/src/assets/images/coldcard_unpaired.png differ diff --git a/src/assets/images/confirmed.png b/src/assets/images/confirmed.png new file mode 100644 index 0000000..2023abd Binary files /dev/null and b/src/assets/images/confirmed.png differ diff --git a/src/assets/images/confirmed.svg b/src/assets/images/confirmed.svg new file mode 100644 index 0000000..710b3f8 --- /dev/null +++ b/src/assets/images/confirmed.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/connect.svg b/src/assets/images/connect.svg new file mode 100644 index 0000000..fbf7be8 --- /dev/null +++ b/src/assets/images/connect.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/copy.png b/src/assets/images/copy.png new file mode 100644 index 0000000..b82da41 Binary files /dev/null and b/src/assets/images/copy.png differ diff --git a/src/assets/images/cutexmrfox.png b/src/assets/images/cutexmrfox.png new file mode 100644 index 0000000..08d3d50 Binary files /dev/null and b/src/assets/images/cutexmrfox.png differ diff --git a/src/assets/images/edit.png b/src/assets/images/edit.png new file mode 100644 index 0000000..71afe78 Binary files /dev/null and b/src/assets/images/edit.png differ diff --git a/src/assets/images/exchange.png b/src/assets/images/exchange.png new file mode 100644 index 0000000..3236959 Binary files /dev/null and b/src/assets/images/exchange.png differ diff --git a/src/assets/images/expired.png b/src/assets/images/expired.png new file mode 100644 index 0000000..6400b8b Binary files /dev/null and b/src/assets/images/expired.png differ diff --git a/src/assets/images/eye1.png b/src/assets/images/eye1.png new file mode 100644 index 0000000..0bded33 Binary files /dev/null and b/src/assets/images/eye1.png differ diff --git a/src/assets/images/feather.png b/src/assets/images/feather.png new file mode 100644 index 0000000..62af0e9 Binary files /dev/null and b/src/assets/images/feather.png differ diff --git a/src/assets/images/file.png b/src/assets/images/file.png new file mode 100644 index 0000000..ae84e25 Binary files /dev/null and b/src/assets/images/file.png differ diff --git a/src/assets/images/ghost.png b/src/assets/images/ghost.png new file mode 100644 index 0000000..d786466 Binary files /dev/null and b/src/assets/images/ghost.png differ diff --git a/src/assets/images/history.png b/src/assets/images/history.png new file mode 100644 index 0000000..7cc3065 Binary files /dev/null and b/src/assets/images/history.png differ diff --git a/src/assets/images/info.png b/src/assets/images/info.png new file mode 100644 index 0000000..f11f996 Binary files /dev/null and b/src/assets/images/info.png differ diff --git a/src/assets/images/key.png b/src/assets/images/key.png new file mode 100644 index 0000000..4470abf Binary files /dev/null and b/src/assets/images/key.png differ diff --git a/src/assets/images/ledger.png b/src/assets/images/ledger.png new file mode 100644 index 0000000..bab69ec Binary files /dev/null and b/src/assets/images/ledger.png differ diff --git a/src/assets/images/ledger_unpaired.png b/src/assets/images/ledger_unpaired.png new file mode 100644 index 0000000..65db1ea Binary files /dev/null and b/src/assets/images/ledger_unpaired.png differ diff --git a/src/assets/images/lightning.png b/src/assets/images/lightning.png new file mode 100644 index 0000000..797d3ca Binary files /dev/null and b/src/assets/images/lightning.png differ diff --git a/src/assets/images/lock.png b/src/assets/images/lock.png new file mode 100644 index 0000000..a190964 Binary files /dev/null and b/src/assets/images/lock.png differ diff --git a/src/assets/images/lock.svg b/src/assets/images/lock.svg new file mode 100644 index 0000000..9024d2a --- /dev/null +++ b/src/assets/images/lock.svg @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/microphone.png b/src/assets/images/microphone.png new file mode 100644 index 0000000..f9a271c Binary files /dev/null and b/src/assets/images/microphone.png differ diff --git a/src/assets/images/network.png b/src/assets/images/network.png new file mode 100644 index 0000000..6a5bcba Binary files /dev/null and b/src/assets/images/network.png differ diff --git a/src/assets/images/offline_tx.png b/src/assets/images/offline_tx.png new file mode 100644 index 0000000..32fee54 Binary files /dev/null and b/src/assets/images/offline_tx.png differ diff --git a/src/assets/images/person.svg b/src/assets/images/person.svg new file mode 100644 index 0000000..c078249 --- /dev/null +++ b/src/assets/images/person.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/photos/1.png b/src/assets/images/photos/1.png new file mode 100644 index 0000000..c3d5e19 Binary files /dev/null and b/src/assets/images/photos/1.png differ diff --git a/src/assets/images/preferences.png b/src/assets/images/preferences.png new file mode 100644 index 0000000..b10ba6e Binary files /dev/null and b/src/assets/images/preferences.png differ diff --git a/src/assets/images/preferences.svg b/src/assets/images/preferences.svg new file mode 100644 index 0000000..39f7bd1 --- /dev/null +++ b/src/assets/images/preferences.svg @@ -0,0 +1,686 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + System Preferences + + + Andreas Nilsson + + + + + category + system + preferences + settings + control center + + + + + Jakub Steiner +Ulisse Perusin + + + + + + + + + + + + + + image/svg+xml + + Preferences + + + Andreas Nilsson + + + + + Lapo Calamandrei, Ulisse Perusin, Jakub Steiner + + + + + + category + system + preferences + settings + control center + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/qrcode.png b/src/assets/images/qrcode.png new file mode 100644 index 0000000..41a84aa Binary files /dev/null and b/src/assets/images/qrcode.png differ diff --git a/src/assets/images/qrcode_white.png b/src/assets/images/qrcode_white.png new file mode 100644 index 0000000..23ea916 Binary files /dev/null and b/src/assets/images/qrcode_white.png differ diff --git a/src/assets/images/revealer.png b/src/assets/images/revealer.png new file mode 100644 index 0000000..9caef09 Binary files /dev/null and b/src/assets/images/revealer.png differ diff --git a/src/assets/images/revealer_c.png b/src/assets/images/revealer_c.png new file mode 100644 index 0000000..993d8fc Binary files /dev/null and b/src/assets/images/revealer_c.png differ diff --git a/src/assets/images/seal.png b/src/assets/images/seal.png new file mode 100644 index 0000000..f6d51ba Binary files /dev/null and b/src/assets/images/seal.png differ diff --git a/src/assets/images/seed.png b/src/assets/images/seed.png new file mode 100644 index 0000000..54c38b6 Binary files /dev/null and b/src/assets/images/seed.png differ diff --git a/src/assets/images/speaker.png b/src/assets/images/speaker.png new file mode 100644 index 0000000..963db53 Binary files /dev/null and b/src/assets/images/speaker.png differ diff --git a/src/assets/images/status_connected.png b/src/assets/images/status_connected.png new file mode 100644 index 0000000..1fe3dac Binary files /dev/null and b/src/assets/images/status_connected.png differ diff --git a/src/assets/images/status_connected.svg b/src/assets/images/status_connected.svg new file mode 100644 index 0000000..e077999 --- /dev/null +++ b/src/assets/images/status_connected.svg @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Lapo Calamandrei + + + + + + + + record + media + + + + + Jakub Steiner + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/status_connected_fork.png b/src/assets/images/status_connected_fork.png new file mode 100644 index 0000000..a65c2a8 Binary files /dev/null and b/src/assets/images/status_connected_fork.png differ diff --git a/src/assets/images/status_connected_proxy.png b/src/assets/images/status_connected_proxy.png new file mode 100644 index 0000000..ff553d9 Binary files /dev/null and b/src/assets/images/status_connected_proxy.png differ diff --git a/src/assets/images/status_connected_proxy.svg b/src/assets/images/status_connected_proxy.svg new file mode 100644 index 0000000..5e44b5e --- /dev/null +++ b/src/assets/images/status_connected_proxy.svg @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Lapo Calamandrei + + + + + + + + record + media + + + + + Jakub Steiner + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/status_connected_proxy_fork.png b/src/assets/images/status_connected_proxy_fork.png new file mode 100644 index 0000000..f6b4541 Binary files /dev/null and b/src/assets/images/status_connected_proxy_fork.png differ diff --git a/src/assets/images/status_disconnected.png b/src/assets/images/status_disconnected.png new file mode 100644 index 0000000..cb5ac1b Binary files /dev/null and b/src/assets/images/status_disconnected.png differ diff --git a/src/assets/images/status_disconnected.svg b/src/assets/images/status_disconnected.svg new file mode 100644 index 0000000..46d1a1d --- /dev/null +++ b/src/assets/images/status_disconnected.svg @@ -0,0 +1,293 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Lapo Calamandrei + + + + + Record + + + record + media + + + + + Jakub Steiner + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/status_lagging.png b/src/assets/images/status_lagging.png new file mode 100644 index 0000000..b558791 Binary files /dev/null and b/src/assets/images/status_lagging.png differ diff --git a/src/assets/images/status_lagging.svg b/src/assets/images/status_lagging.svg new file mode 100644 index 0000000..1fd4879 --- /dev/null +++ b/src/assets/images/status_lagging.svg @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Lapo Calamandrei + + + + + + + + record + media + + + + + Jakub Steiner + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/status_lagging_fork.png b/src/assets/images/status_lagging_fork.png new file mode 100644 index 0000000..8282672 Binary files /dev/null and b/src/assets/images/status_lagging_fork.png differ diff --git a/src/assets/images/status_waiting.png b/src/assets/images/status_waiting.png new file mode 100644 index 0000000..d551383 Binary files /dev/null and b/src/assets/images/status_waiting.png differ diff --git a/src/assets/images/status_waiting.svg b/src/assets/images/status_waiting.svg new file mode 100644 index 0000000..069a4d3 --- /dev/null +++ b/src/assets/images/status_waiting.svg @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + View Refresh + + + reload + refresh + view + + + + + Ricardo 'Rick' González + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/tab_addresses.png b/src/assets/images/tab_addresses.png new file mode 100644 index 0000000..449b23b Binary files /dev/null and b/src/assets/images/tab_addresses.png differ diff --git a/src/assets/images/tab_coins.png b/src/assets/images/tab_coins.png new file mode 100644 index 0000000..a6c8265 Binary files /dev/null and b/src/assets/images/tab_coins.png differ diff --git a/src/assets/images/tab_console.png b/src/assets/images/tab_console.png new file mode 100644 index 0000000..4f70e6f Binary files /dev/null and b/src/assets/images/tab_console.png differ diff --git a/src/assets/images/tab_contacts.png b/src/assets/images/tab_contacts.png new file mode 100644 index 0000000..d21ae9e Binary files /dev/null and b/src/assets/images/tab_contacts.png differ diff --git a/src/assets/images/tab_history.png b/src/assets/images/tab_history.png new file mode 100644 index 0000000..ecdc468 Binary files /dev/null and b/src/assets/images/tab_history.png differ diff --git a/src/assets/images/tab_home.png b/src/assets/images/tab_home.png new file mode 100644 index 0000000..31229b8 Binary files /dev/null and b/src/assets/images/tab_home.png differ diff --git a/src/assets/images/tab_party.png b/src/assets/images/tab_party.png new file mode 100644 index 0000000..8746f11 Binary files /dev/null and b/src/assets/images/tab_party.png differ diff --git a/src/assets/images/tab_receive.png b/src/assets/images/tab_receive.png new file mode 100644 index 0000000..ba48669 Binary files /dev/null and b/src/assets/images/tab_receive.png differ diff --git a/src/assets/images/tab_send.png b/src/assets/images/tab_send.png new file mode 100644 index 0000000..7ef90a4 Binary files /dev/null and b/src/assets/images/tab_send.png differ diff --git a/src/assets/images/tab_settings.png b/src/assets/images/tab_settings.png new file mode 100644 index 0000000..27fa530 Binary files /dev/null and b/src/assets/images/tab_settings.png differ diff --git a/src/assets/images/terminal.png b/src/assets/images/terminal.png new file mode 100644 index 0000000..95afcdf Binary files /dev/null and b/src/assets/images/terminal.png differ diff --git a/src/assets/images/tor_logo.png b/src/assets/images/tor_logo.png new file mode 100644 index 0000000..a4afd84 Binary files /dev/null and b/src/assets/images/tor_logo.png differ diff --git a/src/assets/images/tor_logo_disabled.png b/src/assets/images/tor_logo_disabled.png new file mode 100644 index 0000000..5b1984c Binary files /dev/null and b/src/assets/images/tor_logo_disabled.png differ diff --git a/src/assets/images/trezor.png b/src/assets/images/trezor.png new file mode 100644 index 0000000..3edee94 Binary files /dev/null and b/src/assets/images/trezor.png differ diff --git a/src/assets/images/trezor_unpaired.png b/src/assets/images/trezor_unpaired.png new file mode 100644 index 0000000..c9854be Binary files /dev/null and b/src/assets/images/trezor_unpaired.png differ diff --git a/src/assets/images/unconfirmed.png b/src/assets/images/unconfirmed.png new file mode 100644 index 0000000..6ebfe29 Binary files /dev/null and b/src/assets/images/unconfirmed.png differ diff --git a/src/assets/images/unlock.png b/src/assets/images/unlock.png new file mode 100644 index 0000000..869e4de Binary files /dev/null and b/src/assets/images/unlock.png differ diff --git a/src/assets/images/unlock.svg b/src/assets/images/unlock.svg new file mode 100644 index 0000000..b22e402 --- /dev/null +++ b/src/assets/images/unlock.svg @@ -0,0 +1,509 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/unpaid.png b/src/assets/images/unpaid.png new file mode 100644 index 0000000..579ec4e Binary files /dev/null and b/src/assets/images/unpaid.png differ diff --git a/src/assets/images/update.png b/src/assets/images/update.png new file mode 100644 index 0000000..e774ee1 Binary files /dev/null and b/src/assets/images/update.png differ diff --git a/src/assets/images/warning.png b/src/assets/images/warning.png new file mode 100644 index 0000000..ee3eace Binary files /dev/null and b/src/assets/images/warning.png differ diff --git a/src/assets/images/xmrto.png b/src/assets/images/xmrto.png new file mode 100644 index 0000000..b06c771 Binary files /dev/null and b/src/assets/images/xmrto.png differ diff --git a/src/assets/images/xmrto_big.png b/src/assets/images/xmrto_big.png new file mode 100644 index 0000000..3d2e063 Binary files /dev/null and b/src/assets/images/xmrto_big.png differ diff --git a/src/assets/images/zoom.png b/src/assets/images/zoom.png new file mode 100644 index 0000000..c5b58a3 Binary files /dev/null and b/src/assets/images/zoom.png differ diff --git a/src/assets/mnemonic_25_english.txt b/src/assets/mnemonic_25_english.txt new file mode 100644 index 0000000..9b92e93 --- /dev/null +++ b/src/assets/mnemonic_25_english.txt @@ -0,0 +1,1626 @@ +abbey +abducts +ability +ablaze +abnormal +abort +abrasive +absorb +abyss +academy +aces +aching +acidic +acoustic +acquire +across +actress +acumen +adapt +addicted +adept +adhesive +adjust +adopt +adrenalin +adult +adventure +aerial +afar +affair +afield +afloat +afoot +afraid +after +against +agenda +aggravate +agile +aglow +agnostic +agony +agreed +ahead +aided +ailments +aimless +airport +aisle +ajar +akin +alarms +album +alchemy +alerts +algebra +alkaline +alley +almost +aloof +alpine +already +also +altitude +alumni +always +amaze +ambush +amended +amidst +ammo +amnesty +among +amply +amused +anchor +android +anecdote +angled +ankle +annoyed +answers +antics +anvil +anxiety +anybody +apart +apex +aphid +aplomb +apology +apply +apricot +aptitude +aquarium +arbitrary +archer +ardent +arena +argue +arises +army +around +arrow +arsenic +artistic +ascend +ashtray +aside +asked +asleep +aspire +assorted +asylum +athlete +atlas +atom +atrium +attire +auburn +auctions +audio +august +aunt +austere +autumn +avatar +avidly +avoid +awakened +awesome +awful +awkward +awning +awoken +axes +axis +axle +aztec +azure +baby +bacon +badge +baffles +bagpipe +bailed +bakery +balding +bamboo +banjo +baptism +basin +batch +bawled +bays +because +beer +befit +begun +behind +being +below +bemused +benches +berries +bested +betting +bevel +beware +beyond +bias +bicycle +bids +bifocals +biggest +bikini +bimonthly +binocular +biology +biplane +birth +biscuit +bite +biweekly +blender +blip +bluntly +boat +bobsled +bodies +bogeys +boil +boldly +bomb +border +boss +both +bounced +bovine +bowling +boxes +boyfriend +broken +brunt +bubble +buckets +budget +buffet +bugs +building +bulb +bumper +bunch +business +butter +buying +buzzer +bygones +byline +bypass +cabin +cactus +cadets +cafe +cage +cajun +cake +calamity +camp +candy +casket +catch +cause +cavernous +cease +cedar +ceiling +cell +cement +cent +certain +chlorine +chrome +cider +cigar +cinema +circle +cistern +citadel +civilian +claim +click +clue +coal +cobra +cocoa +code +coexist +coffee +cogs +cohesive +coils +colony +comb +cool +copy +corrode +costume +cottage +cousin +cowl +criminal +cube +cucumber +cuddled +cuffs +cuisine +cunning +cupcake +custom +cycling +cylinder +cynical +dabbing +dads +daft +dagger +daily +damp +dangerous +dapper +darted +dash +dating +dauntless +dawn +daytime +dazed +debut +decay +dedicated +deepest +deftly +degrees +dehydrate +deity +dejected +delayed +demonstrate +dented +deodorant +depth +desk +devoid +dewdrop +dexterity +dialect +dice +diet +different +digit +dilute +dime +dinner +diode +diplomat +directed +distance +ditch +divers +dizzy +doctor +dodge +does +dogs +doing +dolphin +domestic +donuts +doorway +dormant +dosage +dotted +double +dove +down +dozen +dreams +drinks +drowning +drunk +drying +dual +dubbed +duckling +dude +duets +duke +dullness +dummy +dunes +duplex +duration +dusted +duties +dwarf +dwelt +dwindling +dying +dynamite +dyslexic +each +eagle +earth +easy +eating +eavesdrop +eccentric +echo +eclipse +economics +ecstatic +eden +edgy +edited +educated +eels +efficient +eggs +egotistic +eight +either +eject +elapse +elbow +eldest +eleven +elite +elope +else +eluded +emails +ember +emerge +emit +emotion +empty +emulate +energy +enforce +enhanced +enigma +enjoy +enlist +enmity +enough +enraged +ensign +entrance +envy +epoxy +equip +erase +erected +erosion +error +eskimos +espionage +essential +estate +etched +eternal +ethics +etiquette +evaluate +evenings +evicted +evolved +examine +excess +exhale +exit +exotic +exquisite +extra +exult +fabrics +factual +fading +fainted +faked +fall +family +fancy +farming +fatal +faulty +fawns +faxed +fazed +feast +february +federal +feel +feline +females +fences +ferry +festival +fetches +fever +fewest +fiat +fibula +fictional +fidget +fierce +fifteen +fight +films +firm +fishing +fitting +five +fixate +fizzle +fleet +flippant +flying +foamy +focus +foes +foggy +foiled +folding +fonts +foolish +fossil +fountain +fowls +foxes +foyer +framed +friendly +frown +fruit +frying +fudge +fuel +fugitive +fully +fuming +fungal +furnished +fuselage +future +fuzzy +gables +gadget +gags +gained +galaxy +gambit +gang +gasp +gather +gauze +gave +gawk +gaze +gearbox +gecko +geek +gels +gemstone +general +geometry +germs +gesture +getting +geyser +ghetto +ghost +giant +giddy +gifts +gigantic +gills +gimmick +ginger +girth +giving +glass +gleeful +glide +gnaw +gnome +goat +goblet +godfather +goes +goggles +going +goldfish +gone +goodbye +gopher +gorilla +gossip +gotten +gourmet +governing +gown +greater +grunt +guarded +guest +guide +gulp +gumball +guru +gusts +gutter +guys +gymnast +gypsy +gyrate +habitat +hacksaw +haggled +hairy +hamburger +happens +hashing +hatchet +haunted +having +hawk +haystack +hazard +hectare +hedgehog +heels +hefty +height +hemlock +hence +heron +hesitate +hexagon +hickory +hiding +highway +hijack +hiker +hills +himself +hinder +hippo +hire +history +hitched +hive +hoax +hobby +hockey +hoisting +hold +honked +hookup +hope +hornet +hospital +hotel +hounded +hover +howls +hubcaps +huddle +huge +hull +humid +hunter +hurried +husband +huts +hybrid +hydrogen +hyper +iceberg +icing +icon +identity +idiom +idled +idols +igloo +ignore +iguana +illness +imagine +imbalance +imitate +impel +inactive +inbound +incur +industrial +inexact +inflamed +ingested +initiate +injury +inkling +inline +inmate +innocent +inorganic +input +inquest +inroads +insult +intended +inundate +invoke +inwardly +ionic +irate +iris +irony +irritate +island +isolated +issued +italics +itches +items +itinerary +itself +ivory +jabbed +jackets +jaded +jagged +jailed +jamming +january +jargon +jaunt +javelin +jaws +jazz +jeans +jeers +jellyfish +jeopardy +jerseys +jester +jetting +jewels +jigsaw +jingle +jittery +jive +jobs +jockey +jogger +joining +joking +jolted +jostle +journal +joyous +jubilee +judge +juggled +juicy +jukebox +july +jump +junk +jury +justice +juvenile +kangaroo +karate +keep +kennel +kept +kernels +kettle +keyboard +kickoff +kidneys +king +kiosk +kisses +kitchens +kiwi +knapsack +knee +knife +knowledge +knuckle +koala +laboratory +ladder +lagoon +lair +lakes +lamb +language +laptop +large +last +later +launching +lava +lawsuit +layout +lazy +lectures +ledge +leech +left +legion +leisure +lemon +lending +leopard +lesson +lettuce +lexicon +liar +library +licks +lids +lied +lifestyle +light +likewise +lilac +limits +linen +lion +lipstick +liquid +listen +lively +loaded +lobster +locker +lodge +lofty +logic +loincloth +long +looking +lopped +lordship +losing +lottery +loudly +love +lower +loyal +lucky +luggage +lukewarm +lullaby +lumber +lunar +lurk +lush +luxury +lymph +lynx +lyrics +macro +madness +magically +mailed +major +makeup +malady +mammal +maps +masterful +match +maul +maverick +maximum +mayor +maze +meant +mechanic +medicate +meeting +megabyte +melting +memoir +menu +merger +mesh +metro +mews +mice +midst +mighty +mime +mirror +misery +mittens +mixture +moat +mobile +mocked +mohawk +moisture +molten +moment +money +moon +mops +morsel +mostly +motherly +mouth +movement +mowing +much +muddy +muffin +mugged +mullet +mumble +mundane +muppet +mural +musical +muzzle +myriad +mystery +myth +nabbing +nagged +nail +names +nanny +napkin +narrate +nasty +natural +nautical +navy +nearby +necklace +needed +negative +neither +neon +nephew +nerves +nestle +network +neutral +never +newt +nexus +nibs +niche +niece +nifty +nightly +nimbly +nineteen +nirvana +nitrogen +nobody +nocturnal +nodes +noises +nomad +noodles +northern +nostril +noted +nouns +novelty +nowhere +nozzle +nuance +nucleus +nudged +nugget +nuisance +null +number +nuns +nurse +nutshell +nylon +oaks +oars +oasis +oatmeal +obedient +object +obliged +obnoxious +observant +obtains +obvious +occur +ocean +october +odds +odometer +offend +often +oilfield +ointment +okay +older +olive +olympics +omega +omission +omnibus +onboard +oncoming +oneself +ongoing +onion +online +onslaught +onto +onward +oozed +opacity +opened +opposite +optical +opus +orange +orbit +orchid +orders +organs +origin +ornament +orphans +oscar +ostrich +otherwise +otter +ouch +ought +ounce +ourselves +oust +outbreak +oval +oven +owed +owls +owner +oxidant +oxygen +oyster +ozone +pact +paddles +pager +pairing +palace +pamphlet +pancakes +paper +paradise +pastry +patio +pause +pavements +pawnshop +payment +peaches +pebbles +peculiar +pedantic +peeled +pegs +pelican +pencil +people +pepper +perfect +pests +petals +phase +pheasants +phone +phrases +physics +piano +picked +pierce +pigment +piloted +pimple +pinched +pioneer +pipeline +pirate +pistons +pitched +pivot +pixels +pizza +playful +pledge +pliers +plotting +plus +plywood +poaching +pockets +podcast +poetry +point +poker +polar +ponies +pool +popular +portents +possible +potato +pouch +poverty +powder +pram +present +pride +problems +pruned +prying +psychic +public +puck +puddle +puffin +pulp +pumpkins +punch +puppy +purged +push +putty +puzzled +pylons +pyramid +python +queen +quick +quote +rabbits +racetrack +radar +rafts +rage +railway +raking +rally +ramped +randomly +rapid +rarest +rash +rated +ravine +rays +razor +react +rebel +recipe +reduce +reef +refer +regular +reheat +reinvest +rejoices +rekindle +relic +remedy +renting +reorder +repent +request +reruns +rest +return +reunion +revamp +rewind +rhino +rhythm +ribbon +richly +ridges +rift +rigid +rims +ringing +riots +ripped +rising +ritual +river +roared +robot +rockets +rodent +rogue +roles +romance +roomy +roped +roster +rotate +rounded +rover +rowboat +royal +ruby +rudely +ruffled +rugged +ruined +ruling +rumble +runway +rural +rustled +ruthless +sabotage +sack +sadness +safety +saga +sailor +sake +salads +sample +sanity +sapling +sarcasm +sash +satin +saucepan +saved +sawmill +saxophone +sayings +scamper +scenic +school +science +scoop +scrub +scuba +seasons +second +sedan +seeded +segments +seismic +selfish +semifinal +sensible +september +sequence +serving +session +setup +seventh +sewage +shackles +shelter +shipped +shocking +shrugged +shuffled +shyness +siblings +sickness +sidekick +sieve +sifting +sighting +silk +simplest +sincerely +sipped +siren +situated +sixteen +sizes +skater +skew +skirting +skulls +skydive +slackens +sleepless +slid +slower +slug +smash +smelting +smidgen +smog +smuggled +snake +sneeze +sniff +snout +snug +soapy +sober +soccer +soda +software +soggy +soil +solved +somewhere +sonic +soothe +soprano +sorry +southern +sovereign +sowed +soya +space +speedy +sphere +spiders +splendid +spout +sprig +spud +spying +square +stacking +stellar +stick +stockpile +strained +stunning +stylishly +subtly +succeed +suddenly +suede +suffice +sugar +suitcase +sulking +summon +sunken +superior +surfer +sushi +suture +swagger +swept +swiftly +sword +swung +syllabus +symptoms +syndrome +syringe +system +taboo +tacit +tadpoles +tagged +tail +taken +talent +tamper +tanks +tapestry +tarnished +tasked +tattoo +taunts +tavern +tawny +taxi +teardrop +technical +tedious +teeming +tell +template +tender +tepid +tequila +terminal +testing +tether +textbook +thaw +theatrics +thirsty +thorn +threaten +thumbs +thwart +ticket +tidy +tiers +tiger +tilt +timber +tinted +tipsy +tirade +tissue +titans +toaster +tobacco +today +toenail +toffee +together +toilet +token +tolerant +tomorrow +tonic +toolbox +topic +torch +tossed +total +touchy +towel +toxic +toyed +trash +trendy +tribal +trolling +truth +trying +tsunami +tubes +tucks +tudor +tuesday +tufts +tugs +tuition +tulips +tumbling +tunnel +turnip +tusks +tutor +tuxedo +twang +tweezers +twice +twofold +tycoon +typist +tyrant +ugly +ulcers +ultimate +umbrella +umpire +unafraid +unbending +uncle +under +uneven +unfit +ungainly +unhappy +union +unjustly +unknown +unlikely +unmask +unnoticed +unopened +unplugs +unquoted +unrest +unsafe +until +unusual +unveil +unwind +unzip +upbeat +upcoming +update +upgrade +uphill +upkeep +upload +upon +upper +upright +upstairs +uptight +upwards +urban +urchins +urgent +usage +useful +usher +using +usual +utensils +utility +utmost +utopia +uttered +vacation +vague +vain +value +vampire +vane +vapidly +vary +vastness +vats +vaults +vector +veered +vegan +vehicle +vein +velvet +venomous +verification +vessel +veteran +vexed +vials +vibrate +victim +video +viewpoint +vigilant +viking +village +vinegar +violin +vipers +virtual +visited +vitals +vivid +vixen +vocal +vogue +voice +volcano +vortex +voted +voucher +vowels +voyage +vulture +wade +waffle +wagtail +waist +waking +wallets +wanted +warped +washing +water +waveform +waxing +wayside +weavers +website +wedge +weekday +weird +welders +went +wept +were +western +wetsuit +whale +when +whipped +whole +wickets +width +wield +wife +wiggle +wildly +winter +wipeout +wiring +wise +withdrawn +wives +wizard +wobbly +woes +woken +wolf +womanly +wonders +woozy +worry +wounded +woven +wrap +wrist +wrong +yacht +yahoo +yanks +yard +yawning +yearbook +yellow +yesterday +yeti +yields +yodel +yoga +younger +yoyo +zapped +zeal +zebra +zero +zesty +zigzags +zinger +zippers +zodiac +zombie +zones +zoom \ No newline at end of file diff --git a/src/assets/restore_heights_monero_mainnet.txt b/src/assets/restore_heights_monero_mainnet.txt new file mode 100644 index 0000000..60e7353 --- /dev/null +++ b/src/assets/restore_heights_monero_mainnet.txt @@ -0,0 +1,1457 @@ +1397818193:1 +1397900458:1500 +1397988986:3000 +1398072982:4500 +1398150254:6000 +1398239439:7500 +1398327464:9000 +1398414629:10500 +1398503595:12000 +1398589229:13500 +1398674475:15000 +1398759778:16500 +1398853330:18000 +1398940120:19500 +1399029142:21000 +1399108598:22500 +1399199476:24000 +1399276463:25500 +1399359258:27000 +1399430728:28500 +1399529049:30000 +1399617670:31500 +1399704054:33000 +1399788123:34500 +1399876759:36000 +1399966741:37500 +1400048830:39000 +1400137204:40500 +1400227960:42000 +1400306653:43500 +1400390723:45000 +1400481607:46500 +1400562797:48000 +1400642153:49500 +1400733770:51000 +1400824661:52500 +1400909443:54000 +1400995911:55500 +1401087629:57000 +1401174818:58500 +1401259431:60000 +1401346018:61500 +1401446104:63000 +1401533922:64500 +1401615882:66000 +1401711748:67500 +1401800119:69000 +1401890061:70500 +1401981961:72000 +1402068695:73500 +1402161441:75000 +1402251933:76500 +1402342853:78000 +1402430216:79500 +1402521608:81000 +1402607480:82500 +1402694197:84000 +1402782013:85500 +1402877831:87000 +1402961257:88500 +1403051337:90000 +1403142326:91500 +1403227928:93000 +1403317545:94500 +1403402406:96000 +1403489043:97500 +1403581110:99000 +1403672901:100500 +1403762913:102000 +1403853728:103500 +1403942246:105000 +1404030101:106500 +1404121204:108000 +1404209324:109500 +1404299477:111000 +1404389132:112500 +1404479896:114000 +1404568672:115500 +1404658453:117000 +1404748301:118500 +1404841666:120000 +1404931637:121500 +1405021251:123000 +1405111817:124500 +1405202249:126000 +1405292780:127500 +1405384068:129000 +1405474052:130500 +1405560833:132000 +1405648064:133500 +1405738612:135000 +1405826744:136500 +1405917415:138000 +1406009136:139500 +1406098048:141000 +1406187373:142500 +1406276248:144000 +1406366555:145500 +1406454661:147000 +1406545604:148500 +1406634825:150000 +1406725340:151500 +1406814693:153000 +1406904971:154500 +1406994787:156000 +1407085463:157500 +1407175390:159000 +1407267706:160500 +1407356299:162000 +1407449840:163500 +1407538256:165000 +1407626820:166500 +1407724474:168000 +1407809765:169500 +1407902144:171000 +1407993798:172500 +1408082457:174000 +1408172155:175500 +1408262956:177000 +1408354097:178500 +1408443936:180000 +1408532602:181500 +1408622703:183000 +1408710047:184500 +1408800621:186000 +1408889541:187500 +1408978632:189000 +1409069384:190500 +1409161090:192000 +1409252389:193500 +1409341518:195000 +1409431833:196500 +1409523265:198000 +1409615103:199500 +1409706694:201000 +1409798817:202500 +1409887837:204000 +1409975926:205500 +1410066995:207000 +1410157020:208500 +1410247699:210000 +1410338278:211500 +1410426858:213000 +1410517509:214500 +1410603548:216000 +1410697050:217500 +1410786623:219000 +1410879374:220500 +1410968790:222000 +1411061102:223500 +1411150344:225000 +1411240315:226500 +1411333451:228000 +1411426837:229500 +1411517510:231000 +1411609298:232500 +1411700275:234000 +1411786636:235500 +1411879257:237000 +1411969413:238500 +1412059180:240000 +1412146654:241500 +1412240371:243000 +1412327650:244500 +1412419484:246000 +1412505208:247500 +1412598099:249000 +1412689756:250500 +1412779061:252000 +1412871113:253500 +1412958247:255000 +1413046858:256500 +1413143444:258000 +1413233792:259500 +1413326427:261000 +1413418713:262500 +1413513170:264000 +1413600711:265500 +1413691038:267000 +1413782539:268500 +1413873271:270000 +1413963233:271500 +1414051910:273000 +1414141926:274500 +1414235227:276000 +1414324027:277500 +1414416650:279000 +1414508370:280500 +1414600491:282000 +1414690323:283500 +1414780188:285000 +1414869014:286500 +1414960781:288000 +1415056523:289500 +1415146466:291000 +1415242321:292500 +1415326686:294000 +1415416410:295500 +1415513982:297000 +1415605041:298500 +1415690591:300000 +1415782947:301500 +1415872606:303000 +1415962299:304500 +1416054283:306000 +1416140330:307500 +1416233580:309000 +1416322091:310500 +1416414135:312000 +1416506758:313500 +1416595374:315000 +1416689164:316500 +1416780263:318000 +1416874051:319500 +1416962889:321000 +1417055934:322500 +1417146000:324000 +1417236998:325500 +1417324179:327000 +1417416820:328500 +1417507901:330000 +1417597710:331500 +1417686355:333000 +1417777506:334500 +1417862659:336000 +1417955917:337500 +1418046843:339000 +1418136820:340500 +1418233090:342000 +1418324035:343500 +1418414267:345000 +1418505126:346500 +1418595764:348000 +1418688320:349500 +1418779374:351000 +1418872600:352500 +1418966538:354000 +1419055739:355500 +1419144085:357000 +1419238098:358500 +1419326271:360000 +1419418123:361500 +1419507535:363000 +1419597647:364500 +1419683774:366000 +1419774083:367500 +1419866259:369000 +1419955270:370500 +1420044008:372000 +1420140609:373500 +1420231494:375000 +1420324119:376500 +1420413916:378000 +1420507318:379500 +1420606276:381000 +1420694938:382500 +1420789183:384000 +1420876853:385500 +1420964886:387000 +1421056364:388500 +1421145579:390000 +1421237342:391500 +1421326931:393000 +1421416957:394500 +1421502911:396000 +1421596997:397500 +1421688678:399000 +1421778389:400500 +1421868252:402000 +1421962600:403500 +1422053511:405000 +1422143942:406500 +1422233701:408000 +1422325595:409500 +1422417764:411000 +1422505420:412500 +1422598104:414000 +1422687391:415500 +1422777785:417000 +1422868479:418500 +1422956207:420000 +1423049056:421500 +1423138582:423000 +1423229478:424500 +1423317219:426000 +1423406036:427500 +1423499905:429000 +1423588906:430500 +1423680298:432000 +1423772526:433500 +1423862745:435000 +1423952092:436500 +1424041391:438000 +1424139807:439500 +1424229026:441000 +1424318898:442500 +1424409301:444000 +1424499432:445500 +1424588330:447000 +1424678229:448500 +1424767351:450000 +1424856412:451500 +1424945924:453000 +1425037250:454500 +1425127838:456000 +1425218701:457500 +1425304420:459000 +1425398748:460500 +1425487631:462000 +1425582279:463500 +1425668647:465000 +1425759251:466500 +1425851153:468000 +1425944420:469500 +1426035355:471000 +1426125337:472500 +1426216244:474000 +1426305042:475500 +1426396945:477000 +1426488132:478500 +1426579077:480000 +1426668886:481500 +1426757427:483000 +1426847995:484500 +1426937217:486000 +1427027279:487500 +1427118292:489000 +1427209584:490500 +1427297515:492000 +1427390524:493500 +1427480882:495000 +1427570116:496500 +1427659258:498000 +1427749838:499500 +1427840543:501000 +1427932591:502500 +1428024040:504000 +1428113328:505500 +1428207103:507000 +1428294368:508500 +1428385900:510000 +1428475862:511500 +1428566459:513000 +1428656150:514500 +1428745154:516000 +1428836572:517500 +1428927559:519000 +1429016578:520500 +1429108184:522000 +1429198248:523500 +1429288171:525000 +1429377542:526500 +1429471467:528000 +1429558593:529500 +1429653677:531000 +1429746059:532500 +1429836351:534000 +1429925189:535500 +1430016095:537000 +1430107657:538500 +1430197340:540000 +1430289235:541500 +1430378857:543000 +1430469252:544500 +1430559860:546000 +1430649912:547500 +1430737924:549000 +1430831012:550500 +1430922367:552000 +1431010902:553500 +1431101587:555000 +1431192674:556500 +1431285757:558000 +1431375632:559500 +1431466492:561000 +1431558015:562500 +1431649156:564000 +1431737625:565500 +1431828881:567000 +1431918115:568500 +1432011390:570000 +1432100985:571500 +1432189708:573000 +1432280424:574500 +1432369030:576000 +1432457824:577500 +1432550488:579000 +1432641906:580500 +1432730503:582000 +1432821446:583500 +1432914085:585000 +1433004746:586500 +1433094395:588000 +1433187412:589500 +1433276104:591000 +1433367216:592500 +1433460433:594000 +1433551901:595500 +1433637685:597000 +1433733220:598500 +1433825715:600000 +1433916570:601500 +1434006501:603000 +1434096894:604500 +1434187100:606000 +1434273702:607500 +1434367676:609000 +1434455723:610500 +1434545055:612000 +1434635579:613500 +1434730428:615000 +1434817300:616500 +1434906793:618000 +1434998648:619500 +1435090833:621000 +1435182990:622500 +1435273589:624000 +1435366019:625500 +1435453713:627000 +1435548085:628500 +1435636924:630000 +1435729973:631500 +1435822621:633000 +1435908886:634500 +1436001545:636000 +1436088666:637500 +1436178148:639000 +1436269067:640500 +1436362647:642000 +1436450486:643500 +1436539955:645000 +1436630255:646500 +1436721546:648000 +1436812401:649500 +1436903919:651000 +1436994474:652500 +1437085546:654000 +1437182957:655500 +1437275193:657000 +1437366265:658500 +1437455928:660000 +1437546033:661500 +1437633837:663000 +1437722391:664500 +1437810260:666000 +1437902321:667500 +1437993029:669000 +1438084185:670500 +1438171580:672000 +1438264522:673500 +1438354565:675000 +1438443988:676500 +1438535479:678000 +1438623629:679500 +1438716455:681000 +1438811029:682500 +1438904689:684000 +1438995954:685500 +1439086366:687000 +1439177854:688500 +1439267688:690000 +1439359080:691500 +1439447799:693000 +1439536807:694500 +1439628635:696000 +1439719005:697500 +1439804776:699000 +1439896959:700500 +1439989036:702000 +1440080322:703500 +1440170251:705000 +1440259422:706500 +1440351566:708000 +1440442434:709500 +1440537570:711000 +1440625665:712500 +1440717538:714000 +1440811510:715500 +1440903517:717000 +1440993091:718500 +1441084930:720000 +1441176305:721500 +1441265615:723000 +1441355056:724500 +1441446393:726000 +1441536851:727500 +1441628898:729000 +1441718152:730500 +1441805254:732000 +1441897179:733500 +1441986435:735000 +1442080450:736500 +1442172155:738000 +1442263883:739500 +1442355067:741000 +1442449041:742500 +1442542209:744000 +1442635207:745500 +1442724460:747000 +1442812486:748500 +1442902966:750000 +1442994219:751500 +1443085698:753000 +1443178161:754500 +1443264135:756000 +1443355099:757500 +1443446477:759000 +1443535739:760500 +1443625352:762000 +1443720015:763500 +1443811700:765000 +1443902882:766500 +1443998004:768000 +1444089737:769500 +1444182793:771000 +1444270850:772500 +1444361771:774000 +1444454626:775500 +1444544876:777000 +1444634893:778500 +1444725863:780000 +1444814080:781500 +1444904547:783000 +1444996388:784500 +1445086690:786000 +1445175749:787500 +1445267687:789000 +1445360811:790500 +1445449074:792000 +1445543282:793500 +1445632023:795000 +1445722156:796500 +1445813732:798000 +1445908836:799500 +1445998334:801000 +1446091833:802500 +1446185727:804000 +1446275117:805500 +1446367555:807000 +1446458743:808500 +1446548650:810000 +1446636178:811500 +1446729285:813000 +1446818028:814500 +1446909549:816000 +1447003607:817500 +1447093001:819000 +1447184705:820500 +1447278621:822000 +1447372370:823500 +1447468038:825000 +1447558138:826500 +1447652390:828000 +1447742476:829500 +1447828166:831000 +1447923194:832500 +1448013216:834000 +1448102910:835500 +1448193723:837000 +1448283885:838500 +1448375042:840000 +1448465226:841500 +1448556419:843000 +1448649382:844500 +1448740265:846000 +1448829027:847500 +1448923137:849000 +1449020848:850500 +1449111876:852000 +1449206548:853500 +1449295175:855000 +1449383624:856500 +1449475534:858000 +1449567493:859500 +1449656259:861000 +1449747770:862500 +1449839439:864000 +1449928803:865500 +1450020705:867000 +1450116099:868500 +1450206082:870000 +1450295833:871500 +1450393905:873000 +1450484210:874500 +1450576191:876000 +1450674264:877500 +1450763812:879000 +1450854842:880500 +1450945997:882000 +1451036350:883500 +1451125224:885000 +1451213407:886500 +1451306539:888000 +1451395994:889500 +1451487825:891000 +1451578633:892500 +1451673162:894000 +1451762734:895500 +1451855376:897000 +1451950724:898500 +1452044620:900000 +1452138667:901500 +1452229272:903000 +1452321274:904500 +1452411380:906000 +1452503713:907500 +1452593651:909000 +1452685043:910500 +1452774742:912000 +1452871547:913500 +1452955528:915000 +1453045013:916500 +1453139828:918000 +1453235253:919500 +1453322581:921000 +1453418754:922500 +1453508866:924000 +1453599446:925500 +1453692429:927000 +1453785727:928500 +1453874045:930000 +1453967280:931500 +1454056395:933000 +1454149053:934500 +1454238746:936000 +1454332249:937500 +1454422039:939000 +1454517368:940500 +1454604302:942000 +1454697148:943500 +1454792369:945000 +1454883921:946500 +1454976152:948000 +1455069597:949500 +1455162171:951000 +1455253531:952500 +1455344835:954000 +1455435262:955500 +1455523159:957000 +1455614591:958500 +1455704830:960000 +1455795089:961500 +1455885662:963000 +1455979503:964500 +1456067893:966000 +1456159912:967500 +1456252158:969000 +1456343386:970500 +1456436372:972000 +1456531050:973500 +1456626469:975000 +1456722795:976500 +1456812422:978000 +1456904454:979500 +1456992650:981000 +1457081799:982500 +1457174326:984000 +1457265022:985500 +1457353587:987000 +1457446102:988500 +1457536684:990000 +1457626424:991500 +1457717341:993000 +1457807857:994500 +1457902501:996000 +1457995186:997500 +1458089638:999000 +1458180514:1000500 +1458274276:1002000 +1458364317:1003500 +1458455352:1005000 +1458549046:1006500 +1458636174:1008000 +1458729317:1009500 +1458894346:1011000 +1459063482:1012500 +1459243276:1014000 +1459425755:1015500 +1459605826:1017000 +1459782083:1018500 +1459961331:1020000 +1460143746:1021500 +1460331607:1023000 +1460520936:1024500 +1460701361:1026000 +1460884221:1027500 +1461061695:1029000 +1461237934:1030500 +1461414191:1032000 +1461593953:1033500 +1461777761:1035000 +1461952141:1036500 +1462132052:1038000 +1462317051:1039500 +1462495092:1041000 +1462677074:1042500 +1462861748:1044000 +1463044884:1045500 +1463224911:1047000 +1463398580:1048500 +1463578591:1050000 +1463757604:1051500 +1463936022:1053000 +1464117101:1054500 +1464297865:1056000 +1464483584:1057500 +1464671071:1059000 +1464849970:1060500 +1465024863:1062000 +1465205807:1063500 +1465386722:1065000 +1465564285:1066500 +1465738760:1068000 +1465918555:1069500 +1466100427:1071000 +1466276876:1072500 +1466454118:1074000 +1466639653:1075500 +1466820501:1077000 +1467005177:1078500 +1467185150:1080000 +1467362682:1081500 +1467540213:1083000 +1467716652:1084500 +1467893799:1086000 +1468069912:1087500 +1468248812:1089000 +1468427344:1090500 +1468603125:1092000 +1468787751:1093500 +1468965065:1095000 +1469145781:1096500 +1469337233:1098000 +1469521554:1099500 +1469699691:1101000 +1469874679:1102500 +1470053612:1104000 +1470236012:1105500 +1470414476:1107000 +1470595923:1108500 +1470777161:1110000 +1470955781:1111500 +1471138526:1113000 +1471319847:1114500 +1471500943:1116000 +1471682222:1117500 +1471860790:1119000 +1472035420:1120500 +1472217115:1122000 +1472395302:1123500 +1472570739:1125000 +1472751050:1126500 +1472928309:1128000 +1473098267:1129500 +1473276441:1131000 +1473457643:1132500 +1473642257:1134000 +1473826970:1135500 +1474002748:1137000 +1474188317:1138500 +1474374066:1140000 +1474550392:1141500 +1474729572:1143000 +1474911163:1144500 +1475092518:1146000 +1475268122:1147500 +1475442938:1149000 +1475629374:1150500 +1475819480:1152000 +1475997819:1153500 +1476179133:1155000 +1476354939:1156500 +1476536210:1158000 +1476716350:1159500 +1476895225:1161000 +1477073983:1162500 +1477249312:1164000 +1477433801:1165500 +1477614082:1167000 +1477804971:1168500 +1477990372:1170000 +1478169998:1171500 +1478348283:1173000 +1478528413:1174500 +1478705414:1176000 +1478886655:1177500 +1479062832:1179000 +1479243048:1180500 +1479418422:1182000 +1479595192:1183500 +1479778962:1185000 +1479964598:1186500 +1480140671:1188000 +1480324683:1189500 +1480500809:1191000 +1480682239:1192500 +1480856453:1194000 +1481038133:1195500 +1481217124:1197000 +1481392752:1198500 +1481575804:1200000 +1481756751:1201500 +1481934733:1203000 +1482116256:1204500 +1482301346:1206000 +1482479176:1207500 +1482654068:1209000 +1482834659:1210500 +1483004059:1212000 +1483188148:1213500 +1483362554:1215000 +1483539897:1216500 +1483721622:1218000 +1483903190:1219500 +1484088607:1221000 +1484263006:1222500 +1484446963:1224000 +1484626829:1225500 +1484809489:1227000 +1484983861:1228500 +1485170094:1230000 +1485349686:1231500 +1485530749:1233000 +1485709581:1234500 +1485884232:1236000 +1486067414:1237500 +1486245341:1239000 +1486425256:1240500 +1486608991:1242000 +1486786270:1243500 +1486973042:1245000 +1487146309:1246500 +1487325223:1248000 +1487503053:1249500 +1487685365:1251000 +1487863975:1252500 +1488050119:1254000 +1488223036:1255500 +1488410492:1257000 +1488589768:1258500 +1488775148:1260000 +1488949276:1261500 +1489133453:1263000 +1489308790:1264500 +1489485996:1266000 +1489664303:1267500 +1489848401:1269000 +1490027832:1270500 +1490206463:1272000 +1490390593:1273500 +1490567029:1275000 +1490746894:1276500 +1490933137:1278000 +1491106069:1279500 +1491289329:1281000 +1491468486:1282500 +1491643624:1284000 +1491814895:1285500 +1491995475:1287000 +1492178181:1288500 +1492371569:1290000 +1492552114:1291500 +1492729903:1293000 +1492910706:1294500 +1493094028:1296000 +1493277668:1297500 +1493451685:1299000 +1493634509:1300500 +1493814008:1302000 +1493991208:1303500 +1494166238:1305000 +1494350490:1306500 +1494526071:1308000 +1494707137:1309500 +1494887930:1311000 +1495071305:1312500 +1495251430:1314000 +1495429566:1315500 +1495614062:1317000 +1495788802:1318500 +1495965162:1320000 +1496146099:1321500 +1496328368:1323000 +1496504063:1324500 +1496681255:1326000 +1496866740:1327500 +1497043312:1329000 +1497226571:1330500 +1497400684:1332000 +1497583491:1333500 +1497766332:1335000 +1497942512:1336500 +1498119751:1338000 +1498305083:1339500 +1498481551:1341000 +1498659598:1342500 +1498837788:1344000 +1499017991:1345500 +1499192957:1347000 +1499368904:1348500 +1499552117:1350000 +1499732418:1351500 +1499915064:1353000 +1500092067:1354500 +1500266465:1356000 +1500451753:1357500 +1500628055:1359000 +1500809381:1360500 +1500985894:1362000 +1501163425:1363500 +1501344352:1365000 +1501524529:1366500 +1501706158:1368000 +1501887950:1369500 +1502070277:1371000 +1502246128:1372500 +1502426331:1374000 +1502609329:1375500 +1502785502:1377000 +1502965697:1378500 +1503149952:1380000 +1503326470:1381500 +1503502198:1383000 +1503682259:1384500 +1503846976:1386000 +1504025371:1387500 +1504210659:1389000 +1504388051:1390500 +1504571483:1392000 +1504750590:1393500 +1504923930:1395000 +1505104688:1396500 +1505283020:1398000 +1505464381:1399500 +1505644195:1401000 +1505826737:1402500 +1506005392:1404000 +1506184128:1405500 +1506368706:1407000 +1506547393:1408500 +1506725266:1410000 +1506907806:1411500 +1507085344:1413000 +1507267312:1414500 +1507445129:1416000 +1507628097:1417500 +1507803256:1419000 +1507986316:1420500 +1508167088:1422000 +1508347016:1423500 +1508530561:1425000 +1508710041:1426500 +1508886983:1428000 +1509066419:1429500 +1509253136:1431000 +1509429629:1432500 +1509611536:1434000 +1509797649:1435500 +1509973107:1437000 +1510153044:1438500 +1510332372:1440000 +1510509741:1441500 +1510696836:1443000 +1510871459:1444500 +1511052822:1446000 +1511231910:1447500 +1511407518:1449000 +1511587113:1450500 +1511770521:1452000 +1511949617:1453500 +1512129674:1455000 +1512307629:1456500 +1512482822:1458000 +1512653560:1459500 +1512835616:1461000 +1513017827:1462500 +1513197715:1464000 +1513372385:1465500 +1513547532:1467000 +1513728243:1468500 +1513909535:1470000 +1514083183:1471500 +1514266543:1473000 +1514444953:1474500 +1514621027:1476000 +1514798581:1477500 +1514978081:1479000 +1515155541:1480500 +1515339872:1482000 +1515518908:1483500 +1515699380:1485000 +1515875622:1486500 +1516053533:1488000 +1516243460:1489500 +1516414701:1491000 +1516599857:1492500 +1516781257:1494000 +1516964999:1495500 +1517142540:1497000 +1517315501:1498500 +1517489351:1500000 +1517666336:1501500 +1517855270:1503000 +1518027977:1504500 +1518203488:1506000 +1518384465:1507500 +1518558355:1509000 +1518751308:1510500 +1518924052:1512000 +1519106822:1513500 +1519281628:1515000 +1519466837:1516500 +1519648752:1518000 +1519829797:1519500 +1520014254:1521000 +1520184998:1522500 +1520370843:1524000 +1520544780:1525500 +1520728324:1527000 +1520910430:1528500 +1521088410:1530000 +1521268781:1531500 +1521445861:1533000 +1521631805:1534500 +1521805475:1536000 +1521987364:1537500 +1522168759:1539000 +1522349749:1540500 +1522531771:1542000 +1522713608:1543500 +1522889687:1545000 +1523199218:1546500 +1523341007:1548000 +1523527026:1549500 +1523709149:1551000 +1523888851:1552500 +1524065976:1554000 +1524246015:1555500 +1524423554:1557000 +1524602490:1558500 +1524783179:1560000 +1524964360:1561500 +1525151214:1563000 +1525329119:1564500 +1525513042:1566000 +1525692507:1567500 +1525871313:1569000 +1526053870:1570500 +1526230509:1572000 +1526410171:1573500 +1526592816:1575000 +1526773513:1576500 +1526955087:1578000 +1527133612:1579500 +1527316345:1581000 +1527498499:1582500 +1527676559:1584000 +1527855294:1585500 +1528040693:1587000 +1528219591:1588500 +1528395704:1590000 +1528579987:1591500 +1528763026:1593000 +1528943220:1594500 +1529121386:1596000 +1529302157:1597500 +1529479749:1599000 +1529664069:1600500 +1529840212:1602000 +1530015093:1603500 +1530198774:1605000 +1530375043:1606500 +1530556497:1608000 +1530734767:1609500 +1530917375:1611000 +1531096855:1612500 +1531279152:1614000 +1531454376:1615500 +1531642390:1617000 +1531816195:1618500 +1531995687:1620000 +1532180791:1621500 +1532356484:1623000 +1532537384:1624500 +1532719158:1626000 +1532898266:1627500 +1533078869:1629000 +1533257860:1630500 +1533441853:1632000 +1533620709:1633500 +1533798312:1635000 +1533982417:1636500 +1534160192:1638000 +1534343434:1639500 +1534524042:1641000 +1534702092:1642500 +1534879676:1644000 +1535063247:1645500 +1535244194:1647000 +1535420587:1648500 +1535600184:1650000 +1535779496:1651500 +1535956153:1653000 +1536134137:1654500 +1536311328:1656000 +1536494008:1657500 +1536670845:1659000 +1536851610:1660500 +1537033013:1662000 +1537210976:1663500 +1537392240:1665000 +1537574727:1666500 +1537753429:1668000 +1537928751:1669500 +1538111834:1671000 +1538291618:1672500 +1538476427:1674000 +1538652972:1675500 +1538836084:1677000 +1539013906:1678500 +1539198355:1680000 +1539374477:1681500 +1539552789:1683000 +1539736817:1684500 +1539951210:1686000 +1540117344:1687500 +1540296439:1689000 +1540473097:1690500 +1540653573:1692000 +1540834279:1693500 +1541014980:1695000 +1541190938:1696500 +1541369517:1698000 +1541548646:1699500 +1541734186:1701000 +1541913570:1702500 +1542092909:1704000 +1542275017:1705500 +1542449875:1707000 +1542635853:1708500 +1542815406:1710000 +1542997650:1711500 +1543178239:1713000 +1543359208:1714500 +1543540950:1716000 +1543727129:1717500 +1543901392:1719000 +1544084664:1720500 +1544267089:1722000 +1544446105:1723500 +1544624643:1725000 +1544803722:1726500 +1544987704:1728000 +1545170981:1729500 +1545350532:1731000 +1545532466:1732500 +1545710048:1734000 +1545887915:1735500 +1546069559:1737000 +1546245869:1738500 +1546431793:1740000 +1546606116:1741500 +1546786754:1743000 +1546968255:1744500 +1547139298:1746000 +1547319437:1747500 +1547496353:1749000 +1547672846:1750500 +1547850712:1752000 +1548034420:1753500 +1548214308:1755000 +1548391966:1756500 +1548573263:1758000 +1548752471:1759500 +1548928088:1761000 +1549106489:1762500 +1549283115:1764000 +1549456506:1765500 +1549634814:1767000 +1549817916:1768500 +1549998027:1770000 +1550181258:1771500 +1550361109:1773000 +1550539544:1774500 +1550715280:1776000 +1550894562:1777500 +1551079870:1779000 +1551254182:1780500 +1551434299:1782000 +1551619776:1783500 +1551794014:1785000 +1551973350:1786500 +1552162320:1788000 +1552440957:1789500 +1552624599:1791000 +1552807716:1792500 +1552980302:1794000 +1553162414:1795500 +1553342996:1797000 +1553519700:1798500 +1553698458:1800000 +1553881211:1801500 +1554066280:1803000 +1554243249:1804500 +1554425052:1806000 +1554603701:1807500 +1554782591:1809000 +1554964129:1810500 +1555144375:1812000 +1555323612:1813500 +1555506661:1815000 +1555682580:1816500 +1555865552:1818000 +1556045247:1819500 +1556225465:1821000 +1556407651:1822500 +1556582937:1824000 +1556772261:1825500 +1556942721:1827000 +1557123929:1828500 +1557301054:1830000 +1557481698:1831500 +1557663940:1833000 +1557840344:1834500 +1558023818:1836000 +1558203355:1837500 +1558391132:1839000 +1558575667:1840500 +1558746689:1842000 +1558925957:1843500 +1559106354:1845000 +1559287492:1846500 +1559467006:1848000 +1559645231:1849500 +1559825739:1851000 +1560005500:1852500 +1560188695:1854000 +1560369273:1855500 +1560549957:1857000 +1560728250:1858500 +1560908667:1860000 +1561089902:1861500 +1561266483:1863000 +1561452756:1864500 +1561630099:1866000 +1561809391:1867500 +1561988751:1869000 +1562166315:1870500 +1562348668:1872000 +1562528088:1873500 +1562705035:1875000 +1562894124:1876500 +1563072153:1878000 +1563253196:1879500 +1563429474:1881000 +1563612610:1882500 +1563790557:1884000 +1563972425:1885500 +1564152141:1887000 +1564332716:1888500 +1564511944:1890000 +1564693842:1891500 +1564873798:1893000 +1565051050:1894500 +1565230166:1896000 +1565410958:1897500 +1565587893:1899000 +1565768680:1900500 +1565949811:1902000 +1566131254:1903500 +1566309564:1905000 +1566490278:1906500 +1566668500:1908000 +1566847812:1909500 +1567031237:1911000 +1567210421:1912500 +1567391373:1914000 +1567573130:1915500 +1567750424:1917000 +1567930191:1918500 +1568109052:1920000 +1568292141:1921500 +1568475276:1923000 +1568651158:1924500 +1568834035:1926000 +1569016695:1927500 +1569197462:1929000 +1569377087:1930500 +1569552946:1932000 +1569734228:1933500 +1569917274:1935000 +1570098125:1936500 +1570275613:1938000 +1570457750:1939500 +1570639244:1941000 +1570819775:1942500 +1570996968:1944000 +1571176527:1945500 +1571356679:1947000 +1571534462:1948500 +1571718656:1950000 +1571897497:1951500 +1572079573:1953000 +1572257839:1954500 +1572433496:1956000 +1572617030:1957500 +1572800390:1959000 +1572981257:1960500 +1573162090:1962000 +1573343169:1963500 +1573522418:1965000 +1573702490:1966500 +1573880257:1968000 +1574062548:1969500 +1574251843:1971000 +1574424663:1972500 +1574601376:1974000 +1574786775:1975500 +1574964035:1977000 +1575146296:1978500 +1575292812:1980000 +1575466285:1981500 +1575651166:1983000 +1575830411:1984500 +1576005533:1986000 +1576186198:1987500 +1576360710:1989000 +1576541731:1990500 +1576716413:1992000 +1576902518:1993500 +1577081999:1995000 +1577264190:1996500 +1577443608:1998000 +1577623965:1999500 +1577797297:2001000 +1577979977:2002500 +1578159838:2004000 +1578336239:2005500 +1578515304:2007000 +1578699616:2008500 +1578876107:2010000 +1579060229:2011500 +1579242633:2013000 +1579414863:2014500 +1579597542:2016000 +1579772970:2017500 +1579952975:2019000 +1580137609:2020500 +1580317014:2022000 +1580496315:2023500 +1580675324:2025000 +1580849194:2026500 +1581032371:2028000 +1581214733:2029500 +1581397004:2031000 +1581572973:2032500 +1581751875:2034000 +1581931029:2035500 +1582114546:2037000 +1582295872:2038500 +1582472927:2040000 +1582657335:2041500 +1582835968:2043000 +1583012446:2044500 +1583196576:2046000 +1583373753:2047500 +1583560473:2049000 +1583738686:2050500 +1583922736:2052000 +1584105842:2053500 +1584285185:2055000 +1584463972:2056500 +1584642026:2058000 +1584821928:2059500 +1584995845:2061000 +1585184223:2062500 +1585363485:2064000 +1585540102:2065500 +1585721837:2067000 +1585899117:2068500 +1586084634:2070000 +1586262819:2071500 +1586442409:2073000 +1586623044:2074500 +1586801375:2076000 +1586980631:2077500 +1587165890:2079000 +1587341099:2080500 +1587523790:2082000 +1587702237:2083500 +1587883578:2085000 +1588063778:2086500 +1588245212:2088000 +1588424440:2089500 +1588603366:2091000 +1588781424:2092500 +1588964395:2094000 +1589142803:2095500 +1589321977:2097000 +1589506409:2098500 +1589683808:2100000 +1589865852:2101500 +1590042622:2103000 +1590222956:2104500 +1590404367:2106000 +1590581681:2107500 +1590762536:2109000 +1590943308:2110500 +1591125425:2112000 +1591304788:2113500 +1591483294:2115000 +1591666790:2116500 +1591846816:2118000 +1592023700:2119500 +1592207460:2121000 +1592386537:2122500 +1592569543:2124000 +1592747578:2125500 +1592925121:2127000 +1593103239:2128500 +1593277684:2130000 +1593464042:2131500 +1593643273:2133000 +1593824098:2134500 +1594000762:2136000 +1594187379:2137500 +1594369906:2139000 +1594552767:2140500 +1594721587:2142000 +1594908084:2143500 +1595088951:2145000 +1595269262:2146500 +1595454606:2148000 +1595633949:2149500 +1595806853:2151000 +1595988097:2152500 +1596168734:2154000 +1596347710:2155500 +1596523798:2157000 +1596694716:2158500 +1596887172:2160000 +1597077820:2161500 +1597256353:2163000 +1597436569:2164500 +1597622246:2166000 +1597800117:2167500 +1597984768:2169000 +1598161623:2170500 +1598338544:2172000 +1598523532:2173500 +1598704427:2175000 +1598881234:2176500 +1599067666:2178000 +1599247884:2179500 +1599426969:2181000 +1599604157:2182500 +1599786817:2184000 diff --git a/src/assets/restore_heights_monero_stagenet.txt b/src/assets/restore_heights_monero_stagenet.txt new file mode 100644 index 0000000..c28a4a4 --- /dev/null +++ b/src/assets/restore_heights_monero_stagenet.txt @@ -0,0 +1,444 @@ +1518932025:1 +1519057016:1500 +1519148374:3000 +1519251680:4500 +1519344568:6000 +1519443436:7500 +1519538388:9000 +1519630287:10500 +1519706564:12000 +1519797372:13500 +1519887275:15000 +1519977816:16500 +1520068127:18000 +1520163067:19500 +1520267595:21000 +1520378423:22500 +1520470528:24000 +1520547672:25500 +1520637599:27000 +1520727714:28500 +1520817129:30000 +1520907017:31500 +1521042482:33000 +1521203259:34500 +1521379791:36000 +1521565539:37500 +1521768004:39000 +1521952047:40500 +1522127660:42000 +1522284923:43500 +1522510139:45000 +1522676022:46500 +1522871613:48000 +1522969561:49500 +1523145200:51000 +1523316302:52500 +1523550884:54000 +1523758049:55500 +1523917524:57000 +1524106084:58500 +1524290437:60000 +1524464139:61500 +1524728732:63000 +1524905041:64500 +1525093135:66000 +1525239917:67500 +1525443579:69000 +1525663214:70500 +1525839621:72000 +1525989826:73500 +1526182919:75000 +1526437405:76500 +1526649137:78000 +1526812889:79500 +1526991726:81000 +1527184073:82500 +1527351889:84000 +1527567839:85500 +1527759754:87000 +1527916443:88500 +1528110008:90000 +1528285005:91500 +1528486806:93000 +1528666327:94500 +1528872096:96000 +1529015390:97500 +1529205809:99000 +1529384415:100500 +1529595764:102000 +1529770640:103500 +1529950955:105000 +1530115141:106500 +1530306273:108000 +1530491510:109500 +1530677550:111000 +1530823854:112500 +1531032372:114000 +1531175619:115500 +1531371373:117000 +1531541897:118500 +1531706629:120000 +1531888223:121500 +1532104373:123000 +1532314129:124500 +1532503060:126000 +1532663651:127500 +1532894128:129000 +1533095950:130500 +1533302631:132000 +1533464469:133500 +1533670723:135000 +1533833911:136500 +1534030841:138000 +1534203160:139500 +1534397055:141000 +1534577048:142500 +1534752236:144000 +1534931462:145500 +1535119263:147000 +1535300364:148500 +1535471540:150000 +1535640429:151500 +1535836082:153000 +1536059510:154500 +1536209710:156000 +1536366875:157500 +1536560444:159000 +1536749043:160500 +1536926345:162000 +1537105693:163500 +1537296613:165000 +1537501175:166500 +1537667740:168000 +1537844801:169500 +1538000228:171000 +1538199137:172500 +1538418406:174000 +1538612473:175500 +1538979696:177000 +1539147054:178500 +1539303989:180000 +1539488395:181500 +1539652212:183000 +1539819281:184500 +1539971301:186000 +1540146343:187500 +1540330288:189000 +1540505588:190500 +1540688044:192000 +1540869374:193500 +1541049379:195000 +1541223210:196500 +1541393586:198000 +1541577202:199500 +1541762094:201000 +1541909862:202500 +1542199063:204000 +1542399873:205500 +1542579333:207000 +1542763985:208500 +1542947442:210000 +1543124804:211500 +1543323933:213000 +1543489307:214500 +1543672244:216000 +1543837576:217500 +1544042420:219000 +1544222096:220500 +1544402628:222000 +1544546843:223500 +1544730464:225000 +1545134663:226500 +1545301874:228000 +1545488939:229500 +1545664263:231000 +1545834607:232500 +1546014630:234000 +1546192930:235500 +1546373750:237000 +1546556089:238500 +1546738764:240000 +1546917228:241500 +1547091360:243000 +1547272679:244500 +1547463907:246000 +1547636722:247500 +1547817060:249000 +1548001021:250500 +1548185375:252000 +1548380319:253500 +1548555267:255000 +1548741069:256500 +1548926544:258000 +1549140801:259500 +1549297081:261000 +1549478379:262500 +1549651888:264000 +1549860339:265500 +1550024455:267000 +1550217332:268500 +1551312389:270000 +1551527936:271500 +1551665288:273000 +1551836443:274500 +1552026339:276000 +1552218441:277500 +1552443760:279000 +1552680291:280500 +1552854334:282000 +1553030527:283500 +1553211359:285000 +1553385763:286500 +1553588198:288000 +1553760642:289500 +1553937158:291000 +1554121990:292500 +1554302691:294000 +1554479953:295500 +1554666762:297000 +1554850956:298500 +1555057081:300000 +1555228611:301500 +1555400592:303000 +1555615005:304500 +1555789135:306000 +1555995570:307500 +1556183867:309000 +1556362195:310500 +1556541232:312000 +1556728140:313500 +1556903453:315000 +1557065264:316500 +1557273415:318000 +1557443047:319500 +1557618850:321000 +1557798876:322500 +1557976530:324000 +1558172356:325500 +1558356032:327000 +1558534222:328500 +1558719934:330000 +1558892036:331500 +1559075695:333000 +1559253052:334500 +1559462339:336000 +1559647394:337500 +1559827424:339000 +1560002042:340500 +1560189126:342000 +1560343483:343500 +1560548477:345000 +1560709613:346500 +1560888640:348000 +1561072261:349500 +1561249189:351000 +1561433494:352500 +1561609875:354000 +1561789136:355500 +1561971530:357000 +1562146235:358500 +1562283612:360000 +1562536678:361500 +1562727970:363000 +1562896064:364500 +1563081360:366000 +1563222147:367500 +1563471753:369000 +1563648133:370500 +1563844968:372000 +1564019071:373500 +1564194349:375000 +1564378444:376500 +1564557884:378000 +1564733144:379500 +1564931656:381000 +1565088150:382500 +1565272766:384000 +1565457895:385500 +1565632566:387000 +1565824568:388500 +1565992971:390000 +1566155025:391500 +1566345274:393000 +1566534162:394500 +1566736618:396000 +1566937517:397500 +1567128136:399000 +1567296600:400500 +1567482630:402000 +1567671945:403500 +1567828904:405000 +1568061755:406500 +1568241437:408000 +1568413206:409500 +1568589427:411000 +1568777072:412500 +1568950797:414000 +1569140033:415500 +1569321139:417000 +1569497726:418500 +1569685524:420000 +1569858754:421500 +1570025222:423000 +1570195891:424500 +1570412169:426000 +1570568122:427500 +1570772965:429000 +1570968490:430500 +1571107236:432000 +1571359933:433500 +1571520970:435000 +1571737619:436500 +1571890574:438000 +1572104152:439500 +1572299391:441000 +1572483040:442500 +1572663772:444000 +1572839626:445500 +1573049256:447000 +1573229282:448500 +1573407580:450000 +1573589178:451500 +1573735333:453000 +1573840717:454500 +1574096272:456000 +1574280161:457500 +1574455892:459000 +1574604632:460500 +1574809987:462000 +1574975801:463500 +1575140569:465000 +1575422392:466500 +1575583824:468000 +1575763253:469500 +1575944350:471000 +1576125074:472500 +1576324269:474000 +1576508865:475500 +1576669612:477000 +1576891906:478500 +1577078563:480000 +1577265105:481500 +1577431370:483000 +1577744409:484500 +1577874268:486000 +1578038130:487500 +1578231375:489000 +1578439644:490500 +1578625982:492000 +1578808598:493500 +1578985283:495000 +1579175621:496500 +1579347774:498000 +1579517894:499500 +1579687667:501000 +1579868646:502500 +1580046838:504000 +1580240961:505500 +1580428207:507000 +1580572904:508500 +1580823996:510000 +1580994064:511500 +1581183924:513000 +1581351893:514500 +1581521085:516000 +1581702405:517500 +1581943619:519000 +1582098842:520500 +1582299537:522000 +1582480013:523500 +1582659742:525000 +1582839127:526500 +1583020057:528000 +1583266489:529500 +1583429819:531000 +1583615548:532500 +1583785190:534000 +1584011766:535500 +1584192961:537000 +1584342104:538500 +1584521327:540000 +1584706894:541500 +1584883565:543000 +1585062315:544500 +1585244138:546000 +1585427591:547500 +1585600165:549000 +1585784601:550500 +1585961031:552000 +1586147565:553500 +1586322716:555000 +1586513730:556500 +1586698639:558000 +1586878453:559500 +1587062131:561000 +1587234968:562500 +1587391529:564000 +1587591247:565500 +1587752262:567000 +1587969335:568500 +1588148503:570000 +1588405392:571500 +1588593609:573000 +1588778703:574500 +1588949467:576000 +1589172941:577500 +1589358899:579000 +1589536247:580500 +1589730950:582000 +1589882572:583500 +1590062931:585000 +1590237283:586500 +1590430792:588000 +1590599140:589500 +1590807968:591000 +1590987339:592500 +1591166304:594000 +1591348974:595500 +1591542069:597000 +1591723208:598500 +1591908870:600000 +1592060567:601500 +1592259549:603000 +1592465269:604500 +1592647205:606000 +1592828242:607500 +1593006687:609000 +1593201658:610500 +1593492855:612000 +1593636856:613500 +1593811224:615000 +1594004429:616500 +1594162422:618000 +1594348191:619500 +1594523256:621000 +1594685351:622500 +1594890677:624000 +1595073577:625500 +1595269373:627000 +1595477524:628500 +1595668392:630000 +1595867552:631500 +1596043173:633000 +1596209876:634500 +1596419711:636000 +1596600935:637500 +1596770710:639000 +1596979435:640500 +1597172685:642000 +1597347250:643500 +1597508807:645000 +1597698614:646500 +1597871525:648000 +1598058524:649500 +1598368966:651000 +1598552832:652500 +1598715002:654000 +1598902853:655500 +1599078705:657000 +1599253008:658500 +1599430407:660000 +1599636188:661500 +1599809533:663000 +1600001474:664500 diff --git a/src/assets/user_agents.txt b/src/assets/user_agents.txt new file mode 100644 index 0000000..33bc31e --- /dev/null +++ b/src/assets/user_agents.txt @@ -0,0 +1,7477 @@ +Mozilla/5.0 (Amiga; U; AmigaOS 1.3; en; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (AmigaOS; U; AmigaOS 1.3; en-US; rv:1.8.1.21) Gecko/20090303 SeaMonkey/1.1.15 +Mozilla/5.0 (AmigaOS; U; AmigaOS 1.3; en; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (Android 2.2; Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (BeOS; U; BeOS BeBox; fr; rv:1.9) Gecko/2008052906 BonEcho/2.0 +Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.8.1.1) Gecko/20061220 BonEcho/2.0.0.1 +Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.8.1.10) Gecko/20071128 BonEcho/2.0.0.10 +Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.8.1.17) Gecko/20080831 BonEcho/2.0.0.17 +Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.8.1.6) Gecko/20070731 BonEcho/2.0.0.6 +Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.8.1.7) Gecko/20070917 BonEcho/2.0.0.7 +Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.8.1b2) Gecko/20060901 Firefox/2.0b2 +Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.9a1) Gecko/20051002 Firefox/1.6a1 +Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.9a1) Gecko/20060702 SeaMonkey/1.5a +Mozilla/5.0 (BeOS; U; Haiku BePC; en-US; rv:1.8.1.10pre) Gecko/20080112 SeaMonkey/1.1.7pre +Mozilla/5.0 (BeOS; U; Haiku BePC; en-US; rv:1.8.1.14) Gecko/20080429 BonEcho/2.0.0.14 +Mozilla/5.0 (BeOS; U; Haiku BePC; en-US; rv:1.8.1.17) Gecko/20080831 BonEcho/2.0.0.17 +Mozilla/5.0 (BeOS; U; Haiku BePC; en-US; rv:1.8.1.18) Gecko/20081114 BonEcho/2.0.0.18 +Mozilla/5.0 (BeOS; U; Haiku BePC; en-US; rv:1.8.1.21pre) Gecko/20090218 BonEcho/2.0.0.21pre +Mozilla/5.0 (Darwin; FreeBSD 5.6; en-GB; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.5.0 +Mozilla/5.0 (Darwin; FreeBSD 5.6; en-GB; rv:1.9.1b3pre)Gecko/20081211 K-Meleon/1.5.2 +Mozilla/5.0 (Future Star Technologies Corp.; Star-Blade OS; x86_64; U; en-US) iNet Browser 4.7 +Mozilla/5.0 (Linux 2.4.18-18.7.x i686; U) Opera 6.03 [en] +Mozilla/5.0 (Linux 2.4.18-ltsp-1 i686; U) Opera 6.1 [en] +Mozilla/5.0 (Linux 2.4.19-16mdk i686; U) Opera 6.11 [en] +Mozilla/5.0 (Linux 2.4.21-0.13mdk i686; U) Opera 7.11 [en] +Mozilla/5.0 (Linux X86; U; Debian SID; it; rv:1.9.0.1) Gecko/2008070208 Debian IceWeasel/3.0.1 +Mozilla/5.0 (Linux i686 ; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.70 +Mozilla/5.0 (Linux i686; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 +Mozilla/5.0 (Linux i686; U; en; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.51 +Mozilla/5.0 (Linux) Gecko Iceweasel (Debian) Mnenhy +Mozilla/5.0 (Linux; U) Opera 6.02 [en] +Mozilla/5.0 (Linux; U; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13 +Mozilla/5.0 (MSIE 7.0; Macintosh; U; SunOS; X11; gu; SV1; InfoPath.2; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648) +Mozilla/5.0 (Macintosh; ; Intel Mac OS X; fr; rv:1.8.1.1) Gecko/20061204 Opera +Mozilla/5.0 (Macintosh; I; Intel Mac OS X 11_7_9; de-LI; rv:1.9b4) Gecko/2012010317 Firefox/10.0a4 +Mozilla/5.0 (Macintosh; I; PPC Mac OS X Mach-O; en-US; rv:1.9a1) Gecko/20061204 Firefox/3.0a1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20110608 SeaMonkey/2.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b11) Gecko/20110209 Firefox/ SeaMonkey/2.1b2 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b11pre) Gecko/20110126 Firefox/4.0b11pre +Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b8) Gecko/20100101 Firefox/4.0b8 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0a2) Gecko/20111101 Firefox/9.0a2 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.31 (KHTML, like Gecko) Chrome/13.0.748.0 Safari/534.31 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.801.0 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.803.0 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6) AppleWebKit/531.4 (KHTML, like Gecko) Version/4.0.3 Safari/531.4 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_0) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.0 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_0) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_2) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_3) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.32 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_3) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_4) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_4) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_4) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.65 Safari/535.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.12 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.698.0 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.357 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.2 Chrome/11.0.700.2 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.283 Chrome/11.0.696.65 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.292 Chrome/11.0.696.68 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.310 Chrome/11.0.696.68 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.357 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.209 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.423 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.471 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.478 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.494 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.790.0 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.803.0 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.813.0 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.2 Chrome/11.0.700.2 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.494 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.68 Safari/534.30 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.0 Chrome/17.0.1000.0 Safari/535.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.11 Safari/535.19 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.861.0 Safari/535.2 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.54 Safari/535.2 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.36 Safari/535.7 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.1 Iron/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13+ (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.0 Safari/534.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.794.0 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.803.0 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.65 Safari/535.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.861.0 Safari/535.2 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.65 Safari/535.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Iron/16.0.950.0 Chrome/16.0.950.0 Safari/535.7 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.1 (KHTML, like Gecko) Iron/14.0.850.0 Chrome/14.0.850.0 Safari/535.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.22 (KHTML, like Gecko) Chrome/19.0.1047.0 Safari/535.22 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.7 (KHTML, like Gecko) Iron/16.0.950.0 Chrome/16.0.950.0 Safari/535.7 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/535.19 (KHTML, like Gecko) Iron/18.0.1050.0 Chrome/18.0.1050.0 Safari/535.19 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) Iron/19.0.1100.0 Chrome/19.0.1100.0 Safari/536.5 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8) AppleWebKit/536.15 (KHTML, like Gecko) iCab/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.1 Iron/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.0 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.6 Safari/537.11 +Mozilla/5.0 (Macintosh; Intel Mac OS X; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 Opera 9.27 +Mozilla/5.0 (Macintosh; Intel Mac OS X; U; nb; rv:1.7.5) Gecko/20041110 +Mozilla/5.0 (Macintosh; PPC Mac OS X 10.4; rv:10.0.2) Gecko/20120217 Firefox/10.0.2 TenFourFox/G3 +Mozilla/5.0 (Macintosh; PPC Mac OS X 10.5; rv:10.0.2) Gecko/20120216 Firefox/10.0.2 TenFourFox/7450 +Mozilla/5.0 (Macintosh; PPC Mac OS X 10_5_8) AppleWebKit/534.50.2 (KHTML, like Gecko) iCab/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; PPC Mac OS X 10_5_8) AppleWebKit/536.15+ (KHTML, like Gecko) iCab/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; PPC Mac OS X 10_5_8) AppleWebKit/536.17+ (KHTML, like Gecko) iCab/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; PPC Mac OS X 10_5_8) AppleWebKit/536.25+ (KHTML, like Gecko) iCab/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; PPC Mac OS X 10_5_8) AppleWebKit/537.1+ (KHTML, like Gecko) iCab/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; PPC Mac OS X 10_5_8) AppleWebKit/537.3+ (KHTML, like Gecko) iCab/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; PPC Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.790.0 Safari/535.1 +Mozilla/5.0 (Macintosh; PPC Mac OS X; U; en) Opera 8.51 +Mozilla/5.0 (Macintosh; PPC Mac OS X; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 +Mozilla/5.0 (Macintosh; PPC Mac OS X; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 +Mozilla/5.0 (Macintosh; U; Intel 80486Mac OS X; en-US) AppleWebKit/528.16 (KHTML, like Gecko, Safari/528.16) OmniWeb/v622.8.0.112916 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.0.19) Gecko/2010062819 Firefox/3.0.19 Flock/2.6.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.0.4) Gecko/2008111323 Firefox/3.0.4 Flock/2.0.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.0.5) Gecko/2008121716 Firefox/3.0.5 Flock/2.0.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.0.9) Gecko/2009042318 Firefox/3.0.9 Wyzo/3.0.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.0.9) Gecko/2009042318 Firefox/3.0.9 Wyzo/3.0.3 GTB6 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.1b3pre) Gecko/20090223 SeaMonkey/2.0a3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.1) Gecko/2008070206 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.10) Gecko/2009122115 Firefox/3.0.17 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.3) Gecko/2008100716 Firefox/3.0.3 Flock/2.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.3pre) Gecko/2008090704 GranParadiso/3.0.3pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008111323 Firefox/3.0.4 Flock/2.0.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.6) Gecko/2009011912 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.9) Gecko/2009042318 Firefox/3.0.9 Wyzo/3.0.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1a2pre) Gecko/20080826052737 Minefield/3.1a2pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b1pre) Gecko/20080908170408 Minefield/3.1b1pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081202 SeaMonkey/2.0a2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20090204 Firefox/3.1b3pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b4) Gecko/20090423 Firefox/3.5b4 GTB5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.20 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2a1) Gecko/20090806 Namoroka/3.6a1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2a1pre) Gecko/20090224 Minefield/3.2a1pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2a1pre) Gecko/20090225 Minefield/3.2a1pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2a1pre) Gecko/20090302 Minefield/3.2a1pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2a1pre) Gecko/20090315 Minefield/3.2a1pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9b4pre) Gecko/2008022104 Minefield/3.0b4pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-au; rv:1.9.0.1) Gecko/2008070206 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en; rv:1.9.0.10pre) Gecko/2009041800 Camino/2.0b3pre (like Firefox/3.0.10pre) +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en; rv:1.9.0.8pre) Gecko/2009022800 Camino/2.0b3pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; fr; rv:1.9.1b4) Gecko/20090423 Firefox/3.5b4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; it; rv:1.9.2.22) Gecko/20110902 Firefox/3.6.22 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; it; rv:1.9b4) Gecko/2008030317 Firefox/3.0b4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ko; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; pl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 FBSMTWB +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6.0; en-US; rv:1.9.0.7) Gecko/2009030517 Minefield/3.0.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; de; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 GTB5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.16) Gecko/20101123 SeaMonkey/2.0.11 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20091218 Firefox 3.6b5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13; ) Gecko/20101203 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.24) Gecko/20111103 Firefox/3.6.24 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.3) Gecko/20100402 Prism/1.0b4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.3a1pre) Gecko/20091002 Minefield/3.7a1pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.3a1pre) Gecko/20100103 Minefield/3.7a1pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.3a3pre) Gecko/20100306 Minefield/3.7a3pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.3a4pre) Gecko/20100318 Minefield/3.7a4pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en; rv:1.9.0.18) Gecko/2010021619 Camino/2.0.2 (like Firefox/3.0.18) +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en; rv:1.9.0.19) Gecko/2010111021 Camino/2.0.6 (MultiLang) (like Firefox/3.0.19) +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en; rv:1.9.2.14pre) Gecko/20101212 Camino/2.1a1pre (like Firefox/3.6.14pre) +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; fr; rv:1.9.2.23) Gecko/20110920 Firefox/3.6.23 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; he; rv:1.9.1b4pre) Gecko/20100405 Firefox/3.6.3plugin1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; nl; rv:1.9.0.19) Gecko/2010051911 Camino/2.0.3 (MultiLang) (like Firefox/3.0.19) +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6;en-US; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.7; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_4_11; en) AppleWebKit/525.13 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_4_11; en) AppleWebKit/525.18 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_4_11; en) AppleWebKit/525.18 (KHTML, like Gecko) Sunrise/1.7.4 like Safari/4525.22 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_4_11; en) AppleWebKit/528.16 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-au) AppleWebKit/525.8+ (KHTML, like Gecko) Version/3.1 Safari/525.6 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-gb) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-us) AppleWebKit/525.18 (KHTML, like Gecko) Sunrise/1.7.1 like Safari/5525.18 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-us) AppleWebKit/525.7 (KHTML, like Gecko) Version/3.1 Safari/525.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-us) AppleWebKit/525.9 (KHTML, like Gecko) Version/3.1 Safari/525.9 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-us) AppleWebKit/526.1+ (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; es-es) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; fr-fr) AppleWebKit/525.9 (KHTML, like Gecko) Version/3.1 Safari/525.9 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; it-it) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; ja-jp) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.18 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; pt-br) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_3; en-ca) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_3; es-es) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_3; hu-hu) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_3; nb-no) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_3; nl-nl) AppleWebKit/527+ (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_4; en-gb) AppleWebKit/528.4+ (KHTML, like Gecko) Version/4.0dp1 Safari/526.11.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_4; en-us) AppleWebKit/528.1 (KHTML, like Gecko) Version/4.0 Safari/528.1 Stainless/0.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_4; en-us) AppleWebKit/528.4+ (KHTML, like Gecko) Version/4.0dp1 Safari/526.11.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.18 (KHTML, like Gecko) NetNewsWire/3.1.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.25 (KHTML, like Gecko) Version/3.2 Safari/525.25 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Stainless/0.4 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Stainless/0.4.5 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/528.1 (KHTML, like Gecko) Stainless/0.3.5 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; it-it) AppleWebKit/525.18 (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; ja-jp) AppleWebKit/525.18 (KHTML, like Gecko) Sunrise/1.7.5 like Safari/5525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; ja-jp) AppleWebKit/525.26.2 (KHTML, like Gecko) Version/3.2 Safari/525.26.12 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; sv-se) AppleWebKit/525.26.2 (KHTML, like Gecko) Version/3.2 Safari/525.26.12 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; zh-tw) AppleWebKit/525.18 (KHTML, like Gecko) Stainless/0.3 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; zh-tw) AppleWebKit/525.27.1 (KHTML, like Gecko) Stainless/0.4 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; zh-tw) AppleWebKit/525.27.1 (KHTML, like Gecko) Stainless/0.4.5 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; de-de) AppleWebKit/525.27.1 (KHTML, like Gecko) NetNewsWire/3.1.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/528.16 (KHTML, like Gecko, Safari/528.16) OmniWeb/v622.8.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/ Safari/530.5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/530.6 (KHTML, like Gecko) Chrome/ Safari/530.6 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/530.9 (KHTML, like Gecko) Chrome/ Safari/530.9 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-gb) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-gb) AppleWebKit/528.10+ (KHTML, like Gecko) Version/4.0dp1 Safari/526.11.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/528.16 (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/528.16 (KHTML, like Gecko) Fluid/0.9.6 Safari/528.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/528.16 (KHTML, like Gecko) Stainless/0.5.3 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/528.4+ (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/528.7+ (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/530.6+ (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; es-es) AppleWebKit/525.27.1 (KHTML, like Gecko) Stainless/0.4.5 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; fr-fr) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; hr-hr) AppleWebKit/530.1+ (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; it-it) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; it-it) AppleWebKit/528.8+ (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; ko-kr) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; nb-no) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; ru-ru) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; zh-tw) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; de-de) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; de-de) AppleWebKit/525.28.3 (KHTML, like Gecko) NetNewsWire/3.1.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; de-de) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 Safari/525.28.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-US) AppleWebKit/528.16 (KHTML, like Gecko, Safari/528.16) OmniWeb/v622.8.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-US) AppleWebKit/528.16+(KHTML, like Gecko, Safari/528.16) OmniWeb/v622.8.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-US) AppleWebKit/530.18+(KHTML, like Gecko, Safari/528.16) OmniWeb/v622.8.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-US) AppleWebKit/531.3 (KHTML, like Gecko) Chrome/3.0.192 Safari/531.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.196 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.198 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.212.1 Safari/532.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.1 Safari/530.18 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/531.2+ (KHTML, like Gecko) Version/4.0.1 Safari/530.18 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.197 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.198 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.207.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.208.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.210.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.2 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.221.8 Safari/532.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.2 Safari/532.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.5 Safari/532.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Chrome/4.0.302.2 Safari/532.8 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.343.0 Safari/533.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.422.0 Safari/534.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.13 (KHTML, like Gecko) RockMelt/0.9.48.59 Chrome/9.0.597.107 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.549 Chrome/10.0.648.205 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.2 (KHTML, like Gecko) Chrome/6.0.453.1 Safari/534.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.116 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.3 Safari/531.21.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; fi-fi) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; it-it) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; ja-jp) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; nl-nl) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; zh-cn) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; zh-tw) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/528.10 (KHTML, like Gecko) Chrome/2.0.157.2 Safari/528.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.4 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.204.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.206.1 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.212.1 Safari/532.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.307.11 Safari/532.9 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.207.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.209.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.2 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.212.0 Safari/532.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.221.8 Safari/532.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.4 Safari/532.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; nl-nl) AppleWebKit/531.9 (KHTML, like Gecko) Fluid/0.9.6 Safari/531.9 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; nl-nl) AppleWebKit/532.3+ (KHTML, like Gecko) Fluid/0.9.6 Safari/532.3+ +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; nl-nl) AppleWebKit/532.3+ (KHTML, like Gecko) Version/4.0.3 Safari/531.9 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; de-at) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; de-de) AppleWebKit/531.21.8 (KHTML, like Gecko) NetNewsWire/3.2.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/530.6 (KHTML, like Gecko) Chrome/2.0.174.0 Safari/530.6 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/531.21.8+(KHTML, like Gecko, Safari/528.16) OmniWeb/v622.11.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Iron/4.0.275.2 Chrome/4.0.275.2 Safari/532.5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.343.0 Safari/533.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.366.0 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.70 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; ja-jp) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; nb-no) AppleWebKit/533.16 (KHTML, like Gecko) Version/4.1 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; ru-ru) AppleWebKit/533.2+ (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; HTC-P715a; en-ca) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; ca-es) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; de-de) AppleWebKit/531.22.7 (KHTML, like Gecko) NetNewsWire/3.2.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; de-de) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; el-gr) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/531.9+(KHTML, like Gecko, Safari/528.16) OmniWeb/v622.10.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.363.0 Safari/533.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.366.0 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.428.0 Safari/534.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/534.2 (KHTML, like Gecko) Chrome/6.0.453.1 Safari/534.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.456.0 Safari/534.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-au) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/531.21.11 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.4+ (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/534.1+ (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; es-es) AppleWebKit/531.22.7 (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; it-it) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; ja-jp) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; ko-kr) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; ru-ru) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; zh-cn) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.414.0 Safari/534.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.210 Safari/534.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) RockMelt/0.8.40.147 Chrome/8.0.552.231 Safari/534.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.0 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.13 (KHTML, like Gecko) RockMelt/0.9.46.126 Chrome/9.0.597.107 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.13 (KHTML, like Gecko) RockMelt/0.9.48.59 Chrome/9.0.597.107 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.0 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/11.0.655.0 Safari/534.17 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.2 (KHTML, like Gecko) Chrome/6.0.451.0 Safari/534.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.458.1 Safari/534.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.461.0 Safari/534.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.464.0 Safari/534.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.116 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; fr-FR) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.126 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; ha) AppleWebKit/534.13 (KHTML, like Gecko) RockMelt/0.445.436.1326 Chrome/12.0.632.107 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; th-th) AppleWebKit/533.17.8 (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; ar) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; de-de) AppleWebKit/534.15+ (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.0 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.15 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.639.0 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Flock/3.5.0.4568 Chrome/7.0.517.440 Safari/534.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.116 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.79 Safari/534.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; de-de) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.10 (KHTML, like Gecko) RockMelt/0.8.40.147 Chrome/8.0.552.231 Safari/534.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Iron/9.0.600.2 Chrome/9.0.600.2 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) RockMelt/0.9.48.51 Chrome/9.0.597.107 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) RockMelt/0.9.48.59 Chrome/9.0.597.107 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.134 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.459 Chrome/10.0.648.204 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.518 Chrome/10.0.648.205 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.549 Chrome/10.0.648.205 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.18 (KHTML, like Gecko) Chrome/11.0.660.0 Safari/534.18 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Flock/3.5.3.4628 Chrome/7.0.517.450 Safari/534.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.74 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-gb) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; es-es) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; fr-ch) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; fr-fr) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; it-it) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; ja-jp) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; ko-kr) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; sv-se) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; zh-cn) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; da-dk) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/531.21.8+(KHTML, like Gecko, Safari/528.16) Version/5.10.3 OmniWeb/622.14.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Iron/9.0.600.2 Chrome/9.0.600.2 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.13 (KHTML, like Gecko) RockMelt/0.9.48.59 Chrome/9.0.597.107 Safari/534.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.459 Chrome/10.0.648.204 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.549 Chrome/10.0.648.205 Safari/534.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Iron/7.0.520.1 Chrome/7.0.520.1 Safari/534.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) iCab/4.8 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/534.16+ (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; ja-jp) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; nn-no) AppleWebKit/533.21.1 (KHTML, like Gecko) iCab/4.8b Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) iCab/4.8 Safari/533.16 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_7; en-us) AppleWebKit/533.4 (KHTML, like Gecko) Version/4.1 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_7_0; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_7_0; en-US) AppleWebKit/534.21 (KHTML, like Gecko) Chrome/11.0.678.0 Safari/534.21 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_7_5; en-US) AppleWebKit/533.21.1+(KHTML, like Gecko, Safari/533.19.4) Version/5.11.2 OmniWeb/622.19.3.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_8; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X Mach-O; en-US; rv:1.8.1a2) Gecko/20060512 BonEcho/2.0a2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X Mach-O; en; rv:1.8.1.12) Gecko/20080206 Camino/1.5.5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; de-AT; rv:1.9.1.8) Gecko/20100625 Firefox/3.6.6 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; de-de) AppleWebKit/522.11.1 (KHTML, like Gecko) Version/3.0.3 Safari/522.12.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko) NetNewsWire/3.0d7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko) Shiira/1.2.2 Safari/125 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko, Safari) Cheshire/1.0.UNOFFICIAL +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/418.9.1 (KHTML, like Gecko) Shiira/1.2.2 Safari/125 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/418.9.1 (KHTML, like Gecko) Sunrise/1.6.5 like Safari/419.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko) NetNewsWire/2.1.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko, Safari/125) Cheshire/1.0.ALPHA +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko, Safari/419.3) Cheshire/1.0.ALPHA +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/521.32.1 (KHTML, like Gecko) Safari/521.32.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/522+ (KHTML, like Gecko) Version/3.0.2 Safari/522.12 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/522.11 (KHTML, like Gecko) Version/3.0.2 Safari/522.12 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/522.11.1 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/522.11.1 (KHTML, like Gecko) Version/3.0.3 Safari/522.12.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/523.2+ (KHTML, like Gecko) Version/3.0.3 Safari/522.12.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/523.5+ (KHTML, like Gecko) Version/3.0.3 Safari/522.12.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/523.9+ (KHTML, like Gecko) Version/3.0.3 Safari/522.12.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US) AppleWebKit/525.18 (KHTML, like Gecko, Safari/525.20) OmniWeb/v622.6.1.0.111015 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US) AppleWebKit/528.16 (KHTML, like Gecko, Safari/528.16) OmniWeb/v622.8.0.112941 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.1) Gecko/20060203 Camino/1.0rc1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.1) Gecko/20060214 Camino/1.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.10) Gecko/20070228 Camino/1.0.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.11) Gecko/20070321 Firefox/1.5.0.11 Flock/0.7.12 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.12) Gecko/20070530 Firefox/1.5.0.12 Flock/0.7.14 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.4) Gecko/20060613 Camino/1.0.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.7) Gecko/20060911 Camino/1.0.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.8) Gecko/20061109 Firefox/1.5.0.8 Flock/0.7.8 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.9) Gecko/20061211 SeaMonkey/1.0.7 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061018 Camino/1.1a1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061024 BonEcho/2.0 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.10pre) Gecko/20071127 Firefox/2.0.0.10 Navigator/9.0.0.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.11) Gecko/20071127 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.11) Gecko/20071206 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.11pre) Gecko/20071206 Firefox/2.0.0.11 Navigator/9.0.0.5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.12pre) Gecko/20080122 Firefox/2.0.0.12pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.13) Gecko/20080313 Firefox +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.13) Gecko/20080313 SeaMonkey/1.1.9 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.14) Gecko/20080530 Firefox/2.0.0.14 Flock/1.2.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.16) Gecko/20080703 SeaMonkey/1.1.11 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.2) Gecko/20070221 SeaMonkey/1.1.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.22) Gecko/20090605 SeaMonkey/1.1.17 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.23) Gecko/20090823 SeaMonkey/1.1.18 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.24) Gecko/20100301 SeaMonkey/1.1.19 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.3) Gecko/20070322 BonEcho/2.0.0.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6 Camino/1.5.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.8pre) Gecko/20071001 Firefox/2.0.0.7 Navigator/9.0RC1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.8pre) Gecko/20071019 Firefox/2.0.0.8 Navigator/9.0.0.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.9) Gecko/20071106 Firefox/2.0.0.9 Flock/1.0.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.9pre) Gecko/20071102 Firefox/2.0.0.9 Navigator/9.0.0.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1a3) Gecko/20060601 Camino/1.0+ +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1b1) Gecko/20060710 Firefox/2.0b1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8b5) Gecko/20051021 Camino/1.0+ +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.9a8pre) Gecko/2007083104 Minefield/3.0a8pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-au) AppleWebKit/523.10.3 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-us) AppleWebKit/419.2.1 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-us) AppleWebKit/522.11.1 (KHTML, like Gecko) Version/3.0.3 Safari/522.12.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-us) AppleWebKit/525.1+ (KHTML, like Gecko) Version/3.0.4 Safari/523.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.11) Gecko/20071128 Camino/1.5.4 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.1pre) Gecko/20061126 Camino/1.1a1+ +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.2pre) Gecko/20070108 Camino/1.1a2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.2pre) Gecko/20070223 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.2pre) Gecko/20070223 Camino/1.1b +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.4) Gecko/20070509 Camino/1.5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.4) Gecko/20070607 Camino/1.5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.4) Gecko/20070609 Camino/1.5 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.4pre) Gecko/20070417 Camino/1.1b+ +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.4pre) Gecko/20070521 Camino/1.6a1pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.4pre) Gecko/20070526 Camino/1.6a1pre +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.6) Gecko/20070809 Camino/1.5.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.6) Gecko/20070809 Firefox/2.0.0.6 Camino/1.5.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; es-ES; rv:1.8.1.18) Gecko/20081031 SeaMonkey/1.1.13 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; es-es) AppleWebKit/523.15.1 (KHTML, like Gecko) Version/3.0.4 Safari/523.15 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; fr) AppleWebKit/418.9.1 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; fr) AppleWebKit/523.12.2 (KHTML, like Gecko) Sunrise/1.6.0 like Safari/523.12.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; fr) AppleWebKit/523.12.2 (KHTML, like Gecko) Version/3.0.4 Safari/523.12.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; fr-fr) AppleWebKit/523.10.3 (KHTML, like Gecko) Version/3.0.4 Safari/523.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; fr-fr) AppleWebKit/525.1+ (KHTML, like Gecko) Version/3.0.4 Safari/523.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; it-IT) AppleWebKit/521.25 (KHTML, like Gecko) Safari/521.24 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; it-it) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; it-it) AppleWebKit/523.12.2 (KHTML, like Gecko) Version/3.0.4 Safari/523.12.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; ja-jp) AppleWebKit/523.10.3 (KHTML, like Gecko) Version/3.0.4 Safari/523.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; ja-jp) AppleWebKit/523.12.2 (KHTML, like Gecko) Version/3.0.4 Safari/523.12.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; ko-kr) AppleWebKit/523.15.1 (KHTML, like Gecko) Version/3.0.4 Safari/523.15 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; nl-NL; rv:1.8.1.3) Gecko/20080722 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; ru-ru) AppleWebKit/522.11.1 (KHTML, like Gecko) Version/3.0.3 Safari/522.12.1 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; sv-se) AppleWebKit/523.10.3 (KHTML, like Gecko) Version/3.0.4 Safari/523.10 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; sv-se) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; sv-se) AppleWebKit/523.12.2 (KHTML, like Gecko) Version/3.0.4 Safari/523.12.2 +Mozilla/5.0 (Macintosh; U; Intel Mac OS X; zh-tw) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13.3 +Mozilla/5.0 (Macintosh; U; Mac OS X 10_5_7; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/ Safari/530.5 +Mozilla/5.0 (Macintosh; U; Mac OS X 10_6_1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/ Safari/530.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-GB; rv:1.9.2.19) Gecko/20110707 Firefox/3.6.19 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-GB; rv:1.9b5) Gecko/2008032619 Firefox/3.0b5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-US; rv:1.9.0.16) Gecko/2010010314 Firefox/3.0.16 Flock/2.5.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-US; rv:1.9.0.4) Gecko/20081029 Firefox/2.0.0.18 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-US; rv:1.9.1b2pre) Gecko/20081027 Minefield/3.1b2pre +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-US; rv:1.9.1b3pre) Gecko/20090223 SeaMonkey/2.0a3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-US; rv:1.9.2.22) Gecko/20110902 Firefox/3.6.22 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en; rv:1.9.0.19) Gecko/2010051911 Camino/2.0.3 (like Firefox/3.0.19) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en; rv:1.9.2.24) Gecko/20111114 Camino/2.1 (like Firefox/3.6.24) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.0.16) Gecko/2010010314 Firefox/3.0.16 Flock/2.5.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081212 Mozilla/5.0 (Windows; U; Windows NT 5.1; en) AppleWebKit/526.9 (KHTML, like Gecko) Version/4.0dp1 Safari/526.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; it; rv:1.9.0.19) Gecko/2010111021 Camino/2.0.6 (MultiLang) (like Firefox/3.0.19) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; da-dk) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; de) AppleWebKit/528.4+ (KHTML, like Gecko) Version/4.0dp1 Safari/526.11.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; de-de) AppleWebKit/533.16 (KHTML, like Gecko) Version/4.1 Safari/533.16 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; en) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.18 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; en) AppleWebKit/525.3+ (KHTML, like Gecko) Version/3.0.4 Safari/523.12.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; en) AppleWebKit/528.4+ (KHTML, like Gecko) Version/4.0dp1 Safari/526.11.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; es-es) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; fr) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.2 Safari/525.22 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; fr) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; fr-fr) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; hu-hu) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; it-it) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; ja-jp) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.18 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; ja-jp) AppleWebKit/533.16 (KHTML, like Gecko) Version/4.1 Safari/533.16 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; nl-nl) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; nl-nl) AppleWebKit/533.16 (KHTML, like Gecko) Version/4.1 Safari/533.16 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; pl-pl) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; sv-se) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.2 Safari/525.22 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; sv-se) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; tr) AppleWebKit/528.4+ (KHTML, like Gecko) Version/4.0dp1 Safari/526.11.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_2; en) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.18 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_2; en-gb) AppleWebKit/526+ (KHTML, like Gecko) Version/3.1 Safari/525.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_2; en-gb) AppleWebKit/526+ (KHTML, like Gecko) Version/3.1 iPhone +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_3; en) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_3; en-us) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_3; sv-se) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_4; en-us) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.0.4 Safari/523.10 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_4; en-us) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_4; fr-fr) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_5; en-us) AppleWebKit/525.26.2 (KHTML, like Gecko) Version/3.2 Safari/525.26.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_5; fi-fi) AppleWebKit/525.26.2 (KHTML, like Gecko) Version/3.2 Safari/525.26.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_5; fr-fr) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_6; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_6; en-us) AppleWebKit/528.16 (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_6; en-us) AppleWebKit/530.1+ (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_6; fr-fr) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_6; nl-nl) AppleWebKit/530.0+ (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_7; en-us) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; en-us) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; en-us) AppleWebKit/532.0+ (KHTML, like Gecko) Version/4.0.3 Safari/531.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; en-us) AppleWebKit/532.0+ (KHTML, like Gecko) Version/4.0.3 Safari/531.9.2009 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; ja-jp) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/3.2.3 Safari/525.28.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; ja-jp) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; ja-jp) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; ja-jp) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; zh-cn) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_6_1; en_GB, en_US) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_8_1; nn-no) AppleWebKit/533.21.1 (KHTML, like Gecko) iCab/4.8b Safari/533.16 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de; rv:1.8.1.15) Gecko/20080623 Firefox/2.0.0.15 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de; rv:1.8.1.5pre) Gecko/20070605 Camino/1.6a1pre +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-GB; rv:1.8.1a2) Gecko/20060512 BonEcho/2.0a2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20021216 Chimera/0.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20021220 Chimera/0.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20030109 Chimera/0.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20030111 Chimera/0.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20030306 Camino/0.7 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.3a) Gecko/20030101 Phoenix/0.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4a) Gecko/20030401 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5) Gecko/20031026 Firebird/0.7 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5.1) Gecko/20031120 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6) Gecko/20040113 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040517 Camino/0.8b +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040614 Firefox/0.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.13) Gecko/20060410 Firefox/1.0.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.13) Gecko/20060414 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040803 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040825 Camino/0.8.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050319 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.7) Gecko/20050503 Firefox/1.0.3 Madfox/0.3.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.8) Gecko/20050427 Camino/0.8.4 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8) Gecko/20051107 Camino/1.0b1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8) Gecko/20051228 Camino/1.0b1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8) Gecko/20051229 Camino/1.0b2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8) Gecko/20060320 Firefox/2.0a1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8) Gecko/20060322 Firefox/2.0a1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.1) Gecko/20060119 Camino/1.0b2+ +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.1) Gecko/20060214 Camino/1.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.1) Gecko/20060217 Flock/0.5.11 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.1) Gecko/20060307 Camino/1.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.1) Gecko/20060314 Flock/0.5.13.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.1) Gecko/20060331 Flock/0.7 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.10) Gecko/20070228 Camino/1.0.4 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.3) Gecko/20060427 Camino/1.0.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.3) Gecko/20060503 Camino/1.0.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.4) Gecko/20060612 Firefox/1.5.0.4 Flock/0.7.0.17.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.4) Gecko/20060613 Camino/1.0.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.4) Gecko/20060620 Firefox/1.5.0.4 Flock/0.7.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.5) Gecko/20060731 Firefox/1.5.0.5 Flock/0.7.4.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.7) Gecko/20060910 SeaMonkey/1.0.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.7) Gecko/20060911 Camino/1.0.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.7) Gecko/20060911 Camino/1.0.3 (MultiLang) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1) Gecko/20061013 Camino/1.0+ +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1) Gecko/20061013 Camino/1.0+ (Firefox compatible) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1) Gecko/20061025 BonEcho/2.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1) Gecko/20061026 BonEcho/2.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.1) Gecko/20061204 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.11pre) Gecko/20071206 Firefox/2.0.0.11 Navigator/9.0.0.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.12) Gecko/20080219 Firefox/2.0.0.12 Navigator/9.0.0.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.2) Gecko/20070221 SeaMonkey/1.1.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.2) Gecko/20070223 BonEcho/2.0.0.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.3) Gecko/20070329 BonEcho/2.0.0.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.4 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.5pre) Gecko/20070710 Firefox/2.0.0.4 Navigator/9.0b2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.7pre) Gecko/20070815 Firefox/2.0.0.6 Navigator/9.0b3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.8) Gecko/20071101 Firefox/2.0.0.8 Flock/1.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.8pre) Gecko/20071015 Firefox/2.0.0.7 Navigator/9.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1a2) Gecko/20060512 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1a2) Gecko/20060512 BonEcho/2.0a2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1a3) Gecko/20060528 Camino/1.0+ +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1b1) Gecko/20060707 Firefox/2.0b1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1b1) Gecko/20060710 Firefox/2.0b1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1b1) Gecko/20060721 Camino/1.0+ +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1b1) Gecko/20060807 Camino/1.0+ +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1b1) Gecko/20061110 Firefox/2.0b3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050217 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko Camino/0.9+ +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b4) Gecko/20050908 Firefox/1.4 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b4) Gecko/20050914 Camino/1.0a1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b5) Gecko/20051006 Firefox/1.4.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b5) Gecko/20051021 Flock/0.4 Firefox/1.0+ +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.9a1) Gecko/20060707 SeaMonkey/1.5a +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.9a1) Gecko/20061204 Firefox/3.0a1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.9a1) Gecko/20061204 GranParadiso/3.0a1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.7.12) Gecko/20050928 Firefox/1.0.7 Madfox/3.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.12) Gecko/20080206 Camino/1.5.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.21) Gecko/20090327 Camino/1.6.7 (like Firefox/2.0.0.21pre) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.2pre) Gecko/20070227 Camino/1.1b +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.4) Gecko/20070509 Camino/1.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.4pre) Gecko/20070511 Camino/1.6pre +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.6) Gecko/20070809 Camino/1.5.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.9a4pre) Gecko/20070404 Camino/1.2+ +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; es-ES; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; es-ES; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fr-FR; rv:1.7.11) Gecko/20050727 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fr; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; it; rv:1.8.1.21) Gecko/20090327 Camino/1.6.7 (MultiLang) (like Firefox/2.0.0.21pre) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.7.2) Gecko/20040804 Netscape/7.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.7.3) Gecko/20040913 Firefox/0.10 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.8.1.16) Gecko/20080702 Firefox +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ca-es) AppleWebKit/522.11.1 (KHTML, like Gecko) Version/3.0.3 Safari/522.12.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; da-dk) AppleWebKit/522+ (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-CH) AppleWebKit/419.2 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-DE) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558.46 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-ch) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-ch) AppleWebKit/85 (KHTML, like Gecko) Safari/85 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/124 (KHTML, like Gecko) Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12_Adobe +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12_Adobe +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312.3.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/312.1.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/312.5.2 (KHTML, like Gecko) Safari/312.3.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.5_Adobe +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/312.8 (KHTML, like Gecko) Shiira/1.2.2 Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/312.8.1 (KHTML, like Gecko) Safari/312.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/412 (KHTML, like Gecko) Safari/412 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/412.6 (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/412.6 (KHTML, like Gecko) Safari/412.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/412.6 (KHTML, like Gecko) Safari/412.2_Adobe +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/412.6.2 (KHTML, like Gecko) Safari/412.2.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/412.7 (KHTML, like Gecko) Safari/412.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/412.7 (KHTML, like Gecko) Safari/412.5_Adobe +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13_Adobe +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/419.2 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/522.11 (KHTML, like Gecko) Version/3.0.2 Safari/522.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko) Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/85.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.4 (KHTML, like Gecko) Safari/100 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.5.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.1.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.5 (KHTML, like Gecko) Safari/312.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/125.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.5.2 (KHTML, like Gecko) Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.5.2 (KHTML, like Gecko) Safari/312.3.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.3.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.8.1 (KHTML, like Gecko) Safari/312.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412 (KHTML, like Gecko) Safari/412 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412.6 (KHTML, like Gecko) Safari/412.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412.6.2 (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412.6.2 (KHTML, like Gecko) Safari/412.2.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412.7 (KHTML, like Gecko) Safari/412.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412.7 (KHTML, like Gecko) Safari/412.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/416.11 (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/416.11 (KHTML, like Gecko) Safari/416.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/417.9 (KHTML, like Gecko) Hana/1.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/417.9 (KHTML, like Gecko) NetNewsWire/2.0.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/417.9 (KHTML, like Gecko, Safari) Shiira/1.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.8 (KHTML, like Gecko) NetNewsWire/2.1.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.8 (KHTML, like Gecko, Safari) Cheshire/1.0.UNOFFICIAL +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko) AppleWebKit/418.9 Cheshire/1.0.ALPHA +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko) Hana/1.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko) Safari/419.3 Cheshire/1.0.ALPHA +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko) Shiira/1.2.2 Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko, Safari) Safari/419.3 Cheshire/1.0.ALPHA +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko, Safari/111) Cheshire/1.0.ALPHA +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Safari) Cheshire/1.0.ALPHA +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko) Shiira/1.2.2 Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko) Shiira/1.2.3 Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko, Safari/419.3) Cheshire/1.0.ALPHA +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/419.2.1 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/419.3 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/522+ (KHTML, like Gecko) OmniWeb +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/522.10.1 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/522.10.1 (KHTML, like Gecko) Shiira/1.2.2 Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/522.11 (KHTML, like Gecko) Version/3.0.2 Safari/522.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/522.11.1 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/522.11.1 (KHTML, like Gecko) Version/3.0.3 Safari/522.12.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/523.3+ (KHTML, like Gecko) Version/3.0.3 Safari/522.12.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.15 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.57 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.59 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.60 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.66 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/420+ (KHTML, like Gecko, Safari) OmniWeb/v595 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/420+ (KHTML, like Gecko, Safari/420) OmniWeb/v601 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/420+ (KHTML, like Gecko, Safari/420) OmniWeb/v602 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/420+ (KHTML, like Gecko, Safari/420) OmniWeb/v603 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/420+ (KHTML, like Gecko, Safari/420) OmniWeb/v605 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v496 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20021104 Chimera/0.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20021111 Chimera/0.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.1a) Gecko/20020610 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.2) Gecko/20021126 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.2b) Gecko/20021016 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-ca) AppleWebKit/416.11 (KHTML, like Gecko) Safari/416.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/124 (KHTML, like Gecko) Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.7 (KHTML, like Gecko) SunriseBrowser/0.833 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.7 (KHTML, like Gecko) SunriseBrowser/0.84 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.7 (KHTML, like Gecko) SunriseBrowser/0.853 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.7 (KHTML, like Gecko) SunriseBrowser/0.895 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.1 (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.5 (KHTML, like Gecko) Safari/312.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.8.1 (KHTML, like Gecko) Safari/312.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/412 (KHTML, like Gecko) Safari/412 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/412 (KHTML, like Gecko) Safari/412 Privoxy/3.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/412.6 (KHTML, like Gecko) Safari/412.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/412.7 (KHTML, like Gecko) Safari/412.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/416.11 (KHTML, like Gecko) Safari/416.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/417.9 (KHTML, like Gecko) NetNewsWire/2.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.9.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/418.9 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/419 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/419 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/522+ (KHTML, like Gecko) Version/3.0.2 Safari/522.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/522.11 (KHTML, like Gecko) Version/3.0.2 Safari/522.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.3 (KHTML, like Gecko) Version/3.0.4 Safari/523.10 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.15.1 (KHTML, like Gecko) Shiira Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.6 (KHTML, like Gecko) Version/3.0.3 Safari/523.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en_CA) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en_CA) AppleWebKit/419 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en_CA) AppleWebKit/522+ (KHTML, like Gecko) Shiira/1.2.3 Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en_US) AppleWebKit/412 (KHTML, like Gecko) Safari/412 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es) AppleWebKit/419 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-ES) AppleWebKit/412 (KHTML, like Gecko) Safari/412 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/312.5.2 (KHTML, like Gecko) Safari/312.3.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fi-fi) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fi-fi) AppleWebKit/420+ (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/312.5 (KHTML, like Gecko) Safari/312.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/312.5.2 (KHTML, like Gecko) Safari/312.3.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/412 (KHTML, like Gecko) Safari/412 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/412.6 (KHTML, like Gecko) Safari/412.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/412.7 (KHTML, like Gecko) Safari/412.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/416.11 (KHTML, like Gecko) Safari/416.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/416.12 (KHTML, like Gecko) Safari/412.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13_Adobe +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/417.9 (KHTML, like Gecko) +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/417.9 (KHTML, like Gecko) NetNewsWire/2.0.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-FR; rv:0.9.4.1) Gecko/20020315 Netscape6/6.2.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-ca) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-ch) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-ch) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-ch) AppleWebKit/312.1.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/312.1 (KHTML, like Gecko) Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/312.1.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/312.5 (KHTML, like Gecko) Safari/312.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/312.5.2 (KHTML, like Gecko) Safari/312.3.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/412 (KHTML, like Gecko) Safari/412 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/412.7 (KHTML, like Gecko) Safari/412.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/416.11 (KHTML, like Gecko) Safari/416.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/523.10.3 (KHTML, like Gecko) Version/3.0.4 Safari/523.10 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-IT) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.15 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/412.6 (KHTML, like Gecko) Safari/412.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/412.7 (KHTML, like Gecko) Safari/412.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.9.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/418.9 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/419 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/412.7 (KHTML, like Gecko) Safari/412.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/418.9 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/419 (KHTML, like Gecko) Shiira/1.2.3 Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nb-no) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nb-no) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nb-no) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/416.11 (KHTML, like Gecko) Safari/312 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/416.11 (KHTML, like Gecko) Safari/416.12 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.8 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.9.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pl-PL; rv:1.0.1) Gecko/20021111 Chimera/0.6 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pl-pl) AppleWebKit/312.8 (KHTML, like Gecko) Shiira/1.2.1 Safari/125 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pl-pl) AppleWebKit/312.8 (KHTML, like Gecko, Safari) DeskBrowse/1.0 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pt-pt) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/312.5.2 (KHTML, like Gecko) Safari/312.3.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.8_Adobe +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/418.9 (KHTML, like Gecko) Safari/ +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/418.9 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/419 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/523.12.2 (KHTML, like Gecko) Version/3.0.4 Safari/523.12.2 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; tr-tr) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS; en) iCab 3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS; en-en) AppleWebKit/412 (KHTML, like Gecko) Safari/412 +Mozilla/5.0 (Macintosh; U; PPC Mac OS; pl-pl) AppleWebKit/412 (KHTML, like Gecko) Safari/412 +Mozilla/5.0 (Macintosh; U; PPC Max OS X Mach-O; it-IT; rv:1.8.0.7) Gecko/200609211 Camino/1.0.3 +Mozilla/5.0 (Macintosh; U; PPC; de-DE; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Macintosh; U; PPC; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Macintosh; U; PPC; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Macintosh; U; PPC; en-US; mimic; rv:9.3.0) Clecko/20120101 Classilla/CFM +Mozilla/5.0 (Macintosh; U; PPC; en-US; mimic; rv:9.3.0) Gecko/20120117 Firefox/3.6.25 Classilla/CFM +Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.3) Gecko/20010802 +Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.4.1) Gecko/20020318 Netscape6/6.2.2 +Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0.2) Gecko/20021216 +Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0rc2) Gecko/20020512 Netscape/7.0b1 +Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.2a) Gecko/20020910 +Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.2b) Gecko/20021016 +Mozilla/5.0 (Macintosh; U; PPC; fr-FR; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Macintosh; U; PPC; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Macintosh; U; PPC; ja-JP; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Macintosh; U; PowerPC Mac OS X 10_5_8; en-US) AppleWebKit/531.9+(KHTML, like Gecko, Safari/528.16) OmniWeb/v622.10.0 +Mozilla/5.0 (Macintosh; U; i386 Mac OS X; en) AppleWebKit/417.9 (KHTML, like Gecko) Hana/1.0 +Mozilla/5.0 (Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_0_1 like Mac OS X; fr-fr) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5G77 Safari/525.20 +Mozilla/5.0 (OS/2; U; Warp 4.5; de-DE; rv:1.7.5) Gecko/20050523 +Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.8.0.6) Gecko/20060730 MultiZilla/1.8.2.0i SeaMonkey/1.0.4 +Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.8.0.7) Gecko/20060910 MultiZilla/1.8.2.0i SeaMonkey/1.0.5 +Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.8.1.3pre) Gecko/20070307 SeaMonkey/1.1.1+ +Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.9a1) Gecko/20051119 MultiZilla/1.8.1.0s SeaMonkey/1.5a +Mozilla/5.0 (Photon; U; QNX x86pc; en-US; rv:1.6) Gecko/20040429 +Mozilla/5.0 (SunOS 5.8 sun4u; U) Opera 5.0 [en] +Mozilla/5.0 (U; Windows NT 5.1; en-GB; rv:1.8.1.17) Gecko/20080808 Firefox/2.0.0.17 +Mozilla/5.0 (U; Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (U;) AppleWebKit/532.0 (KHTML, like Gecko) Iron/3.0.197.0 Safari/532.0 +Mozilla/5.0 (Windows 2000; U) Opera 6.01 [de] +Mozilla/5.0 (Windows 2000; U) Opera 6.01 [en] +Mozilla/5.0 (Windows 2000; U) Opera 6.02 [en] +Mozilla/5.0 (Windows 2000; U) Opera 6.03 [en] +Mozilla/5.0 (Windows 2000; U) Opera 6.04 [en] +Mozilla/5.0 (Windows 2000; U) Opera 7.0 [en] +Mozilla/5.0 (Windows 8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (Windows 98; U) Opera 5.12 [de] +Mozilla/5.0 (Windows 98; U; en) Opera 8.54 +Mozilla/5.0 (Windows 98; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 +Mozilla/5.0 (Windows ME; U) Opera 6.05 [de] +Mozilla/5.0 (Windows ME; U; en) Opera 8.51 +Mozilla/5.0 (Windows NT 4.0; U) Opera 6.05 [en] +Mozilla/5.0 (Windows NT 5.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.1 Iron/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (Windows NT 5.0; U) Opera 7.01 [en] +Mozilla/5.0 (Windows NT 5.0; U) Opera 7.11 [en] +Mozilla/5.0 (Windows NT 5.0; U) Opera 7.21 [en] +Mozilla/5.0 (Windows NT 5.0; U) Opera 7.54 [en] +Mozilla/5.0 (Windows NT 5.0; U; de) Opera 8.50 +Mozilla/5.0 (Windows NT 5.0; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (Windows NT 5.0; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0 +Mozilla/5.0 (Windows NT 5.0; rv:1.9.1.19) Gecko/20110420 Firefox/3.6 SeaMonkey/2.0.14 +Mozilla/5.0 (Windows NT 5.0; rv:2.0.1) Gecko/20110608 Firefox/4.0.1 SeaMonkey/2.1 +Mozilla/5.0 (Windows NT 5.0; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (Windows NT 5.0; rv:5.0) Gecko/20110706 Firefox/5.0 SeaMonkey/2.2 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.43 Safari/534.24 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.700.3 Safari/534.24 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.1 Chrome/11.0.700.1 Safari/534.24 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.2 Chrome/11.0.700.2 Safari/534.24 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.3 Chrome/11.0.700.3 Safari/534.24 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.310 Chrome/11.0.696.68 Safari/534.24 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.357 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.484 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.494 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.25 (KHTML, like Gecko) Chrome/12.0.704.0 Safari/534.25 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.25 (KHTML, like Gecko) Chrome/12.0.706.0 Safari/534.25 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30 ChromePlus/1.6.3.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Comodo_Dragon/12.1.0.0 Chrome/12.0.742.91 Safari/534.30 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Iron/12.0.750.0 Chrome/12.0.750.0 Safari/534.30 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.20 Safari/535.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.792.0 Safari/535.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.809.0 Safari/535.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.810.0 Safari/535.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.813.0 Safari/535.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.815.0 Safari/535.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Iron/13.0.800.0 Chrome/13.0.800.0 Safari/535.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.0 Chrome/17.0.1000.0 Safari/535.11 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.1 Chrome/17.0.1000.1 Safari/535.11 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.860.0 Safari/535.2 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.864.0 Safari/535.2 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.872.0 Safari/535.2 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.6 (KHTML, like Gecko) Chrome/16.0.897.0 Safari/535.6 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.0 Iron/20.0.1150.0 Safari/536.11 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.1 Iron/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.0 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.1 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1250.0 Iron/22.0.2150.0 Safari/537.4 +Mozilla/5.0 (Windows NT 5.1; U) Opera 7.03 [de] +Mozilla/5.0 (Windows NT 5.1; U) Opera 7.11 [en] +Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54 [de] +Mozilla/5.0 (Windows NT 5.1; U; ; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.52 +Mozilla/5.0 (Windows NT 5.1; U; Firefox/3.5; en; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.53 +Mozilla/5.0 (Windows NT 5.1; U; Firefox/4.5; en; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.53 +Mozilla/5.0 (Windows NT 5.1; U; Firefox/5.0; en; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.53 +Mozilla/5.0 (Windows NT 5.1; U; de) Opera 8.50 +Mozilla/5.0 (Windows NT 5.1; U; de) Opera 8.52 +Mozilla/5.0 (Windows NT 5.1; U; de; rv:1.7.5) Gecko/20041110 +Mozilla/5.0 (Windows NT 5.1; U; de; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 +Mozilla/5.0 (Windows NT 5.1; U; de; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.51 +Mozilla/5.0 (Windows NT 5.1; U; de; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.52 +Mozilla/5.0 (Windows NT 5.1; U; de; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 11.00 +Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.0 +Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.01 +Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.02 +Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.50 +Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.51 +Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.52 +Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.53 +Mozilla/5.0 (Windows NT 5.1; U; en-GB; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.51 +Mozilla/5.0 (Windows NT 5.1; U; en-GB; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.61 +Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.7.5) Gecko/20041110 +Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 +Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 Opera 9.22 +Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 Opera 9.24 +Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 Opera 9.26 +Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.51 +Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/5.0 Opera 11.11 +Mozilla/5.0 (Windows NT 5.1; U; es-es; rv:1.7.5) Gecko/20041110 +Mozilla/5.0 (Windows NT 5.1; U; es-la; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 Opera 9.27 +Mozilla/5.0 (Windows NT 5.1; U; fr) Opera 8.51 +Mozilla/5.0 (Windows NT 5.1; U; pl) Opera 8.54 +Mozilla/5.0 (Windows NT 5.1; U; pl; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 11.00 +Mozilla/5.0 (Windows NT 5.1; U; pt-br; rv:1.7.5) Gecko/20041110 +Mozilla/5.0 (Windows NT 5.1; U; ru) Opera 8.51 +Mozilla/5.0 (Windows NT 5.1; U; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (Windows NT 5.1; U; tr; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 +Mozilla/5.0 (Windows NT 5.1; U; zh-cn; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50 +Mozilla/5.0 (Windows NT 5.1; U; zh-cn; rv:1.8.1) Gecko/20091102 Firefox/3.5.5 +Mozilla/5.0 (Windows NT 5.1; U; zh-cn; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.53 +Mozilla/5.0 (Windows NT 5.1; U; zh-cn; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.70 +Mozilla/5.0 (Windows NT 5.1; U; zh-tw) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.2 Chrome/11.0.700.2 Safari/534.24 +Mozilla/5.0 (Windows NT 5.1; rv:1.9.2.8) Gecko/20110608 Firefox/3.6.8 Seamonkey/2.1 +Mozilla/5.0 (Windows NT 5.1; rv:1.9a1) Gecko/20060217 Firefox/1.6a1 +Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 +Mozilla/5.0 (Windows NT 5.1; rv:12.0) Gecko/20120403211507 Firefox/12.0 +Mozilla/5.0 (Windows NT 5.1; rv:12.0) Gecko/20120605 Firefox/12.2 Palemoon/12.2 +Mozilla/5.0 (Windows NT 5.1; rv:12.2) Gecko/20120605 Firefox/12.2 PaleMoon/12.2 +Mozilla/5.0 (Windows NT 5.1; rv:12.2.1) Gecko/20120616 Firefox/12.2.1 PaleMoon/12.2.1 +Mozilla/5.0 (Windows NT 5.1; rv:12.2.1) Gecko/20120616 PaleMoon/12.2.1 +Mozilla/5.0 (Windows NT 5.1; rv:12.3) Gecko/20120714 Firefox/12.3 PaleMoon/12.3 +Mozilla/5.0 (Windows NT 5.1; rv:12.3) Gecko/20120717 Firefox/12.3 PaleMoon/12.3 +Mozilla/5.0 (Windows NT 5.1; rv:12.3) Gecko/20120728 Firefox/12.3r2 PaleMoon/12.3r2 +Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20120405 Firefox/14.0a1 +Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20100101 Firefox/13.0.1 +Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20120819 Firefox/15.0 PaleMoon/15.0 +Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20120911 Firefox/15.1 PaleMoon/15.1 +Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20110511 Firefox/4.0.1 SeaMonkey/2.1 +Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20110608 Firefox/4.0.1 SeaMonkey/2.1 +Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20110608 Firefox/4.0.1 SeaMonkey/2.1 Lightning/1.0b4pre +Mozilla/5.0 (Windows NT 5.1; rv:2.0b13pre) Gecko/20110223 Firefox/4.0b13pre +Mozilla/5.0 (Windows NT 5.1; rv:2.0b8pre) Gecko/20101127 Firefox/4.0b8pre +Mozilla/5.0 (Windows NT 5.1; rv:2.0b9pre) Gecko/20110105 Firefox/4.0b9pre +Mozilla/5.0 (Windows NT 5.1; rv:6.0) Gecko/20100101 Firefox/6.0 FirePHP/0.6 +Mozilla/5.0 (Windows NT 5.1; rv:7.0a1) Gecko/20110612 Firefox/7.0a1 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 5.1; rv:7.0a1) Gecko/20110619 Firefox/7.0a1 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 5.1; rv:8.0; en_us) Gecko/20100101 Firefox/8.0 +Mozilla/5.0 (Windows NT 5.2) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (Windows NT 5.2) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.792.0 Safari/535.1 +Mozilla/5.0 (Windows NT 5.2) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.794.0 Safari/535.1 +Mozilla/5.0 (Windows NT 5.2) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.813.0 Safari/535.1 +Mozilla/5.0 (Windows NT 5.2) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.0 Chrome/17.0.1000.0 Safari/535.11 +Mozilla/5.0 (Windows NT 5.2) AppleWebKit/535.7 (KHTML, like Gecko) Iron/16.0.950.0 Chrome/16.0.950.0 Safari/535.7 +Mozilla/5.0 (Windows NT 5.2) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.1 Iron/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (Windows NT 5.2) AppleWebKit/536.5 (KHTML, like Gecko) Iron/19.0.1100.0 Chrome/19.0.1100.0 Safari/536.5 +Mozilla/5.0 (Windows NT 5.2) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.0 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (Windows NT 5.2; U; de; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 +Mozilla/5.0 (Windows NT 5.2; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 Opera 9.27 +Mozilla/5.0 (Windows NT 5.2; U; ru; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.70 +Mozilla/5.0 (Windows NT 5.2; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 (Windows NT 5.2; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7 +Mozilla/5.0 (Windows NT 5.2; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (Windows NT 5.2; rv:10.0.1) Gecko/20100101 Firefox/10.0.1 SeaMonkey/2.7.1 +Mozilla/5.0 (Windows NT 5.2; rv:15.0) Gecko/20120909 Firefox/15.0.1 SeaMonkey/2.12.1 +Mozilla/5.0 (Windows NT 5.2; rv:2.0b13pre) Gecko/20110304 Firefox/4.0b13pre +Mozilla/5.0 (Windows NT 5.2; rv:2.0b13pre) Gecko/20110317 SeaMonkey/2.1b3pre +Mozilla/5.0 (Windows NT 5.2; rv:2.0b5pre) Gecko/20100830 SeaMonkey/2.1b1pre +Mozilla/5.0 (Windows NT 5.2; rv:2.0b7pre) Gecko/20100915 Firefox/4.0b7pre SeaMonkey/2.1b1pre +Mozilla/5.0 (Windows NT 5.2; rv:2.0b8pre) Gecko/20101014 SeaMonkey/2.1b2pre +Mozilla/5.0 (Windows NT 5.2; rv:2.0b8pre) Gecko/20101028 SeaMonkey/2.1b2pre +Mozilla/5.0 (Windows NT 5.2; rv:2.0b9pre) Gecko/20101231 SeaMonkey/2.1b2pre +Mozilla/5.0 (Windows NT 5.2; rv:2.0b9pre) Gecko/20110110 SeaMonkey/2.1b2pre +Mozilla/5.0 (Windows NT 5.2; rv:2.2a1pre) Gecko/20110327 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:6.0a1) Gecko/20110512 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110524 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110525 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110526 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110527 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110529 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110530 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110601 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110602 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110603 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110605 SeaMonkey/2.2a1pre +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110607 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110610 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110613 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110614 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110616 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110618 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110619 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110621 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 5.2; rv:7.0a1) Gecko/20110622 SeaMonkey/2.4a1 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.3 Safari/534.24 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.1 Chrome/11.0.700.1 Safari/534.24 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.2 Chrome/11.0.700.2 Safari/534.24 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.3 Chrome/11.0.700.3 Safari/534.24 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/534.30 (KHTML, like Gecko) Iron/12.0.750.0 Chrome/12.0.750.0 Safari/534.30 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.1 Safari/535.1 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.20 Safari/535.1 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.792.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Iron/13.0.800.0 Chrome/13.0.800.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.0 Chrome/17.0.1000.0 Safari/535.11 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.1 Chrome/17.0.1000.1 Safari/535.11 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.2 (KHTML, like Gecko) Iron/15.0.900.1 Chrome/15.0.900.1 Safari/535.2 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.1 Iron/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5 +Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.0 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (Windows NT 6.0; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.51 +Mozilla/5.0 (Windows NT 6.0; U; hu; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 +Mozilla/5.0 (Windows NT 6.0; U; ja; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 11.00 +Mozilla/5.0 (Windows NT 6.0; U; sv; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 +Mozilla/5.0 (Windows NT 6.0; U; tr; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 +Mozilla/5.0 (Windows NT 6.0; U; tr; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 10.10 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.34 Safari/534.24 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.699.0 Safari/534.24 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.2 Chrome/11.0.700.2 Safari/534.24 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.36 Safari/535.7 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7 +Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Iron/16.0.950.0 Chrome/16.0.950.0 Safari/535.7 +Mozilla/5.0 (Windows NT 6.0; WOW64; rv:12.2) Gecko/20120605 Firefox/12.2 PaleMoon/12.2 +Mozilla/5.0 (Windows NT 6.0; rv:11.0) Gecko/20120319 Firefox/11.0 PaleMoon/11.0 +Mozilla/5.0 (Windows NT 6.0; rv:12.0) Gecko/20120424 Firefox/12.0 PaleMoon/12.0 +Mozilla/5.0 (Windows NT 6.0; rv:12.3) Gecko/20120717 Firefox/12.3 PaleMoon/12.3 +Mozilla/5.0 (Windows NT 6.0; rv:12.3) Gecko/20120728 Firefox/12.3r2 PaleMoon/12.3r2 +Mozilla/5.0 (Windows NT 6.0; rv:14.0) Gecko/20100101 Firefox/14.0.1 +Mozilla/5.0 (Windows NT 6.0; rv:15.0) Gecko/20120819 Firefox/15.0 PaleMoon/15.0 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.694.0 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.3 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.697.0 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.699.0 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/12.0.702.0 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.1 Chrome/11.0.700.1 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.2 Chrome/11.0.700.2 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.3 Chrome/11.0.700.3 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.3 Chrome/11.0.700.3 Safari/534.66 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.777.3 Chrome/11.0.777.3 Safari/534.66 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.310 Chrome/11.0.696.68 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.357 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.390 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.113 Safari/534.30 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30 ChromePlus/1.6.3.0alpha4 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Comodo_Dragon/12.1.0.0 Chrome/12.0.742.91 Safari/534.30 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Iron/12.0.750.0 Chrome/12.0.750.0 Safari/534.30 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Iron/12.0.750.0 Chrome/12.0.750.0 Safari/534.30 Lightning/1.0b4pre +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.801.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.812.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.815.10913 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Iron/13.0.800.0 Chrome/13.0.800.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Iron/13.0.800.1 Chrome/13.0.800.1 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Iron/16.0.950.0 Chrome/16.0.950.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.0 Chrome/17.0.1000.0 Safari/535.11 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.2 Chrome/17.0.1000.2 Safari/535.11 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.861.0 Safari/535.2 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/18.6.872.0 Safari/535.2 UNTRUSTED/1.0 3gpp-gba UNTRUSTED/1.0 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/535.7ad-imcjapan-syosyaman-xkgi3lqg03!wgz +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.8 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.8 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.0 Iron/20.0.1150.0 Safari/536.11 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.1 Iron/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.0 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.13 (KHTML, like Gecko) Chrome/24.0.1284.0 Safari/537.13 +Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2 +Mozilla/5.0 (Windows NT 6.1.1; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (Windows NT 6.1; U; de; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 11.01 +Mozilla/5.0 (Windows NT 6.1; U; en-GB; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.51 +Mozilla/5.0 (Windows NT 6.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 +Mozilla/5.0 (Windows NT 6.1; U; nl; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 11.01 +Mozilla/5.0 (Windows NT 6.1; U; ru; rv:5.0.1.6) Gecko/20110501 Firefox/5.0.1 Firefox/5.0.1 +Mozilla/5.0 (Windows NT 6.1; U;WOW64; de;rv:11.0) Gecko Firefox/11.0 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.12 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/12.0.702.0 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.1 Chrome/11.0.700.1 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.2 Chrome/11.0.700.2 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.3 Chrome/11.0.700.3 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.283 Chrome/11.0.696.65 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.292 Chrome/11.0.696.68 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.310 Chrome/11.0.696.68 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.343 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.56.357 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.423 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.478 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.484 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) RockMelt/0.9.58.494 Chrome/11.0.696.71 Safari/534.24 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.53 Safari/534.30 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Comodo_Dragon/12.1.0.0 Chrome/12.0.742.91 Safari/534.30 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Iron/12.0.750.0 Chrome/12.0.750.0 Safari/534.30 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.34 (KHTML, like Gecko) Arora/0.11.0 Safari/534.34 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.810.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.811.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.813.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.814.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Iron/13.0.800.0 Chrome/13.0.800.0 Safari/535.1 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.0 Chrome/17.0.1000.0 Safari/535.11 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.1 Chrome/17.0.1000.1 Safari/535.11 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.36 Safari/535.7 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7xs5D9rRDFpg2g +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Iron/16.0.950.0 Chrome/16.0.950.0 Safari/535.7 [] +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.8 (KHTML, like Gecko) Chrome/17.0.940.0 Safari/535.8 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.0 Iron/20.0.1150.0 Safari/536.11 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.1 Iron/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.0 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1250.0 Iron/22.0.2150.0 Safari/537.4 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko Firefox/11.0 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.2.1) Gecko/20120616 Firefox/12.2.1 PaleMoon/12.2.1 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.2.1) Gecko/20120616 Firefox/13.0 PaleMoon/12.2.1 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.2.1) Gecko/20120616 Firefox/13.0.1 PaleMoon/12.2.1 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.3) Gecko/20120717 Firefox/12.3 PaleMoon/12.3 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.3) Gecko/20120728 Firefox/12.3r2 PaleMoon/12.3r2 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120427 Firefox/15.0a1 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120819 Firefox/15.0 PaleMoon/15.0 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120911 Firefox/15.1 PaleMoon/15.1 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20110608 Firefox/4.0.1 SeaMonkey/2.1 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20110608 SeaMonkey/2.1 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b11pre) Gecko/20110128 Firefox/4.0b11pre +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b4pre) Gecko/20100815 Minefield/4.0b4pre +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b7) Gecko/20100101 Firefox/4.0b7 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b7) Gecko/20101111 Firefox/4.0b7 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b8pre) Gecko/20101114 Firefox/4.0b8pre +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0a2) Gecko/20110612 Firefox/6.0a2 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0a2) Gecko/20110613 Firefox/6.0a2 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:12.2) Gecko/20120606 Firefox/12.2-x64 PaleMoon/12.2-x64 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:12.2.1) Gecko/20120616 Firefox/12.2.1-x64 PaleMoon/12.2.1-x64 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:12.3) Gecko/20120714 Firefox/12.3-x64 PaleMoon/12.3-x64 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:14.0) Gecko/20120405 Firefox/14.0a1 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:15.0) Gecko/20120819 Firefox/15.0-x64 PaleMoon/15.0-x64 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:15.0) Gecko/20120912 Firefox/15.1-x64 PaleMoon/15.1-x64 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:15.0) Gecko/20120919 Firefox/15.1.1-x64 PaleMoon/15.1.1-x64 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b10pre) Gecko/20110118 Firefox/4.0b10pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b11pre) Gecko/20110128 Firefox/4.0b11pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b11pre) Gecko/20110129 Firefox/4.0b11pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b11pre) Gecko/20110131 Firefox/4.0b11pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b8pre) Gecko/20101114 Firefox/4.0b8pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b8pre) Gecko/20101128 Firefox/4.0b8pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b8pre) Gecko/20101213 Firefox/4.0b8pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b9pre) Gecko/20101228 Firefox/4.0b9pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.2a1pre) Gecko/20110208 Firefox/4.2a1pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.2a1pre) Gecko/20110323 Firefox/4.2a1pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.2a1pre) Gecko/20110324 Firefox/4.2a1pre +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:5.0) Gecko/20110619 Firefox/5.0 +Mozilla/5.0 (Windows NT 6.1; de;rv:12.0) Gecko/20120403211507 Firefox/12.0 +Mozilla/5.0 (Windows NT 6.1; en-US) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.750.0 Safari/534.30 +Mozilla/5.0 (Windows NT 6.1; rv:1.9) Gecko/20100101 Firefox/4.0 +Mozilla/5.0 (Windows NT 6.1; rv:10.0.1) Gecko/20100101 Firefox/10.0.1 SeaMonkey/2.7.1 +Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/ 20120405 Firefox/14.0.1 +Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0 +Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/14.0.1 +Mozilla/5.0 (Windows NT 6.1; rv:12.2.1) Gecko/20120616 Firefox/12.2.1 PaleMoon/12.2.1 +Mozilla/5.0 (Windows NT 6.1; rv:12.3) Gecko/20120714 Firefox/12.3 PaleMoon/12.3 +Mozilla/5.0 (Windows NT 6.1; rv:12.3) Gecko/20120717 Firefox/12.3 PaleMoon/12.3 +Mozilla/5.0 (Windows NT 6.1; rv:12.3) Gecko/20120728 Firefox/12.3r2 PaleMoon/12.3r2 +Mozilla/5.0 (Windows NT 6.1; rv:14.0) Gecko/20120405 Firefox/14.0a1 +Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0a2 +Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120819 Firefox/15.0 PaleMoon/15.0 +Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120911 Firefox/15.1 PaleMoon/15.1 +Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120919 Firefox/15.1.1 PaleMoon/15.1.1 +Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20110319 Firefox/4.0 +Mozilla/5.0 (Windows NT 6.1; rv:2.0b10) Gecko/20110126 Firefox/4.0b10 +Mozilla/5.0 (Windows NT 6.1; rv:2.0b10pre) Gecko/20110113 Firefox/4.0b10pre +Mozilla/5.0 (Windows NT 6.1; rv:2.0b11pre) Gecko/20110126 Firefox/4.0b11pre +Mozilla/5.0 (Windows NT 6.1; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre Firefox/4.0b6pre +Mozilla/5.0 (Windows NT 6.1; rv:2.0b7pre) Gecko/20100921 Firefox/4.0b7pre +Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20110814 Firefox/6.0 +Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3 +Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3 +Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3 +Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6 +Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.65 Safari/535.11 +Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.0 Chrome/17.0.1000.0 Safari/535.11 +Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24 +Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) Iron/19.0.1100.0 Chrome/19.0.1100.0 Safari/536.5 +Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1 +Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.0 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.17 Safari/537.11 +Mozilla/5.0 (Windows NT 6.2; WOW64; rv:12.2) Gecko/20120605 Firefox/12.2 PaleMoon/12.2 +Mozilla/5.0 (Windows NT 6.2; WOW64; rv:15.0) Gecko/20120910144328 Firefox/15.0.2 +Mozilla/5.0 (Windows NT 6.2; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:12.2.1) Gecko/20120616 Firefox/12.2.1-x64 PaleMoon/12.2.1-x64 +Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:15.0) Gecko/20120819 Firefox/15.0-x64 PaleMoon/15.0-x64 +Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:15.0) Gecko/20120919 Firefox/15.1.1-x64 PaleMoon/15.1.1-x64 +Mozilla/5.0 (Windows NT 6.2; rv:9.0.1) Gecko/20100101 Firefox/9.0.1 +Mozilla/5.0 (Windows NT 7.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (Windows NT) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20 +Mozilla/5.0 (Windows U Windows NT 5.1 en-US) AppleWebKit/534.12 (KHTML, like Gecko) Chrome/9.0.583.0 Safari/534.12 +Mozilla/5.0 (Windows XP; U) Opera 6.05 [de] +Mozilla/5.0 (Windows XP; U) Opera 6.06 [en] +Mozilla/5.0 (Windows; ; Windows NT 5.1; rv:1.7.2) Gecko/20040804 +Mozilla/5.0 (Windows; N; Windows NT 5.1; en-US) AppleWebKit/529 (KHTML, like Gecko, Safari/529.0) Lunascape/4.9.9.94 +Mozilla/5.0 (Windows; N; Windows NT 5.1; hu-HU) AppleWebKit/529 (KHTML, like Gecko, Safari/529.0) Lunascape/4.9.9.94 +Mozilla/5.0 (Windows; N; Windows NT 5.1; id-ID) AppleWebKit/529 (KHTML, like Gecko, Safari/529.0) Lunascape/4.9.9.94 +Mozilla/5.0 (Windows; N; Windows NT 5.2; ru-RU) AppleWebKit/529 (KHTML, like Gecko, Safari/529.0) Lunascape/4.9.9.94 +Mozilla/5.0 (Windows; U; ; cs-CZ) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.1.0.0 +Mozilla/5.0 (Windows; U; ; cs-CZ) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.1.1.0 +Mozilla/5.0 (Windows; U; ; cs-CZ) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.1.2.0 +Mozilla/5.0 (Windows; U; ; cs-CZ) AppleWebKit/532+ (KHTML, like Gecko, Safari/532.0) Lunascape/5.1.2.3 +Mozilla/5.0 (Windows; U; ; en-NZ) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.8.0 +Mozilla/5.0 (Windows; U; ; hu-HU) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.10.0 +Mozilla/5.0 (Windows; U; BeOS; en-US; rv:1.9.0.7) Gecko/2009021910 +Mozilla/5.0 (Windows; U; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727) +Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 5.2) +Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; el-GR) +Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US) +Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US)) +Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US) +Mozilla/5.0 (Windows; U; Win 9x 4.90; SG; rv:1.9.2.4) Gecko/20101104 Netscape/9.1.0285 +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-AT; rv:1.7.11) Gecko/20050728 +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-AT; rv:1.7.2) Gecko/20040803 +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-AT; rv:1.8.1.23) Gecko/20090825 SeaMonkey/1.1.18 +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2 +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-GB; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-GB; rv:1.8.1.6) Gecko/20070802 SeaMonkey/1.1.4 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.1) Gecko/20040707 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax) +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20050603 Netscape/8.0.2 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8.0.1) Gecko/20060130 SeaMonkey/1.0 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8.1.16) Gecko/20080702 SeaMonkey/1.1.11 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8.1.22) Gecko/20090605 SeaMonkey/1.1.17 +Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8.1.8pre) Gecko/20071015 Firefox/2.0.0.7 Navigator/9.0 +Mozilla/5.0 (Windows; U; Win 9x 4.90; es-ES; rv:1.8.1.10) Gecko/20071116 K-Meleon/1.1.3 +Mozilla/5.0 (Windows; U; Win 9x 4.90; fr-FR; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Win 9x 4.90; rv:1.7) Gecko/20040803 Firefox/0.9.3 +Mozilla/5.0 (Windows; U; Win95; de-AT; rv:1.7.11) Gecko/20050728 +Mozilla/5.0 (Windows; U; Win95; de-DE; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; Win95; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; Win95; en-GB; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 +Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.5) Gecko/20031007 Firebird/0.7 +Mozilla/5.0 (Windows; U; Win98; de-AT; rv:1.5) Gecko/20031007 +Mozilla/5.0 (Windows; U; Win98; de-AT; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.8.1.24) Gecko/20100228 K-Meleon/1.5.4 +Mozilla/5.0 (Windows; U; Win98; en-GB; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.1) Gecko/20010607 Netscape6/6.1b1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.9) Gecko/20020311 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0rc2) Gecko/20020510 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.1a) Gecko/20020611 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.2a) Gecko/20020910 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3) Gecko/20030312 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3.1) Gecko/20030425 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3a) Gecko/20021212 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3b) Gecko/20030210 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4a) Gecko/20030401 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031007 Firebird/0.7 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.13) Gecko/20060410 Firefox/1.0.8 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax) +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20050603 Netscape/8.0.2 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20060127 Netscape/8.1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2 (ax) +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.0.1) Gecko/20060130 SeaMonkey/1.0 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.0.2) Gecko/20060404 SeaMonkey/1.0.1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.0.6) Gecko/20060729 SeaMonkey/1.0.4 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.0.7) Gecko/20060910 SeaMonkey/1.0.5 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.0.7) Gecko/20060917 K-Meleon/1.02 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.0.7) Gecko/20060917 K-Ninja/2.0.4 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.0.8) Gecko/20061030 SeaMonkey/1.0.6 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.0.9) Gecko/20061211 SeaMonkey/1.0.7 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1) Gecko/20061101 SeaMonkey/1.1b +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.12) Gecko/20080201 SeaMonkey/1.1.8 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.13) Gecko/20080313 SeaMonkey/1.1.9 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.17) Gecko/20080919 K-Meleon/1.5.1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.1.6 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.2) Gecko/20070222 SeaMonkey/1.1.1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.23) Gecko/20090825 MultiZilla/1.8.3.4e SeaMonkey/1.1.18 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.24) Gecko/20100228 K-Meleon/1.5.4 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.24) Gecko/20100228 SeaMonkey/1.1.19 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.24pre) Gecko/20091010 K-Meleon/1.5.4 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.2pre) Gecko/20070111 SeaMonkey/1.1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.4) Gecko/20070509 SeaMonkey/1.1.2 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.4pre) Gecko/20070404 K-Ninja/2.1.3 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.6) Gecko/20070802 SeaMonkey/1.1.4 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.8pre) Gecko/20070928 Firefox/2.0.0.7 Navigator/9.0RC1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.8pre) Gecko/20071019 Firefox/2.0.0.8 Navigator/9.0.0.1 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.9) Gecko/20071030 SeaMonkey/1.1.6 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1.9pre) Gecko/20071102 Firefox/2.0.0.9 Navigator/9.0.0.3 +Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a6) Gecko/20050111 +Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.6) Gecko/20050318 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Win98; fr; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Windows; U; Win98; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Win98; rv:1.7.3) Gecko/20040913 Firefox/0.10 +Mozilla/5.0 (Windows; U; Win98; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 +Mozilla/5.0 (Windows; U; WinNT3.51; en-US; rv:1.8.1.8) Gecko/20071009 SeaMonkey/1.1.5 +Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.2) Gecko/20021126 +Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.3.1) Gecko/20030425 +Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.7.11) Gecko/20050728 +Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2 +Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 +Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; WinNT4.0; en-CA; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; WinNT4.0; en-GB; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:0.9.5) Gecko/20011011 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.0) Gecko/20020530 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.1a) Gecko/20020611 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.2) Gecko/20021126 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.2b) Gecko/20021016 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.2b) Gecko/20021016 K-Meleon 0.7 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.2b) Gecko/20021029 Phoenix/0.4 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.3) Gecko/20030312 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.3a) Gecko/20021212 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4) Gecko/20030624 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4a) Gecko/20030401 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4b) Gecko/20030507 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4b) Gecko/20030610 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040616 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.12) Gecko/20050915 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5 +Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16 +Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.0.0) Gecko/20020530 +Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; WinNT4.0; it-IT; rv:1.4b) Gecko/20030507 +Mozilla/5.0 (Windows; U; WinNT; en; Preview) Gecko/20020603 Beonex/0.8-stable +Mozilla/5.0 (Windows; U; WinNT; en; rv:1.0.2) Gecko/20030311 Beonex/0.8.2-stable +Mozilla/5.0 (Windows; U; Windows 98; en-US; rv:1.8.1.5pre) Gecko/20070710 Firefox/2.0.0.4 Navigator/9.0b2 +Mozilla/5.0 (Windows; U; Windows 98; en-US; rv:1.8.1.8pre) Gecko/20071019 Firefox/2.0.0.8 Navigator/9.0.0.1 +Mozilla/5.0 (Windows; U; Windows CE 6.0; en-US; rv:1.9.2a1pre) Gecko/20090219 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 4.0; SG; rv:1.7.5) Gecko/20050610 Netscape/8.0.2 +Mozilla/5.0 (Windows; U; Windows NT 4.0; en-US; rv:1.8.0.2) Gecko/20060418 Firefox/1.5.0.2; +Mozilla/5.0 (Windows; U; Windows NT 5.0; ; rv:1.8.0.1) Gecko/20060111 Firefox/1.9.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; ; rv:1.8.0.10) Gecko/20070216 Firefox/1.9.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; ; rv:1.8.0.7) Gecko/20060917 Firefox/1.9.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; cs-CZ; rv:1.7.5) Gecko/20041217 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:0.9.8) Gecko/20020204 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.0.0) Gecko/20020530 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.0.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.0rc2) Gecko/20020510 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.1b) Gecko/20020721 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.2) Gecko/20021126 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.3.1) Gecko/20030425 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.3a) Gecko/20021212 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.3b) Gecko/20030210 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.5) Gecko/20031007 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.6) Gecko/20040113 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7) Gecko/20040616 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.11) Gecko/20050728 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.13) Gecko/20060414 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.6) Gecko/20050319 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.7) Gecko/20050414 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.8) Gecko/20050511 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.8) Gecko/20050511 (No IDN) +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7b) Gecko/20040421 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8) Gecko/20051219 SeaMonkey/1.0b +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8.0.8) Gecko/20061030 SeaMonkey/1.0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8.1.16) Gecko/20080702 SeaMonkey/1.1.11 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8.1.16) Gecko/20080702 SeaMonkey/1.1.11 Mnenhy/0.7.5.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8.1.21) Gecko/20090303 SeaMonkey/1.1.15 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8.1.21) Gecko/20090303 SeaMonkey/1.1.15 Mnenhy/0.7.6.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8.1.22) Gecko/20090605 SeaMonkey/1.1.17 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8.1.4) Gecko/20070509 SeaMonkey/1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8a4) Gecko/20040927 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.0rc2) Gecko/20020512 Netscape/7.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) Gecko/20040206 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040626 Firefox/0.9.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.6) Gecko/20050321 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.8.1.12) Gecko/20080203 K-Meleon/1.1.4 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.8.1.17) Gecko/20080919 K-Meleon/1.5.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.8.1.4) Gecko/20070511 K-Meleon/1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.8.1.8) Gecko/20071013 K-Meleon/1.5 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de; rv:1.9.1.10) Gecko/20100504 SeaMonkey/2.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.0; de; rv:1.9.1.8) Gecko/20100205 SeaMonkey/2.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en) AppleWebKit/522.12.1 (KHTML, like Gecko) Version/3.0.1 Safari/522.12.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-EN; rv:1.8.1.8) Gecko/20071013 K-Meleon/1.5 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.6) Gecko/20050321 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.55 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.27 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.6 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.198 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.5) Gecko/20011011 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.7) Gecko/20011221 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.0) Gecko/20020530 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020815 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape6/6.2.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc1) Gecko/20020417 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc2) Gecko/20020510 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc2) Gecko/20020512 Netscape/7.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc3) Gecko/20020523 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1a) Gecko/20020611 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1b) Gecko/20020721 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2) Gecko/20021126 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2a) Gecko/20020910 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20021001 Phoenix/0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20021014 Phoenix/0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20021016 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20021016 K-Meleon 0.7 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20021029 Phoenix/0.4 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3) Gecko/20030312 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3.1) Gecko/20030425 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3a) Gecko/20021203 Phoenix/0.4 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3a) Gecko/20021212 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3a) Gecko/20030105 Phoenix/0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3b) Gecko/20030204 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3b) Gecko/20030210 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030529 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030612 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4.1) Gecko/20031008 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4a) Gecko/20030401 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4a) Gecko/20030403 Phoenix/0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030504 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030507 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030514 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20030916 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031007 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5a) Gecko/20030718 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5b) Gecko/20030827 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040616 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.1) Gecko/20040707 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.11) Gecko/20050728 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.12) Gecko/20050610 K-Meleon/0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040803 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20050208 Netscape/7.20 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041217 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20050519 Netscape/8.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20050603 Netscape/8.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20050729 Netscape/8.0.3.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20051012 Netscape/8.0.4 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20060127 Netscape/8.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20060912 Netscape/8.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.7) Gecko/20050414 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.8) Gecko/20050511 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.0.1) Gecko/20060130 SeaMonkey/1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.0.6) Gecko/20060729 SeaMonkey/1.0.4 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.0.7) Gecko/20060917 K-Meleon/1.02 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.0.8) Gecko/20061030 SeaMonkey/1.0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.1) Gecko/20061204 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.11pre) Gecko/20071206 Firefox/2.0.0.11 Navigator/9.0.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.1.5 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.5.0beta +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.15) Gecko/20080623 Firefox/2.0.0.15 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.17) Gecko/20080829 SeaMonkey/1.1.12 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.17) Gecko/20080919 K-Meleon/1.5.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.19) Gecko/20081217 KMLite/1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.2) Gecko/20070222 SeaMonkey/1.1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.21) Gecko/20090303 SeaMonkey/1.1.15 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.21) Gecko/20090403 SeaMonkey/1.1.16 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.2pre) Gecko/20070111 SeaMonkey/1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.3pre) Gecko/20070301 BonEcho/2.0.0.3pre +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.4) Gecko/20070509 Firefox/2.0.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.4) Gecko/20070509 SeaMonkey/1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.9) Gecko/20071030 SeaMonkey/1.1.6 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.9) Gecko/20071110 Sylera/3.0.20 SeaMonkey/1.1.6 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1b1) Gecko/20060710 Firefox/2.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1b2) Gecko/20060831 BonEcho/2.0b2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050702 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b4) Gecko/20050908 Firefox/1.4 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b4) Gecko/20050910 SeaMonkey/1.0a +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.0.2) Gecko/2008092313 Firefox/3.1.6 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.1.17) Gecko/20110123 SeaMonkey/2.0.12 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.1.19) Gecko/20110420 SeaMonkey/2.0.14 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.1.3) Gecko/20090804 Firefox/3.5.3 Lunascape/5.1.5.19059 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.1b4pre) Gecko/20090419 SeaMonkey/2.0b1pre +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.2.30) Gecko/20120217 Firefox/3.6.30 (Palemoon/3.6.30) +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.2a1pre) Gecko +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.2a1pre) Gecko/20081228 SeaMonkey/2.0a3pre +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.2a1pre) Gecko/20090117 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9a1) Gecko/20060206 SeaMonkey/1.5a +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9a1) Gecko/20061204 GranParadiso/2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9a1) Gecko/20061204 GranParadiso/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9a2pre) Gecko/20061225 Minefield/3.0a2pre +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9a3) Gecko/20070409 BonEcho/2.0.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9a3) Gecko/20070409 GranParadiso/2.0.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9a3) Gecko/20070409 IceWeasel/2.0.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9b2pre) Gecko/2007110913 Minefield/3.0b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.5) Gecko/20060912 Netscape/8.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.0.0) Gecko/20020530 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.4) Gecko/20030624 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.1) Gecko/20040707 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.8.1.12) Gecko/20080201 SeaMonkey/1.1.8 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.5.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.8.1.2) Gecko/20070222 SeaMonkey/1.1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.8.1.2pre) Gecko/20070111 SeaMonkey/1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7.8) Gecko/20050511 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.8.1.9pre) Gecko/20071102 Firefox/2.0.0.9 Navigator/9.0.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.9b4pre) Gecko/2008022502 SeaMonkey/2.0a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; it; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP) AppleWebKit/529 (KHTML, like Gecko, Safari/529.0) Lunascape/4.9.9.96 +Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; Windows NT 5.0; ja; rv:1.9.1.10) Gecko/20100624 Firefox/3.5.10 Lunascape/6.1.7.21880 +Mozilla/5.0 (Windows; U; Windows NT 5.0; pl; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.0; pt-BR; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; Windows NT 5.0; ru; rv:1.9.1.13) Gecko/20100914 Firefox/3.5.13 +Mozilla/5.0 (Windows; U; Windows NT 5.0; ru; rv:1.9.2.13) Gecko/20101203 IceWeasel/2.0.0.11 Mnenhy/0.8.3 +Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10 +Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 +Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-TW; rv:1.8.0.1) Gecko/20060111 Firefox/0.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1 ; x64; en-US; rv:1.9.1b2pre) Gecko/20081026 Firefox/3.1b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1) AppleWebKit/532.0 (KHTML, like Gecko) Iron/3.0.197.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ) Sundance/0.9x +Mozilla/5.0 (Windows; U; Windows NT 5.1; ; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.8.1.13) Gecko/20080313 SeaMonkey/1.1.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.8.1.15) Gecko/20080621 SeaMonkey/1.1.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.8.1.18) Gecko/20081031 SeaMonkey/1.1.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.8.1.2) Gecko/20070222 SeaMonkey/1.1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; bg-BG; rv:1.9.1b4pre) Gecko/20090307 Shiretoko/3.1b4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; ca-es) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.20 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ca; rv:1.8.1b1) Gecko/20060710 Firefox/2.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; cs) AppleWebKit/522.13.1 (KHTML, like Gecko) Version/3.0.2 Safari/522.13.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; cs) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 Safari/525.29 +Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.1.1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/533.3 (KHTML, like Gecko) Lunascape/6.1.0.20995 Safari/533.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; cs; rv:1.8.1.18) Gecko/20081029 Firefox/2.0.0.18 +Mozilla/5.0 (Windows; U; Windows NT 5.1; cs; rv:1.9) Gecko/2008052906 +Mozilla/5.0 (Windows; U; Windows NT 5.1; cs; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.20 +Mozilla/5.0 (Windows; U; Windows NT 5.1; da) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK) AppleWebKit/523.11.1+ (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; da-dk) AppleWebKit/523.15.1 (KHTML, like Gecko) Version/3.0.4 Safari/523.15 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.0.0) Gecko/20020530 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.0.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.3) Gecko/20030312 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.3a) Gecko/20021212 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.3b) Gecko/20030210 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.4) Gecko/20030624 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.4a) Gecko/20030401 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.5) Gecko/20031007 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.6) Gecko/20040113 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7) Gecko/20040616 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.1) Gecko/20040707 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.11) Gecko/20050728 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.11) Gecko/20050728 (No IDN) +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.5) Gecko/20041217 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.6) Gecko/20050319 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.7) Gecko/20050414 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.8) Gecko/20050511 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7b) Gecko/20040316 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8) Gecko/20051219 SeaMonkey/1.0b +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.0.5) Gecko/20060706 K-Meleon/1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.0.5) Gecko/20060730 K-Meleon/1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.1.13) Gecko/20080313 SeaMonkey/1.1.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.1.15) Gecko/20080621 SeaMonkey/1.1.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.1.17) Gecko/20080829 SeaMonkey/1.1.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.1.18) Gecko/20081031 SeaMonkey/1.1.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.1.2) Gecko/20070222 SeaMonkey/1.1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.1.4) Gecko/20070509 SeaMonkey/1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.1.5) Gecko/20070716 SeaMonkey/1.1.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8.1.6) Gecko/20070802 SeaMonkey/1.1.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8a1) Gecko/20040520 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8a5) Gecko/20041122 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8b) Gecko/20050217 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-CH) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.4 (Change: ) +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE) AppleWebKit/532+ (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE) AppleWebKit/532.0 (KHTML, like Gecko) Iron/3.0.197.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Safari/534 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE) Chrome/4.0.223.3 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.3a) Gecko/20021207 Phoenix/0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.5) Gecko/20031007 Firebird/0.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040626 Firefox/0.9.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20060127 Netscape/8.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050321 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.8.0.1) Gecko/20060115 K-Meleon/1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.1.5 (+http://www.kangaroo-personal.de) +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.8.1.17) Gecko/20080919 K-Meleon/1.5.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.5.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.8.1.23) Gecko/20090825 SeaMonkey/1.1.18 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.8.1.6) Gecko/20070727 K-Meleon/1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.9.2.20) Gecko/20110803 Firefox +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-LI; rv:1.9.0.16) Gecko/2009120208 Firefox/3.0.16 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8) Gecko/20051111 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.19) Gecko/20081201 Firefox/2.0.0.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.21 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.8) Gecko/20071008 SeaMonkey +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1b1) Gecko/20060710 Firefox/2.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9) Gecko/2008052906 Firefox/3.0.1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.2pre) Gecko/2008082305 Firefox/3.0.2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.4) Firefox/3.0.8) +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.8) Gecko/2009032609 Firefox/3.07 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.17) Gecko/20110123 SeaMonkey/2.0.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.19) Gecko/20110420 SeaMonkey/2.0.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.4) Gecko/20091007 Firefox/3.5.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20100104 Firefox/3.5.8 (SeaMonkey/2.0.2) +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20100104 SeaMonkey/2.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1b1pre) Gecko/20080925121544 SeaMonkey/2.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 ( .NET CLR 3.0.04506.30) +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 ( .NET CLR 3.0.04506.648) +Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9b3) Gecko/2008020514 Opera 9.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; el) AppleWebKit/522.13.1 (KHTML, like Gecko) Version/3.0.2 Safari/522.13.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en) AppleWebKit/522.12.1 (KHTML, like Gecko) Version/3.0.1 Safari/522.12.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en) AppleWebKit/522.13.1 (KHTML, like Gecko) Version/3.0.2 Safari/522.13.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en) AppleWebKit/522.4.1+ (KHTML, like Gecko) Version/3.0.1 Safari/522.12.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en) AppleWebKit/526.9 (KHTML, like Gecko) Version/4.0dp1 Safari/526.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.7.5) Gecko/20050610 Netscape/8.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB) AppleWebKit/523.15 (KHTML, like Gecko) QtWeb Internet Browser/1.2 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB) AppleWebKit/529 (KHTML, like Gecko, Safari/529.0) Lunascape/4.9.9.96 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050321 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.1) Gecko/20061230 BonEcho/2.0.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1b2) Gecko/20060821 Firefox/2.0b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.6) Gecko/2009011913 Firefox +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1.16) Gecko/20101130 Firefox/3.5.16 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1.16) Gecko/20101130 Firefox/3.5.16 GTB7.1 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1b4) Gecko/20090423 Firefox/3.5b4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.14) Gecko/20110218 Firefox/3.6.14 GTB7.1 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.16) Gecko/20110319 AskTbUTR/3.11.3.15590 Firefox/3.6.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/523.15 (KHTML, like Gecko) QtWeb Internet Browser/1.2 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525+ (KHTML, like Gecko) Version/3.1.1 Safari/525.17 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.29 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/4.0.202.0 Safari/525.13. +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/7.0.0 Safari/700.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Fluid/0.9.4 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13(KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.17 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.151.0 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.152.0 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.153.0 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.153.1 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.3.155.0 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.4.154.18 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.39 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.43 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.48 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.50 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.53 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.55 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12079480.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12207312.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12272384.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12279816.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12282560.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12285712.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12475112.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12535056.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12542120.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12595016.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12733120.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/13543896.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/28768176.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.28 (KHTML, like Gecko) Version/3.2.2 Safari/525.28.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 ChromePlus/4.0.222.3 Chrome/4.0.222.3 Safari/525.28.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/1.2 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/1.5 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/1.7 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/2.0 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/3.0 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6 (Change: ) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.0.2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.1.2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.10 (KHTML, like Gecko) Chrome/2.0.157.0 Safari/528.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.10 (KHTML, like Gecko) Chrome/2.0.157.2 Safari/528.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.11 (KHTML, like Gecko) Chrome/2.0.157.0 Safari/528.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.4 (KHTML, like Gecko) Chrome/0.3.155.0 Safari/528.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.4 (KHTML, like Gecko) Iron/0.3.155.0 Safari/13506912.528 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.7 (KHTML, like Gecko) Iron/1.0.155.0 Safari/528.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.8 (KHTML, like Gecko) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.8 (KHTML, like Gecko) Chrome/2.0.156.0 Safari/528.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.8 (KHTML, like Gecko) Chrome/2.0.156.0 Version/3.2.1 Safari/528.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.8 (KHTML, like Gecko) Chrome/2.0.156.1 Safari/528.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528.9 (KHTML, like Gecko) Chrome/2.0.157.0 Safari/528.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Chrome/2.0.169.0 Safari/530.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Chrome/2.0.170.0 Safari/530.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Iron/2.0.168.0 Safari/530.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.0 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.2 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.39 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.40 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.42 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.43 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.8 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.173.0 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.173.1 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.174.0 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.6 (KHTML, like Gecko) Chrome/2.0.174.0 Safari/530.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.6 (KHTML, like Gecko) Chrome/2.0.175.0 Safari/530.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.7 (KHTML, like Gecko) Chrome/2.0.175.0 Safari/530.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.7 (KHTML, like Gecko) Chrome/2.0.176.0 Safari/530.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.7 (KHTML, like Gecko) Chrome/2.0.177.0 Safari/530.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.8 (KHTML, like Gecko) Chrome/2.0.177.0 Safari/530.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.8 (KHTML, like Gecko) Chrome/2.0.177.1 Safari/530.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.8 (KHTML, like Gecko) Chrome/2.0.178.0 Safari/530.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/531.0 (KHTML, like Gecko) Chrome/3.0.191.0 Safari/531.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/531.2 (KHTML, like Gecko) Chrome/3.0.191.3 Safari/531.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.1 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.10 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.17 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.20 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.21 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.24 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.27 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.6 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.196.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.197.11 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.198.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.201.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.201.1 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.204.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.206.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.206.1 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.207.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.208.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.209.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.4 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.7 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.212.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML,like Gecko) Chrome/3.0.195.27 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.213.0 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.213.1 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.0 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.3 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.4 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.5 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.6 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.221.6 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.0 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.12 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.3 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.4 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.5 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.7 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.1 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.2 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.3 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.4 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) ChromePlus/4.0.222.3 Chrome/4.0.222.3 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.3 (KHTML, like Gecko) Iron/4.0.227.0 Chrome/4.0.227.0 Safari/532.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Comodo_Dragon/4.1.1.11 Chrome/4.1.249.1042 Safari/532.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Chrome/4.0.288.1 Safari/532.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Iron/4.0.275.2 Chrome/4.0.275.2 Safari/532.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Iron/4.0.280.0 Chrome/4.0.280.0 Safari/532.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.2 Safari/533.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.353.0 Safari/533.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.355.0 Safari/533.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.356.0 Safari/533.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.357.0 Safari/533.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4 ChromePlus/1.4.1.0alpha1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.8 (KHTML, like Gecko) Chrome/6.0.397.0 Safari/533.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/7.0.548.0 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10 ChromePlus/1.5.1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10 ChromePlus/1.5.2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) RockMelt/0.8.40.147 Chrome/8.0.552.231 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.0 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.15 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13 ChromePlus/1.5.3.0alpha4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.599.0 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Iron/9.0.600.2 Chrome/9.0.600.2 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/10.0.601.0 Safari/534.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/10.0.602.0 Safari/534.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.600.0 Safari/534.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.634.0 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.134 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.549 Chrome/10.0.648.205 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.18 (KHTML, like Gecko) Chrome/11.0.661.0 Safari/534.18 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.19 (KHTML, like Gecko) Chrome/11.0.661.0 Safari/534.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.21 (KHTML, like Gecko) Chrome/11.0.678.0 Safari/534.21 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.21 (KHTML, like Gecko) Chrome/11.0.682.0 Safari/534.21 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.458.1 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.461.0 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.53 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Safari/534 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.724.100 Safari/534.30 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.6 (KHTML, like Gecko) Chrome/7.0.500.0 Safari/534.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.514.0 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7 ChromePlus/1.5.0.0 ChromePlus/1.5.0.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7 ChromePlus/1.5.0.0alpha1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Flock/3.5.2.4599 Chrome/7.0.517.442 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Iron/7.0.520.0 Chrome/7.0.520.0 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Iron/7.0.520.1 Chrome/7.0.520.1 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Iron/7.0.520.1 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.116 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.128 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.9 (KHTML, like Gecko) Chrome/7.0.531.0 Safari/534.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US)AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/13657880.525 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.0) Gecko/20020509 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.0) Gecko/20020530 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021216 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0rc2) Gecko/20020512 Netscape/7.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0rc2) Gecko/20020618 Netscape/7.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.1) Gecko/20020826 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2) Gecko/20021126 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2b) Gecko/20020923 Phoenix/0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2b) Gecko/20021014 Phoenix/0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2b) Gecko/20021016 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2b) Gecko/20021029 Phoenix/0.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3) Gecko/20030312 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3.1) Gecko/20030425 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3a) Gecko/20021212 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3b) Gecko/20030210 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030529 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4a) Gecko/20030401 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4a) Gecko/20030411 Phoenix/0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4b) Gecko/20030427 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4b) Gecko/20030503 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4b) Gecko/20030507 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4b) Gecko/20030615 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20030916 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007 Firebird/0.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5a) Gecko/20030630 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5a) Gecko/20030702 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5a) Gecko/20030718 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5b) Gecko/20030819 Mozilla Firebird/0.6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5b) Gecko/20030827 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6a) Gecko/20031002 Firebird/0.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6a) Gecko/20031030 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6b) Gecko/20031212 Firebird/0.7+ +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040514 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040616 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.1) Gecko/20040707 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.10) Gecko/20050716 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.11) Gecko/20050728 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050610 K-Meleon/0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.13) Gecko/20060410 Firefox/1.0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.13) Gecko/20060414 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040803 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050519 Netscape/8.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050519 Netscape/8.0.1 FirePHP/0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050729 Netscape/8.0.3.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050817 Netscape/8.0.3.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20051012 Netscape/8.0.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20060111 Netscape/8.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20060127 Netscape/8.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050319 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.7) Gecko/20050414 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.8) Gecko/20050511 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040421 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8) Gecko/20051119 Flock/0.4.11 Firefox/1.0+ +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8) Gecko/20051219 SeaMonkey/1.0b +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8) Gecko/20060102 SeaMonkey/1.0b +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8) Gecko/20060319 Firefox/2.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.1) Gecko/20060130 SeaMonkey/1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.10) Gecko/20070228 Firefox/1.5.0.10 Flock/0.7.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.10) Gecko/20070306 SeaMonkey/1.0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.10pre) Gecko/20070211 Firefox/1.5.0.10pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.11) Gecko/20070502 Firefox/1.5.0.11 Flock/0.7.13.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.12) Gecko/20070508 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.2) Gecko/20060309 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.2) Gecko/20060404 SeaMonkey/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.2) Gecko/20060406 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.2) Gecko/20060419 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.4) Gecko/20060612 Firefox/1.5.0.4 Flock/0.7.0.17.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.4) Gecko/20060620 Firefox/1.5.0.4 Flock/0.7.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.5) Gecko/20060706 K-Meleon/1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.5) Gecko/20060706 K-Ninja/2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.5) Gecko/20060719 KHTML/3.5.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.5) Gecko/20060731 Firefox/1.5.0.5 Flock/0.7.4.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060728 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060729 SeaMonkey/1.0.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060730 K-Meleon/1.01 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060731 K-Ninja/2.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060910 MultiZilla/1.7.9.0a SeaMonkey/1.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060910 SeaMonkey/1.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060915 Firefox/1.5.0.7 Flock/0.7.5.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060917 K-Meleon/1.02 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060917 K-Ninja/2.0.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060929 Firefox/1.5.0.7 Flock/0.7.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20061025 Firefox/1.5.0.8 Flock/0.7.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.8) Gecko/20061025 Firefox/1.5.0.8 Flock/0.7.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.8) Gecko/20061030 MultiZilla/1.8.3.0a SeaMonkey/1.0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.8) Gecko/20061030 SeaMonkey/1.0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.9) Gecko/20061206 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.9) Gecko/20061211 SeaMonkey/1.0.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.9) Gecko/20061219 Flock/0.7.9.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.9pre) Gecko/20061219 Firefox/1.5.0.9 Flock/0.7.9.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20060930 BonEcho/2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061112 BonEcho/2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061113 BonEcho/2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061121 BonEcho/2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061209 BonEcho/2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061210 BonEcho/2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061222 BonEcho/2.0.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.10) Gecko/20071116 K-Meleon/1.1.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071128 SeaMonkey/1.1.7 Mnenhy/0.7.5.666 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071213 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071231 Firefox/2.0.0.11 Flock/1.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20080126 Firefox/2.0.0.11 Flock/1.0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11pre) Gecko/20071206 Firefox/2.0.0.11 Navigator/9.0.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11pre) Gecko/20071206 Firefox/2.0.0.11 Navigator/9.0.0.5 GTB5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080201 MultiZilla/1.8.3.4e SeaMonkey/1.1.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080201 SeaMonkey/1.1.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080201 SeaMonkey/1.1.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080203 K-Meleon/1.1.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080211 Firefox/2.0.0.12 Flock/1.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080219 Firefox/2.0.0.12 Navigator/9.0.0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080304 Firefox/2.0.0.12 Flock/1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080326 Firefox/2.0.0.13 Flock/1.1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080414 Firefox/2.0.0.13 Pogo/2.0.0.13.6866 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.1.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.5.0b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080514 Firefox/2.0.0.14 Flock/1.1.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080530 Firefox/2.0.0.14 Flock/1.2.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080608 Firefox/2.0.0.14 Flock/1.2.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.15) Gecko/20080621 SeaMonkey/1.1.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.15) Gecko/20080621 SeaMonkey/1.1.10 Mnenhy/0.7.5.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.16) Gecko/20080702 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.9.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.16) Gecko/20080702 MultiZilla/1.8.3.4e SeaMonkey/1.1.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.16) Gecko/20080702 SeaMonkey/1.1.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.16) Gecko/20080714 Firefox/2.0.0.16 Flock/1.2.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.17) Gecko/20080829 SeaMonkey/1.1.12 Mnenhy/0.7.5.666 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.17) Gecko/20080910 Firefox/2.0.0.17 Flock/1.2.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.17) Gecko/20080915 Firefox/2.0.0.17 Flock/1.2.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.17) Gecko/20080919 K-Meleon/1.5.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.17) Gecko/20090224 SeaMonkey/1.1.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.17pre) Gecko/20080715 Firefox/2.0.0.8pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.1.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.5.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.18) Gecko/20081029 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.18) Gecko/20081031 SeaMonkey/1.1.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.18) Gecko/20081107 Firefox/2.0.0.18 Flock/1.2.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.19) Gecko/20081204 MultiZilla/1.8.3.5c SeaMonkey/1.1.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 Mnenhy/0.7.5.666 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 Mnenhy/0.7.6.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.19) Gecko/20081217 KMLite/1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1pre) Gecko/20061122 BonEcho/2.0.0.1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1pre) Gecko/20061202 BonEcho/2.0.0.1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1pre) Gecko/20061203 BonEcho/2.0.0.1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070222 SeaMonkey/1.1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070224 lolifox/0.3.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070224 lolifox/0.3.2 MEGAUPLOAD 1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070225 lolifox/0.32 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070227 BonEcho/2.0.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090303 SeaMonkey/1.1.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090303 SeaMonkey/1.1.15 Mnenhy/0.7.5.666 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090303 SeaMonkey/1.1.15 Mnenhy/0.7.6.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090403 Firefox/1.1.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090403 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090403 MultiZilla/1.8.3.4e SeaMonkey/1.1.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090403 SeaMonkey/1.1.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090403 SeaMonkey/1.1.16 Mnenhy/0.7.5.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090403 SeaMonkey/1.1.16 Mnenhy/0.7.5.666 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.22) Gecko/20090605 SeaMonkey/1.1.17 Firefox/3.0.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.22) Gecko/20090605 SeaMonkey/1.1.17 Mnenhy/0.7.6.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.22) Gecko/20090623 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.22pre) Gecko/20090502 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.24) Gecko/20100228 K-Meleon/1.5.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.24) Gecko/20100228 Sylera/3.0.20 SeaMonkey/1.1.19 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070111 SeaMonkey/1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070111 SeaMonkey/1.1 Mnenhy/0.7.4.10005 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070118 Firefox/2.0.0.2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070213 BonEcho/2.0.0.2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Mozilla/4.8 [en] (Windows NT 5.1; U) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070321 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3pre) Gecko/20070302 BonEcho/2.0.0.3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070416 BonEcho/2.0.0.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070509 SeaMonkey/1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070511 K-Meleon/1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070707 Firefox/2.0.0.4 Flock/0.9.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4pre) Gecko/20070404 K-Ninja/2.1.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4pre) Gecko/20070410 BonEcho/2.0.0.4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4pre) Gecko/20070416 BonEcho/2.0.0.4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.5) Gecko/20070716 SeaMonkey/1.1.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.5pre) Gecko/20070622 BonEcho/2.0.0.5pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070727 K-Meleon/1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070801 Firefox/2.0 Wyzo/0.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070801 Firefox/2.0.0.6 Flock/0.9.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070802 Firefox/2.0.0.11 SeaMonkey/1.1.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070802 SeaMonkey/1.1.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070809 Sylera/3.0.18 SeaMonkey/1.1.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.7) Gecko/20071013 Firefox/2.0.0.7 Flock/0.9.1.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.7pre) Gecko/20070815 Firefox/2.0.0.6 Navigator/9.0b3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.7pre) Gecko/20070901 BonEcho/2.0.0.7pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.8) Gecko/20071013 K-Meleon/1.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.8) Gecko/20071018 Firefox/2.0.0.8 Flock/1.0RC3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.8pre) Gecko/20071012 BonEcho/2.0.0.8pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.8pre) Gecko/20071012 lolifox/0.3.6 Firefox/2.0.0.7 compatible +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.8pre) Gecko/20071015 Firefox/2.0.0.7 Navigator/9.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.8pre) Gecko/20071019 Firefox/2.0.0.8 Navigator/9.0.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071110 Sylera/3.0.20 SeaMonkey/1.1.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9pre) Gecko/20071102 Firefox/2.0.0.9 Navigator/9.0.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1a2) Gecko/20060512 BonEcho/2.0a2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1a3) Gecko/20060526 BonEcho/2.0a3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1b1) Gecko/20060707 Firefox/2.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1b1) Gecko/20060710 Firefox/2.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1b1) Gecko/20060713 lolifox/0.2.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1b2) Gecko/20060821 Firefox/2.0b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1b2) Gecko/20060821 SeaMonkey/1.1a +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1b2) Gecko/20060826 BonEcho/2.0b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a1) Gecko/20040520 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040817 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a4) Gecko/20040927 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050217 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b4) Gecko/20050729 Firefox/1.0+ +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b4) Gecko/20050908 Firefox/1.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b4) Gecko/20050910 SeaMonkey/1.0a +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b5) Gecko/20051006 Firefox/1.4.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b5) Gecko/20051021 Flock/0.4 Firefox/1.0+ +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b5) Gecko/20051103 Flock/0.4 Firefox/1.0+ +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9) Gecko +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/2.0.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008071523 Firefox/3.0.1 Flock/2.0b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.10) Gecko/2009042815 Firefox/3.0.10 Wyzo/3.0.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 (.NET CLR 3.5.30729) FBSMTWB +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.16) Gecko/2009120208 Firefox/3.0.16 FBSMTWB +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.16) Gecko/2010010414 Firefox/3.0.19 Flock/2.5.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.19) Gecko/2010061201 Firefox/3.0.19 Flock/2.6.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.2) Gecko/2008083108 Firefox/3.0.2 Flock/2.0b3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.2pre) Gecko/2008071405 GranParadiso/3.0.2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.2pre) Gecko/2008072405 GranParadiso/3.0.2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.3) Gecko/2008092417 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.3) Gecko/2008100719 Firefox/3.0.3 Flock/2.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.4) Gecko/2008112016 Firefox/3.0.4 Flock/2.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.4pre) Gecko/2008101305 GranParadiso/3.0.4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.4pre) Gecko/2008102405 GranParadiso/3.0.4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.5) Gecko/2009011615 Firefox/3.0.5 CometBird/3.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009022300 Firefox/3.0.6 Orca/1.1 build 1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6pre) Gecko/2008121605 Firefox/3.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6pre) Gecko/2009011606 Firefox/3.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009030821 Firefox/3.0.7 Orca/1.1 build 2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.0 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.9) Gecko/2009042410 Firefox/3.0.9 Wyzo/3.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1) Gecko K-Meleon/1.6.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.1) Gecko/20090721 Firefox/3.5.1 Lunascape/5.1.3.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.10) Gecko/20100504 Firefox/3.5.11 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.10) Gecko/20100624 Firefox/3.5.10 Lunascape/6.2.0.22177 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11) Gecko/20100722 SeaMonkey/2.0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11) Gecko/20100821 Firefox/3.5.11 Lunascape/6.3.1.22729 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11pre) Gecko/20100508 SeaMonkey/2.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11pre) Gecko/20100515 SeaMonkey/2.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.13) Gecko/20100914 Mnenhy/0.8.3 SeaMonkey/2.0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.14) Gecko/20100930 SeaMonkey/2.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.16) Gecko/20101130 AskTbPLTV5/3.8.0.12304 Firefox/3.5.16 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.16) Gecko/20101130 Firefox/3.5.16 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.16) Gecko/20120427 Firefox/15.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.17pre) Gecko/20101211 SeaMonkey/2.0.12pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.18) Gecko/20110320 Lightning/1.0b1 SeaMonkey/2.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.19) Gecko/20110420 Firefox/3.5.19 SeaMonkey/2.0.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090805 Shiretoko/3.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2pre) Gecko/20090723 SeaMonkey/2.0b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 MRA 5.5 (build 02842) Firefox/3.5.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 MRA 5.5 (build 02842) Firefox/3.5.5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5pre) Gecko/20091016 Shiretoko/3.5.5pre GTB6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729) FBSMTWB +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 GTB6 (.NET CLR 3.5.30729) FBSMTWB +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 MRA 5.5 (build 02842) Firefox/3.5.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 MRA 5.5 (build 02842) Firefox/3.5.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091206 Firefox/2.0.0.20 SeaMonkey/2.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20100121 Firefox/3.5.6 Wyzo/3.5.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 AppleWebKit/531.21.8 (KHTML, like Gecko) Firefox/3.5.7 Flock/2.5.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 AppleWebKit/531.21.8 KHTML/4.3.2 (like Gecko) Firefox/3.5.7 Flock/2.5.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 AppleWebKit/531.21.8 KHTML/4.3.5 (like Gecko) Firefox/3.5.7 Flock/2.5.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 Flock/2.5.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 Prism/1.0b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 MRA 5.5 (build 02842) Firefox/3.5.7 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.8) Gecko/20100223 Firefox/3.5.8 Lunascape/6.1.0.20995 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1a1pre) Gecko/2008062005 Minefield/3.1a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1a1pre) Gecko/2008071003 Minefield/3.1a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1a1pre) Gecko/2008071603 Firefox Minefield/3.1a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b1pre) Gecko/20080904053130 Minefield/3.1b1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b1pre) Gecko/20080913185648 Minefield/3.1b1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b1pre) Gecko/20080920085411 Minefield/3.1b1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b1pre) Gecko/20080926033937 Minefield/3.1b1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b1pre) Gecko/20080927033433 Minefield/3.1b1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b1pre) Gecko/20080930093007 Minefield/3.1b1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b1pre) Gecko/20081001 Minefield/3.1b1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b2pre) Gecko/20081020 Minefield/3.1b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b2pre) Gecko/20081026 Minefield/3.1b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b2pre) Gecko/20081031 Minefield/3.1b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20081201 Minefield/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20081208 SeaMonkey/2.0a3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20081212 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20081218 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20081221 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20081228 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20090102 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20090113 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20090121 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20090206 Minefield/3.1b2pre Firefox/3.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20090207 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/20090213 Firefox/3.0.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b4) Gecko/20090423 Firefox/3.5b4 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b4pre) Gecko/20090323 Shiretoko/3.5b4pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b4pre) Gecko/20090401 Firefox/3.5b4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b4pre) Gecko/20090409 Firefox/3.5b4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b4pre) Gecko/20090411 Shiretoko/3.5b4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b4pre) Gecko/20090413 Shiretoko/3.5b4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b5pre) Gecko/20090428 SeaMonkey/2.0b1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b5pre) Gecko/20090517 Firefox/3.5b4pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1pre) Gecko/20090629 Vonkeror/1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2) Gecko/20100206 Palemoon/3.6.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2) Gecko/20100206 Palemoon/3.6.0.5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.11) Gecko/20101023 Firefox/3.6.11 (Palemoon/3.6.11) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.17) Gecko/20110531 Firefox/3.6.17 (Palemoon/3.6.17) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.19pre) Gecko/20110620 Namoroka/3.6.19pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.2) Gecko/20100324 Firefox/3.6.2 (Palemoon/3.6.2) (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.20) Gecko/20110803 AskTbFWV5/3.13.0.17701 Firefox/3.6.20 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.21pre) Gecko K-Meleon/1.7.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.28) Gecko/20120306 Firefox/3.6.28 ( .NET CLR 3.5.30729; .NET4.0C) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.28) Gecko/20120306 Firefox/5.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.2pre) Gecko/20100312 Namoroka/3.6.2pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.0.16 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.9.0.2) Gecko/2008092313 Ubuntu/9.25 (jaunty) Firefox/3.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 (Palemoon/3.6.3) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 (Palemoon/3.6.3) (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.30) Gecko/20120217 Firefox/3.6.30 (Palemoon/3.6.30) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.32) Gecko/20120529 Firefox/3.6.32 (Palemoon/3.6.32) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.4) Gecko/20100624 Firefox/3.6.4 Lunascape/6.2.0.22177 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.9pre) Gecko/20100812 Namoroka/3.6.9pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1) Gecko/20090806 Namoroka/3.6a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1) Gecko/20090806 Namoroka/3.6a1 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090113 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090120 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090219 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090304 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090306 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090410 Minefield/3.6a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090413 Minefield/3.6a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090415 Minefield/3.6a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090418 Minefield/3.6a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090424 Minefield/3.6a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090425 Minefield/3.6a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090709 Minefield/3.6a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a2pre) Gecko/20090816 Namoroka/3.6a2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a2pre) Gecko/20090826 Namoroka/3.6a2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2b4) Gecko/20091124 Firefox/3.6b4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2pre) Gecko/20100115 Prism/1.0b3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.3a1pre) Gecko/20091130 Minefield/3.7a1pre GTB6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.3a1pre) Gecko/20091219 Minefield/3.7a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.3a3pre) Gecko/20100311 Minefield/3.7a3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.3a5pre) Gecko/20100418 Minefield/3.7a5pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20051220 Firefox/1.6a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060121 Firefox/1.6a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060323 Firefox/1.6a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060520 SeaMonkey/1.5a +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060725 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060809 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060816 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060826 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060906 SeaMonkey/1.5a +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060910 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20061102 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/2006112204 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20061123 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20061124 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20061125 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20061129 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20061204 GranParadiso/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20061204 GranParadiso/3.0a1 MEGAUPLOAD 1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20061217 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a2) Gecko/20070206 GranParadiso/3.0a2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a2pre) Gecko/20061221 Minefield/3.0a2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a2pre) Gecko/20061230 Minefield/3.0a2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a2pre) Gecko/20061231 Minefield/3.0a2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a2pre) Gecko/20070105 Minefield/3.0a2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a2pre) Gecko/20070109 SeaMonkey/1.5a +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a2pre) Gecko/20070130 SeaMonkey/1.5a +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a2pre) Gecko/20070204 Minefield/3.0a2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a3) Gecko/20070322 GranParadiso/3.0a3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a3pre) Gecko/20070218 Minefield/3.0a3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a3pre) Gecko/20070317 SeaMonkey/1.5a +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a4) Gecko/20070427 GranParadiso/3.0a4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a4) Gecko/2007042705 GranParadiso/3.0a4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a4pre) Gecko/20070404 SeaMonkey/1.5a +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a4pre) Gecko/20070407 Minefield/3.0a4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a4pre) Gecko/20070416 Minefield/3.0a4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a4pre) Gecko/20070427 Minefield/3.0a4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a5pre) Gecko/20070517 Minefield/3.0a5pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a5pre) Gecko/20070527 SeaMonkey/1.5a +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a5pre) Gecko/20070529 Minefield/3.0a5pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a5pre) Gecko/20070529 SeaMonkey/2.0a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a6pre) Gecko/20070602 Minefield/3.0a6pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a6pre) Gecko/20070603 Minefield/3.0a6pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a6pre) Gecko/20070604 Minefield/3.0a6pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a6pre) Gecko/20070622 Minefield/3.0a6pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a6pre) Gecko/20070625 SeaMonkey/2.0a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a6pre) Gecko/20070626 Minefield/3.0a6pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a6pre) Gecko/20070630 Minefield/3.0a6pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a7) Gecko/2007080210 GranParadiso/3.0a7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a7pre) Gecko/2007073105 Minefield/3.0a7pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a8pre) Gecko/2007082705 Minefield/3.0a8pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a9pre) Gecko/2007102105 Minefield/3.0a9pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a9pre) Gecko/2007110705 Minefield/3.0a9pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b1) Gecko/2007110703 Firefox/3.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b2pre) Gecko/2007110805 Minefield/3.0b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b2pre) Gecko/2007111605 Minefield/3.0b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b2pre) Gecko/2007120405 Minefield/3.0b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b2pre) Gecko/2007120505 Minefield/3.0b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b3) Gecko/2008020514 Firefox/3.0b3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b3pre) Gecko/2007122205 Minefield/3.0b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b4pre) Gecko/2008020708 Firefox/3.0b4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b4pre) Gecko/2008021304 Minefield/3.0b4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b5pre) Gecko/2008030706 Firefox/3.0b5pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b5pre) Gecko/2008030706 Minefield/3.0b5pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b5pre) Gecko/2008031004 Minefield/3.0b5pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9b5pre) Gecko/2008032204 Minefield/3.0b5pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9pre) Gecko/2008032904 Minefield/3.0pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9pre) Gecko/2008040907 Minefield/3.0pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9pre) Gecko/2008041406 Minefield/3.0pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9pre) Gecko/2008041506 Minefield/3.0pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:2.0a1pre) Gecko/2008032902 Minefield/4.0a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:x.xx) Gecko/20030504 Mozilla Firebird/0.6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en; rv:1.7.10) Gecko/20050716 Firefox/1.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en; rv:1.8.0.5) Gecko/20060721 SeaMonkey/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en; rv:1.8.0.7) Gecko/20060917 K-Meleon/1.02 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en; rv:1.8.1.11) Gecko/20071127 Mozilla +Mozilla/5.0 (Windows; U; Windows NT 5.1; en; rv:1.9.1.13) Gecko/20100914 Firefox/3.6.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; en; rv:1.9a1) Gecko/20061128 BonEcho/0.7b1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.5) Gecko/20060912 Netscape/8.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.8.0.7) Gecko/20060917 K-Meleon/1.02 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.8.1.4) Gecko/20070511 K-Meleon/1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.9.1.19) Gecko/20110420 SeaMonkey/2.0.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.9b2) Gecko/2007121120 Firefox/3.0b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-CO) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/1.7 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES) AppleWebKit/525.28 (KHTML, like Gecko) Version/3.2.2 Safari/525.28.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7) Gecko/20040803 Firefox/0.9.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20060127 Netscape/8.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8) Gecko/20060321 Firefox/2.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.1.16) Gecko/20080831 Firefox/2.0.0.16 Flock/1.2.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.5.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.1.18) Gecko/20081029 Firefox/2.0.0.18 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.1.18) Gecko/20081031 SeaMonkey/1.1.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.1.5) Gecko/20070716 SeaMonkey/1.1.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.9.0.16) Gecko/2009120208 Firefox/3.0.16 FBSMTWB +Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; fa; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fi; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-BE) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30) +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR) AppleWebKit/523.15 (KHTML, like Gecko) Version/3.0 Safari/523.15 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR) AppleWebKit/525.28 (KHTML, like Gecko) Version/3.2.2 Safari/525.28.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR) AppleWebKit/534.16 (KHTML, like Gecko) Iron/10.0.650.0 Chrome/10.0.650.0 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.0) Gecko/20020530 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.2) Gecko/20030208 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0rc2) Gecko/20020512 Netscape/7.0b1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.6) Gecko/20040113 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.11) Gecko/20050728 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050318 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050319 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.7) Gecko/20050414 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.1.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.8.1.17) Gecko/20080919 K-Meleon/1.5.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.8.1.21) Gecko/20090403 SeaMonkey/1.1.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.8.1.23) Gecko/20090825 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.8.1.2pre) Gecko/20070111 SeaMonkey/1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-be; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.3.1) Gecko/20030425 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.6) Gecko/20040206 Firefox/0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Gecko/20040707 Firefox/0.9.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Gecko/20040803 Firefox/0.9.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7.2) Gecko/20040803 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7.3) Gecko/20040910 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7.8) Gecko/20050511 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.10) Gecko/20070216 Firefox/1.5.0.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.7) Gecko/20060917 K-Meleon/1.02 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1.12) Gecko/20080201 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 (.NET CLR 3.0.04506.30) +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1.18) Gecko/20081029 Firefox/2.0.0.18 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1.2) Gecko/20070222 SeaMonkey/1.1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1.2pre) Gecko/20070111 SeaMonkey/1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1.5) Gecko/20070713 Firefox/2.0.0.3C +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 ( .NET CLR 3.5.30729; .NET4.0C) +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.1.14) Gecko/20100930 SeaMonkey/2.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2.13) Gecko/20101203 iPhone +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2b4) Gecko/20091124 Firefox/3.6b4 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2b5) Gecko/20091204 Firefox/3.6b5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9b5) Gecko/2008032620 Firefox/3.0b5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; hr) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; hu-HU) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; hu-HU; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.6) Gecko/20040113 +Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.9.1.11) Gecko/20100701 Firefox/3.5.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.20 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; id) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it) AppleWebKit/522.13.1 (KHTML, like Gecko) Version/3.0.2 Safari/522.13.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT) AppleWebKit/525+ (KHTML, like Gecko) Version/3.1.2 Safari/525.21 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20060127 Netscape/8.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.6) Gecko/20050318 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.9.2.32) Gecko/20120529 Firefox/3.6.32 (Palemoon/3.6.32) +Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.9a1) Gecko/20100202 Firefox/3.0.18 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.0.12) Gecko/20070508 Firefox/1.5.0.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.18) Gecko/20081029 Firefox/2.0.0.18 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8b5) Gecko/20051006 Firefox/1.4.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.0.16) Gecko/2009120208 Firefox/3.0.16 FBSMTWB +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.1.12) Gecko/20100825 SeaMonkey/2.0.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.2.28) Gecko/20120306 AskTbSTC-SRS/3.13.1.18132 Firefox/3.6.28 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9b2) Gecko/2007121120 Firefox/3.0b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JA; rv:1.8.1.24pre) Gecko/20100228 K-Meleon/1.5.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP) AppleWebKit/529 (KHTML, like Gecko, Safari/529.0) Lunascape/4.9.9.99 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP) AppleWebKit/533.3 (KHTML, like Gecko) Lunascape/6.3.4.23051 Safari/533.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.8.1.5) Gecko/20070713 Firefox/2.0.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.9.2) Gecko/20100206 Palemoon/3.6.0.5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 (Palemoon/3.6.3) (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 (Palemoon/3.6.3) GTB7.0 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.9.2.8) Gecko/20100817 Firefox/3.6.8 (Palemoon/3.6.8a) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-jp) AppleWebKit/534.7 (KHTML, like Gecko) Iron/7.0.520.1 Chrome/7.0.520.1 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.8.0.10) Gecko/20070216 Firefox/1.5.0.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.8.1.5) Gecko/20070713 Firefox/2.0.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 GTB7.0 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1) Gecko/20090701 Firefox/3.5 Lunascape/5.1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.10) Gecko/20100624 Firefox/3.5.10 Lunascape/6.2.0.22177 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.10) Gecko/20100624 Firefox/3.5.10 Lunascape/6.2.0.22177 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.11) Gecko/20100723 Firefox/3.5.11 Lunascape/6.2.1.22445 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.13) Gecko/20100917 Firefox/3.5.13 Lunascape/6.3.3.22929 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.15) Gecko/20101029 Firefox/3.5.15 Lunascape/6.3.4.23051 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.15) Gecko/20101029 Firefox/3.5.15 Lunascape/6.3.4.23051 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.17) Gecko/20110123 SeaMonkey/2.0.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 GTB7.0 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.9) Gecko/20100331 Firefox/3.5.9 Lunascape/6.1.4.21478 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.9) Gecko/20100331 Firefox/3.5.9 Lunascape/6.1.4.21478 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.2.25) Gecko/20111212 Firefox/3.6.25 ( .NET CLR 3.5.30729; .NET4.0C) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.2.32) Gecko/20120529 Firefox/3.6.32 (Palemoon/3.6.32) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.2a1pre) Gecko/20090402 Firefox/3.6a1pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9b5) Gecko/2008032620 Firefox/3.0b5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ko-KR) AppleWebKit/525.28 (KHTML, like Gecko) Version/3.2.2 Safari/525.28.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ko-KR; rv:1.8.0.7) Gecko/20060917 K-Meleon/1.02 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ko; rv:1.8.0.12) Gecko/20070508 Firefox/1.5.0.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ko; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ko; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ko; rv:1.9.2.16) Gecko/20110325 Firefox/3.6.16 Lunascape/6.4.5.23569 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ko; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; lt; rv:1.9b4) Gecko/2008030714 Firefox/3.0b4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nb) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO) AppleWebKit/525.28 (KHTML, like Gecko) Version/3.2.2 Safari/525.28.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl) AppleWebKit/522.12.1 (KHTML, like Gecko) Version/3.0.1 Safari/522.12.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl) AppleWebKit/522.13.1 (KHTML, like Gecko) Version/3.0.2 Safari/522.13.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.6) Gecko/20050318 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.8.0.12) Gecko/20070508 Firefox/1.5.0.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.9.1.13) Gecko/20100914 Lightning/1.0b1 SeaMonkey/2.0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.9b4) Gecko/2008030714 Firefox/3.0b4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL) AppleWebKit/523.12.9 (KHTML, like Gecko) Version/3.0 Safari/523.12.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL) AppleWebKit/523.15 (KHTML, like Gecko) Version/3.0 Safari/523.15 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.17 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.8.0.7) Gecko/20060910 SeaMonkey/1.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.8.1.13) Gecko/20080313 SeaMonkey/1.1.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.8.1.16) Gecko/20080702 SeaMonkey/1.1.11 Mnenhy/0.7.5.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.8.1.22) Gecko/20090623 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.8.1.24pre) Gecko/20100228 K-Meleon/1.5.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.8.1.9) Gecko/20071030 SeaMonkey/1.1.6 Mnenhy/0.7.5.666 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.9a1) Gecko/20060812 SeaMonkey/1.5a +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.0.5) Gecko/20060801 Firefox/1.5.0.5 Flock/0.7.4.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.1.1) Gecko/20061204 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.1.1) Gecko/20061204 Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1) Gecko/20060918 Firefox/2.0b2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.0.6) Gecko/2009011913 Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20041221 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.1b3pre) Gecko/20090205 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 GTB6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.3) Gecko/20100401 Lightningquail/3.6.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR) AppleWebKit/523.15 (KHTML, like Gecko) Version/3.0 Safari/523.15 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR) AppleWebKit/525+ (KHTML, like Gecko) Version/3.0 Safari/523.15 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR) AppleWebKit/532.4 (KHTML, like Gecko) WeltweitimnetzBrowser/0.25 Safari/532.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR) AppleWebKit/533.3 (KHTML, like Gecko) QtWeb Internet Browser/3.7 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR) AppleWebKit/533.3 (KHTML, like Gecko) WeltweitimnetzBrowser/0.25 Safari/533.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR) AppleWebKit/534.12 (KHTML, like Gecko) Navscape/Pre-0.1 Safari/534.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR) AppleWebKit/534.12 (KHTML, like Gecko) NavscapeNavigator/Pre-0.1 Safari/534.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR) AppleWebKit/534.12 (KHTML, like Gecko) WeltweitimnetzBrowser/0.25 Safari/534.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR) AppleWebKit/534.8 (KHTML, like Gecko) Navscape/Pre-0.2 Safari/534.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.1.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.8.1.15) Gecko/20080623 Firefox/2.0.0.15 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.8.1.21) Gecko/20090303 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.8.1.21) Gecko/20090403 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 GTB6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.9.1.11) Gecko/20100701 Firefox/3.5.11 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.8.1.21) Gecko/20090303 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.9.2.7) Gecko/20100713 Firefox/3.6.7 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; pt; rv:1.9.1.13) Gecko/20100917 Firefox/3.5.13 Lunascape/6.3.2.22803 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ro-RO; rv:1.7.6) Gecko/20050318 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ro; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU) AppleWebKit/525.26.2 (KHTML, like Gecko) Version/3.2 Safari/525.26.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU) AppleWebKit/525.28 (KHTML, like Gecko) Version/3.2.2 Safari/525.28.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.6) Gecko/20050319 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.8.0.1) Gecko/20060130 SeaMonkey/1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.8.1.12) Gecko/20080203 K-Meleon/1.1.4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.8.1.17) Gecko/20080919 K-Meleon/1.5.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.0.8) Gecko/20061025 Firefox/1.5.0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.14) Gecko/20080603 Firefox/2.0.0.14 Flock/1.2.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.15) Gecko/20080706 Firefox/2.0.0.15 Flock/1.2.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.12) Gecko/20100824 MRA 5.7 (build 03755) Firefox/3.5.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.18pre) Gecko/20110610 Namoroka/3.6.18pre ( ) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.20pre) Gecko/20110718 Namoroka/3.6.20pre ( ) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.7 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9b3) Gecko/2008020514 Firefox/3.0b3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040911 Firefox/0.10.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.8.1.4) Gecko/20070511 K-Meleon/1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.9.1b3pre) Gecko/20081202 SeaMonkey/2.0a2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.9b3pre) Gecko/2008010602 SeaMonkey/2.0a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; sl; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; sl; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; sv) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; sv) AppleWebKit/522.12.1 (KHTML, like Gecko) Version/3.0.1 Safari/522.12.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; sv) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.6) Gecko/20050318 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.8.0.10) Gecko/20070216 Firefox/1.5.0.10 +Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.8.0.12) Gecko/20070508 Firefox/1.5.0.12 +Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.9.2.32) Gecko/20120529 Firefox/3.6.32 (Palemoon/3.6.32) +Mozilla/5.0 (Windows; U; Windows NT 5.1; th) AppleWebKit/522.12.1 (KHTML, like Gecko) Version/3.0.1 Safari/522.12.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR) AppleWebKit/523.15 (KHTML, like Gecko) Version/3.0 Safari/523.15 +Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/1.5 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.7.6) Gecko/20050321 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.8b5) Gecko/20051006 Firefox/1.4.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17 +Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 5.1; uk; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30) +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/533.16 (KHTML, like Gecko) Chrome/5.0.335.0 Safari/533.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.7.12) Gecko/20051001 Firefox/1.0.7 Madfox/0.3.2u3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.1.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.18) Gecko/20081029 Firefox/2.0.0.18 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.0.1) Gecko/20080722 Firefox/3.0.1 Kapiko/3.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.0.7pre) Gecko/2009012106 GranParadiso/3.0.7pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1b4) Gecko/20090423 Firefox/3.5b4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1b4) Gecko/20090423 Firefox/3.5b4 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.31) Gecko/20120408 Firefox/3.6.31 (Palemoon/3.6.31) +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.4) Gecko/20100503 Firefox/3.6.4 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9a1) Gecko/20061204 GranParadiso/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9a4pre) Gecko/20070427 Minefield/3.0a4pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9b2pre) Gecko/2007112619 Minefield/3.0b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9b3) Gecko/2008020514 Firefox/3.0b3 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9b3pre) Gecko/2007121805 Minefield/3.0b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9b4) Gecko/2008030714 Firefox/3.0b4 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW) AppleWebKit/523.15 (KHTML, like Gecko) Version/3.0 Safari/523.15 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.0.9) Gecko/2009040821 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 GTB6 +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.1b4pre) Gecko/20090308 Shiretoko/3.1b4pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.2.15pre) Gecko/20110127 Namoroka/3.6.15pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 GTB7.0 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9b4) Gecko/2008030714 Firefox/3.0b4 +Mozilla/5.0 (Windows; U; Windows NT 5.2 x64; en-US; rv:1.9.0.7) Gecko/2009030713 Minefield/3.0.7 +Mozilla/5.0 (Windows; U; Windows NT 5.2 x64; en-US; rv:1.9a1) Gecko/20060214 Firefox/1.6a1 +Mozilla/5.0 (Windows; U; Windows NT 5.2 x64; en-US; rv:1.9a1) Gecko/20061007 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; da; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de-AT; rv:1.8.1.16) Gecko/20080702 SeaMonkey/1.1.11 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de-AT; rv:1.8.1.21) Gecko/20090403 SeaMonkey/1.1.16 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de-DE) AppleWebKit/528+ (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de-DE) AppleWebKit/528+ (KHTML, like Gecko) Version/3.2.2 Safari/525.28.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de-DE) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de-DE) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de-DE; rv:1.7.6) Gecko/20050321 Firefox/1.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de-DE; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de; rv:1.8.1.5) Gecko/20070713 Firefox/2.0.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de; rv:1.9.1.15) Gecko/20101027 SeaMonkey/2.0.10 +Mozilla/5.0 (Windows; U; Windows NT 5.2; de; rv:1.9.1.16) Gecko/20101123 SeaMonkey/2.0.11 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en) AppleWebKit/522.13.1 (KHTML, like Gecko) Version/3.0.2 Safari/522.13.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100605 SeaMonkey/2.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100617 SeaMonkey/2.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100622 SeaMonkey/2.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100623 SeaMonkey/2.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100625 SeaMonkey/2.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100627 SeaMonkey/2.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100629 SeaMonkey/2.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100630 SeaMonkey/2.0.6pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.9pre) Gecko/20100305 SeaMonkey/2.0.4pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.3a3pre) Gecko/20100312 SeaMonkey/2.1a1pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.8.1.2pre) Gecko/20070226 BonEcho/2.0.0.2pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.8.1.3pre) Gecko/20070302 BonEcho/2.0.0.3pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.29 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.30 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.6 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.151.0 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.3.154.6 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.43 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.53 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.59 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/525.28 (KHTML, like Gecko) Version/3.2.2 Safari/525.28.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/530.4 (KHTML, like Gecko) Chrome/2.0.172.0 Safari/530.4 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.43 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/531.3 (KHTML, like Gecko) Chrome/3.0.193.2 Safari/531.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/0.0.0 Safari/532.0 Iron/3.0.197.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.21 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.27 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.33 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.6 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.206.1 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.210.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.212.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Iron/3.0.197.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.213.0 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.213.1 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.3 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.5 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.221.6 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.6 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.2 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Iron/4.0.275.2 Chrome/4.0.275.2 Safari/532.8 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.310.0 Safari/532.9 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/533.17.8 (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.126 Safari/533.4 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/7.0.540.0 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10 ChromePlus/1.5.1.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.558.0 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Iron/10.0.650.0 Chrome/10.0.650.0 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Iron/10.0.650.1 Chrome/10.0.650.1 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/11.0.652.0 Safari/534.17 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.2 (KHTML, like Gecko) Chrome/6.0.454.0 Safari/534.2 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.458.0 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.460.0 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.462.0 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.463.0 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.33 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.4 (KHTML, like Gecko) Chrome/6.0.481.0 Safari/534.4 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7 ChromePlus/1.5.0.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7 ChromePlus/1.5.0.0alpha1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) Chrome/0.0.0 Iron/3.0.197.0 AppleWebKit/532.0 (KHTML, like Gecko) Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.1) Gecko/20040707 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.2) Gecko/20040709 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.0.12) Gecko/20070508 Firefox/1.5.0.12 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.0.7) Gecko/20060917 K-Meleon/1.02 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.0.8) Gecko/20061025 Firefox/1.5.0.8 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.1.6 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.5.0 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.4pre) Gecko/20070510 BonEcho/2.0.0.4pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.5) Gecko/20070722 K-Meleon/1.11 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.6) Gecko/20070727 K-Meleon/1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.7pre) Gecko/20070815 Firefox/2.0.0.6 Navigator/9.0b3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1a2) Gecko/20060512 BonEcho/2.0a2 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8b5) Gecko/20051006 Firefox/1.4.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.0.9) Gecko/2009042410 Firefox/3.0.9 Wyzo/3.0.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.10) Gecko/20100504 Lightning/1.0b1 SeaMonkey/2.0.5 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.4) Gecko/20091007 Firefox/3.5.4 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.6) Gecko/20091222 Shiretoko/3.5.6 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.7) Gecko/20100104 SeaMonkey/2.0.2 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1b2pre) Gecko/20081110 Minefield/3.1b2pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1b3pre) Gecko/20090104 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1b3pre) Gecko/20090105 Firefox/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1b3pre) Gecko/20090105 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.20 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9a1) Gecko/20060926 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9a3pre) Gecko/20070320 Minefield/3.0a3pre +Mozilla/5.0 (Windows; U; Windows NT 5.2; es-ES; rv:1.9.1.10) Gecko/20100624 Firefox/3.5.10 Lunascape/6.1.7.21880 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.2; eu) AppleWebKit/530.4 (KHTML, like Gecko) Chrome/2.0.172.0 Safari/530.4 +Mozilla/5.0 (Windows; U; Windows NT 5.2; fr-FR; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; fr; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 3.0.04506.648) +Mozilla/5.0 (Windows; U; Windows NT 5.2; fr; rv:1.9b5) Gecko/2008032620 Firefox/3.0b5 +Mozilla/5.0 (Windows; U; Windows NT 5.2; nl) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; nl; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (Windows; U; Windows NT 5.2; nl; rv:1.9b5) Gecko/2008032620 Firefox/3.0b5 +Mozilla/5.0 (Windows; U; Windows NT 5.2; pt) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; pt-BR) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21 +Mozilla/5.0 (Windows; U; Windows NT 5.2; pt-BR) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.4 (Change: ) +Mozilla/5.0 (Windows; U; Windows NT 5.2; ru-RU) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13.3 +Mozilla/5.0 (Windows; U; Windows NT 5.2; ru; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11 +Mozilla/5.0 (Windows; U; Windows NT 5.2; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11 +Mozilla/5.0 (Windows; U; Windows NT 5.2; sk; rv:1.8.1.15) Gecko/20080623 Firefox/2.0.0.15 +Mozilla/5.0 (Windows; U; Windows NT 5.2; zh) AppleWebKit/522.13.1 (KHTML, like Gecko) Version/3.0.2 Safari/522.13.1 +Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.1.5) Gecko/Firefox/3.5.5 +Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-TW; rv:1.9.1.5) Gecko/20091106 Shiretoko/3.5.5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-TW; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 +Mozilla/5.0 (Windows; U; Windows NT 6.0 (x86_64); de-DE) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0 ; x64; en-US; rv:1.9.1b2pre) Gecko/20081026 Firefox/3.1b2pre +Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9.0.3pre) Gecko/2008111500 Minefield/3.0.5pre +Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9.1b2pre) Gecko/20081026 Firefox/3.1b2pre +Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9.1b2pre) Gecko/20081026 Minefield/3.1b2pre +Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9a1) Gecko/20061007 Minefield/3.0a1 +Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9a8pre) Gecko/2007090213 Minefield/3.0a8pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; bg; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; cs) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; cs; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 +Mozilla/5.0 (Windows; U; Windows NT 6.0; cs; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; cs; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; da-DK) AppleWebKit/523.12.9 (KHTML, like Gecko) Version/3.0 Safari/523.12.9 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de-AT; rv:1.8.0.5) Gecko/20060706 K-Meleon/1.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de-AT; rv:1.8.1.18) Gecko/20081031 SeaMonkey/1.1.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de-AT; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de-DE) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de-DE) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.4 (Change: ) +Mozilla/5.0 (Windows; U; Windows NT 6.0; de-DE) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de-DE) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de-DE; rv:1.8.1.12) Gecko/20080203 K-Meleon/1.1.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.8.1.5) Gecko/20070713 Firefox/2.0.0.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.8.1.5pre) Gecko/20070604 BonEcho/2.0.0.5pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 (.NET CLR 4.0.20506) +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.15) Gecko/2009101601 Firefox 2.1 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.16) Gecko/20101123 SeaMonkey/2.0.11 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.2) Gecko/20090729 Firefox/2.0.0.15 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.8) Gecko/20100205 SeaMonkey/2.0.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB7.0 (.NET CLR 3.0.30618) +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.2.13) Gecko/20101203 Firefox/3.5.9 (de) +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.20 +Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9b5) Gecko/2008032620 Firefox/3.0b5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en) AppleWebKit/522.12.1 (KHTML, like Gecko) Version/3.0.1 Safari/522.12.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en) AppleWebKit/525+ (KHTML, like Gecko) Version/3.0.4 Safari/523.11 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.8.1.5) Gecko/20070713 Firefox/2.0.0.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.12) Gecko/2009070611 Firefox/3.0.12 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.13) Gecko/2009073022 EnigmaFox/3.0.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 (.NET CLR 3.5.30729) FirePHP/0.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.7) Gecko/2009021910 MEGAUPLOAD 1.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1 GTB5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1 GTB5 (.NET CLR 4.0.20506) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.1.10) Gecko/20100504 Firefox/3.5.10 GTB7.0 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.1b4) Gecko/20090423 Firefox/3.5b4 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.15) Gecko/20110303 AskTbBT4/3.11.3.15590 Firefox/3.6.15 ( .NET CLR 3.5.30729; .NET4.0C) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.24) Gecko/20111103 Firefox/3.6.24 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9 ( .NET CLR 3.5.30729; .NET CLR 4.0.20506) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-MY) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.10.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/523.15 (KHTML, like Gecko) Version/3.0 Safari/523.15 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.29 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.30 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.6 Safari/525.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.17 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.151.0 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.152.0 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.153.0 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.4.154.31 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.42 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.43 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.46 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.50 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.53 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.59 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/14871328.525 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/41562480.525 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/1.7 http://www.QtWeb.net +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.4 (Change: ) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6 (Change: ) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.1.2.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.10 (KHTML, like Gecko) Chrome/2.0.157.2 Safari/528.10 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.11 (KHTML, like Gecko) Chrome/2.0.157.0 Safari/528.11 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.4 (KHTML, like Gecko) Iron/0.3.155.0 Safari/18455624.528 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.4 (KHTML, like Gecko) Iron/0.3.155.0 Safari/19322656.528 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.5 (KHTML, like Gecko) Iron/0.4.155.0 Safari/528.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.7 (KHTML, like Gecko) Iron/1.0.155.0 Safari/528.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.8 (KHTML, like Gecko) Chrome/2.0.156.1 Safari/528.8 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/529 (KHTML, like Gecko, Safari/529.0) Lunascape/4.9.9.100 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.0 (KHTML, like Gecko) Chrome/2.0.160.0 Safari/530.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.0 (KHTML, like Gecko) Chrome/2.0.162.0 Safari/530.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Chrome/2.0.164.0 Safari/530.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Chrome/2.0.168.0 Safari/530.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Iron/2.0.168.0 Safari/530.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.4 (KHTML, like Gecko) Chrome/2.0.171.0 Safari/530.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.2 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.23 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.39 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.40 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.43 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.6 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.173.1 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.6 (KHTML, like Gecko) Chrome/2.0.174.0 Safari/530.6 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.7 (KHTML, like Gecko) Chrome/2.0.176.0 Safari/530.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/531.3 (KHTML, like Gecko) Chrome/3.0.193.0 Safari/531.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/531.3 (KHTML, like Gecko) Chrome/3.0.193.2 Safari/531.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.1 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.10 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.17 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.20 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.21 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.27 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.3 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.6 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.196.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.197.11 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.198.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.201.1 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.206.1 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.207.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.208.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.4 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.7 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.213.1 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.220.1 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.221.6 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.12 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.0 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.3 (KHTML, like Gecko) Chrome/4.0.224.2 Safari/532.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.3 (KHTML, like Gecko) Iron/4.0.227.0 Chrome/4.0.227.0 Safari/532.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.4 (KHTML, like Gecko) Chrome/4.0.241.0 Safari/532.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Iron/4.0.275.2 Chrome/4.0.275.2 Safari/532.8 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Iron/4.0.280.0 Chrome/4.0.280.0 Safari/532.9 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.1 (KHTML, like Gecko) Maxthon/3.0.8.2 Safari/533.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.5 Safari/533.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/533.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.127 Safari/533.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10 ChromePlus/1.5.1.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10 ChromePlus/1.5.2.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.10 (KHTML, like Gecko) RockMelt/0.8.40.147 Chrome/8.0.552.231 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.0 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Iron/9.0.600.2 Chrome/9.0.600.2 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.13 (KHTML, like Gecko) RockMelt/0.9.46.126 Chrome/9.0.597.107 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.13 (KHTML, like Gecko) RockMelt/0.9.48.58 Chrome/9.0.597.107 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Iron/10.0.650.0 Chrome/10.0.650.0 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.518 Chrome/10.0.648.205 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.549 Chrome/10.0.648.205 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.0 Chrome/11.0.700.0 Safari/534.24 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.458.1 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Chrome/6.0.475.0 Safari/14183168.534 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Chrome/6.0.475.0 Safari/42721888.534 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Chrome/6.0.475.0 Safari/56984160.534 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Chrome/6.0.475.0 Safari/59178784.534 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Chrome/6.0.475.0 Safari/87693504.534 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Iron/7.0.520.0 Chrome/7.0.520.0 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.116 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.128 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.79 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.8 (KHTML, like Gecko) Chrome/7.0.521.0 Safari/534.8 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/535.1 (KHTML, like Gecko) Iron/13.0.800.0 Chrome/13.0.800.0 Safari/535.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.7.12) Gecko/20050915 K-Meleon/0.9 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.7.13) Gecko/20060414 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.7.5) Gecko/20060912 Netscape/8.1.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.7.5) Gecko/20070321 Netscape/8.1.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.0.10pre) Gecko/20070207 Firefox/1.5.0.10pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.0.12) Gecko/20070508 Firefox/1.5.0.12 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.0.12) Gecko/20070508 Firefox/1.5.0.12 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.0.6) Gecko/20060730 K-Meleon/1.01 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.0.8) Gecko/20061025 Firefox/1.5.0.8 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.10) Gecko/20071116 K-Meleon/1.1.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.11) Gecko/20071128 SeaMonkey/1.1.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.12) Gecko/20080203 K-Meleon/1.1.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.12) Gecko/20080219 Firefox/2.0.0.12 Navigator/9.0.0.6 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.13) Gecko/20080326 Firefox/2.0.0.13 Flock/1.1.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.1.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.14) Gecko/20080414 Firefox/2.0.0.14 Flock/1.1.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.17) Gecko/20080915 Firefox/2.0.0.17 Flock/1.2.6 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.17) Gecko/20080919 K-Meleon/1.5.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.5.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.18) Gecko/20081031 SeaMonkey/1.1.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.2) Gecko/20070222 K-Meleon/1.02 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.21) Gecko/20090303 SeaMonkey/1.1.15 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.21) Gecko/20090403 K-Meleon/1.02 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.21) Gecko/20090403 SeaMonkey/1.1.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.2pre) Gecko/20070221 K-Meleon/0.9 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.6) Gecko/20070801 Firefox/2.0 Wyzo/0.5.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.7) Gecko/20070925 Firefox/2.0.0.7 Flock/0.9.1.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.8pre) Gecko/20070928 Firefox/2.0.0.7 Navigator/9.0RC1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.8pre) Gecko/20071019 Firefox/2.0.0.8 Navigator/9.0.0.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1b2) Gecko/20060821 Firefox/2.0b2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8b5) Gecko/20051019 Flock/0.4 Firefox/1.0+ +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9) Gecko/2008061302 Firefox/3.0 Flock/2.0b1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9) Gecko/2008071513 Minefield/3.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.12) Gecko/2009070611 Firefox/3.0.12 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.12) Gecko/2009070611 Firefox/3.0.12 GTB5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.12) Gecko/2009070611 Firefox/3.5.12 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.2) Gecko/2008092122 Firefox/3.0.2 Flock/2.0b3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.3) Gecko/2008100719 Firefox/3.0.3 Flock/2.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.4) Gecko/2008112016 Firefox/3.0.4 Flock/2.0.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.5) Gecko/2008121620 Firefox/3.0.5 Flock/2.0.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.5) Gecko/2009011615 Firefox/3.0.5 CometBird/3.0.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.7) Gecko/2009030821 Firefox/3.0.7 Orca/1.1 build 2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.9) Gecko/2009042410 Firefox/3.0.9 Wyzo/3.0.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1) Gecko/20090701 Firefox/3.5 Lunascape/5.1.2.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.1) Gecko/20090722 Firefox/3.5.1 Orca/1.2 build 2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.15) Gecko/20101029 Firefox/3.5.15 Lunascape/6.3.4.23051 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.16) Gecko/20101123 SeaMonkey/2.0.11 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.16) Gecko/20101130 MRA 5.4 (build 02647) Firefox/3.5.16 ( .NET CLR 3.5.30729; .NET4.0C) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.19) Gecko/20110420 SeaMonkey/2.0.14 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.1pre) Gecko/20090717 SeaMonkey/2.0b1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 2.0.50727; .NET CLR 3.0.30618; .NET CLR 3.5.21022; .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.6) Gecko/20091201 MRA 5.4 (build 02647) Firefox/3.5.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 (.NET CLR 3.5.30729) FirePHP/0.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1a1pre) Gecko/2008071403 Minefield/3.1a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1a2pre) Gecko/2008072403 Minefield/3.1a2pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b2) Gecko/20081127 Firefox/3.1b1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b2pre) Gecko/20081011 Minefield/3.1b2pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b3) Gecko/20090305 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b3) Gecko/20090405 Firefox/3.1b3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b3pre) Gecko/20081204 Shiretoko/3.1b3pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b3pre) Gecko/20081207 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b4) Gecko/20090423 Firefox/3.5b4 GTB5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b4pre) Gecko/20090307 Shiretoko/3.1b4pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b4pre) Gecko/20090311 Shiretoko/3.1b4pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b4pre) Gecko/20090312 Firefox/3.1b4pre Lunascape/5.0.3.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b4pre) Gecko/20090312 Firefox/3.1b4pre Lunascape/5.0.5.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b5pre) Gecko/20090519 Shiretoko/3.5b5pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1pre) Gecko/20090516 Firefox/3.5pre Lunascape/5.1.0.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.10pre) Gecko/20100828 Namoroka/3.6.10pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 (.NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET CLR 3.5.21022) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 (Palemoon/3.6.3) (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.3) Gecko/20100405 Namoroka/3.6.3 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100527 Firefox/3.6.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100527 Firefox/3.6.4 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1) Gecko/20090806 Namoroka/3.6a1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1) Gecko/20090806 Namoroka/3.6a1 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20090207 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20090210 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20090226 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20090306 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20090324 Minefield/3.6a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20090401 Minefield/3.6a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20090407 Minefield/3.6a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20090411 Minefield/3.6a1pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20090420 Minefield/3.6a1pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a1pre) Gecko/20090707 Minefield/3.6a1pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a2pre) Gecko/20090826 Namoroka/3.6a2pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.3a1pre) Gecko/20090829 Minefield/3.7a1pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.3a1pre) Gecko/20091118 Minefield/3.7a1pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.3a3pre) Gecko/20100312 Minefield/3.7a3pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9a5pre) Gecko/20070428 Minefield/3.0a5pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9a6pre) Gecko/20070615 Minefield/3.0a6pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9a9pre) Gecko/2007092705 Minefield/3.0a9pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9b3) Gecko/2008020514 Firefox/3.0b3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:2.0a1pre) Gecko/2008032002 Minefield/4.0a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-gb) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en; rv:1.9.1b4pre) Gecko/20090419 SeaMonkey/2.0b1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; en_US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; es-AR; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; es-ES; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; es-ES; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.1.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; es-ES; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; es-ES; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.5.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; es-ES; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; es-MX; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; es-es) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fi) AppleWebKit/522.12.1 (KHTML, like Gecko) Version/3.0.1 Safari/522.12.2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fi; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr-FR) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr-FR) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr-FR) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr-FR) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr-FR; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.1.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr-ch) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.1.17) Gecko/20110123 SeaMonkey/2.0.12 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.1b1) Gecko/20081007 Firefox/3.1b1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.2.28) Gecko/20120306 Firefox/3.6.28 +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9b3pre) Gecko/2008011205 Minefield/3.0b3pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9b5) Gecko/2008032620 Firefox/3.0b5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; he-IL) AppleWebKit/528+ (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; he-IL) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; hu-HU) AppleWebKit/525.26.2 (KHTML, like Gecko) Version/3.2 Safari/525.26.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; hu-HU) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; hu-HU) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; hu; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.20 +Mozilla/5.0 (Windows; U; Windows NT 6.0; id; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; it-IT; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (Windows; U; Windows NT 6.0; it; rv:1.8.1.17) Gecko/20080922 Firefox/2.0.0.17 Flock/1.2.6 +Mozilla/5.0 (Windows; U; Windows NT 6.0; it; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (Windows; U; Windows NT 6.0; it; rv:1.9.1.16) Gecko/20101130 Firefox/3.5.16 GTB7.1 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; it; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; it; rv:1.9.2.12) Gecko/20101114 IceCat/3.6.12 (like Firefox/3.6.12) +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja-JP) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.0.3.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja-JP) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.1.1.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja-JP) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.1.2.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja-JP) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja-JP) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja-JP) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja-JP) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.1.15) Gecko/20101029 Firefox/3.5.15 Lunascape/6.3.4.23051 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.2.12) Gecko/20101029 Firefox/3.6.12 Lunascape/6.3.4.23051 ( .NET CLR 3.5.30729; .NET4.0C) +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.3a5pre) Gecko/20100605 Minefield/3.7a5pre ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; ko; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; ko; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; nb-NO) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; nl) AppleWebKit/522.11.3 (KHTML, like Gecko) Version/3.0 Safari/522.11.3 +Mozilla/5.0 (Windows; U; Windows NT 6.0; nl) AppleWebKit/522.13.1 (KHTML, like Gecko) Version/3.0.2 Safari/522.13.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.0.12) Gecko/2009070611 Firefox/3.0.12 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 +Mozilla/5.0 (Windows; U; Windows NT 6.0; pl-PL) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21 +Mozilla/5.0 (Windows; U; Windows NT 6.0; pl-PL) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.8.1.14) Gecko/20080519 Firefox/2.0.0.14 Flock/1.2.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 +Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 GTB7.1 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9b4) Gecko/2008030714 Firefox/3.0b4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; pt-BR; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; ru-RU) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12; MEGAUPLOAD 2.0 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.12) Gecko/2009070611 Firefox/3.0.12 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.1.5) Gecko/20091102 MRA 5.5 (build 02842) Firefox/3.5.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.1b4pre) Gecko/20090419 SeaMonkey/2.0b1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.2) Gecko/20100115 Firefox/3.6 +Mozilla/5.0 (Windows; U; Windows NT 6.0; rv:1.9.1b4pre) Gecko/20090419 SeaMonkey/2.0b1pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; sr; rv:1.9.0.12) Gecko/2009070611 Firefox/3.0.12 +Mozilla/5.0 (Windows; U; Windows NT 6.0; sv-SE) AppleWebKit/523.13 (KHTML, like Gecko) Version/3.0 Safari/523.13 +Mozilla/5.0 (Windows; U; Windows NT 6.0; sv-SE) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; sv-SE; rv:1.8.1.15) Gecko/20080623 Firefox/2.0.0.15 +Mozilla/5.0 (Windows; U; Windows NT 6.0; sv-SE; rv:1.9.0.18) Gecko/2010020220 Firefox/3.0.18 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; sv-SE; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; sv-SE; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 +Mozilla/5.0 (Windows; U; Windows NT 6.0; sv-SE; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 +Mozilla/5.0 (Windows; U; Windows NT 6.0; tr-TR) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; tr; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (Windows; U; Windows NT 6.0; tr; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; x64; en-US; rv:1.9.1b2pre) Gecko/20081026 Firefox/3.1b2pre +Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-CN; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.19 +Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-CN; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-CN; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 +Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-CN; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-TW) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1 +Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-TW; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 +Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-TW; rv:1.8.1.5) Gecko/20070713 Firefox/2.0.0.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-TW; rv:1.9.1) Gecko/20090624 Firefox/3.5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; WOW64; cs; rv:1.9.2.6) Gecko/20100723 myibrow/4.0.0.0 (Firefox/3.6 compatible) +Mozilla/5.0 (Windows; U; Windows NT 6.1; WOW64; en-US; rv:2.0.4) Gecko/20120718 AskTbAVR-IDW/3.12.5.17700 Firefox/14.0.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ar; rv:1.9.2) Gecko/20100115 Firefox/3.6 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ar; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ca; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; cs-CZ) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Windows; U; Windows NT 6.1; cs; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; cs; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; cs; rv:1.9.2.6) Gecko/20100628 myibrow/4alpha2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; cs; rv:1.9.2a2pre) Gecko/20090912 Namoroka/3.6a2pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; de-AT; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de-DE) AppleWebKit/525.28 (KHTML, like Gecko) Version/3.2.2 Safari/525.28.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de-DE) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de-DE) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/7.0.540.0 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de-DE) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de-DE) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/10.0.649.0 Safari/534.17 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de-DE; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.1) Gecko/20090624 Firefox/3.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.1) Gecko/20090624 Firefox/3.5 (.NET CLR 4.0.20506) +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.1.11) Gecko/20100701 Firefox/3.5.11 ( .NET CLR 3.5.30729; .NET4.0C) +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.1.16) Gecko/20101130 AskTbMYC/3.9.1.14019 Firefox/3.5.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.1.19) Gecko/20110420 SeaMonkey/2.0.14 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.3) Gecko/20121221 Firefox/3.6.8 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.8) Gecko/20100722 Firefox 3.6.8 +Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.3a1pre) Gecko/20091013 Minefield/3.7a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-AU; rv:1.9.2.14) Gecko/20110218 Firefox/3.6.14 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-CA; rv:1.9.0.5) Gecko/2009012102 Firefox/3.0.5 Flock/2.0.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.428.0 Safari/534.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.0.16) Gecko/2010021003 Firefox/3.0.16 Flock/2.5.6 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.0.5) Gecko/2009012105 Firefox/3.0.5 Flock/2.0.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1.17) Gecko/20110123 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070225 lolifox/0.32 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1.17) Gecko/20110123 SeaMonkey/2.0.12 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 GTB5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.3) Gecko/20100401 Firefox/3.6;MEGAUPLOAD 1.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0C) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.3.154.9 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.43 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.53 Safari/525.19 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/528.7 (KHTML, like Gecko) Iron/1.0.155.0 Safari/528.7 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/528.8 (KHTML, like Gecko) Chrome/1.0.156.0 Safari/528.8 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/528.8 (KHTML, like Gecko) Chrome/2.0.156.1 Safari/528.8 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/530.0 (KHTML, like Gecko) Chrome/2.0.182.0 Safari/531.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/530.19.2 (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/530.4 (KHTML, like Gecko) Chrome/2.0.172.0 Safari/530.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.43 Safari/530.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/530.6 (KHTML, like Gecko) Chrome/2.0.174.0 Safari/530.6 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/530.9 (KHTML, like Gecko) Iron/2.0.178.0 Safari/530.9 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/531.0 (KHTML, like Gecko) Chrome/2.0.182.0 Safari/531.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/531.0 (KHTML, like Gecko) Chrome/2.0.182.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/531.0 (KHTML, like Gecko) Chrome/3.0.191.0 Safari/531.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/531.0 (KHTML, like Gecko) Iron/3.0.189.0 Safari/531.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/531.3 (KHTML, like Gecko) Chrome/3.0.193.2 Safari/531.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/531.4 (KHTML, like Gecko) Chrome/3.0.194.0 Safari/531.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532+ (KHTML, like Gecko) Version/4.0.2 Safari/530.19.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.1 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.10 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.21 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.27 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.3 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.4 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.6 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.196.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.197.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.197.11 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.201.1 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.2 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.204.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.206.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.206.1 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.208.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.4 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.212.0 Safari/532.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.213.1 Safari/532.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.12 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.3 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.1 Safari/532.2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.3 (KHTML, like Gecko) Chrome/4.0.223.5 Safari/532.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.3 (KHTML, like Gecko) Chrome/4.0.227.0 Safari/532.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.3 (KHTML, like Gecko) Iron/4.0.227.0 Chrome/4.0.227.0 Safari/532.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.4 (KHTML, like Gecko) Maxthon/3.0.6.27 Safari/532.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.246.0 Safari/532.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.1.249.1025 Safari/532.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Chrome/4.0.275.2 Safari/532.8 Iron/4.0.275.2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Chrome/4.0.280.0 Safari/532.8 Iron/4.0.280.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Iron/4.0.275.2 Chrome/4.0.275.2 Safari/532.8 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.307.1 Safari/532.9 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Iron/4.0.280.0 Chrome/4.0.275.0 Safari/532.9 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Iron/4.0.280.0 Chrome/4.0.280.0 Safari/532.9 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533+ (KHTML, like Gecko) Element Browser 5.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.1 (KHTML, like Gecko) Chrome/5.0.336.0 Safari/533.1 ChromePlus/1.3.8.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.1 (KHTML, like Gecko) Iron/5.0.326.0 Chrome/5.0.326.0 Safari/533.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.3 Safari/533.2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/6.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.354.0 Safari/533.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Lunascape/6.4.2.23236 Safari/533.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.370.0 Safari/533.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.999 Safari/533.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.9 (KHTML, like Gecko) Chrome/6.0.400.0 Safari/533.9 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.428.0 Safari/534.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/7.0.540.0 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10 ChromePlus/1.5.1.0alpha3 ChromePlus/1.5.1.0alpha3 ChromePlus/1.5.1.0alpha3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10 ChromePlus/1.5.1.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.216 Safari/534.10 ChromePlus/1.5.1.0alpha1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10 ChromePlus/1.5.2.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10 ChromePlus/1.5.2.0alpha1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) RockMelt/0.8.40.147 Chrome/8.0.552.231 Safari/534.10 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.596.0 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.0 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.19 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13 ChromePlus/1.6.0.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) RockMelt/0.9.48.51 Chrome/9.0.597.107 Safari/534.13 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/10.0.601.0 Safari/534.14 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.638.0 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.11 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.134 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Iron/10.0.650.0 Chrome/10.0.650.0 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.459 Chrome/10.0.648.204 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.518 Chrome/10.0.648.205 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.549 Chrome/10.0.648.205 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/10.0.649.0 Safari/534.17 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/11.0.654.0 Safari/534.17 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/11.0.655.0 Safari/534.17 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.2 (KHTML, like Gecko) Chrome/6.0.454.0 Safari/534.2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.669.0 Safari/534.20 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.458.1 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.459.0 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.460.0 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.461.0 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.464.0 Safari/534.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Chrome/6.0.475.0 Safari/112818688.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Chrome/6.0.475.0 Safari/42050816.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Chrome/6.0.475.0 Safari/53013696.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Chrome/6.0.475.0 Safari/66529120.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475 Chrome/6.0.475.0 Safari/92861792.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/58473792.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/61170080.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/61389024.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/6316928.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/65209600.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/65969728.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/67162016.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/6838624.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/69296032.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/73530880.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/76829344.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/83554272.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/89895776.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/94403424.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/95066112.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/9724672.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/97486176.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/98035072.534 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.6 (KHTML, like Gecko) Chrome/7.0.498.0 Safari/534.6 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7 ChromePlus/1.4.3.0alpha3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Flock/3.5.2.4599 Chrome/7.0.517.442 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Iron/7.0.520.0 Chrome/7.0.520.0 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Iron/7.0.520.1 Chrome/7.0.520.1 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.116 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.128 Chrome/7.0.517.44 Safari/534.7 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.8.0.7) Gecko/20060910 SeaMonkey/1.0.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 GTB5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.8.1.24) Gecko/20100228 Sylera/3.0.20 SeaMonkey/1.1.19 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.0.12) Gecko/2009070611 Firefox/3.0.12 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.0.12) Gecko/2009070611 Firefox/3.0.12 (.NET CLR 3.5.30729) FirePHP/0.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.0.9) Gecko/2009042410 Firefox/3.0.9 Wyzo/3.0.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1) Gecko/20090612 Firefox/3.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1) Gecko/20090612 Firefox/3.5 (.NET CLR 4.0.20506) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1) Gecko/20090624 Firefox/3.1b3;MEGAUPLOAD 1.0 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1) Gecko/20090701 Firefox/3.5 Lunascape/5.1.1.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.1) Gecko/20090718 Firefox/3.5.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.1) Gecko/20090722 Firefox/3.5.1 Orca/1.2 build 2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.14) Gecko/20100930 SeaMonkey/2.0.9 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.16) Gecko/20101130 Firefox/3.5.16 FirePHP/0.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 (.NET CLR 3.5.30729) FBSMTWB +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 MRA 5.5 (build 02842) Firefox/3.5.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20100121 Firefox/3.5.6 Wyzo/3.5.6.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.7pre) Gecko K-Meleon/1.5.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.8) Gecko/20100223 Firefox/3.5.8 Lunascape/6.1.0.20940 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.9) Gecko/20100317 Lightning/1.0b1 SeaMonkey/2.0.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1b3pre) Gecko/20081208 SeaMonkey/2.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1b3pre) Gecko/20081208 SeaMonkey/2.0a3pre +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1b4pre) Gecko/20090420 Shiretoko/3.5b4pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.11) Gecko/20101023 Firefox/3.6.11 (Palemoon/3.6.11) ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101211 Firefox/3.6.13 (Palemoon/3.6.13) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101211 Firefox/3.6.13 (Palemoon/3.6.13) GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101213 Opera/9.80 (Windows NT 6.1; U; zh-tw) Presto/2.7.62 Version/11.01 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15 ( .NET CLR 3.5.30729; .NET4.0C) FirePHP/0.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.17) Gecko/20110420 Firefox/3.6 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.2) Gecko/20100316 AskTbSPC2/3.9.1.14019 Firefox/3.6.2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.2) Gecko/20100324 Firefox/3.6.2 (Palemoon/3.6.2) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.28) Gecko/20120410 Firefox/3.6.28 Lunascape/6.7.1.25446 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.5.3;MEGAUPLOAD 1.0 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 (Palemoon/3.6.3) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.30) Gecko/20120217 Firefox/3.6.30 (Palemoon/3.6.30) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.32) Gecko/20120529 Firefox/3.6.32 (Palemoon/3.6.32) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3pre) Gecko/20100403 Lorentz/3.6.3plugin2pre (.NET CLR 4.0.20506) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3pre) Gecko/20100405 Firefox/3.6.3plugin1 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.8) Gecko/20100806 Firefox/3.6 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2a1) Gecko/20090806 Namoroka/3.6a1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2a1) Gecko/20090806 Namoroka/3.6a1 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2a1pre) Gecko/20090316 Minefield/3.2a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2a2pre) Gecko/20090917 Namoroka/3.6a2pre +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2a2pre) Gecko/20090918 Namoroka/3.6a2pre +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b1) Gecko/20091014 Firefox/3.6b1 GTB5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b5) Gecko/20091204 Firefox/3.6b5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.3a1pre) Gecko/20090829 Minefield/3.7a1pre +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.3a3pre) Gecko/20100305 Minefield/3.7a3pre +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.3a3pre) Gecko/20100306 Firefox3.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.3a3pre) Gecko/20100306 Minefield/3.7a3pre (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.3a3pre) Gecko/20100313 Minefield/3.7a3pre (.NET CLR 4.0.20506) +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:2.0b10) Gecko/20110126 Firefox/4.0b10 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7 +Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.1) Gecko/20090624 Firefox/3.5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15 +Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.0 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; et; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 +Mozilla/5.0 (Windows; U; Windows NT 6.1; fr-FR) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 +Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 GTB7.0 +Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.6pre) Gecko/20100604 Namoroka/3.6.6pre +Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.8) Gecko/20100722 Firefox 3.6.8 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; he; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 +Mozilla/5.0 (Windows; U; Windows NT 6.1; hu; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (Windows; U; Windows NT 6.1; hu; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; hu; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; hu; rv:1.9.2.7) Gecko/20100713 Firefox/3.6.7 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; it-IT) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.25 Safari/532.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 +Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.8) Gecko/20100722 AskTbADAP/3.9.1.14019 Firefox/3.6.8 +Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:2.0b4) Gecko/20100818 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ja-JP) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ja-JP) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ja-JP; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 (Palemoon/3.6.3) +Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.1.15) Gecko/20101029 Firefox/3.5.15 Lunascape/6.3.4.23051 ( .NET CLR 3.5.30729; .NET4.0C) +Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ko-KR) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ko-KR) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Windows; U; Windows NT 6.1; lt; rv:1.9.2) Gecko/20100115 Firefox/3.6 +Mozilla/5.0 (Windows; U; Windows NT 6.1; nl; rv:1.9.0.9) Gecko/2009040821 Firefox/3.0.9 FirePHP/0.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; nl; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (Windows; U; Windows NT 6.1; nl; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.1) Gecko/20090624 Firefox/3.5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 GTB5 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-BR; rv:1.9.1b3pre) Gecko/20090103 Shiretoko/3.1b3pre +Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-BR; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-BR; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-PT; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ro; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ru-RU) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.11 Safari/534.16 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ru-RU; AppleWebKit/534.16; KHTML; like Gecko; Chrome/10.0.648.11;Safari/534.16) +Mozilla/5.0 (Windows; U; Windows NT 6.1; ru-RU; rv:1.9.2) Gecko/20100105 MRA 5.6 (build 03278) Firefox/3.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.1.10) Gecko/20100504 Lightning/1.0b1 SeaMonkey/2.0.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/4.0 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2b5) Gecko/20091204 Firefox/3.6b5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.3a4pre) Gecko/20100402 Minefield/3.7a4pre +Mozilla/5.0 (Windows; U; Windows NT 6.1; rv:1.9.2.9) Gecko/20100913 Firefox/3.6.9 +Mozilla/5.0 (Windows; U; Windows NT 6.1; rv:2.2) Gecko/20110201 +Mozilla/5.0 (Windows; U; Windows NT 6.1; sl; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 +Mozilla/5.0 (Windows; U; Windows NT 6.1; sv-SE) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Mozilla/5.0 (Windows; U; Windows NT 6.1; tr-TR) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27 +Mozilla/5.0 (Windows; U; Windows NT 6.1; tr; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB7.1 +Mozilla/5.0 (Windows; U; Windows NT 6.1; uk; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; x64; fr; rv:1.9.1.1) Gecko/20090722 Firefox/3.5.1 Orca/1.2 build 2 +Mozilla/5.0 (Windows; U; Windows NT 6.1; x64; fr; rv:1.9.2.13) Gecko/20101203 Firebird/3.6.13 +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN) AppleWebKit/533+ (KHTML, like Gecko) +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.13) Gecko/20101210 Namoroka/3.6.13 Firefox/3.6.12 +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.14) Gecko/20110218 Firefox/3.6.14 +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-HK) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-TW) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10 +Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-TW; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 ( .NET CLR 3.5.30729) +Mozilla/5.0 (Windows; U; Windows NT 9.0; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 +Mozilla/5.0 (Windows; U; Windows NT5.1; en; rv:1.7.10) Gecko/20050716 Firefox/1.0.5 +Mozilla/5.0 (Windows; U; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.1.2 Safari/525.21 +Mozilla/5.0 (Windows; U;) AppleWebKit/532.0 (KHTML, like Gecko) Iron +Mozilla/5.0 (Windows; U;) AppleWebKit/532.0 (KHTML, like Gecko) Iron/3.0.197.0 Safari/532.0 +Mozilla/5.0 (Windows; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (Windows; Windows NT 5.1; en-US; rv:1.9.2a1pre) Gecko/20090402 Firefox/3.6a1pre +Mozilla/5.0 (Windows; Windows NT 5.1; es-ES; rv:1.9.2a1pre) Gecko/20090402 Firefox/3.6a1pre +Mozilla/5.0 (Windows; Windows NT 5.2; rv:2.0b3pre) Gecko/20100803 SeaMonkey/2.1a3pre +Mozilla/5.0 (Windows; Windows NT 6.1; rv:2.0b2pre) Gecko/20100720 SeaMonkey/2.1a3pre +Mozilla/5.0 (X11) KHTML/4.9.1 (like Gecko) Konqueror/4.9 +Mozilla/5.0 (X11; ; Linux i686; en-US; rv:1.8.1.3) Gecko +Mozilla/5.0 (X11; ; Linux i686; rv:1.9.2.20) Gecko/20110805 +Mozilla/5.0 (X11; ; Linux x86_64; rv:1.8.1.6) Gecko/20070802 Firefox +Mozilla/5.0 (X11; Arch Linux i686; rv:2.0) Gecko/20110321 Firefox/4.0 +Mozilla/5.0 (X11; CrOS i686 0.13.507) AppleWebKit/534.35 (KHTML, like Gecko) Chrome/13.0.763.0 Safari/534.35 +Mozilla/5.0 (X11; CrOS i686 0.13.587) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.14 Safari/535.1 +Mozilla/5.0 (X11; CrOS i686 1193.158.0) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7 +Mozilla/5.0 (X11; CrOS i686 12.0.742.91) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.93 Safari/534.30 +Mozilla/5.0 (X11; CrOS i686 12.433.109) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.93 Safari/534.30 +Mozilla/5.0 (X11; CrOS i686 12.433.216) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.105 Safari/534.30 +Mozilla/5.0 (X11; CrOS i686 13.587.48) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.43 Safari/535.1 +Mozilla/5.0 (X11; CrOS i686 1660.57.0) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.46 Safari/535.19 +Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11 +Mozilla/5.0 (X11; FreeBSD amd64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.65 Safari/535.11 +Mozilla/5.0 (X11; FreeBSD amd64; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (X11; FreeBSD amd64; rv:6.0) Gecko/20110818 Firefox/6.0 SeaMonkey/2.3 +Mozilla/5.0 (X11; FreeBSD i386) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2 +Mozilla/5.0 (X11; FreeBSD i686) Firefox/3.6 +Mozilla/5.0 (X11; FreeBSD x86_64; rv:2.0) Gecko/20100101 Firefox/3.6.12 +Mozilla/5.0 (X11; Gentoo Linux x86_64; rv:11.0a2) Gecko/20111230 Firefox/11.0a2 Iceweasel/11.0a2 +Mozilla/5.0 (X11; Linux 3.5.4-1-ARCH i686; es) KHTML/4.9.1 (like Gecko) Konqueror/4.9 +Mozilla/5.0 (X11; Linux AMD64) Gecko Firefox/5.0 +Mozilla/5.0 (X11; Linux Debian i686; rv:8.0) Gecko/20100101 Firefox/8.0 Iceweasel/8.0 +Mozilla/5.0 (X11; Linux amd64) AppleWebKit/534.36 (KHTML, like Gecko) Chrome/13.0.766.0 Safari/534.36 +Mozilla/5.0 (X11; Linux amd64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1 +Mozilla/5.0 (X11; Linux armv6l; rv:10.0.5) Gecko/20100101 Firefox/10.0.5 Iceweasel/10.0.5 +Mozilla/5.0 (X11; Linux armv6l; rv:10.0.6) Gecko/20100101 Firefox/10.0.6 Iceweasel/10.0.6 +Mozilla/5.0 (X11; Linux i386; U) Opera 7.60 [en-GB] +Mozilla/5.0 (X11; Linux i686 on x86_64; rv:10.0.6) Gecko/20100101 Firefox/10.0.6 Iceweasel/10.0.6 +Mozilla/5.0 (X11; Linux i686 on x86_64; rv:5.0) Gecko/20100101 Firefox/3.6.17 Firefox/3.6.17 +Mozilla/5.0 (X11; Linux i686 on x86_64; rv:5.0a2) Gecko/20110524 Firefox/5.0a2 +Mozilla/5.0 (X11; Linux i686 on x86_64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2 Iceweasel/6.0.2 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.23 (KHTML, like Gecko) Chrome/11.0.686.3 Safari/534.23 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.14 Safari/534.24 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.2 Chrome/11.0.700.2 Safari/534.24 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.702.0 Chrome/12.0.702.0 Safari/534.24 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.91 Chromium/12.0.742.91 Safari/534.30 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Iron/12.0.750.0 Chrome/12.0.750.0 Safari/534.30 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Slackware/Chrome/12.0.742.100 Safari/534.30 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/10.04 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/11.04 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.33 (KHTML, like Gecko) Ubuntu/9.10 Chromium/13.0.752.0 Chrome/13.0.752.0 Safari/534.33 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.35 (KHTML, like Gecko) Ubuntu/10.10 Chromium/13.0.764.0 Chrome/13.0.764.0 Safari/534.35 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.803.0 Safari/535.1 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Iron/13.0.800.0 Chrome/13.0.800.0 Safari/535.1 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/10.04 Chromium/14.0.804.0 Chrome/14.0.804.0 Safari/535.1 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/10.04 Chromium/14.0.808.0 Chrome/14.0.808.0 Safari/535.1 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/10.04 Chromium/14.0.813.0 Chrome/14.0.813.0 Safari/535.1 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/11.04 Chromium/14.0.803.0 Chrome/14.0.803.0 Safari/535.1 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/11.04 Chromium/14.0.814.0 Chrome/14.0.814.0 Safari/535.1 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/11.04 Chromium/14.0.825.0 Chrome/14.0.825.0 Safari/535.1 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.65 Safari/535.11 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.0 Chrome/17.0.1000.0 Safari/535.11 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/17.0.963.65 Chrome/17.0.963.65 Safari/535.11 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.2 (KHTML, like Gecko) Ubuntu/11.10 Chromium/15.0.874.120 Chrome/15.0.874.120 Safari/535.2 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.21 (KHTML, like Gecko) Chrome/19.0.1041.0 Safari/535.21 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.1 Iron/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.0 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (X11; Linux i686; Debian Testing; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 Iceweasel/7.0.1 +Mozilla/5.0 (X11; Linux i686; U) Opera 7.54 [en] +Mozilla/5.0 (X11; Linux i686; U; en) Opera 8.52 +Mozilla/5.0 (X11; Linux i686; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 +Mozilla/5.0 (X11; Linux i686; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 Opera 9.23 +Mozilla/5.0 (X11; Linux i686; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.51 +Mozilla/5.0 (X11; Linux i686; U; pl; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 +Mozilla/5.0 (X11; Linux i686; U; rv:1.7) Gecko/0 Kazehakase/0.4.3 +Mozilla/5.0 (X11; Linux i686; U;) AppleWebKit/146.1 (KHTML, like Gecko) Kazehakase0.4.5 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/0 Kazehakase/0.3.1 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/0 Kazehakase/0.3.5 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/0 Kazehakase/0.3.8 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/0 Kazehakase/0.3.9 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/0 Kazehakase/0.4.3 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/0 Kazehakase/0.4.3 Debian/0.4.3-1ubuntu1 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/20050923 Kazehakase/0.2.8 Debian/0.2.8-1ubuntu2 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/20050923 Kazehakase/0.3.9 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/20051128 Kazehakase/0.3.3 Debian/0.3.3-1 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/20060216 Kazehakase/0.4.2 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/20060717 Kazehakase/0.3.8 Debian/0.3.8-2 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070224 Kazehakase/0.3.9 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070304 Kazehakase/0.4.6 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.7 +Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070610 Kazehakase/0.4.7 +Mozilla/5.0 (X11; Linux i686; rv: 5.0) Gecko/20100101 Firefox/5.0 Iceweasel/5.0 +Mozilla/5.0 (X11; Linux i686; rv:1.7.5) Gecko/20041108 Firefox/1.0 +Mozilla/5.0 (X11; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0 Iceweasel/10.0 +Mozilla/5.0 (X11; Linux i686; rv:10.0.6) Gecko/20100101 Firefox/10.0.6 Iceweasel/10.0.6 +Mozilla/5.0 (X11; Linux i686; rv:10.0.7) Gecko/20100101 Firefox/10.0.7 Iceweasel/10.0.7 +Mozilla/5.0 (X11; Linux i686; rv:10.0.7) Gecko/20100101 Iceweasel/10.0.7 +Mozilla/5.0 (X11; Linux i686; rv:13.0) Gecko/20100101 Firefox/13.0.1 Iceweasel/13.0.1 +Mozilla/5.0 (X11; Linux i686; rv:14.0) Gecko/20100101 Firefox/14.0 Iceweasel/14.0 +Mozilla/5.0 (X11; Linux i686; rv:14.0) Gecko/20100101 Firefox/14.0.1 Iceweasel/14.0.1 +Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0 Iceweasel/15.0 +Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1 Iceweasel/15.0.1 +Mozilla/5.0 (X11; Linux i686; rv:2.0) Gecko/20100101 Firefox/3.6 +Mozilla/5.0 (X11; Linux i686; rv:2.0) Gecko/20110322 Firefox/4.0 Iceweasel/4.0 +Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20110518 Firefox/4.0.1 +Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20110608 Firefox/4.0.1 SeaMonkey/2.1 +Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20110608 Firefox/4.0.1 SeaMonkey/2.1 Lightning/1.0b4pre +Mozilla/5.0 (X11; Linux i686; rv:2.0b10) Gecko/20100101 Firefox/4.0b10 +Mozilla/5.0 (X11; Linux i686; rv:2.0b12pre) Gecko/20100101 Firefox/4.0b12pre +Mozilla/5.0 (X11; Linux i686; rv:2.0b12pre) Gecko/20110204 Firefox/4.0b12pre +Mozilla/5.0 (X11; Linux i686; rv:2.0b12pre) Gecko/20110204 SeaMonkey/2.1b3pre +Mozilla/5.0 (X11; Linux i686; rv:2.0b13pre) Gecko/20110316 SeaMonkey/2.1b3pre +Mozilla/5.0 (X11; Linux i686; rv:2.0b13pre) Gecko/20110321 SeaMonkey/2.1b3pre +Mozilla/5.0 (X11; Linux i686; rv:2.0b3pre) Gecko/20100731 Firefox/4.0b3pre +Mozilla/5.0 (X11; Linux i686; rv:2.0b7pre) Gecko/20101008 Firefox/4.0b7pre SeaMonkey/2.1b1 +Mozilla/5.0 (X11; Linux i686; rv:2.0b8) Gecko/20101227 IceCat/4.0b8 +Mozilla/5.0 (X11; Linux i686; rv:2.0b9pre) Gecko/20101230 SeaMonkey/2.1b2pre +Mozilla/5.0 (X11; Linux i686; rv:2.0b9pre) Gecko/20101231 SeaMonkey/2.1b2pre +Mozilla/5.0 (X11; Linux i686; rv:2.0b9pre) Gecko/20110101 SeaMonkey/2.1b2pre +Mozilla/5.0 (X11; Linux i686; rv:2.2a1pre) Gecko/20110324 SeaMonkey/2.1b3pre +Mozilla/5.0 (X11; Linux i686; rv:2.2a1pre) Gecko/20110327 SeaMonkey/2.2a1pre +Mozilla/5.0 (X11; Linux i686; rv:2.2a1pre) Gecko/20110407 SeaMonkey/2.2a1pre +Mozilla/5.0 (X11; Linux i686; rv:5.0) Gecko/20100101 Firefox/5.0 Iceweasel/5.0 +Mozilla/5.0 (X11; Linux i686; rv:6.0) Gecko/20100101 Firefox/6.0 +Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/20111106 IceCat/7.0.1 +Mozilla/5.0 (X11; Linux i686; rv:7.0a1) Gecko/20110526 SeaMonkey/2.2a1pre +Mozilla/5.0 (X11; Linux i686; rv:7.0a1) Gecko/20110530 SeaMonkey/2.2a1pre +Mozilla/5.0 (X11; Linux i686; rv:7.0a1) Gecko/20110603 SeaMonkey/2.2a1pre +Mozilla/5.0 (X11; Linux i686; rv:7.0a1) Gecko/20110604 SeaMonkey/2.2a1pre +Mozilla/5.0 (X11; Linux i686; rv:8.0) Gecko/20100101 Firefox/8.0 Iceweasel/8.0 +Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1 Iceweasel/9.0.1 +Mozilla/5.0 (X11; Linux i686; rv:9.0a2) Gecko/20111104 Firefox/9.0a2 Iceweasel/9.0a2 +Mozilla/5.0 (X11; Linux ppc; rv:10.0.7) Gecko/20100101 Firefox/10.0.7 Iceweasel/10.0.7 +Mozilla/5.0 (X11; Linux ppc; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.3 Safari/534.24 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.34 Safari/534.24 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Iron/11.0.700.2 Chrome/11.0.700.2 Safari/534.24 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/10.04 Chromium/11.0.696.0 Chrome/11.0.696.0 Safari/534.24 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.703.0 Chrome/12.0.703.0 Safari/534.24 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Iron/12.0.750.0 Chrome/12.0.750.0 Safari/534.30 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/10.04 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/11.04 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) Arora/0.10.2 Safari/534.34 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.36 (KHTML, like Gecko) Chrome/13.0.766.0 Safari/534.36 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.20 Safari/535.1 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.803.0 Safari/535.1 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.824.0 Safari/535.1 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/10.10 Chromium/14.0.808.0 Chrome/14.0.808.0 Safari/535.1 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/11.04 Chromium/13.0.782.41 Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Iron/17.0.1000.0 Chrome/17.0.1000.0 Safari/535.11 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/10.10 Chromium/17.0.963.65 Chrome/17.0.963.65 Safari/535.11 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.04 Chromium/17.0.963.56 Chrome/17.0.963.56 Safari/535.11 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.04 Chromium/17.0.963.65 Chrome/17.0.963.65 Safari/535.11 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/17.0.963.65 Chrome/17.0.963.65 Safari/535.11 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/11.10 Chromium/18.0.1025.142 Chrome/18.0.1025.142 Safari/535.19 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.2 (KHTML, like Gecko) Ubuntu/11.04 Chromium/15.0.871.0 Chrome/15.0.871.0 Safari/535.2 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.21 (KHTML, like Gecko) Chrome/19.0.1042.0 Safari/535.21 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.7 (KHTML, like Gecko) Iron/16.0.950.0 Chrome/16.0.950.0 Safari/535.7 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1150.1 Iron/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Iron/19.0.1100.0 Chrome/19.0.1100.0 Safari/536.5 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1200.0 Iron/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (X11; Linux x86_64) Gecko Firefox/5.0 +Mozilla/5.0 (X11; Linux x86_64; U; de; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.62 +Mozilla/5.0 (X11; Linux x86_64; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 +Mozilla/5.0 (X11; Linux x86_64; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.60 +Mozilla/5.0 (X11; Linux x86_64; U;) Gecko/20070610 Kazehakase/0.4.7 +Mozilla/5.0 (X11; Linux x86_64; en-US; rv:2.0b2pre) Gecko/20100712 Minefield/4.0b2pre +Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0 Iceweasel/10.0 +Mozilla/5.0 (X11; Linux x86_64; rv:10.0.6) Gecko/20100101 Firefox/10.0.6 Iceweasel/10.0.6 +Mozilla/5.0 (X11; Linux x86_64; rv:10.0.7) Gecko/20100101 Firefox/10.0.7 Iceweasel/10.0.7 +Mozilla/5.0 (X11; Linux x86_64; rv:10.0a2) Gecko/20111118 Firefox/10.0a2 Iceweasel/10.0a2 +Mozilla/5.0 (X11; Linux x86_64; rv:11.0a2) Gecko/20111230 Firefox/11.0a2 Iceweasel/11.0a2 +Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Debian Iceweasel/14.0 +Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20120721 Debian Iceweasel/15.0 +Mozilla/5.0 (X11; Linux x86_64; rv:13.0) Gecko/20100101 Firefox/13.0 Iceweasel/13.0 +Mozilla/5.0 (X11; Linux x86_64; rv:13.0) Gecko/20100101 Firefox/13.0.1 Iceweasel/13.0.1 +Mozilla/5.0 (X11; Linux x86_64; rv:14.0) Gecko/20100101 Firefox/14.0 Iceweasel/14.0 +Mozilla/5.0 (X11; Linux x86_64; rv:14.0) Gecko/20100101 Firefox/14.0.1 Iceweasel/14.0.1 +Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0 Iceweasel/15.0 +Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1 Iceweasel/15.0.1 +Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20120724 Debian Iceweasel/15.0 +Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20110506 Firefox/4.0.1 +Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20110609 Firefox/4.0.1 SeaMonkey/2.1 +Mozilla/5.0 (X11; Linux x86_64; rv:2.0b4) Gecko/20100818 Firefox/4.0b4 +Mozilla/5.0 (X11; Linux x86_64; rv:2.0b9pre) Gecko/20110111 Firefox/4.0b9pre +Mozilla/5.0 (X11; Linux x86_64; rv:2.2a1pre) Gecko/20100101 Firefox/4.2a1pre +Mozilla/5.0 (X11; Linux x86_64; rv:2.2a1pre) Gecko/20110324 Firefox/4.2a1pre +Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0 FirePHP/0.5 +Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0 Firefox/5.0 +Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0 Iceweasel/5.0 +Mozilla/5.0 (X11; Linux x86_64; rv:6.0.1) Gecko/20110831 conkeror/0.9.3 +Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 Iceweasel/7.0.1 Debian +Mozilla/5.0 (X11; Linux x86_64; rv:7.0a1) Gecko/20110602 Firefox/7.0a1 SeaMonkey/2.2a1pre Lightning/1.1a1pre +Mozilla/5.0 (X11; Linux x86_64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1 Iceweasel/9.0.1 +Mozilla/5.0 (X11; Linux) Gecko Firefox/5.0 +Mozilla/5.0 (X11; Linux) KHTML/4.9.1 (like Gecko) Konqueror/4.9 +Mozilla/5.0 (X11; Linux; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Midori/0.4 +Mozilla/5.0 (X11; U; AIX 0048013C4C00; en-US; rv:1.0.1) Gecko/20021009 Netscape/7.0 +Mozilla/5.0 (X11; U; AIX 005A471A4C00; en-US; rv:1.0rc2) Gecko/20020514 +Mozilla/5.0 (X11; U; AIX 5.3; en-US; rv:1.7.12) Gecko/20051025 +Mozilla/5.0 (X11; U; CrOS i686 0.9.128; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.339 +Mozilla/5.0 (X11; U; CrOS i686 0.9.128; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.339 Safari/534.10 +Mozilla/5.0 (X11; U; CrOS i686 0.9.128; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.341 Safari/534.10 +Mozilla/5.0 (X11; U; CrOS i686 0.9.128; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.343 Safari/534.10 +Mozilla/5.0 (X11; U; CrOS i686 0.9.130; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.344 Safari/534.10 +Mozilla/5.0 (X11; U; Darwin i386; en-US; rv:1.9.0.8) Gecko/2009040414 GranParadiso/3.0.8 +Mozilla/5.0 (X11; U; Darwin i386; en-US; rv:1.9.1.4) Gecko/20100311 Shiretoko/3.5.5 +Mozilla/5.0 (X11; U; DragonFly i386; de; rv:1.9.1) Gecko/20090720 Firefox/3.5.1 +Mozilla/5.0 (X11; U; DragonFly i386; de; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 +Mozilla/5.0 (X11; U; Fedora 12 i686; nb-NO; rv:1.9.1.8) Gecko/20100205 SeaMonkey/2.0.3 +Mozilla/5.0 (X11; U; Fedora i686; en-US; rv:1.9.1.19) Gecko/20110429 Fedora/2.0.14-1.fc14 SeaMonkey/2.0.14 +Mozilla/5.0 (X11; U; FreeBSD amd64; en-US; rv:1.8.0.8) Gecko/20061116 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; FreeBSD amd64; en-US; rv:1.8.1.21) Gecko/20090424 SeaMonkey/1.1.16 +Mozilla/5.0 (X11; U; FreeBSD amd64; en-us) AppleWebKit/531.2+ (KHTML, like Gecko) Safari/531.2+ Epiphany/2.30.0 +Mozilla/5.0 (X11; U; FreeBSD i386; de-CH; rv:1.9.2.8) Gecko/20100729 Firefox/3.6.8 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.207.0 Safari/532.0 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.1) Gecko/20021223 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040406 Galeon/1.3.15 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.12) Gecko/20051105 Firefox/1.0.8 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.12) Gecko/20051105 Galeon/1.3.21 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.13) Gecko/20061230 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041114 Firefox/1.0 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.7) Gecko/20050420 Firefox/1.0.3 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.7) Gecko/20060303 Firefox/1.0.3 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7b) Gecko/20040429 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.0.2) Gecko/20060414 Firefox/1.5.0.2 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.0.8) Gecko/20061210 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.1) Gecko/20070322 Epiphany/2.18 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.1.16) Gecko/20080816 Firefox/2.0.0.16 Kazehakase/0.5.4 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.1.2) Gecko/20070303 SeaMonkey/1.1.1 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.1.20) Gecko/20090225 Firefox/2.0.0.20 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.1.20) Gecko/20090413 Firefox/2.0.0.20 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.9.0.10) Gecko/20090624 Firefox/3.5 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.9.1) Gecko/20090703 Firefox/3.5 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.9.1.16) Gecko/20110227 SeaMonkey/2.0.11 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.9.2.9) Gecko/20100913 Firefox/3.6.9 +Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.9a2) Gecko/20080530 Firefox/3.0a2 +Mozilla/5.0 (X11; U; FreeBSD i386; en; rv:1.8.1.12) Gecko/20080213 Epiphany/2.20 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; FreeBSD i386; ja-JP; rv:1.7.2) Gecko/20050330 +Mozilla/5.0 (X11; U; FreeBSD i386; ja-JP; rv:1.9.1.8) Gecko/20100305 Firefox/3.5.8 +Mozilla/5.0 (X11; U; FreeBSD i386; pl; rv:1.8.1.12) Gecko/20080213 Epiphany/2.20 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; FreeBSD i386; ru-RU; rv:1.9.1.3) Gecko/20090913 Firefox/3.5.3 +Mozilla/5.0 (X11; U; FreeBSD i386; rv:1.8.1.12) Gecko/0 Kazehakase/0.4.9 +Mozilla/5.0 (X11; U; FreeBSD x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16 +Mozilla/5.0 (X11; U; FreeBSD; i386; en-US; rv:1.7) Gecko +Mozilla/5.0 (X11; U; FreeBSD; i386; it-IT; rv:1.7) Gecko +Mozilla/5.0 (X11; U; Gentoo Linux x86_64; pl-PL) Gecko Firefox +Mozilla/5.0 (X11; U; Gentoo Linux x86_64; pl-PL; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.0.0) Gecko/20020605 +Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.2) Gecko/20021203 +Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.3) Gecko/20030321 +Mozilla/5.0 (X11; U; HP-UX 9000/785; es-ES; rv:1.0.1) Gecko/20020827 Netscape/7.0 +Mozilla/5.0 (X11; U; IRIX64 IP35; en-US; rv:1.4.3) Gecko/20040909 +Mozilla/5.0 (X11; U; Linux 2.6.34.1-SquidSheep; en-US; rv:1.9.2.3) Gecko/20100402 Iceweasel/3.6.3 (like Firefox/3.6.3) +Mozilla/5.0 (X11; U; Linux AMD64; en-US; rv:1.9.2.3) Gecko/20100403 Ubuntu/10.10 (maverick) Firefox/3.6.3 +Mozilla/5.0 (X11; U; Linux Gentoo i686; pl; rv:1.8.0.8) Gecko/20061219 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux Gentoo; pl-PL; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; Linux MIPS32 1074Kf CPS QuadCore; en-US; rv:1.9.2.13) Gecko/20110103 Fedora/3.6.13-1.fc14 Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux amd64) Iron/20.0.1150.1 Chrome/20.0.1150.1 Safari/536.11 +Mozilla/5.0 (X11; U; Linux amd64) Iron/21.0.1200.0 Chrome/21.0.1200.0 Safari/537.1 +Mozilla/5.0 (X11; U; Linux amd64; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; Linux amd64; en-US; rv:5.0) Gecko/20110619 Firefox/5.0 +Mozilla/5.0 (X11; U; Linux amd64; rv:5.0) Gecko/20100101 Firefox/5.0 (Debian) +Mozilla/5.0 (X11; U; Linux armv7l; en-GB; rv:1.9.2.3pre) Gecko/20100723 Firefox/3.6.11 +Mozilla/5.0 (X11; U; Linux armv7l; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16 +Mozilla/5.0 (X11; U; Linux armv7l; en-US; rv:1.9.0.1) Gecko/2009010915 Minefield/3.0.1 +Mozilla/5.0 (X11; U; Linux armv7l; en-US; rv:1.9.2.14) Gecko/20110224 Firefox/3.6.14 MB860/Version.0.43.3.MB860.AmericaMovil.en.MX +Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.1) Gecko/20020826 +Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; Linux i586; de-AT; rv:1.4) Gecko/20030908 Debian/1.4-4 +Mozilla/5.0 (X11; U; Linux i586; de; rv:5.0) Gecko/20100101 Firefox/5.0 +Mozilla/5.0 (X11; U; Linux i586; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2 +Mozilla/5.0 (X11; U; Linux i586; en-US) Gecko/20030908 Epiphany/0.9.2 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:0.9.9) Gecko/20020513 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.0) Gecko/20020623 Debian/1.0.0-0.woody.1 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0rc3) Gecko/20020523 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.1) Gecko/20020826 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.2) Gecko/20050223 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.2.1) Gecko/20021204 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.2b) Gecko/20021016 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.3) Gecko/20030312 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040413 Epiphany/1.2.6 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040924 Epiphany/1.4.4 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040924 Epiphany/1.4.4 (Ubuntu) +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.8.0.11) Gecko/20070217 Iceape/1.0.8 (Debian-1.0.8-4) +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.8.1.2) Gecko/20070227 SeaMonkey/1.1.1 +Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.8.1.9pre) Gecko/20071102 Firefox/2.0.0.9 Navigator/9.0.0.3 +Mozilla/5.0 (X11; U; Linux i586; fr-FR; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.8.0.6) Gecko/20060728 SUSE/1.5.0.6-1.3 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.9.1) Gecko/20090624 Firefox/3.5 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-GB; rv:1.8.1.5) Gecko/20070718 Fedora/2.0.0.5-1.fc7 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-GB; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-GB; rv:1.9.1.3) Gecko/20091010 Iceweasel/3.5.3 (Debian-3.5.3-2) +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-GB; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US) AppleWebKit/530.7 (KHTML, like Gecko) Chrome/2.0.175.0 Safari/530.7 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.196.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.197.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.198.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.198.1 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.2 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.221.8 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US) AppleWebKit/532.3 (KHTML, like Gecko) Iron/4.0.227.0 Chrome/4.0.227.0 Safari/532.3 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US) AppleWebKit/534.12 (KHTML, like Gecko) Chrome/9.0.576.0 Safari/534.12 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.634.0 Safari/534.16 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.7.12) Gecko/20051007 Galeon/1.3.21 (Debian package 1.3.21-8) +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.7.13) Gecko/20060417 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.10) Gecko/20060911 SUSE/1.5.0.10-0.2 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.12) Gecko/20080326 CentOS/1.5.0.12-14.el5.centos Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.5) Gecko/20060726 Red Hat/1.5.0.5-0.el4.1 Firefox/1.5.0.5 pango-text +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.6) Gecko/20060728 SUSE/1.5.0.6-1.2 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.7) Gecko/20060928 (Debian-1.8.0.7-1) Epiphany/2.14 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.8) Gecko/20061025 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.0.9) Gecko/20061219 Fedora/1.5.0.9-1.fc6 Firefox/1.5.0.9 pango-text +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.1) Gecko/20070131 BonEcho/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.10) Gecko/20071015 SUSE/2.0.0.10-0.1 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.10) Gecko/20071015 SUSE/2.0.0.10-0.2 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.10) Gecko/20071115 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.11) Gecko/20080126 Firefox/2.0.0.11 Flock/1.0.8 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.12pre) Gecko/20080103 BonEcho/2.0.0.12pre +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.13) Gecko/20080313 SeaMonkey/1.1.9 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.14) Gecko/20080417 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.16) Gecko/20080702 SeaMonkey/1.1.11 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.16) Gecko/20080716 Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.17) Gecko/20080829 SeaMonkey/1.1.12 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.17) Gecko/20080913 Firefox/2.0.0.17 Flock/1.2.6 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.2) Gecko/20070221 SeaMonkey/1.1.1 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.20) Gecko/20090206 Firefox/2.0.0.20 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.2pre) Gecko/20061023 SUSE/2.0.0.1-0.1 Firefox/2.0.0.2pre +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.5) Gecko/20070718 Fedora/2.0.0.5-1.fc7 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9) Gecko/20070314 GranParadiso/3.0 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.0.16) Gecko/2009122206 Firefox/3.0.16 Flock/2.5.6 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.15) Gecko/20101027 SeaMonkey/2.0.10 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.16) Gecko/20101123 SeaMonkey/2.0.11 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.19) Gecko/20110420 SeaMonkey/2.0.14 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.9) Gecko/20100317 Firefox/3.5.9 Seamonkey/2.0.4 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9a1) Gecko/20060127 Firefox/1.6a1 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9a1) Gecko/20061204 GranParadiso/3.0a1 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9b2) Gecko/2007121016 Firefox/3.0b2 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en; rv:1.8.1) Gecko/20061024 Iceweasel/2.0 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); en; rv:1.8.1) Gecko/20061024 Iceweasel/2.0 (Debian-2.0+dfsg-1) +Mozilla/5.0 (X11; U; Linux i686 (x86_64); fr; rv:1.7.12) Gecko/20051010 Debian/1.7.12-0ubuntu2 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); fr; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); fr; rv:1.8.1.2) Gecko/20070221 SeaMonkey/1.1.1 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); fr; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); nl; rv:1.8.0.6) Gecko/20060728 SUSE/1.5.0.6-1.2 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); ru; rv:1.8.0.3) Gecko/20060425 SUSE/1.5.0.3-7 Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux i686 (x86_64); zh-TW; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686 Gentoo; en-US; rv:1.8.1.13) Gecko/20080413 Firefox/2.0.0.13 (Gentoo Linux) +Mozilla/5.0 (X11; U; Linux i686) Gecko/20030327 Galeon/1.3.4 Debian/1.3.3.20030419-1 +Mozilla/5.0 (X11; U; Linux i686) Gecko/20030430 Galeon/1.3.4 Debian/1.3.4.20030509-1 +Mozilla/5.0 (X11; U; Linux i686; Ubuntu 7.04; de-CH; rv:1.8.1.5) Gecko/20070309 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686; bg; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 +Mozilla/5.0 (X11; U; Linux i686; ca-AD; rv:1.9.0.3) Gecko/2008092816 Iceweasel/3.0.3 (Debian-3.0.3-3) +Mozilla/5.0 (X11; U; Linux i686; ca; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 +Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.7.12) Gecko/20050929 +Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 +Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.8.0.10) Gecko/20070313 Fedora/1.5.0.10-5.fc6 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.8.0.11) Gecko/20070327 Ubuntu/dapper-security Firefox/1.5.0.11 +Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.9.0.16) Gecko/2009121601 Ubuntu/9.04 (jaunty) Firefox/3.0.16 +Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.9.1.6) Gecko/20100107 Fedora/3.5.6-1.fc12 Firefox/3.5.6 +Mozilla/5.0 (X11; U; Linux i686; da-DK; rv:1.7.13) Gecko/20060411 Firefox/1.0.8 SUSE/1.0.8-0.2 +Mozilla/5.0 (X11; U; Linux i686; de) AppleWebKit/523 midori/0.1 +Mozilla/5.0 (X11; U; Linux i686; de) AppleWebKit/523+ (KHTML like Gecko) midori/0.1 +Mozilla/5.0 (X11; U; Linux i686; de) AppleWebKit/523+ midori/0.1 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:0.9.8) Gecko/20020204 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.0.0) Gecko/20020615 Debian/1.0.0-3 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.1) Gecko/20020826 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.1) Gecko/20020913 Debian/1.1-1 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.2) Gecko/20021203 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.2.1) Gecko/20021130 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.2.1) Gecko/20021204 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.2.1) Gecko/20021226 Debian/1.2.1-9 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.2a) Gecko/20020910 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.3) Gecko/20030312 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.3) Gecko/20030327 Debian/1.3-4 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.3) Gecko/20030430 Debian/1.3-5 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.3b) Gecko/20030210 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4) Gecko/20030624 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4) Gecko/20030812 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4) Gecko/20030908 Debian/1.4-4 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.5) Gecko/20031007 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040114 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040114 Epiphany/1.0.7 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040115 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.10) Gecko/20050722 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.10) Gecko/20050727 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.12) Gecko/20050923 Fedora/1.7.12-1.5.1 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.12) Gecko/20060205 Debian/1.7.12-1.1 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.2) Gecko/20040804 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.2) Gecko/20040810 Debian/1.7.2-2 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.2) Gecko/20040906 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4) +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1) +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.7) Gecko/20050415 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8.0.10) Gecko/20070306 SeaMonkey/1.0.8 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8.1.15) Gecko/20080620 Mozilla/4.0 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 Mnenhy/0.7.6.0 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8.1.5) Gecko/20070716 SeaMonkey/1.1.3 +Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8.1.9) Gecko/20071030 SeaMonkey/1.1.6 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:0.9.4) Gecko/20011126 Netscape6/6.2.1 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040207 Firefox/0.8 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.13) Gecko/20060411 Firefox/1.0.8 SUSE/1.0.8-0.2 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.13) Gecko/20060418 Firefox/1.0.8 (Ubuntu package 1.0.8) +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2) +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050322 Firefox/1.0.1 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.8.1.1) Gecko/20061205 Iceweasel/2.0.0.1 (Debian-2.0.0.1+dfsg-1) +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.8.1.21) Gecko/20090322 SeaMonkey/1.1.15 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.8.1.9) Gecko/20071103 Midori/0.0.10 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.9.0.11) Gecko/2009061212 Iceweasel/3.0.9 (Debian-3.0.9-1) +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.9.0.8) Gecko/2009033017 GranParadiso/3.0.8 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.9.1.16) Gecko/20101124 SUSE/2.0.11-2.2 SeaMonkey/2.0.11 +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.9.1.18) Gecko/20110324 Iceweasel/3.5.18 (like Firefox/3.5.18) +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.9.1.9) Gecko/20100501 Iceweasel/3.5.9 (like Firefox/3.5.9) +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.9.1a2pre) Gecko/20080826020557 Minefield/3.1a2pre +Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.9.2.8) Gecko/20100725 Gentoo Firefox/3.6.8 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.0.11) Gecko/20070327 Ubuntu/dapper-security Firefox/1.5.0.11 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.0.12) Gecko/20070719 CentOS/1.5.0.12-3.el5.centos Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.0.3) Gecko/20060425 SUSE/1.5.0.3-7 Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.0.5) Gecko/20060731 Ubuntu/dapper-security Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.0.6) Gecko/20060808 Fedora/1.5.0.6-2.fc5 Firefox/1.5.0.6 pango-text +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.0.8) Gecko/20060911 SUSE/1.5.0.8-0.2 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.0.8) Gecko/20061025 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.0.8) Gecko/20061115 Ubuntu/dapper-security Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.1) Gecko/20061205 Firefox/2.0.0.1 (Debian-2.0.0.1+dfsg-2) +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.1) Gecko/20061205 Iceweasel/2.0.0.1 (Debian-2.0.0.1+dfsg-2) +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.1) Gecko/20061220 Firefox/2.0.0.1 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.10) Gecko/20071126 Ubuntu/7.10 (gutsy) Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.12) Gecko/20080207 Ubuntu/7.10 (gutsy) Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.13) Gecko/20080325 Ubuntu/7.10 (gutsy) Firefox/2.0.0.13 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.14) Gecko/20080410 SUSE/2.0.0.14-0.1 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.14) Gecko/20080418 Ubuntu/7.10 (gutsy) Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.16) Gecko/20080718 Ubuntu/8.04 (hardy) Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.19) Gecko/20081213 SUSE/2.0.0.19-0.1 Firefox/2.0.0.19 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.22pre) Gecko/20090327 Ubuntu/7.10 (gutsy) Firefox/2.0.0.22pre +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.3) Gecko/20070310 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.5) Gecko/20060911 SUSE/2.0.0.5-1.2 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.5) Gecko/20070713 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.10) Gecko/2009042523 Ubuntu/9.04 (jaunty) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.11) Gecko/2009061212 Iceweasel/3.0.12 (Debian-3.0.12-1) +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.11) Gecko/2009062218 Gentoo Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.12) Gecko/2009070811 Ubuntu/9.04 (jaunty) Firefox/3.0.12 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.12) Gecko/2009070812 Ubuntu/8.04 (hardy) Firefox/3.0.12 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.13) Gecko/2009080315 Ubuntu/9.04 (jaunty) Firefox/3.0.13 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.14) Gecko/2009082505 Red Hat/3.0.14-1.el5_4 Firefox/3.0.14 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.14) Gecko/2009090216 Ubuntu/9.04 (jaunty) Firefox/3.0.14 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.18) Gecko/2010020400 SUSE/3.0.18-0.1.1 Firefox/3.0.18 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.18) Gecko/2010021501 Firefox/3.0.18 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.2) Gecko/2008092313 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.9) Gecko/2009041500 SUSE/3.0.9-2.2 Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.9) Gecko/2009042113 Ubuntu/8.04 (hardy) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.9) Gecko/2009042113 Ubuntu/8.10 (intrepid) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.9) Gecko/2009042113 Ubuntu/9.04 (jaunty) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1) Gecko/20090624 Firefox/3.5 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1) Gecko/20090624 Ubuntu/8.04 (hardy) Firefox/3.5 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.1) Gecko/20090714 SUSE/3.5.1-1.1 Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.1) Gecko/20090722 Gentoo Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.10) Gecko/20100504 Lightning/1.0b1 Mnenhy/0.8.2 SeaMonkey/2.0.5 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.19) Gecko/20110420 SeaMonkey/2.0.14 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.19) Gecko/20110430 Iceweasel/3.5.19 (like Firefox/3.5.19) +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.5) Gecko/20091112 Iceweasel/3.5.5 (like Firefox/3.5.5; Debian-3.5.5-1) +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.6) Gecko/20091201 SUSE/3.5.6-1.1.1 Firefox/3.5.6 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 GTB7.0 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.10) Gecko/20100914 SUSE/3.6.10-0.3.1 Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.10) Gecko/20100915 Ubuntu/10.04 (lucid) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.10) Gecko/20100915 Ubuntu/9.10 (karmic) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.12) Gecko/20101027 Fedora/3.6.12-1.fc13 Firefox/3.6.12 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.13) Gecko/20101209 CentOS/3.6-2.el5.centos Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.13) Gecko/20101221 IceCat/3.6.13 (like Firefox/3.6.13) (Zenwalk GNU Linux) +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.15) Gecko/20110330 CentOS/3.6-1.el5.centos Firefox/3.6.15 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.18) Gecko/20110615 Ubuntu/10.10 (maverick) Firefox/3.6.18 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.18) Gecko/20110628 Ubuntu/10.10 (maverick) Firefox/3.6.18 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.21) Gecko/20110830 Ubuntu/10.10 (maverick) Firefox/3.6.21 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9b5) Gecko/2008041514 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9b5) Gecko/2008050509 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux i686; en-CA; rv:1.8.0.10) Gecko/20070223 Fedora/1.5.0.10-1.fc5 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-CA; rv:1.9.0.3) Gecko/2008092921 IceCat/3.0.3-g1 +Mozilla/5.0 (X11; U; Linux i686; en-CA; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux i686; en-GB) AppleWebKit/533.3 (KHTML, like Gecko) rekonq Safari/533.3 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040113 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.13) Gecko/20060418 Fedora/1.0.8-1.1.fc4 Firefox/1.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.6) Gecko/20050405 Firefox/1.0 (Ubuntu package 1.0.2) +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.7) Gecko/20050414 Firefox/1.0.3 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.0.12) Gecko/20070718 Fedora/1.5.0.12-4.fc6 Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.0.5) Gecko/20060731 Ubuntu/dapper-security Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.0.5) Gecko/20060805 CentOS/1.0.3-0.el4.1.centos4 SeaMonkey/1.0.3 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.0.6) Gecko/20060808 Fedora/1.5.0.6-2.fc5 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.0.8) Gecko/20061025 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1) Gecko/20061031 BonEcho/2.0 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.1) Gecko/20061208 Firefox/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.1) Gecko/20070110 BonEcho/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.10) Gecko/20071126 Ubuntu/7.10 (gutsy) Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.12) Gecko/20080203 SUSE/2.0.0.12-2.1 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.16) Gecko/20080715 Ubuntu/7.10 (gutsy) Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.17) Gecko/20080827 Iceweasel/2.0.0.17 (Debian-2.0.0.17-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.17) Gecko/20080925 Fedora/1.1.12-1.fc9 SeaMonkey/1.1.12 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.2pre) Gecko/20061023 Firefox/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-2) +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.6) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.8) Gecko/20071008 Ubuntu/7.10 (gutsy) Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.8) Gecko/20071022 Ubuntu/7.10 (gutsy) Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.9) Gecko/20071105 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1b1) Gecko/20060710 Firefox/2.0b1 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.10) Gecko/2009042513 Ubuntu/8.04 (hardy) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.10) Gecko/2009042523 Ubuntu/8.10 (intrepid) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.11) Gecko/2009060214 Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.11) Gecko/2009060308 Ubuntu/9.04 (jaunty) Firefox/3.0.11 GTB5 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.11) Gecko/2009060309 Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.13) Gecko/2009080316 Ubuntu/8.04 (hardy) Firefox/3.0.13 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.18) Gecko/2010021501 Ubuntu/9.04 (jaunty) Firefox/3.0.18 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.19) Gecko/2010040118 Ubuntu/8.10 (intrepid) Firefox/3.0.19 GTB7.1 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.2) Gecko/2008092313 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.10 (intrepid) Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.7) Gecko/2009030814 Iceweasel Firefox/3.0.7 (Debian-3.0.7-1) +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.7) Gecko/2009030814 Iceweasel/3.0.9 (Debian-3.0.9-1) +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.1.11) Gecko/20100819 Iceweasel/3.5.11 (like Firefox/3.5.11) +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.1.15) Gecko/20101027 Fedora/3.5.15-1.fc12 Firefox/3.5.15 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.1.17) Gecko/20110123 SeaMonkey/2.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 GTB5 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 GTB6 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.2.11) Gecko/20101013 Ubuntu/10.10 (maverick) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.10 (maverick) Firefox/3.6.12 GTB7.1 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.2.18) Gecko/20110628 Ubuntu/10.10 (maverick) Firefox/3.6.18 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9b5) Gecko/2008041514 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:2.0) Gecko/20110404 Fedora/16-dev Firefox/4.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/531.4 (KHTML, like Gecko) Chrome/3.0.194.0 Safari/531.4 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.1 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.196.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.197.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.197.11 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.198.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.198.1 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.202.2 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.2 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.204.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.205.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.206.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.206.1 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.207.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.209.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.2 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.212.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Iron/3.0.197.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.212.0 Safari/532.1 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.213.0 Safari/532.1 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.213.1 Safari/532.1 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.221.0 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.221.8 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.2 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.3 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.4 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.5 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.6 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.8 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.1 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.2 Safari/532.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.3 (KHTML, like Gecko) Iron/4.0.227.0 Chrome/4.0.227.0 Safari/532 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.3 (KHTML, like Gecko) Iron/4.0.227.0 Chrome/4.0.227.0 Safari/532.3 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.4 (KHTML, like Gecko) Chrome/4.0.237.0 Safari/532.4 Debian +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Chrome/4.0.277.0 Safari/532.8 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Iron/4.0.275.2 Chrome/4.0.275.2 Safari/532.8 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.358.0 Safari/533.3 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.366.2 Safari/533.4 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.416.0 Safari/534.1 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.1 SUSE/6.0.428.0 (KHTML, like Gecko) Chrome/6.0.428.0 Safari/534.1 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.551.0 Safari/534.10 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.12 (KHTML, like Gecko) Chrome/9.0.579.0 Safari/534.12 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.44 Safari/534.13 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.84 Safari/534.13 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Ubuntu/9.10 Chromium/9.0.592.0 Chrome/9.0.592.0 Safari/534.13 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.15 (KHTML, like Gecko) Chrome/10.0.612.1 Safari/534.15 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.15 (KHTML, like Gecko) Ubuntu/10.04 Chromium/10.0.612.3 Chrome/10.0.612.3 Safari/534.15 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.15 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.611.0 Chrome/10.0.611.0 Safari/534.15 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.15 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.613.0 Chrome/10.0.613.0 Safari/534.15 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.134 Safari/534.16 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Iron/10.0.650.0 Chrome/10.0.650.0 Safari/534.16 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.0 Chrome/10.0.648.0 Safari/534.16 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.2 (KHTML, like Gecko) Chrome/6.0.453.1 Safari/534.2 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.457.0 Safari/534.3 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.458.0 Safari/534.3 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.460.0 Safari/534.3 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.462.0 Safari/534.3 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Iron/6.0.475.1 Chrome/6.0.475.1 Safari/534.3 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.24 Safari/534.7 +Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Iron/7.0.520.0 Chrome/7.0.520.0 Safari/534.7 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.2) Gecko/20010809 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.2.1) Gecko/20010901 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.3) Gecko/20010801 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20010923 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20011022 Netscape6/6.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20011126 Netscape6/6.2.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.6) Gecko/20011202 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.8) Gecko/20020204 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020313 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020408 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020423 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020513 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020529 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020605 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020612 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020623 Debian/1.0.0-0.woody.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20021004 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020826 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020830 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020903 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020912 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020918 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020919 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021003 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021110 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021122 Debian/1.0.1-2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021203 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030716 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0rc2) Gecko/20020510 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0rc2) Gecko/20020513 Netscape/7.0b1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0rc3) Gecko/20020529 Debian/1.0rc3-1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020826 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020828 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020829 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020913 Debian/1.1-1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1a) Gecko/20020610 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1b) Gecko/20020722 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2) Gecko/20021126 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2) Gecko/20021202 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021130 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021203 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021204 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021208 Debian/1.2.1-2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021213 Debian/1.2.1-2.bunk +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030113 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030225 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030409 Debian/1.2.1-9woody2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030427 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2a) Gecko/20020910 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2b) Gecko/20021014 Phoenix/0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2b) Gecko/20021016 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2b) Gecko/20021029 Phoenix/0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030312 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030313 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030314 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030320 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030326 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030327 Debian/1.3-4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030401 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030413 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030523 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3.1) Gecko/20030425 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3.1) Gecko/20030428 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3b) Gecko/20021213 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3b) Gecko/20030125 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3b) Gecko/20030210 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030723 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030818 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030821 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030827 Debian/1.4-3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030828 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030908 Debian/1.4-4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030908 Epiphany/0.9.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031114 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20040406 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040220 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4a) Gecko/20030401 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4a) Gecko/20030425 Mozilla Firebird/0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030505 Mozilla Firebird/0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030607 Mozilla Firebird/0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030630 Mozilla Firebird/0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031007 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040114 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040114 Epiphany/1.0.7 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040225 Firefox/0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Debian/1.6-5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Galeon/1.3.16 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040614 Firefox/0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040514 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040630 Firefox/0.9.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040802 Firefox/0.9.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040917 Firefox/0.9.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050715 Firefox/1.0.6 SUSE/1.0.6-16 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050716 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050719 Red Hat/1.0.6-1.4.1 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050720 Fedora/1.0.6-1.1.fc3 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050720 Fedora/1.0.6-1.1.fc4.k12ltsp.4.4.0 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050721 Firefox/1.0.6 (Ubuntu package 1.0.6) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050811 Fedora/1.7.10-1.2.1.legacy +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050811 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050815 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050911 Firefox/1.0.6 (Debian package 1.0.6-5) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050918 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050920 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050921 Firefox/1.5.0.2 Mandriva/1.0.6-15mdk (2006.0) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20051106 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20051111 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20060410 Firefox/1.0.8 Mandriva/1.0.6-16.5.20060mdk (2006.0) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20060927 Firefox/1.0.4 (Debian package 1.0.4-2sarge12) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20061113 Firefox/1.0.4 (Debian package 1.0.4-2sarge13) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20070116 Firefox/1.0.4 (Debian package 1.0.4-2sarge15) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20070530 Firefox/1.0.4 (Debian package 1.0.4-2sarge17) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.11) Gecko/20050729 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20050920 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20050921 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20050921 Red Hat/1.7.12-1.1.3.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20050923 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20050926 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20050929 Galeon/1.3.21 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20051007 Debian/1.7.12-1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20051007 Galeon/2.0.0 (Debian package 2.0.0-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20051010 Debian/1.7.12-0ubuntu2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20051010 Epiphany/1.8.2 (Ubuntu) (Ubuntu package 1.0.7) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20051010 Firefox/1.0.4 (Ubuntu package 1.0.7) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20051013 Debian/1.7.12-1ubuntu1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20051203 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20051215 Epiphany/1.8.4.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20060122 Galeon/2.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20060202 Fedora/1.7.12-1.5.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20060205 Debian/1.7.12-1.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20060208 Epiphany/1.8.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20060216 Debian/1.7.12-1.1ubuntu2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20060607 Debian/1.7.12-1.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.13) Gecko/20060411 Firefox/1.0.8 SUSE/1.0.8-0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.13) Gecko/20060413 Red Hat/1.0.8-1.4.1 Firefox/1.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.13) Gecko/20060417 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.13) Gecko/20060427 Debian/1.7.13-0ubuntu05.04 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.13) Gecko/20060501 Epiphany/2.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.13) Gecko/20060501 Galeon/2.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.13) Gecko/20060717 Debian/1.7.13-0.2ubuntu1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040805 Netscape/7.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040906 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040906 Galeon/1.3.17 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040913 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040924 Epiphany/1.4.4 (Ubuntu) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Epiphany/1.4.7 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Galeon/1.3.18 (Debian package 1.3.18-1.1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041013 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041117 Firefox/1.0 (Debian package 1.0-2.0.0.45.linspire0.4) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041204 Firefox/1.0 (Debian package 1.0.x.2-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041215 Firefox/1.0 Red Hat/1.0-12.EL4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041218 Firefox/1.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041221 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050221 Firefox/1.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050814 Firefox/1.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20060127 Netscape/8.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20070321 Netscape/8.1.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20070321 Netscape/9.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050310 Firefox/1.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050311 Firefox/1.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050319 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050328 Fedora/1.7.6-1.2.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050405 Firefox/1.0 (Ubuntu package 1.0.2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.7) Gecko/20050414 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.7) Gecko/20050420 Debian/1.7.7-2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.7) Gecko/20050421 Firefox/1.0.3 (Debian package 1.0.3-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.7) Gecko/20050427 Red Hat/1.7.7-1.1.3.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050511 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050511 Firefox/1.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050511 Firefox/1.0.4 SUSE/1.0.4-1.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050512 Firefox/1.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050512 Red Hat/1.7.8-1.1.3.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050513 Debian/1.7.8-1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050513 Epiphany/1.4.8 (Debian) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050513 Fedora/1.0.4-1.3.1 Firefox/1.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050513 Firefox/1.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050513 Galeon/1.3.20 (Debian package 1.3.20-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050517 Firefox/1.0.4 (Debian package 1.0.4-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050523 Firefox/1.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050524 Fedora/1.0.4-4 Firefox/1.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050610 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050610 Firefox/1.0.4 (Debian package 1.0.4-3) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050718 Galeon/1.3.20 (Debian package 1.3.20-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050831 Debian/1.7.8-1sarge2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050831 Epiphany/1.4.8 (Debian) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050921 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050927 Debian/1.7.8-1sarge3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050927 Epiphany/1.4.8 (Debian) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.9) Gecko/20050711 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8) Gecko/20051219 SeaMonkey/1.0b +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8) Gecko/20060102 Flock/0.4.11 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8) Gecko/20060110 Debian/1.5.dfsg-4 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8) Gecko/20060111 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8) Gecko/20060118 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8) Gecko/20060119 Debian/1.5.dfsg-4ubuntu3 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8) Gecko/20060130 Ubuntu/1.5.dfsg-4ubuntu6 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8) Gecko/20060301 SeaMonkey/1.1a Mnenhy/0.7.3.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8) Gecko/20060806 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/20060027 (Debian-1.8.0.1-11) Galeon/2.0.1 (Debian package 2.0.1-3) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/20060126 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/20060217 Flock/0.5.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/20060313 Debian/1.5.dfsg+1.5.0.1-4 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/20060313 Fedora/1.5.0.1-9 Firefox/1.5.0.1 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/20060314 Flock/0.5.13.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/20060316 SUSE/1.0-27 SeaMonkey/1.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/20060324 Ubuntu/dapper Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/20060404 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/Debian-1.8.0.1-5 Galeon/2.0.1 (Debian package 2.0.1-3) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20060911 SUSE/1.5.0.10-0.2 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070216 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070221 Red Hat/1.5.0.10-0.1.el4 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070223 CentOS/1.5.0.10-0.1.el4.centos Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070223 Fedora/1.0.8-0.5.1.fc5 SeaMonkey/1.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070226 Fedora/1.5.0.10-1.fc6 Firefox/1.5.0.10 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070226 Red Hat/1.5.0.10-0.1.el4 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070301 SUSE/1.8_seamonkey_1.0.8-0.1 SeaMonkey/1.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070302 Ubuntu/dapper-security Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070306 SeaMonkey/1.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070409 CentOS/1.5.0.10-2.el5.centos Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.10) Gecko/20070510 Fedora/1.5.0.10-6.fc6 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.11) Gecko/20070217 Iceape/1.0.8 (Debian-1.0.8-4) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.11) Gecko/20070501 Firefox/1.5.0.11 Flock/0.7.13.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070510 Iceape/1.0.9 (Debian-1.0.9-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070529 Red Hat/1.5.0.12-0.1.el4 Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070530 Fedora/1.5.0.12-1.fc6 Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070719 CentOS/1.5.0.12-0.3.el4.centos Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20071126 Fedora/1.5.0.12-7.fc6 Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.13pre) Gecko/20070505 (Debian-1.8.0.14~pre071019b-0lenny1) Epiphany/2.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.13pre) Gecko/20070505 (Debian-1.8.0.15~pre080131b-0etch1) Epiphany/2.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.13pre) Gecko/20070505 Iceape/1.0.9 (Debian-1.0.10~pre070720-0etch3) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.13pre) Gecko/20070717 Red Hat/1.0.9-4.el4 SeaMonkey/1.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.13pre) Gecko/20080207 Galeon/2.0.1 (Ubuntu package 2.0.1-1ubuntu2) Firefox/1.5.0.13pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.13pre) Gecko/20080207 Ubuntu/dapper-security Firefox/1.5.0.13pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.14eol) Gecko/20070505 (Debian-1.8.0.15~pre080614d-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.14eol) Gecko/20090422 CentOS/1.0.9-0.37.el3.centos3 SeaMonkey/1.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.14eol) Gecko/20101004 Red Hat/1.0.9-64.el4 SeaMonkey/1.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.2) Gecko Firefox/1.5.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.2) Gecko/20060419 Fedora/1.5.0.2-1.2.fc5 Firefox/1.5.0.2 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.2) Gecko/20060630 Red Hat/1.0.1-0.1.9.EL3 SeaMonkey/1.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.3) Gecko/20060326 Firefox/1.5.0.3 (Debian-1.5.dfsg+1.5.0.3-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.3) Gecko/20060425 SUSE/1.5.0.3-7 Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.3) Gecko/20060504 Fedora/1.5.0.3-1.1.fc5 Firefox/1.5.0.3 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.3) Gecko/20060523 Ubuntu/dapper Epiphany/2.14 Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.3) Gecko/20060523 Ubuntu/dapper Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060406 Firefox/1.5.0.4 (Debian-1.5.dfsg+1.5.0.4-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060508 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060516 SeaMonkey/1.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060527 SUSE/1.5.0.4-1.3 Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Epiphany/2.14 Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060612 Firefox/1.5.0.4 Flock/0.7.0.17.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060613 Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060614 Fedora/1.5.0.4-1.2.fc5 Firefox/1.5.0.4 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060619 SeaMonkey/1.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060627 Galeon/2.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060629 Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060704 Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060711 Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060716 Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060912 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060719 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060731 Firefox/1.5.0.5 Flock/0.7.4.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060731 Ubuntu/dapper-security Epiphany/2.14 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060731 Ubuntu/dapper-security Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060801 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060803 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060806 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060812 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060813 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060820 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.5) Gecko/20060831 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 (Debian-1.5.dfsg+1.5.0.6-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 (Debian-1.5.dfsg+1.5.0.6-4) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060728 SUSE/1.5.0.6-0.1 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060730 SeaMonkey/1.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060802 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060803 Firefox/1.5.0.6 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060803 SeaMonkey/1.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060807 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060808 Fedora/1.5.0.6-2.fc5 Firefox/1.5.0.6 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060905 Fedora/1.5.0.6-10 Firefox/1.5.0.6 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060910 SeaMonkey/1.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060911 Red Hat/1.5.0.7-0.1.el4 Firefox/1.5.0.1 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060914 SeaMonkey/1.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060924 Epiphany/2.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060928 (Debian-1.8.0.7-1) Epiphany/2.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20061014 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20061022 Iceweasel/1.5.0.7-g2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.8) Gecko/20060802 Mandriva/1.5.0.8-1.1mdv2007.0 (2007.0) Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.8) Gecko/20060911 SUSE/1.5.0.8-0.2 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.8) Gecko/20061025 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.8) Gecko/20061105 Red Hat/1.0.6-0.1.el3 SeaMonkey/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.8) Gecko/20061107 Fedora/1.5.0.8-1.fc6 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.8) Gecko/20061110 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.8) Gecko/20061115 Ubuntu/dapper-security Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.8pre) Gecko/20061001 Firefox/1.5.0.8pre (Iceweasel) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20060911 SUSE/1.5.0.9-0.2 Firefox/1.5.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20060911 SUSE/1.5.0.9-3.2 Firefox/1.5.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20061205 (Debian-1.8.0.9-1) Epiphany/2.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20061211 SeaMonkey/1.0.7 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20061215 Red Hat/1.5.0.9-0.1.el4 Firefox/1.5.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20061219 Fedora/1.5.0.9-1.fc6 Firefox/1.5.0.9 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20061219 Iceape/1.0.7 (Debian-1.0.7-3) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20061221 Fedora/1.5.0.9-1.fc5 Firefox/1.5.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20070102 Ubuntu/dapper-security Firefox/1.5.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20070104 Red Hat/1.0.7-0.6.fc5 SeaMonkey/1.0.7 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20070126 Ubuntu/dapper-security Firefox/1.5.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20070316 CentOS/1.5.0.9-10.el5.centos Firefox/1.5.0.9 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061001 Firefox/2.0b (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061003 BonEcho/2.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061024 Iceweasel/2.0 (Debian-2.0+dfsg-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061026 BonEcho/2.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061031 BonEcho/2.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061127 lolifox/0.3.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061129 BonEcho/2.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20060601 Firefox/2.0.0.1 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20061205 Firefox/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20061205 Firefox/2.0.0.1 (Debian-2.0.0.1+dfsg-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20061205 Iceweasel/2.0.0.1 (Debian-2.0.0.1+dfsg-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20061205 Iceweasel/2.0.0.1 (Debian-2.0.0.1+dfsg-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20061205 Mozilla/5.0 (Debian-2.0.0.1+dfsg-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20061208 Firefox/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20061220 Firefox/2.0.0.1 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20070110 Firefox/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20070115 BonEcho/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20070215 BonEcho/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20070217 BonEcho/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20070220 BonEcho/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20070222 BonEcho/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20070224 Firefox/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20060601 Firefox/2.0.0.10 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20061201 Firefox/2.0.0.10 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20071015 SUSE/2.0.0.10-0.2 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20071115 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20071115 Firefox/2.0.0.10 (Debian-2.0.0.10-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20071126 Ubuntu/7.10 (gutsy) Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20071128 Fedora/2.0.0.10-2.fc7 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20071203 Ubuntu/7.10 (gutsy) Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20071213 Fedora/2.0.0.10-3.fc8 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071201 (Debian-1.8.1.11-1) Epiphany/2.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071203 IceCat/2.0.0.11-g1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071204 BonEcho/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071204 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071204 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071206 Firefox/2.0.0.11 Flock/1.0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071217 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20080201 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11pre) Gecko/20071206 Firefox/2.0.0.11 Navigator/9.0.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080129 Firefox/2.0.0.12 (Debian-2.0.0.12-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12 Mnenhy/0.7.5.666 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080201 SeaMonkey/1.1.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080208 Fedora/2.0.0.12-1.fc8 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080208 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080208 Firefox/2.0b2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080208 SeaMonkey/1.1.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080219 Firefox/2.0.0.12 Navigator/9.0.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080304 Firefox/2.0.0.12 Flock/1.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20061201 Firefox/2.0.0.13 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0 Iceweasel/2.0.0.3 (Debian-2.0.0.13-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.3 Iceweasel/2.0.0.13 (Debian-2.0.0.13-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080313 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080313 SeaMonkey/1.1.9 (Ubuntu-1.1.9+nobinonly-0ubuntu1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080316 SUSE/2.0.0.13-0.1 Firefox/2.0.0.13 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080316 SUSE/2.0.0.13-1.1 Firefox/2.0.0.13 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080325 Firefox/2.0.0.13 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080330 Ubuntu/7.10 (gutsy) Firefox/2.0.0.13 (Linux Mint) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080401 BonEcho/2.0.0.13 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20061201 Firefox/2.0.0.14 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080404 Iceweasel/2.0.0.14 (Debian-2.0.0.14-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080404 Iceweasel/2.0.0.14 (Debian-2.0.0.14-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080410 SUSE/2.0.0.14-0.4 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080414 Firefox/2.0.0.14 Flock/1.1.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080416 Fedora/2.0.0.14-1.fc8 Firefox/2.0.0.14 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080417 BonEcho/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080417 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080419 Ubuntu/8.04 (hardy) Firefox/2.0.0.12 MEGAUPLOAD 1.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080423 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080428 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080508 Ubuntu/8.04 (hardy) Firefox/2.0.0.14 (Linux Mint) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080525 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080530 Firefox/2.0.0.14 Flock/1.2.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.15) Gecko/20061201 Firefox/2.0.0.15 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.15) Gecko/20080612 Iceweasel/2.0.0.15 (Debian-2.0.0.15-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.15) Gecko/20080702 Ubuntu/8.04 (hardy) Firefox/2.0.0.15 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080715 Fedora/2.0.0.16-1.fc8 Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080715 Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080715 Ubuntu/7.10 (gutsy) Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080716 (Gentoo) Galeon/2.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080716 (Gentoo) Galeon/2.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080716 Fedora/1.1.11-1.fc8 SeaMonkey/1.1.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080716 Firefox/3.07 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080716 SeaMonkey/1.1.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080718 Ubuntu/8.04 (hardy) Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.16) Gecko/20080722 Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.17) Gecko/20080703 Mandriva/2.0.0.17-1.1mdv2008.1 (2008.1) Firefox/2.0.0.17 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.17) Gecko/20080827 Firefox/2.0.0.10 (Debian-2.0.0.17-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.17) Gecko/20080829 SeaMonkey/1.1.12 (Ubuntu-1.1.12+nobinonly-0ubuntu1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.17) Gecko/20080921 SUSE/2.0.0.17-1.2 Firefox/2.0.0.17 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.17) Gecko/20080922 Ubuntu/7.10 (gutsy) Firefox/2.0.0.17 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.17) Gecko/20080924 Ubuntu/8.04 (hardy) Firefox/2.0.0.17 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.18) Gecko/20080921 SUSE/2.0.0.18-0.1 Firefox/2.0.0.18 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.18) Gecko/20081030 SeaMonkey/1.1.13 (Ubuntu-1.1.13+nobinonly-0ubuntu1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.18) Gecko/20081112 Fedora/2.0.0.18-1.fc8 Firefox/2.0.0.18 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.18) Gecko/20081113 Fedora/1.1.13-1.fc8 SeaMonkey/1.1.13 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.18) Gecko/20081113 SeaMonkey/1.1.13 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.18) Gecko/20081113 Ubuntu/8.04 (hardy) Firefox/2.0.0.18 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081202 Firefox (Debian-2.0.0.19-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081204 Iceape/1.1.14 (Debian-1.1.14-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081213 SUSE/2.0.0.19-0.1 Firefox/2.0.0.19 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081216 Fedora/2.0.0.19-1.fc8 Firefox/2.0.0.19 pango-text +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081216 Galeon/2.0.4 Firefox/2.0.0.19 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081216 SeaMonkey/1.1.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081218 SeaMonkey/1.1.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081221 SeaMonkey/1.1.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081230 Firefox/2.0.0.19 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20061201 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20061201 Firefox/2.0.0.2 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070208 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070208 Iceweasel/2.0.0.2 (Debian-2.0.0.2+dfsg-3) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070220 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070221 SUSE/2.0.0.2-6.1 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070221 SeaMonkey/1.1.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070224 BonEcho/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070225 Firefox/2.0.0.2 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070226 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070302 BonEcho/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070307 Firefox/2.0.0.2 Flock/0.7.99 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070309 SeaMonkey/1.1.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070314 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.2) Gecko/20070317 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.20) Gecko/20081217 Firefox(2.0.0.20) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.21) Gecko/20090322 SeaMonkey/1.1.15 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.22) Gecko/20090605 SeaMonkey/1.1.17 (Ubuntu-1.1.17+nobinonly-0ubuntu1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.22) Gecko/20090624 SeaMonkey/1.1.17 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.22) Gecko/20090708 SeaMonkey/1.1.17 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.22pre) Gecko/20090327 Ubuntu/7.10 (gutsy) Firefox/2.0.0.22pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.22pre) Gecko/20090327 Ubuntu/8.04 (hardy) Firefox/2.0.0.22pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.23) Gecko/20090907 SeaMonkey/1.1.18 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.23) Gecko/20090908 Fedora/1.1.18-1.fc10 SeaMonkey/1.1.18 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.1 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 MEGAUPLOAD 1.0 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20070517 BonEcho/2.0.0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3pre) Gecko/20070307 Firefox/2.0.0.3pre (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20061201 Mozilla/5.0 (Linux Mint) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070508 (Debian-1.8.1.4-2ubuntu5) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070508 (Debian-1.8.1.4-3) Galeon/2.0.2 (Debian package 2.0.2-4) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070508 Iceweasel/2.0.0.4 (Debian-2.0.0.4-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070508 Iceweasel/2.0.0.4 (Debian-2.0.0.4-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070509 Iceape/1.1.2 (Debian-1.1.2-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4 (Kubuntu) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070530 Fedora/2.0.0.4-1.fc7 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070531 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070531 BonEcho/2.0.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070531 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070531 Firefox/2.0.0.4 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20070602 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4pre) Gecko/20070414 BonEcho/2.0.0.4pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4pre) Gecko/20070509 Firefox/2.0.0.4pre (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.5) Gecko/20061201 Firefox/2.0.0.5 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.5) Gecko/20070713 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.5) Gecko/20070718 Fedora/2.0.0.5-1.fc7 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.5) Gecko/20070719 Firefox/2.0.0.5 (Debian-2.0.0.5-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.5) Gecko/20070725 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.5) Gecko/20070728 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.6) Gecko/20070723 Iceweasel/2.0.0.6 (Debian-2.0.0.6-0etch1+lenny1) (.NET CLR 3.5.30729) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.6) Gecko/20070802 SeaMonkey/1.1.4 Mnenhy/0.7.5.666 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.6) Gecko/20070804 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.6) Gecko/20070807 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.6) Gecko/20070831 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.6) Gecko/20070914 Firefox/2.0.0.6 Flock/0.9.1.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.7) Gecko/20070921 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.7) Gecko/20070923 Firefox/2.0.0.7 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.7) Gecko/20071018 BonEcho/2.0.0.7 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.7pre) Gecko/20070815 Firefox/2.0.0.6 Navigator/9.0b3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20061201 Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071004 Firefox/2.0.0.8 (Debian-2.0.0.8-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071004 Iceweasel/2.0.0.8 (Debian-2.0.0.6+2.0.0.8-0etch1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071008 FreeBSD/i386 Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071008 Iceape/1.1.5 (Ubuntu-1.1.5-1ubuntu0.7.10) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071019 Fedora/2.0.0.8-1.fc7 Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071022 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071022 Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071201 Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8pre) Gecko/20071015 Firefox/2.0.0.7 Navigator/9.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/1.5.0.9 (Debian-2.0.0.9-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071025 FreeBSD/i386 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071030 Iceape/1.1.6 (Debian-1.1.6-3) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071103 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071103 Firefox/2.0.0.9 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071105 Fedora/2.0.0.9-1.fc7 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071105 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071113 BonEcho/2.0.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1b2) Gecko/20060821 BonEcho/2.0b2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b5) Gecko/20051006 Firefox/1.4.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b5) Gecko/20051008 Fedora/1.5-0.5.0.beta2 Firefox/1.4.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061920 IceCat/3.0-g1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008062113 Iceweasel/3.0 (Debian-3.0~rc2-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko Kazehakase/0.5.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071523 Firefox/3.0.1 Flock/2.0b2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071910 Minefield/3.0.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008072716 IceCat/3.0.1-g1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008072820 Ubuntu/8.04 (hardy) (Linux Mint) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko Galeon/2.0.6 (Ubuntu 2.0.6-2.1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko Kazehakase/0.5.4 Debian/0.5.4-2.1ubuntu3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042513 Linux Mint/5 (Elyssa) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042523 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042523 Linux Mint/6 (Felicia) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042523 Linux Mint/7 (Gloria) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042523 Ubuntu/8.10 (intrepid) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042708 Fedora/3.0.10-1.fc10 Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042812 Gentoo Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.11) Gecko/2009060308 Linux Mint/7 (Gloria) Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.11) Gecko/2009060310 Linux Mint/6 (Felicia) Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.11) Gecko/2009061212 Iceweasel/3.0.9 (Debian-3.0.9-1) GTB5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.12) Gecko/2009070610 Firefox/3.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.12) Gecko/2009070812 Linux Mint/5 (Elyssa) Firefox/3.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.12) Gecko/2009070818 Firefox/3.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.12) Gecko/2009070818 Ubuntu/8.10 (intrepid) Firefox/3.0.12 FirePHP/0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.13) Gecko/2009080315 Ubuntu/9.04 (jaunty) Firefox/3.0.13 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.14) Gecko/2009090216 Ubuntu/9.04 (jaunty) Firefox/3.0.14 GTB5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.14) Gecko/2009090905 Fedora/3.0.14-1.fc10 Firefox/3.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.14) Gecko/2009091010 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.14) Gecko/2009091010 Firefox/3.0.14 (Debian-3.0.14-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.14) Gecko/20090916 Ubuntu/9.04 (jaunty) Firefox/3.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.17) Gecko/2010010604 Ubuntu/9.04 (jaunty) Firefox/3.0.17 FirePHP/0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.18) Gecko/2010021720 Iceweasel/3.0.9 (Debian-3.0.9-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.19) Gecko/2010072023 Firefox/3.0.6 (Debian-3.0.6-3) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.19) Gecko/2010091807 Firefox/3.0.6 (Debian-3.0.6-3) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1pre) Gecko/2008062222 Firefox/3.0.1pre (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko Fedora/1.9.0.2-1.fc9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008090211 Ubuntu/9.04 (jaunty) Iceweasel/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008091816 Red Hat/3.0.2-3.el5 Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008092000 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008092313 Ubuntu/1.4.0 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008092313 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008092313 Ubuntu/8.04 (hardy) Firefox/3.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008092313 Ubuntu/8.04 (hardy) Firefox/3.1.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008092318 Fedora/3.0.2-1.fc9 Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008092418 CentOS/3.0.2-3.el5.centos Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008092809 Gentoo Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008100722 IceCat/3.0.2-g1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008110715 ASPLinux/3.0.2-3.0.120asp Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008090713 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092816 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092816 Mobile Safari 1.1.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092921 IceCat/3.0.3-g1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008100320 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3pre) Gecko/2008090713 Firefox/3.0.3pre (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3pre) Gecko/2008091304 GranParadiso/3.0.3pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3pre) Gecko/2008092604 GranParadiso/3.0.3pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4) Gecko/2008111318 Ubuntu/8.10 (intrepid) Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4pre) Gecko/2008092704 GranParadiso/3.0.4pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4pre) Gecko/2008101311 Firefox/3.0.4pre (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121622 Linux Mint/6 (Felicia) Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121718 Gentoo Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121914 Ubuntu/8.04 (hardy) Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2009011301 Gentoo Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009012700 SUSE/3.0.6-0.1 Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020409 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020410 Fedora/3.0.6-1.fc10 Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020410 Fedora/3.0.6-1.fc9 Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020518 Ubuntu/9.04 (jaunty) Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020616 Gentoo Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 FirePHP/0.2.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009022111 Gentoo Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009022714 Ubuntu/9.04 (jaunty) Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009030302 Minefield/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.7) Gecko Galeon/2.0.6 (Debian 2.0.6-2.1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.7) Gecko Kazehakase/0.5.4 Debian/0.5.4-2.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.7) Gecko Kazehakase/0.5.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.7) Gecko/2009030719 GranParadiso/3.0.7 FirePHP/0.2.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.7) Gecko/2009032018 Firefox/3.0.4 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.7) Gecko/2009032803 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.7) Gecko/2009032803 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Galeon/2.0.6 (Ubuntu 2.0.6-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko/20090327 Galeon/2.0.7 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko/2009032811 Iceweasel/3.0.7 (Debian-3.0.7-1) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko/2009033017 GranParadiso/3.0.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.9) Gecko/2009040820 Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.9) Gecko/2009041408 Red Hat/3.0.9-1.el5 Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.9) Gecko/2009042113 Linux Mint/6 (Felicia) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.9) Gecko/2009042113 Ubuntu/8.10 (intrepid) Firefox/3.0.9 GTB5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.9) Gecko/2009042210 GranParadiso/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1) Gecko/20090630 Ubuntu/9.04 (jaunty) Shiretoko/3.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1) Gecko/20090701 Linux Mint/7 (Gloria) Shiretoko/3.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1) Gecko/20090701 Ubuntu/9.04 (jaunty) Firefox/3.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1) Gecko/20090701 Ubuntu/9.10 (karmic) Shiretoko/3.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1) Gecko/20090704 Iceweasel/3.5 (Debian-3.5-0) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1 GTB5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.11) Gecko/20100722 SeaMonkey/2.0.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20101123 SeaMonkey/2.0.11 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120421 Firefox/11.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120421 Gecko Firefox/11.0 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.17) Gecko/20110123 SeaMonkey/2.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.17) Gecko/20110303 SeaMonkey/2.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.17) Gecko/20110309 Lightning/1.0b2pre SeaMonkey/2.0.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.18) Gecko/20110320 SeaMonkey/2.0.13 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.19) Gecko/20110429 Gentoo/2.0.14 SeaMonkey/2.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.19) Gecko/20110518 SeaMonkey/2.0.14 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.2) Gecko/20090729 Slackware/13.0 Firefox/3.5.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.2) Gecko/20090803 Ubuntu/9.04 (jaunty) Shiretoko/3.5.2 FirePHP/0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.2pre) Gecko/20090729 Ubuntu/9.04 (jaunty) Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.3) Gecko/20090912 Gentoo Firefox/3.5.3 FirePHP/0.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.3) Gecko/20090919 Firefox/3.5.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.3pre) Gecko/20090730 Ubuntu/9.04 (jaunty) Shiretoko/3.5.2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.3pre) Gecko/20090803 Ubuntu/9.04 (jaunty) Shiretoko/3.5.3pre (.NET CLR 3.5.30729) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.4) Gecko/20091028 Ubuntu/9.10 (karmic) Firefox/3.5.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.4pre) Gecko/20090921 Ubuntu/8.10 (intrepid) Shiretoko/3.5.4pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.4pre) Gecko/20090921 Ubuntu/9.04 (jaunty) Shiretoko/3.5.4pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.5) Gecko/20100309 Ubuntu/9.04 (jaunty) Shiretoko/3.5.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.6) Gecko/20100118 Gentoo Firefox/3.5.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100315 Ubuntu/9.10 (karmic) Firefox/3.5.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100318 Mandriva/2.0.4-69.1mib2010.0 SeaMonkey/2.0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9 GTB7.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100501 Iceweasel/3.5.6 (like Firefox/3.5.6; Debian-3.5.6-2) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100501 Iceweasel/3.5.8 (like Firefox/3.5.8) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b1pre) Gecko/20080916020338 Minefield/3.1b1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b1pre) Gecko/20080926001251 SeaMonkey/2.0a2pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b1pre) Gecko/20080930020755 Minefield/3.1b1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b2) Gecko/20090128 Fedora/3.1-0.4.beta2.fc11 Minefield/3.1b2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b3) Gecko/20090407 Firefox/3.1b3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b3pre) Gecko/20081203 Shiretoko/3.1b3pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b3pre) Gecko/20090105 Shiretoko/3.1b3pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b3pre) Gecko/20090106 Shiretoko/3.1b3pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b3pre) Gecko/20090207 Ubuntu/9.04 (jaunty) IceWeasel/3.1b3pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b4pre) Gecko/20090311 Ubuntu/9.04 (jaunty) Shiretoko/3.1b4pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b4pre) Gecko/20090405 SeaMonkey/2.0b1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b4pre) Gecko/20090405 Shiretoko/3.5b4pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 FirePHP/0.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100115 Ubuntu/10.04 (lucid) Firefox/3.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100128 Gentoo Firefox/3.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100206 Namoroka/3.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.1) Gecko/20100122 firefox/3.6.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.10) Gecko/20100915 Ubuntu/9.04 (jaunty) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.10pre) Gecko/20100902 Ubuntu/9.10 (karmic) Firefox/3.6.1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.12) Gecko/20101114 Gentoo Firefox/3.6.12 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.12pre) Gecko/20101010 Ubuntu/10.04 (lucid) Namoroka/3.6.12pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.13) Gecko/20101206 Prism/1.0b3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14pre) Gecko/20110105 Firefox/3.6.14pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 FirePHP/0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.16) Gecko/20110323 Ubuntu/9.10 (karmic) Firefox/3.6.16 FirePHP/0.5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.16pre) Gecko/20110304 Ubuntu/10.10 (maverick) Firefox/3.6.15pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17pre) Gecko/20110322 Ubuntu/10.10 (maverick) Namoroka/3.6.17pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17pre) Gecko/20110401 Ubuntu/10.04 (lucid) Namoroka/3.6.17Pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.18pre) Gecko/20110419 Ubuntu/10.04 (lucid) Namoroka/3.6.18pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.18pre) Gecko/20110419 Ubuntu/10.10 (maverick) Namoroka/3.6.18pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.18pre) Gecko/20110419 Ubuntu/9.10 (karmic) Namoroka/3.6.18pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.18pre) Gecko/20110509 Ubuntu/10.10 (maverick) Namoroka/3.6.18pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.2pre) Gecko/20100129 Ubuntu/9.10 (karmic) Namoroka/3.6.2pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.2pre) Gecko/20100310 Ubuntu/8.10 (intrepid) Namoroka/3.6.2pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.2pre) Gecko/20100312 Ubuntu/9.04 (jaunty) Firefox/3.6 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.2pre) Gecko/20100315 Ubuntu/9.10 (karmic) Namoroka/3.6.2pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100404 Ubuntu/10.04 (lucid) Firefox/3.6.3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3pre) Gecko/20100316 Ubuntu/9.10 (karmic) Namoroka/3.6.3pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.4) Gecko/20100625 Gentoo Firefox/3.6.4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.7) Gecko/20100726 CentOS/3.6-3.el5.centos Firefox/3.6.7 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.8) Gecko/20100727 Firefox/3.6.8 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.9) Gecko/20100827 Red Hat/3.6.9-2.el6 Firefox/3.6.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2a1) Gecko/20090806 Namoroka/3.6a1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2a1pre) Gecko/20090102 Ubuntu/9.04 (jaunty) Minefield/3.2a1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2a1pre) Gecko/20090327 Minefield/3.6a1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2a1pre) Gecko/20090403 Minefield/3.6a1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2a2pre) Gecko/20090825 Namoroka/3.6a2pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2a2pre) Gecko/20090906 Ubuntu/9.04 (jaunty) Namoroka/3.6a2pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2a2pre) Gecko/20090921 Ubuntu/9.04 (jaunty) Namoroka/3.6a2pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.3a1pre) Gecko/20091022 Minefield/3.7a1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.3a4pre) Gecko/20100404 SeaMonkey/2.1a1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.3a5pre) Gecko/20100527 Minefield/3.7a5pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20051215 Firefox/1.6a1 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20060117 Firefox/1.6a1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20060217 Firefox/1.6a1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20060609 Minefield/3.0a1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20060814 Firefox/3.0a1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20060819 Minefield/3.0a1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20061016 Minefield/3.0a1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20061111 Minefield/3.0a1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20061204 GranParadiso/3.0a1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20070308 Minefield/3.0a1 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a2) Gecko/20070221 Minefield/3.0a2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a3) Gecko/20070322 GranParadiso/3.0a3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a3) Gecko/20070328 Minefield/3.0a3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a3pre) Gecko/20070301 Minefield/3.0a3pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a3pre) Gecko/20070330 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a4) Gecko/20070427 GranParadiso/3.0a4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a5) Gecko/20070605 GranParadiso/3.0a5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a8pre) Gecko/2007092004 Minefield/3.0a8pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b2) Gecko/2007121016 Firefox/3.0b2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b2) Gecko/2008011913 Minefield/3.0b2 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b2pre) Gecko/2007112704 Minefield/3.0b2pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b3) Gecko/2008020513 Firefox/3.0b3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b3) Gecko/2008021322 Minefield/3.0b3 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b3pre) Gecko/2008010404 Minefield/3.0b3pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b3pre) Gecko/2008010415 Firefox/3.0b +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b3pre) Gecko/2008020507 Firefox/3.0b3pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b4) Gecko/2008031317 Firefox/3.0b4 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b4pre) Gecko/2008021712 Firefox/3.0b4pre (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b4pre) Gecko/2008021714 Firefox/3.0b4pre (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b4pre) Gecko/2008022304 Minefield/3.0b4pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b5) Gecko/2008042623 Iceweasel/3.0b5 (Debian-3.0~b5-3) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b5) Gecko/2008050509 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9pre) Gecko/2008032621 Fedora/3.0-0.49.cvs20080326.fc9 Minefield/3.0pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9pre) Gecko/2008040318 Firefox/3.0pre (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9pre) Gecko/2008051917 Firefox/3.0pre Flock/2.0a1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9pre) Gecko/2008061501 SeaMonkey/2.0a1pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9pre) Gecko/2008061504 Minefield/3.0pre +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:2.0a1pre) Gecko/2008060602 Minefield/4.0a1pre +Mozilla/5.0 (X11; U; Linux i686; en-ZW; rv:1.8.0.7) Gecko/20061018 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux i686; en-gb) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) epiphany-webkit +Mozilla/5.0 (X11; U; Linux i686; en-us; rv:1.9.0.2) Gecko/2008092313 Ubuntu/9.04 (jaunty) Firefox/3.5 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.0.7) Gecko/20060928 Epiphany/2.14 (Ubuntu) +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.1) Gecko/20070117 Epiphany/2.16 BonEcho/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.10) Gecko/20071213 Epiphany/2.20 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.11) Gecko/20071216 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.12) Gecko/20080208 (Debian-1.8.1.12-2) Epiphany/2.20 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.12) Gecko/20080208 (Debian-1.8.1.12-5) Epiphany/2.20 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.14) Gecko/20080416 Fedora/2.18.3-9.fc7 Epiphany/2.18 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.14) Gecko/20080418 Epiphany/2.20 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.17) Gecko/20080927 Epiphany/2.20 Firefox/2.0.0.17 (Dropline GNOME) +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.19) Gecko/20081216 Epiphany/2.20 Firefox/2.0.0.19 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.2) Gecko/20070220 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.3) Gecko/20061201 Epiphany/2.18 Firefox/2.0.0.3 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.3) Gecko/20070322 Epiphany/2.18 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.3) Gecko/20070403 Epiphany/2.16 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.4) Gecko/20070508 (Debian-1.8.1.4-1) Epiphany/2.18 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.5) Gecko/20070712 (Debian-1.8.1.5-1) Epiphany/2.18 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9) Gecko/20080528 (Gentoo) Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9) Gecko/2008062113 Iceweasel/3.0 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.12) Gecko/20080528 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.14) Gecko/20080528 Epiphany/2.22 (Debian/2.26.3-2) +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.15) Gecko/20080528 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.4) Gecko/20080528 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.5) Gecko/20080528 Fedora/2.24.1-3.fc10 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.6) Gecko/20080528 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.10 (intrepid) Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.7) Gecko/20080528 Epiphany/2.22 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.8) Gecko/20080528 Epiphany/2.22 (Debian/2.24.3-2) +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.8) Gecko/20080528 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.9) Gecko/20080528 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9a4) Gecko/20070427 GranParadiso/3.0a4 +Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9b3) Gecko Epiphany/2.20 +Mozilla/5.0 (X11; U; Linux i686; en_GB; rv:1.9.0.1) Gecko/20080528 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; en_US; rv:1.8.1b1) Gecko/20060813 Firefox/2.0b1 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.2.1) Gecko/20021130 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.8.0.7) Gecko/20060909 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.8.1.11) Gecko/20071204 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.8.1.12) Gecko/20080207 Ubuntu/7.10 (gutsy) Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.8.1.4) Gecko/20070508 Iceweasel/2.0.0.4 (Debian-2.0.0.4-0etch1) +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.8.1.6) Gecko/20070723 Iceweasel/2.0.0.6 (Debian-2.0.0.6-0etch1+lenny1) +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.8.1.6) Gecko/20070803 Firefox/2.0.0.6 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.8.1.6) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.0.4) Gecko/2008111317 Linux Mint/5 (Elyssa) Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.0.4) Gecko/2008111317 Ubuntu/8.04 (hardy) Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.0.7) Gecko/2009032803 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.0.9) Gecko/2009042113 Ubuntu/9.04 (jaunty) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9b5) Gecko/2008041514 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.12) Gecko/20050929 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.0.1) Gecko/20060124 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.0.11) Gecko/20070327 Ubuntu/dapper-security Firefox/1.5.0.11 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.0.7) Gecko/20060830 Firefox/1.5.0.7 (Debian-1.5.dfsg+1.5.0.7-1~bpo.1) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.12) Gecko/20080213 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.13) Gecko/20080311 Iceweasel/2.0.0.13 (Debian-2.0.0.13-0etch1) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.14) Gecko/20080404 Iceweasel/2.0.0.14 (Debian-2.0.0.14-0etch1) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.14) Gecko/20080404 Iceweasel/2.0.0.14 (Debian-2.0.0.14-2) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.14) Gecko/20080419 Ubuntu/8.04 (hardy) Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.18) Gecko/20081030 Iceweasel/2.0.0.18 (Debian-2.0.0.18-0etch1) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.2) Gecko/20060601 Firefox/2.0.0.2 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.2) Gecko/20070220 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.2) Gecko/20070225 Firefox/2.0.0.2 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.4) Gecko/20061201 Firefox/2.0.0.4 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.5) Gecko/20070718 Fedora/2.0.0.5-1.fc7 Firefox/2.0.0.5 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.9) Gecko/20071025 Iceweasel/2.0.0.9 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.8.1.9) Gecko/20071025 Iceweasel/2.0.0.9 (Debian-2.0.0.9-2) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.10) Gecko/2009042513 Linux Mint/5 (Elyssa) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.10) Gecko/2009042523 Ubuntu/9.04 (jaunty) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.11) Gecko/2009060309 Linux Mint/5 (Elyssa) Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.11) Gecko/2009060310 Ubuntu/8.10 (intrepid) Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.11) Gecko/2009061118 Fedora/3.0.11-1.fc9 Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.11) Gecko/2009061212 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.11) Gecko/2009061319 Iceweasel/3.0.11 (Debian-3.0.11-1) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.14) Gecko/2009090216 Firefox/3.0.14 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.16) Gecko/20111108 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.6) Gecko/20091201 SUSE/3.5.6-1.1.1 Firefox/3.5.6 GTB6 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.7) Gecko/20091222 SUSE/3.5.7-1.1.1 Firefox/3.5.7 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.9) Gecko/20100317 SUSE/3.5.9-0.1 Firefox/3.5.9 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.2.13) Gecko/20101206 Ubuntu/9.10 (karmic) Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.2.17pre) Gecko/20110404 Ubuntu/10.10 (Maverick) Namoroka/3.6.17pre +Mozilla/5.0 (X11; U; Linux i686; eu; rv:1.9.0.6) Gecko/2009012700 SUSE/3.0.6-0.1.2 Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; fa; rv:1.8.1.4) Gecko/20100527 Firefox/3.6.4 +Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.9.0.11) Gecko/2009060308 Ubuntu/9.04 (jaunty) Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.9.0.13) Gecko/2009080315 Linux Mint/6 (Felicia) Firefox/3.0.13 +Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.9.0.5) Gecko/2008121622 Ubuntu/8.10 (intrepid) Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.9.0.9) Gecko/2009042113 Ubuntu/9.04 (jaunty) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:0.9.4) Gecko/20011126 Netscape6/6.2.1 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.0.0) Gecko/20020623 Debian/1.0.0-0.woody.1 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.0.1) Gecko/20020823 Netscape/7.0 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.5) Gecko/20031007 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.10) Gecko/20050716 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.10) Gecko/20050925 Firefox/1.0.4 (Debian package 1.0.4-2sarge5) +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.3) Gecko/20040913 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.8) Gecko/20050511 Firefox/1.0.4 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8) Gecko/20051111 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8.0.8) Gecko/20061029 SeaMonkey/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8.1.6) Gecko/20080208 Ubuntu/7.10 (gutsy) Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.9.0.5) Gecko/2008123017 Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.9.0.7) Gecko/2009030719 GranParadiso/3.0.7 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.9.1) Gecko/20090624 Ubuntu/9.04 (jaunty) Firefox/3.5 +Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux i686; fr-be; rv:1.9.0.8) Gecko/2009073022 Ubuntu/9.04 (jaunty) Firefox/3.0.13 +Mozilla/5.0 (X11; U; Linux i686; fr-fr) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori/1.19 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.10) Gecko/20050721 Firefox/1.0.6 (Ubuntu package 1.0.6) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.10) Gecko/20050925 Firefox/1.0.4 (Debian package 1.0.4-2sarge5) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.12) Gecko/20050922 Fedora/1.0.7-1.1.fc4 Firefox/1.0.7 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.12) Gecko/20050922 Firefox/1.0.7 (Debian package 1.0.7-1) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.12) Gecko/20051010 Firefox/1.0.7 (Ubuntu package 1.0.7) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.2) Gecko/20040804 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.8) Gecko/20050524 Fedora/1.0.4-4 Firefox/1.0.4 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8) Gecko/20051111 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8) Gecko/20060110 Debian/1.5.dfsg-4 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.0.1) Gecko/20060124 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.0.10) Gecko/20070223 Fedora/1.5.0.10-1.fc5 Firefox/1.5.0.10 pango-text +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.0.5) Gecko/20060731 Ubuntu/dapper-security Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.0.7) Gecko/20060909 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.0.7) Gecko/20060921 Ubuntu/dapper-security Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.0.8) Gecko/20061213 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1) Gecko/20060916 Firefox/2.0b2 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1) Gecko/20060918 Firefox/2.0b2 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.1) Gecko/20060601 Firefox/2.0.0.1 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.12) Gecko/20080208 Fedora/2.0.0.12-1.fc8 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.13) Gecko/20080311 Iceweasel/2.0.0.13 (Debian-2.0.0.13-1) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.16) Gecko/20080702 Iceweasel/2.0.0.16 (Debian-2.0.0.16-0etch1) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.19) Gecko/20081216 Ubuntu/7.10 (gutsy) Firefox/2.0.0.19 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.2) Gecko/20060601 Firefox/2.0.0.2 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.3) Gecko/20070310 Firefox/2.0.0.3 (Debian-2.0.0.3-2) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-2) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.6) Gecko/20071008 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.8) Gecko/20071022 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.8) Gecko/20071022 Ubuntu/7.10 (gutsy) Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.8.1.8) Gecko/20071030 Fedora/2.0.0.8-2.fc8 Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.1) Gecko/2008070206 Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.10) Gecko/2009042513 Ubuntu/8.04 (hardy) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.10) Gecko/2009042708 Fedora/3.0.10-1.fc10 Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.13) Gecko/2009082121 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.19) Gecko/2010102906 Iceweasel/3.0.6 (Debian-3.0.6-3) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.19) Gecko/2011092908 Iceweasel/3.0.6 (Debian-3.0.6-3) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.2) Gecko/2008092313 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.2) Gecko/2008092318 Fedora/3.0.2-1.fc9 Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.03 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.7) Gecko/2009030422 Ubuntu/8.10 (intrepid) Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.7) Gecko/2009031218 Gentoo Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.9) Gecko/2009042113 Ubuntu/8.04 (hardy) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.0.9) Gecko/2009042113 Ubuntu/9.04 (jaunty) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.1) Gecko/20090624 Firefox/3.5 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.1.16) Gecko/20120714 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.1.3) Gecko/20090913 Firefox/3.5.3 +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.2.17pre) Gecko/20110322 Ubuntu/10.10 (maverick) Namoroka/3.6.17pre +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.2.17pre) Gecko/20110413 Ubuntu/10.04 (lucid) Namoroka/3.6.17pre +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.2.18pre) Gecko/20110419 Ubuntu/10.04 (lucid) Namoroka/3.6.18pre +Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 +Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.3.1) Gecko +Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.7.12) Gecko/20051010 Firefox/1.0.7 (Ubuntu package 1.0.7) +Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.9.0.10) Gecko/2009042718 CentOS/3.0.10-1.el5.centos Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.9.0.7) Gecko/2009030422 Ubuntu/8.10 (intrepid) Firefox/3.0.7 FirePHP/0.2.4 +Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.9.1.9) Gecko/20100330 Fedora/3.5.9-1.fc12 Firefox/3.5.9 +Mozilla/5.0 (X11; U; Linux i686; hu-hu) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux i686; hu; rv:1.7.3) Gecko/20050130 +Mozilla/5.0 (X11; U; Linux i686; hu; rv:1.7.3) Gecko/20050130 Galeon/1.3.19 +Mozilla/5.0 (X11; U; Linux i686; hu; rv:1.8.0.7) Gecko/20060911 SUSE/1.5.0.7-0.1 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux i686; hu; rv:1.8.1.1) Gecko/20061208 Firefox/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; hu; rv:1.8.1.2) Gecko/20070220 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; hu; rv:1.8.1.8) Gecko/20071022 Ubuntu/7.10 (gutsy) Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; hu; rv:1.8b4) Gecko/20050827 Firefox/1.0+ +Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.1) Gecko/20020826 +Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.12) Gecko/20051010 Firefox/1.0.7 (Ubuntu package 1.0.7) +Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.9.0.11) Gecko/2009060308 Linux Mint/7 (Gloria) Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.9.0.2) Gecko/2008092313 Ubuntu/9.04 (jaunty) Firefox/3.5 +Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.9.0.2) Gecko/2008092313 Ubuntu/9.25 (jaunty) Firefox/3.8 +Mozilla/5.0 (X11; U; Linux i686; it-it) AppleWebKit/531.2+ (KHTML, like Gecko) Safari/531.2+ Epiphany/2.30.2 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.8) Gecko/20060113 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.8.0.1) Gecko/20060124 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.8.1.12) Gecko/20080129 Iceweasel/2.0.0.12 (Debian-2.0.0.12-0etch1) +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.8.1.12) Gecko/20080129 Iceweasel/2.0.0.12 (Debian-2.0.0.12-1) +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.8.1.14) Gecko/20080416 Fedora/2.0.0.14-1.fc7 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.8.1.14) Gecko/20080420 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.8.1.3) Gecko/20070406 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.8.1.3) Gecko/20070410 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.8.1.4) Gecko/20060601 Firefox/2.0.0.4 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.8.1.4) Gecko/20070621 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9) Gecko/2008061015 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.0.1) Gecko/2008071618 Iceweasel/3.0.1 (Debian-3.0.1-1) +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.0.11) Gecko/2009061118 Fedora/3.0.11-1.fc10 Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.0.19) Gecko/2010120923 Iceweasel/3.0.6 (Debian-3.0.6-3) +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.0.2) Gecko/2008092313 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.0.4) Gecko/2008111217 Red Hat Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.0.5) Gecko/2008121711 Ubuntu/9.04 (jaunty) Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.0.6) Gecko/2009020409 Iceweasel 3.0.6 (Debian 5.0 +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.1.16) Gecko/20120602 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.2.13) Gecko/20110109 Iceweasel/3.6.13 (like Firefox/3.6.13) +Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.8.1.11) Gecko/20071204 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8 +Mozilla/5.0 (X11; U; Linux i686; ja-jp) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.8.0.10) Gecko/20070510 Fedora/1.5.0.10-6.fc6 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.8.1.11) Gecko/20071128 Firefox/2.0.0.11 (Debian-2.0.0.11-1) +Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.8.1.11) Gecko/20071128 Iceweasel/2.0.0.11 (Debian-2.0.0.11-1) +Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.8.1.6) Gecko/20061201 Firefox/2.0.0.6 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.9.0.5) Gecko/2008121622 Ubuntu/8.10 (intrepid) Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.9.0.7) Gecko/2009032803 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.9.1) Gecko/20090624 Firefox/3.5 (.NET CLR 3.5.30729) +Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.9.1.6) Gecko/20091216 Shiretoko/3.5.6 +Mozilla/5.0 (X11; U; Linux i686; ko-KR; rv:1.8.0.7) Gecko/20060913 Fedora/1.5.0.7-1.fc5 Firefox/1.5.0.7 pango-text +Mozilla/5.0 (X11; U; Linux i686; ko-KR; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux i686; ko-KR; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.10 (maverick) Firefox/3.6.12 +Mozilla/5.0 (X11; U; Linux i686; ko-KR; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3 +Mozilla/5.0 (X11; U; Linux i686; lt-LT; rv:1.6) Gecko/20051114 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; lt; rv:1.6) Gecko/20051114 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; nb-NO; rv:1.8.1.3) Gecko/20070310 Firefox/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux i686; nb-NO; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux i686; nb-NO; rv:1.9.1.10) Gecko/20100623 Fedora/2.0.5-1.fc12 Fedora SeaMonkey/2.0.3 +Mozilla/5.0 (X11; U; Linux i686; nb-NO; rv:1.9.1.16) Gecko/20110420 SeaMonkey/2.0.14 +Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.8.1.9) Gecko/20071105 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.9.0.19) Gecko/20090720 Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.9.1b4) Gecko/20090423 Firefox/3.5b4 +Mozilla/5.0 (X11; U; Linux i686; nl-nl) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.0.12) Gecko/20070601 Ubuntu/dapper-security Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.1.1) Gecko/20070311 Firefox/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.1.3) Gecko/20060601 Firefox/2.0.0.3 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.1b2) Gecko/20060821 BonEcho/2.0b2 (Debian-1.99+2.0b2+dfsg-1) +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9) Gecko/2008061015 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.0.11) Gecko/2009060308 Ubuntu/9.04 (jaunty) Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.0.11) Gecko/2009060309 Ubuntu/8.04 (hardy) Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.0.11) Gecko/2009061212 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.0.4) Gecko/2008111317 Ubuntu/8.04 (hardy) Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9 +Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.2.15) Gecko/20110303 Ubuntu/8.04 (hardy) Firefox/3.6.15 +Mozilla/5.0 (X11; U; Linux i686; pl-PL) AppleWebKit/533.3 (KHTML, like Gecko) rekonq Safari/533.3 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.10) Gecko/20050717 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.10) Gecko/20050730 Firefox/1.0.6 (Debian package 1.0.6-2) +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.12) Gecko/20051010 Firefox/1.0.7 (Ubuntu package 1.0.7) +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.0.1) Gecko/20060130 SeaMonkey/1.0 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.0.1) Gecko/20060313 Fedora/1.5.0.1-9 Firefox/1.5.0.1 pango-text Mnenhy/0.7.3.0 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.0.5) Gecko/20060731 Ubuntu/dapper-security Firefox/1.5.0.5 Mnenhy/0.7.4.666 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.0.7) Gecko/20060914 Firefox/1.5.0.7 (Swiftfox) Mnenhy/0.7.4.666 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.1) Gecko/20061010 Firefox/2.0 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.1.1) Gecko/20061205 Iceweasel/2.0.0.1 (Debian-2.0.0.1+dfsg-1) +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.1.10) Gecko/20071126 Ubuntu/7.10 (gutsy) Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.1.10) Gecko/20071128 Fedora/2.0.0.10-2.fc7 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.1.10) Gecko/20071213 Fedora/2.0.0.10-3.fc8 Firefox/2.0.0.10 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.1.14) Gecko/20080404 Iceweasel/2.0.0.14 (Debian-2.0.0.14-0etch1) +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.1.2) Gecko/20060601 Firefox/2.0.0.2 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.8.1.8) Gecko/20071022 Ubuntu/7.10 (gutsy) Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.1) Gecko/2008071222 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.1) Gecko/2008071719 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.10) Gecko/2009042513 Ubuntu/8.04 (hardy) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.13) Gecko/2009080315 Ubuntu/9.04 (jaunty) Firefox/3.0.13 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.2) Gecko/2008092313 Ubuntu/9.25 (jaunty) Firefox/3.8 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.2) Gecko/20121223 Ubuntu/9.25 (jaunty) Firefox/3.8 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.3) Gecko/2008092700 SUSE/3.0.3-2.2 Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.4) Gecko/20081031100 SUSE/3.0.4-4.6 Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.5) Gecko/2008121300 SUSE/3.0.5-0.1 Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.5) Gecko/2008121622 Slackware/2.6.27-PiP Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.6) Gecko/2009020911 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.10 (intrepid) Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.7) Gecko/2009030422 Kubuntu/8.10 (intrepid) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.7) Gecko/2009030503 Fedora/3.0.7-1.fc10 Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.9) Gecko/2009042113 Ubuntu/8.10 (intrepid) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.2.10) Gecko/20100915 Ubuntu/10.04 (lucid) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.2a1pre) Gecko/20090128 Kubuntu/8.10 (intrepid) Minefield/3.2a1pre +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.2a1pre) Gecko/20090330 Kubuntu/8.10 (intrepid) Minefield/3.2a1pre +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9b4) Gecko/2008030800 SUSE/2.9.94-4.2 Firefox/3.0b4 +Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9b5) Gecko/2008050509 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux i686; pl-pl) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) epiphany-browser +Mozilla/5.0 (X11; U; Linux i686; pl-pl) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux i686; pl-pl) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) midori +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8) Gecko/20051111 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8) Gecko/20051111 Firefox/1.5 Ubuntu +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.1) Gecko/20060124 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.1) Gecko/20060124 Firefox/1.5.0.1 Ubuntu +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.1) Gecko/20060201 Firefox/1.5.0.1 (Swiftfox) Mnenhy/0.7.3.0 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.1) Gecko/20060313 Fedora/1.5.0.1-9 Firefox/1.5.0.1 pango-text Mnenhy/0.7.3.0 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.1) Gecko/20060314 Flock/0.5.13.2 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.4) Gecko/20060527 SUSE/1.5.0.4-1.7 Firefox/1.5.0.4 Mnenhy/0.7.4.0 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.4) Gecko/20060614 Fedora/1.5.0.4-1.2.fc5 Firefox/1.5.0.4 pango-text Mnenhy/0.7.4.0 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.5) Gecko/20060801 Firefox/1.5.0.5 Flock/0.7.4.1 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.7) Gecko/20060914 Firefox/1.5.0.7 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.1) Gecko/20061003 Firefox/2.0 Ubuntu +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.1) Gecko/20061010 Firefox/2.0 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.1) Gecko/20061010 Firefox/2.0 Ubuntu +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.1) Gecko/20061024 Firefox/2.0 (Swiftfox) +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.1) Gecko/20061127 Firefox/2.0 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.1) Gecko/20061127 Firefox/2.0 (Gentoo Linux) +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.1.2) Gecko/20070220 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.1b1) Gecko/20060710 Firefox/2.0b1 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.9.0.6) Gecko/2009011912 Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.9.2a1) Gecko/20090806 Namoroka/3.6a1 (Debian GNU/Linux Sid) +Mozilla/5.0 (X11; U; Linux i686; pt-BR) AppleWebKit/533.3 (KHTML, like Gecko) Navscape/Pre-0.2 Safari/533.3 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.7.10) Gecko/20050717 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.7.12) Gecko/20051010 Firefox/1.0.7 (Ubuntu package 1.0.7) +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.8) Gecko/20051111 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.8.0.3) Gecko/20060523 Ubuntu/dapper Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.8.1.1) Gecko/20061208 Firefox/2.0.0.1 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.8.1.4) Gecko/20070509 SeaMonkey/1.1.2 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.2) Gecko/2008092313 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.4) Gecko/2008111217 Fedora/3.0.4-1.fc10 Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.4) Gecko/2008111317 Ubuntu/8.04 (hardy) Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.2.13) Gecko/20101209 Fedora/3.6.13-1.fc13 Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux i686; pt-PT; rv:1.8.1.11) Gecko/20071204 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; pt-PT; rv:1.9.0.5) Gecko/2008121622 Ubuntu/8.10 (intrepid) Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux i686; pt-PT; rv:1.9.2.3) Gecko/20100402 Iceweasel/3.6 (like Firefox/3.6) GTB7.0 +Mozilla/5.0 (X11; U; Linux i686; pt-PT; rv:1.9.2.3) Gecko/20100402 Iceweasel/3.6.3 (like Firefox/3.6.3) GTB7.0 +Mozilla/5.0 (X11; U; Linux i686; pt-br; rv:1.8.1) Gecko/20061010 Firefox/2.0 Midori/0.2.0 +Mozilla/5.0 (X11; U; Linux i686; pt-pt) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.6) Gecko/20050318 Firefox/1.0.2 +Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.8.1.11) Gecko/20071201 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.9.1.2) Gecko/20090804 Firefox/3.5.2 +Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.9.2a1pre) Gecko/20090405 Ubuntu/9.04 (jaunty) Firefox/3.6a1pre +Mozilla/5.0 (X11; U; Linux i686; ru-ru) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.8.0.7) Gecko/20060921 Ubuntu/dapper-security Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.8.1.11) Gecko/20080131 Firefox/2.0.0.11 Flock/1.0.8 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.8.1.8) Gecko/20071004 Iceweasel/2.0.0.8 (Debian-2.0.0.6+2.0.0.8-0etch1) +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.8.1.8) Gecko/20071022 Ubuntu/7.10 (gutsy) Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9) Gecko/2008061812 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.1) Gecko/2008071719 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.5) Gecko/2008120121 Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.5) Gecko/2008121622 Ubuntu/8.10 (intrepid) Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.8) Gecko/2009032711 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.1.3) Gecko/20091020 Ubuntu/10.04 (lucid) Firefox/4.0.1 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.1.3) Gecko/20091020 Ubuntu/9.10 (karmic) Firefox/3.5.3 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8 +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.3a5pre) Gecko/20100526 Firefox/3.7a5pre +Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9b5) Gecko/2008032600 SUSE/2.9.95-25.1 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040913 Firefox/0.10 +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040914 Firefox/0.10 +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040914 Firefox/0.10.1 +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041020 Firefox/0.10.1 +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.8) Gecko/20050831 Debian/1.7.8-1sarge2 +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.8) Gecko/20050831 Epiphany/1.4.8 (Debian) +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.8) Gecko/20050927 Debian/1.7.8-1sarge3 +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.8) Gecko/20060628 Debian/1.7.8-1sarge7.1 +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.8) Gecko/20060628 Epiphany/1.4.8 (Debian) +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.8) Gecko/20060904 Debian/1.7.8-1sarge7.2.2 +Mozilla/5.0 (X11; U; Linux i686; rv:1.7.8) Gecko/20061113 Debian/1.7.8-1sarge8 +Mozilla/5.0 (X11; U; Linux i686; rv:1.8.0.1) Gecko/20060124 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; Linux i686; rv:1.9) Gecko/2008080808 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; rv:1.9) Gecko/20080810020329 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux i686; rv:1.9.1a2pre) Gecko/20080824052448 SeaMonkey/2.0a1pre +Mozilla/5.0 (X11; U; Linux i686; sk; rv:1.8.0.7) Gecko/20060909 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux i686; sk; rv:1.9) Gecko/2008061015 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; sk; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux i686; sk; rv:1.9.1) Gecko/20090630 Fedora/3.5-1.fc11 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.8.0.13pre) Gecko/20071126 Ubuntu/dapper-security Firefox/1.5.0.13pre +Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.8.0.5) Gecko/20060731 Ubuntu/dapper-security Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.8.0.8) Gecko/20061108 Fedora/1.5.0.8-1.fc5 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.8.1.2) Gecko/20061023 SUSE/2.0.0.2-1.1 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux i686; sv-se) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux i686; sv-se) AppleWebKit/531.2+ (KHTML, like Gecko) Safari/531.2+ Epiphany/2.30.6 +Mozilla/5.0 (X11; U; Linux i686; tr-TR; rv:1.8.1) Gecko/20061023 SUSE/2.0-30 Firefox/2.0 +Mozilla/5.0 (X11; U; Linux i686; tr-TR; rv:1.9.0) Gecko/2008061600 SUSE/3.0-1.2 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux i686; tr-TR; rv:1.9.0.10) Gecko/2009042523 Ubuntu/9.04 (jaunty) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux i686; tr-TR; rv:1.9b5) Gecko/2008032600 SUSE/2.9.95-25.1 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.2.1) Gecko/20030225 +Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.4.1) Gecko/20031114 +Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.6) Gecko/20091216 Fedora/3.5.6-1.fc11 Firefox/3.5.6 GTB6 +Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8 +Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.2.8) Gecko/20100722 Ubuntu/10.04 (lucid) Firefox/3.6.8 +Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.8.0.10) Gecko/20070508 Fedora/1.5.0.10-1.fc5 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.8.1) Gecko/20061010 Firefox/2.0 +Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.9.0.13) Gecko/2009080315 Ubuntu/9.04 (jaunty) Firefox/3.0.13 +Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.9.0.5) Gecko/2009012219 Firefox/3.0.5 Flock/2.0.3 +Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.9.0.7) Gecko/2009030422 Ubuntu/8.04 (hardy) Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux i686; zh-cn) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux i686; zh-tw) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux i686;en-US; rv:1.2.1) Gecko/20030225 +Mozilla/5.0 (X11; U; Linux ia64; de; rv:1.9.1.11) Gecko/20100820 Lightning/1.0b2pre SeaMonkey/2.0.6 +Mozilla/5.0 (X11; U; Linux ia64; de; rv:1.9.1.18) Gecko/20110331 Lightning/1.0b2pre SeaMonkey/2.0.13 +Mozilla/5.0 (X11; U; Linux ia64; de; rv:1.9.1.19) Gecko/20110429 Lightning/1.0b2pre SeaMonkey/2.0.14 +Mozilla/5.0 (X11; U; Linux ia64; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux ia64; pl; rv:1.8.0.5) Gecko/20060801 Firefox/1.5.0.5 Flock/0.7.4.1 +Mozilla/5.0 (X11; U; Linux mips; en-US; rv:1.8.1.1) Gecko/20070628 BonEcho/2.0.0.1 +Mozilla/5.0 (X11; U; Linux ppc64; en-US; rv:1.8.1.14) Gecko/20080418 Ubuntu/7.10 (gutsy) Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux ppc; da-DK; rv:1.7.12) Gecko/20051010 Firefox/1.0.7 (Ubuntu package 1.0.7) +Mozilla/5.0 (X11; U; Linux ppc; de; rv:1.8.1.15) Gecko/20080612 Iceweasel/2.0.0.15 (Debian-2.0.0.15-0etch1) +Mozilla/5.0 (X11; U; Linux ppc; en-GB; rv:1.9.0.12) Gecko/2009070818 Ubuntu/8.10 (intrepid) Firefox/3.0.12 +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.0.0) Gecko/20020622 Debian/1.0.0-0.woody.1 +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.1) Gecko/20020927 +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.4) Gecko/20030714 Debian/1.4-2 +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.12) Gecko/20051222 Firefox/1.0.7 +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.8.0.11) Gecko/20070217 Iceape/1.0.8 (Debian-1.0.8-4) +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.8.0.13pre) Gecko/20070505 Iceape/1.0.9 (Debian-1.0.10~pre070720-0etch1) +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.8.0.6) Gecko/20060815 SeaMonkey/1.0.4 +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.8.0.9) Gecko/20061219 Iceape/1.0.7 (Debian-1.0.7-2) +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.8.0.9) Gecko/20061219 Iceape/1.0.7 (Debian-1.0.7-3) +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.8.1.1) Gecko/20061219 BonEcho/2.0.0.1 +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.8.1.13) Gecko/20080313 Iceape/1.1.9 (Debian-1.1.9-5) +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.8.1.3) Gecko/20070310 Firefox/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.9) Gecko/2008062909 Iceweasel/3.0 (Debian-3.0~rc2-2) +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.9.0.1) Gecko/2008072112 Iceweasel/3.0.1 (Debian-3.0.1-1) +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.9.0.1) Gecko/2008072112 Iceweasel/3.0.3 (Debian-3.0.3-2) +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.9.0.4) Gecko/2008111317 Ubuntu/8.04 (hardy) Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.9a8) Gecko/2007100620 GranParadiso/3.0a8 +Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.9a8) Gecko/2007100620 GranParadiso/3.1 +Mozilla/5.0 (X11; U; Linux ppc; en; rv:1.8.1.13) Gecko/20080325 Epiphany/2.20 Firefox/2.0.0.13 +Mozilla/5.0 (X11; U; Linux ppc; fr; rv:1.8.1.13) Gecko/20080313 Iceape/1.1.9 (Debian-1.1.9-5) +Mozilla/5.0 (X11; U; Linux ppc; fr; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.10 (maverick) Firefox/3.6.12 +Mozilla/5.0 (X11; U; Linux sparc64; en-GB; rv:1.8.1.11) Gecko/20071217 Galeon/2.0.3 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux sparc64; en-US; rv:1.8.0.14eol) Gecko/20070505 (Debian-1.8.0.15~pre080323b-0etch2) Epiphany/2.14 +Mozilla/5.0 (X11; U; Linux sparc64; en-US; rv:1.8.1.14) Gecko/20080404 Iceweasel/2.0.0.14 (Debian-2.0.0.14-0etch1) +Mozilla/5.0 (X11; U; Linux sparc64; en-US; rv:1.8.1.17) Gecko/20081108 Firefox/2.0.0.17 +Mozilla/5.0 (X11; U; Linux sparc64; es-PY; rv:5.0) Gecko/20100101 IceCat/5.0 (like Firefox/5.0; Debian-6.0.1) +Mozilla/5.0 (X11; U; Linux x64; en-US; rv:1.8.1.6) Gecko/20070723 Iceweasel/2.0.0.6 (Debian-2.0.0.6-1) +Mozilla/5.0 (X11; U; Linux x64; en-US; rv:1.8.1.7) Gecko/20070914 Iceweasel/2.0.0.7 (Debian-2.0.0.7-1) +Mozilla/5.0 (X11; U; Linux x64_64; es-AR; rv:1.9.0.3) Gecko/2008092515 Ubuntu/8.10 (intrepid) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux x86-64; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0 +Mozilla/5.0 (X11; U; Linux x86; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Epiphany/2.30.6 Safari/534.7 +Mozilla/5.0 (X11; U; Linux x86; en-US; rv:1.8.1.6) Gecko/20061201 Firefox/2.0.0.6 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux x86; es-ES; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux x86; rv:1.9.1.1) Gecko/20090716 Linux Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux x86; sv-SE; rv:1.8.1.12) Gecko/20080207 Ubuntu/8.04 (hardy) Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux x86_64) Gecko/2008072820 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; ca-ad) AppleWebKit/531.2+ (KHTML, like Gecko) Safari/531.2+ Epiphany/2.30.6 +Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ) AppleWebKit/533.3 (KHTML, like Gecko) rekonq Safari/533.3 +Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.0.4) Gecko/2008111318 Ubuntu/8.04 (hardy) Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.1.16) Gecko/20120602 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.1.7) Gecko/20100106 Ubuntu/9.10 (karmic) Firefox/3.5.7 +Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.1.9) Gecko/20100317 SUSE/3.5.9-0.1.1 Firefox/3.5.9 +Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.2.10) Gecko/20100915 Ubuntu/10.04 (lucid) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.2a2pre) Gecko/20090826 Namoroka/3.6a2pre +Mozilla/5.0 (X11; U; Linux x86_64; da-DK; rv:1.9.0.10) Gecko/2009042523 Ubuntu/9.04 (jaunty) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux x86_64; da-DK; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; de-AT; rv:1.7.8) Gecko/20050513 Debian/1.7.8-1 +Mozilla/5.0 (X11; U; Linux x86_64; de-AT; rv:1.8.0.2) Gecko/20060422 Firefox/1.5.0.2 +Mozilla/5.0 (X11; U; Linux x86_64; de-DE; rv:1.8.1.6) Gecko/20070802 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; de-at) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux x86_64; de-de) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.8.1.1) Gecko/20061205 Iceweasel/2.0.0.1 (Debian-2.0.0.1+dfsg-2) +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.8.1.1) Gecko/2006120502 Iceweasel/2.0.0.1 (Debian-2.0.0.1+dfsg-2) +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.8.1.12) Gecko/20080129 Iceweasel/2.0.0.12 (Debian-2.0.0.12-1) +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.8.1.12) Gecko/20080203 SUSE/2.0.0.12-6.1 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.8.1.12) Gecko/20080208 Fedora/2.0.0.12-1.fc8 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9) Gecko/2008061017 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.1) Gecko/2008070400 SUSE/3.0.1-0.1 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.11) Gecko/2009070611 Gentoo Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.16) Gecko/2009121609 Iceweasel/3.0.6 (Debian-3.0.6-3) +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.18) Gecko/2010021501 Ubuntu/9.04 (jaunty) Firefox/3.0.18 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.19) Gecko/2012013123 Iceweasel/3.0.6 (Debian-3.0.6-3) +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.3) Gecko/2008090713 Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.10 (intrepid) Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.03 [de] +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.7) Gecko/2009030620 Gentoo Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.7) Gecko/2009030810 Iceweasel/3.0.7 (Debian-3.0.7-1) +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.7) Gecko/2009031819 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.8) Gecko/2009032917 Gentoo Iceweasel/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.9) Gecko/2009042114 Ubuntu/9.04 (jaunty) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.1.10) Gecko/20100506 SUSE/3.5.10-0.1.1 Firefox/3.5.10 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.1.16) Gecko/20120131 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.1.16) Gecko/20120714 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.1.6) Gecko/20091210 SUSE/2.0.1-1.1.1 SeaMonkey/2.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2) Gecko/20100308 Ubuntu/10.04 (lucid) Firefox/3.6 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10 GTB7.1 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.17) Gecko/20110415 Ubuntu/10.10 (maverick) Namoroka/3.6.17 +Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.3) Gecko/20100401 SUSE/3.6.3-1.1 Firefox/3.6.3 +Mozilla/5.0 (X11; U; Linux x86_64; el-GR; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.8.1.12) Gecko/20080203 SUSE/2.0.0.12-0.1 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.8.1.12) Gecko/20080207 Ubuntu/7.10 (gutsy) Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.8.1b1) Gecko/20060601 BonEcho/2.0b1 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.1) Gecko/2008072820 Firefox/3.0.1 FirePHP/0.1.1.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.10) Gecko/2009042523 Ubuntu/9.04 (jaunty) Firefox/3.0.10 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.11) Gecko/2009060308 Ubuntu/9.04 (jaunty) Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.11) Gecko/2009061208 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.12) Gecko/2009070811 Ubuntu/9.04 (jaunty) Firefox/3.0.12 FirePHP/0.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.2) Gecko/2008092213 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.5) Gecko/2008122010 Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.7) Gecko/2009030503 Fedora/3.0.7-1.fc9 Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.7) Gecko/2009030719 GranParadiso/3.0.7 FirePHP/0.2.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.8) Gecko/2009032712 Ubuntu/8.10 (intrepid) Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.8) Gecko/2009032712 Ubuntu/8.10 (intrepid) Firefox/3.0.8 FirePHP/0.2.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.9) Gecko/2009042113 Ubuntu/8.10 (intrepid) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.0.9) Gecko/2009050519 iceweasel/2.0 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.2.13) Gecko/20101206 Red Hat/3.6-2.el5 Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.2.13) Gecko/20101206 Ubuntu/9.10 (karmic) Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-NZ; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.24 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.203.2 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.204.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.206.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.207.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.208.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.209.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.211.2 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.212.0 Safari/532.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.213.0 Safari/532.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.213.1 Safari/532.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.3 Safari/532.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.221.3 Safari/532.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.221.7 Safari/532.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.1 Safari/532.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.4 Safari/532.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.5 Safari/532.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.6 Safari/532.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.223.2 Safari/532.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Comodo_Dragon/4.1.1.11 Chrome/4.1.249.1042 Safari/532.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Iron/4.0.275.2 Chrome/4.0.275.2 Safari/532.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.308.0 Safari/532.9 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.309.0 Safari/532.9 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.1 (KHTML, like Gecko) Chrome/5.0.335.0 Safari/533.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.3 Safari/533.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Arora/0.11.0 Safari/533.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.353.0 Safari/533.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.354.0 Safari/533.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.358.0 Safari/533.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.368.0 Safari/533.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.417.0 Safari/534.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.427.0 Safari/534.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/7.0.544.0 Safari/534.10 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.200 Safari/534.10 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Ubuntu/10.10 Chromium/8.0.552.237 Chrome/8.0.552.237 Safari/534.10 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.0 Safari/534.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13 v1333515017.9196 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Ubuntu/10.04 Chromium/9.0.595.0 Chrome/9.0.595.0 Safari/534.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Ubuntu/10.10 Chromium/9.0.600.0 Chrome/9.0.600.0 Safari/534.14 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.15 (KHTML, like Gecko) Chrome/10.0.613.0 Safari/534.15 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.11 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.82 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Iron/10.0.650.0 Chrome/10.0.650.0 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Iron/10.0.650.1 Chrome/10.0.650.1 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.642.0 Chrome/10.0.642.0 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.0 Chrome/10.0.648.0 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.127 Chrome/10.0.648.127 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 SUSE/10.0.626.0 (KHTML, like Gecko) Chrome/10.0.626.0 Safari/534.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.458.1 Safari/534.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.470.0 Safari/534.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.514.0 Safari/534.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Epiphany/2.30.6 Safari/534.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Iron/7.0.520.0 Chrome/7.0.520.0 Safari/534.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.20 Safari/535.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/540.0 (KHTML, like Gecko) Ubuntu/10.10 Chrome/8.1.0.0 Safari/540.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/540.0 (KHTML, like Gecko) Ubuntu/10.10 Chrome/9.1.0.0 Safari/540.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/540.0 (KHTML,like Gecko) Chrome/9.1.0.0 Safari/540.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US) Gecko Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.10) Gecko/20050724 Firefox/1.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.12) Gecko/20050922 Fedora/1.0.7-1.1.fc4 Firefox/1.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.12) Gecko/20051010 Firefox/1.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.12) Gecko/20051010 Firefox/1.0.7 (Ubuntu package 1.0.7) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.12) Gecko/20051127 Firefox/1.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.12) Gecko/20051218 Firefox/1.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.12) Gecko/20060202 CentOS/1.0.7-1.4.3.centos4 Firefox/1.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050405 Firefox/1.0 (Ubuntu package 1.0.2) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.8) Gecko/20050511 Firefox/1.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8) Gecko/20051201 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8) Gecko/20051212 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.1) Gecko/20060313 Fedora/1.5.0.1-9 Firefox/1.5.0.1 pango-text +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.10) Gecko/20070409 CentOS/1.5.0.10-2.el5.centos Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.12) Gecko/20070530 Fedora/1.5.0.12-1.fc6 Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.12) Gecko/20070718 Red Hat/1.5.0.12-3.el5 Firefox/1.5.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.12) Gecko/20080419 CentOS/1.5.0.12-0.15.el4.centos Firefox/1.5.0.12 pango-text +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.3) Gecko/20060522 Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.3) Gecko/20060523 Ubuntu/dapper Firefox/1.5.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.5) Gecko/20060731 Ubuntu/dapper-security Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.5) Gecko/20060911 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.7) Gecko/20060911 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.7) Gecko/20060919 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.7) Gecko/20060921 Ubuntu/dapper-security Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.7) Gecko/20060924 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.8) Gecko/20061109 SeaMonkey/1.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.9) Gecko/20070126 Ubuntu/dapper-security Firefox/1.5.0.9 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20060601 Firefox/2.0 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20061023 SUSE/2.0-37 Firefox/2.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20061024 Iceweasel/2.0 (Debian-2.0+dfsg-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20061122 Firefox/2.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20061127 lolifox/0.3.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20061128 Firefox/2.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20061202 Firefox/2.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.1) Gecko/20060601 Firefox/2.0.0.1 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.1) Gecko/20061205 Iceweasel/2.0.0.1 (Debian-2.0.0.1+dfsg-2) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.1) Gecko/20061205 Iceweasel/2.0.0.1 (Debian-2.0.0.1+dfsg-4) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.10) Gecko/20061201 Firefox/2.0.0.10 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.11) Gecko/20070914 Mandriva/2.0.0.11-1.1mdv2008.0 (2008.0) Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.11) Gecko/20071128 Iceweasel/2.0.0.11 (Debian-2.0.0.11-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.11) Gecko/20071201 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080129 Firefox/2.0.0.8 (Debian-2.0.0.12-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080203 SUSE/2.0.0.12-0.1 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080208 BonEcho/2.0.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080209 SeaMonkey/1.1.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080214 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.13) Gecko/20080208 Mandriva/2.0.0.13-1mdv2008.1 (2008.1) Firefox/2.0.0.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.14) Gecko/20080404 Iceweasel/2.0.0.14 (Debian-2.0.0.14-2) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.15) Gecko/20080702 Ubuntu/8.04 (hardy) Firefox/2.0.0.15 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.16) Gecko/20080702 Iceweasel/2.0.0.16 (Debian-2.0.0.16-0etch1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.16) Gecko/20080718 Ubuntu/8.04 (hardy) Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.16) Gecko/20080719 Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.17) Gecko/20080829 SeaMonkey/1.1.12 (Ubuntu-1.1.12+nobinonly-0ubuntu1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.17) Gecko/20080922 SUSE/1.1.12-0.1 SeaMonkey/1.1.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.18) Gecko/20081110 SUSE/1.1.13-1.10 SeaMonkey/1.1.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.18) Gecko/20081112 Fedora/2.0.0.18-1.fc8 Firefox/2.0.0.18 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.18) Gecko/20081113 Ubuntu/8.04 (hardy) Firefox/2.0.0.18 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.19) Gecko/20081202 Iceweasel/2.0.0.19 (Debian-2.0.0.19-0etch1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.19) Gecko/20081204 Iceape/1.1.14 (Debian-1.1.14-1) Mnenhy/0.7.6.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.19) Gecko/20081213 SUSE/2.0.0.19-0.1 Firefox/2.0.0.19 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.2) Gecko/20070224 SeaMonkey/1.1.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.21) Gecko/20090328 Fedora/1.1.15-3.fc10 SeaMonkey/1.1.15 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.21) Gecko/20090413 SeaMonkey/1.1.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.3) Gecko/20070322 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.3) Gecko/20070324 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.3) Gecko/20070415 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.4) Gecko/20061201 Firefox/2.0.0.4 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.4) Gecko/20070529 SUSE/2.0.0.4-6.1 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.4) Gecko/20070604 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.4) Gecko/20070627 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.5) Gecko/20061201 Firefox/2.0.0.5 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.6) Gecko/20061201 Firefox/2.0.0.6 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.6) Gecko/20070723 Iceweasel/2.0.0.6 (Debian-2.0.0.6-0etch1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.6) Gecko/20070812 BonEcho/2.0.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.7) Gecko/20070918 BonEcho/2.0.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.7) Gecko/20070918 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.8) Gecko/20071015 SUSE/2.0.0.8-1.1 Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.8) Gecko/20071022 Ubuntu/7.10 (gutsy) Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.9) Gecko/20071103 BonEcho/2.0.0.9 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9) Gecko/2008061317 (Gentoo) Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9) Gecko/2008062315 (Gentoo) Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9) Gecko/2008062908 Firefox/3.0 (Debian-3.0~rc2-2) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9) Gecko/2008062908 Iceweasel/3.0 (Debian-3.0~rc2-2) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0) Gecko/2008061600 SUSE/3.0-1.2 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.1) Gecko/2008071420 Iceweasel/3.0.1 (Debian-3.0.1-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.1) Gecko/2008071818 GranParadiso/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.1) Gecko/2008072610 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.1) Gecko/2008072610 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.1) Gecko/2008072820 Kubuntu/8.04 (hardy) Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.1) Gecko/2008110312 Gentoo Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.11) Gecko/2009060309 Linux Mint/7 (Gloria) Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.11) Gecko/2009061118 Fedora/3.0.11-1.fc9 Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.11) Gecko/2009061417 Gentoo Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.11) Gecko/2009070612 Gentoo Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.12) Gecko/2009070811 Ubuntu/9.04 (jaunty) Firefox/3.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.12) Gecko/2009070818 Ubuntu/8.10 (intrepid) Firefox/3.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.12) Gecko/2009072220 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.13) Gecko/2009080315 Ubuntu/9.04 (jaunty) Firefox/3.0.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.14) Gecko/2009090217 Ubuntu/9.04 (jaunty) Firefox/3.0.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.14) Gecko/2009090217 Ubuntu/9.04 (jaunty) Firefox/3.0.14 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.16) Gecko/2009121609 Firefox/3.0.6 (Windows NT 5.1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.17) Gecko/2010010604 prism/0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.17) Gecko/2010011010 Mandriva/1.9.0.17-0.1mdv2009.1 (2009.1) Firefox/3.0.17 GTB6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.19) Gecko/2011050707 Iceweasel/3.0.6 (Debian-3.0.6-3) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.2) Gecko/2008092213 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.2) Gecko/2008092313 Ubuntu/8.04 (hardy) Firefox/3.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.2) Gecko/2008092318 Fedora/3.0.2-1.fc9 Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.2) Gecko/2008092418 CentOS/3.0.2-3.el5.centos Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 (Linux Mint) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.3) Gecko/2008092814 (Debian-3.0.1-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.4) Gecko/2008112012 Minefield/3.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.4) Gecko/2008120512 Gentoo Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.5) Gecko/2008121711 Ubuntu/9.04 (jaunty) Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.5) Gecko/2008121806 Gentoo Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.5) Gecko/2008121911 CentOS/3.0.5-1.el5.centos Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.5) Gecko/2008122010 Firefox/2.0.0.3 (Debian-3.0.5-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.5) Gecko/2008122014 CentOS/3.0.5-1.el4.centos Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.5) Gecko/2008122120 Gentoo Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.5) Gecko/2008122406 Gentoo Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.5) Gecko/2008122903 Gentoo Iceweasel/3.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009012700 SUSE/3.0.6-1.4 Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009020407 Firefox/3.0.4 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009020407 Iceweasel/3.0.7 (Debian-3.0.7-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009020519 Ubuntu/9.04 (jaunty) Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.10 (intrepid) Minefield/3.0 MEGAUPLOAD 2.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2010012717 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko Kazehakase/0.5.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009030423 Ubuntu/8.10 (intrepid) Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009030516 Ubuntu/9.04 (jaunty) Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009030516 Ubuntu/9.04 (jaunty) Firefox/3.0.7 GTB5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009030719 Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009030810 Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009031120 Mandriva Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009031120 Mandriva/1.9.0.7-0.1mdv2009.0 (2009.0) Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009031802 Gentoo Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009032319 Gentoo Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009032606 Red Hat/3.0.7-1.el5 Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009032813 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009032600 SUSE/3.0.8-1.1 Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009032600 SUSE/3.0.8-1.1.1 Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009032712 Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009032712 Ubuntu/8.04 (hardy) Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009032712 Ubuntu/8.10 (intrepid) Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009032713 Ubuntu/9.04 (jaunty) Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009032809 Iceweasel/3.0.7 (Debian-3.0.7-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009032908 Gentoo Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009033008 GranParadiso/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009033100 Ubuntu/9.04 (jaunty) Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009033109 Gentoo Iceweasel/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009040312 Gentoo Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1) Gecko/20090630 Firefox/3.5 GTB6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.1) Gecko/20090714 SUSE/3.5.1-1.1 Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.1) Gecko/20090716 Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.1) Gecko/20090716 Linux Mint/7 (Gloria) Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.1) Gecko/20090716 Ubuntu/9.04 (jaunty) Shiretoko/3.5.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.10) Gecko/20100623 Fedora/2.0.5-1.fc12 SeaMonkey/2.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100714 SUSE/2.0.6-2.1 SeaMonkey/2.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100720 Fedora/2.0.6-1.fc12 SeaMonkey/2.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100721 Iceape/2.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100721 SeaMonkey/2.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.13) Gecko/20100916 Iceape/2.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.14) Gecko/20101020 Conkeror/0.9.2 (Debian-0.9.2+git100804-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.15) Gecko/20101027 Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/7.0.540.0 Safari/534.10 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.15) Gecko/20101028 Conkeror/0.9.2 (Debian-0.9.2+git100804-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20101206 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080514 Firefox/2.0.0.14 Flock/1.1.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20101209 Conkeror/0.9.2 (Debian-0.9.2+git100804-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20101227 Iceape/2.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20110107 Iceweasel/3.5.16 (Debian-3.0.5-1) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20110302 Iceape/2.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20111108 Iceweasel/3.5.16 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20120602 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20120714 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.17) Gecko/20110121 SUSE/2.0.12-0.2.1 SeaMonkey/2.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.17) Gecko/20110303 SeaMonkey/2.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.1pre) Gecko/20090701 Ubuntu/9.04 (jaunty) Shiretoko/3.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.2) Gecko/20090803 Firefox/3.5.2 Slackware +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.2) Gecko/20090803 Slackware Firefox/3.5.2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.3) Gecko/20090913 Firefox/3.5.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.3) Gecko/20090914 Slackware/13.0_stable Firefox/3.5.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.3) Gecko/20091010 Iceweasel/3.5.3 (Debian-3.5.3-2) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.5) Gecko/20091114 Gentoo Firefox/3.5.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.6) Gecko/20100117 Gentoo Firefox/3.5.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8) Gecko/20100206 SUSE/2.0.3-0.1.1 SeaMonkey/2.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8) Gecko/20100318 Gentoo Firefox/3.5.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8pre) Gecko/20091227 Ubuntu/9.10 (karmic) Firefox/3.5.5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8pre) Gecko/20100110 Shiretoko/3.5.8pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8pre) Gecko/20100112 Shiretoko/3.5.8pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100317 SUSE/2.0.4-3.2 Lightning/1.0b1 SeaMonkey/2.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100502 Iceape/2.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9pre) Gecko/20100212 SeaMonkey/2.0.4pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1a2pre) Gecko/2008080205 Minefield/3.1a2pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b1pre) Gecko/20080929020931 Minefield/3.1b1pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b2pre) Gecko/20081115 Minefield/3.1b2pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3) Gecko/20090312 Firefox/3.1b3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3) Gecko/20090327 Fedora/3.1-0.11.beta3.fc11 Firefox/3.1b3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3) Gecko/20090327 GNU/Linux/x86_64 Firefox/3.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3pre) Gecko/20081222 Shiretoko/3.1b3pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3pre) Gecko/20081223 Shiretoko/3.1b3pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3pre) Gecko/20090109 Shiretoko/3.1b3pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3pre) Gecko/20090302 SeaMonkey/2.0b1pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b4pre) Gecko/20090401 Ubuntu/9.04 (jaunty) Shiretoko/3.5b4pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b4pre) Gecko/20090404 Shiretoko/3.5b4pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b5pre) Gecko/20090424 Shiretoko/3.5b5pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2) Gecko/20100130 Gentoo Firefox/3.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2) Gecko/20100222 Ubuntu/10.04 (lucid) Firefox/3.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2) Gecko/20100305 Gentoo Firefox/3.5.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10 GTB7.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.10) Gecko/20100928 Namoroka/3.6.10 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.10pre) Gecko/20100826 Ubuntu/9.04 (jaunty) Namoroka/3.6.10pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.12) Gecko/20101102 Firefox/3.6.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.12) Gecko/20101102 Gentoo Firefox/3.6.12 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.12pre) Gecko/20101011 Ubuntu/10.04 (lucid) Namoroka/3.6.12pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101206 Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101206 Red Hat/3.6-3.el4 Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101214 IceCat/3.6.13 (like Firefox/3.6.13) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101219 Gentoo Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101223 Gentoo Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14pre) Gecko/20110111 Ubuntu/8.04 (hardy) Namoroka/3.6.14pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15pre) Gecko/20110130 Ubuntu/10.10 (maverick) Namoroka/3.6.15pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18pre) Gecko/20110419 Ubuntu/10.10 (maverick) Namoroka/3.6.18pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18pre) Gecko/20110515 Ubuntu/10.04 (lucid) Namoroka/3.6.18pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18pre) Gecko/20110515 Ubuntu/9.10 (karmic) Namoroka/3.6.18pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.20) Gecko/20110804 Red Hat/3.6-2.el5 Firefox/3.6.20 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.2pre) Gecko/20100129 Ubuntu/9.10 (karmic) Namoroka/3.6.2pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.2pre) Gecko/20100306 Namoroka/3.6.2pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.2pre) Gecko/20100310 Ubuntu/9.10 (karmic) Namoroka/3.6.2pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.3) Gecko/20100402 Namoroka/3.6.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.3) Gecko/20100524 Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.3pre) Gecko/20100324 Ubuntu/9.04 (jaunty) Namoroka/3.6.3pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.4) Gecko/20100614 Ubuntu/10.04 (lucid) Firefox/3.6.4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.5pre) Gecko/20100526 Namoroka/3.6.5pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.5pre) Gecko/20100526 Ubuntu/10.04 (lucid) Namoroka/3.6.5pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 (.NET CLR 3.5.30729) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 GTB7.0 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 GTB7.1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.7) Gecko/20100723 Fedora/3.6.7-1.fc13 Firefox/3.6.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.7) Gecko/20100809 Fedora/3.6.7-1.fc14 Firefox/3.6.7 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100723 SUSE/3.6.8-0.1.1 Firefox/3.6.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100804 Gentoo Firefox/3.6.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100805 Namoroka/3.6.8 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.9) Gecko/20100915 Gentoo Firefox/3.6.9 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a1pre) Gecko/20081205 Minefield/3.2a1pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a1pre) Gecko/20090331 Minefield/3.6a1pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a1pre) Gecko/20090405 Firefox/3.6a1pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a1pre) Gecko/20090417 Minefield/3.6a1pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a1pre) Gecko/20090418 Minefield/3.6a1pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a1pre) Gecko/20090428 Firefox/3.6a1pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a1pre) Gecko/20090501 Minefield/3.6a1pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a1pre) Gecko/20090716 Minefield/3.6a1pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a2pre) Gecko/20090817 Ubuntu/9.04 (jaunty) Namoroka/3.6a2pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a2pre) Gecko/20090824 Ubuntu/9.10 (karmic) Namoroka/3.6a2pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a2pre) Gecko/20090901 Ubuntu/9.10 (karmic) Namoroka/3.6a2pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a2pre) Gecko/20090908 Ubuntu/9.04 (jaunty) Namoroka/3.6a2pre GTB5 (.NET CLR 3.5.30729) +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.3a4pre) Gecko/20100318 Minefield/3.7a4pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9a1) Gecko/20060112 Firefox/1.6a1 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9b2) Gecko/2007122607 Minefield/3.0b2 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9b3pre) Gecko/2008011321 Firefox/3.0b3pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9b3pre) Gecko/2008020509 Firefox/3.0b3pre +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9b4) Gecko/2008031318 Firefox/3.0b4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9b4) Gecko/2008040813 Firefox/3.0b4 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9b5) Gecko/2008040514 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9b5) Gecko/2008041816 Fedora/3.0-0.55.beta5.fc9 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9pre) Gecko/2008042312 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9pre) Gecko/2008042312 Minefield/3.0pre +Mozilla/5.0 (X11; U; Linux x86_64; en-ca) AppleWebKit/531.2+ (KHTML, like Gecko) Version/5.0 Safari/531.2+ +Mozilla/5.0 (X11; U; Linux x86_64; en-gb) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux x86_64; en-gb) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) midori +Mozilla/5.0 (X11; U; Linux x86_64; en-us) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux x86_64; en-us) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) midori +Mozilla/5.0 (X11; U; Linux x86_64; en-us) AppleWebKit/531.2+ (KHTML, like Gecko) Version/5.0 Safari/531.2+ +Mozilla/5.0 (X11; U; Linux x86_64; en-us) AppleWebKit/532+ (KHTML, like Gecko) Safari/419.3 Midori/0.1.8 +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.8.1.13) Gecko/20080322 Epiphany/2.22 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.8.1.13) Gecko/20080326 (Debian-1.8.1.13-1) Epiphany/2.20 +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.8.1.14) Gecko/20080616 Fedora/2.20.3-4.fc8 Epiphany/2.20 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.8.1.3) Gecko/20061201 Epiphany/2.18 Firefox/2.0.0.3 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.8.1.4) Gecko/20061201 Epiphany/2.18 Firefox/2.0.0.4 (Ubuntu-feisty) +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.8.1.4) Gecko/20070628 Epiphany/2.16 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.9) Gecko/20080528 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.9.0.1) Gecko/20080528 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.9.0.14) Gecko/20080528 Epiphany/2.22 (Debian/2.26.3-2) +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.9.0.14) Gecko/20080528 Ubuntu/9.10 (karmic) Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.9.0.7) Gecko/20080528 Epiphany/2.22 +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.9.0.8) Gecko/20080528 Epiphany/2.22 (Debian/2.24.3-2) +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.9.0.8) Gecko/20080528 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.9.0.8) Gecko/20080528 Fedora/2.24.3-4.fc10 Epiphany/2.22 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; es-AR; rv:1.9) Gecko/2008061015 Ubuntu/8.04 (hardy) Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; es-AR; rv:1.9) Gecko/2008061017 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; es-AR; rv:1.9.0.2) Gecko/2008091920 Firefox/3.0.2 Flock/2.0b3 +Mozilla/5.0 (X11; U; Linux x86_64; es-AR; rv:1.9.0.3) Gecko/2008092515 Ubuntu/8.10 (intrepid) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; es-AR; rv:1.9.0.4) Gecko/2008110510 Red Hat/3.0.4-1.el5_2 Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; es-CL; rv:1.9.1.9) Gecko/20100402 Ubuntu/9.10 (karmic) Firefox/3.5.9 +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.8.1.11) Gecko/20071128 Iceweasel/2.0.0.11 (Debian-2.0.0.11-1) +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.8.1.18) Gecko/20081112 Fedora/1.1.13-1.fc10 SeaMonkey/1.1.13 +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.0.1) Gecko/2008072820 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.0.12) Gecko/2009070811 Ubuntu/9.04 (jaunty) Firefox/3.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.0.12) Gecko/2009072711 CentOS/3.0.12-1.el5.centos Firefox/3.0.12 +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.0.4) Gecko/2008111217 Fedora/3.0.4-1.fc10 Firefox/3.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.0.7) Gecko/2009022800 SUSE/3.0.7-1.4 Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.0.9) Gecko/2009042114 Ubuntu/9.04 (jaunty) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.1.16) Gecko/20120315 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.1.16) Gecko/20120602 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc11 Firefox/3.5.8 +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.2.12) Gecko/20101026 SUSE/3.6.12-0.7.1 Firefox/3.6.12 +Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.2.12) Gecko/20101027 Fedora/3.6.12-1.fc13 Firefox/3.6.12 +Mozilla/5.0 (X11; U; Linux x86_64; es-MX; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.04 (lucid) Firefox/3.6.12 +Mozilla/5.0 (X11; U; Linux x86_64; fi-FI; rv:1.8.1.1) Gecko/20060601 Firefox/2.0.0.1 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux x86_64; fi-FI; rv:1.9.0.14) Gecko/2009090217 Firefox/3.0.14 +Mozilla/5.0 (X11; U; Linux x86_64; fi-FI; rv:1.9.0.8) Gecko/2009032712 Ubuntu/8.10 (intrepid) Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; fr-FR) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.514.0 Safari/534.7 +Mozilla/5.0 (X11; U; Linux x86_64; fr-FR) AppleWebKit/534.7 (KHTML, like Gecko) Epiphany/2.30.6 Safari/534.7 +Mozilla/5.0 (X11; U; Linux x86_64; fr-FR; rv:1.8.1.12) Gecko/20080209 SeaMonkey/1.1.8 +Mozilla/5.0 (X11; U; Linux x86_64; fr-FR; rv:1.8.1.13) Gecko/20080313 SeaMonkey/1.1.9 (Ubuntu-1.1.9+nobinonly-0ubuntu1) +Mozilla/5.0 (X11; U; Linux x86_64; fr-FR; rv:1.8.1.4) Gecko/20070528 SeaMonkey/1.1.2 +Mozilla/5.0 (X11; U; Linux x86_64; fr-FR; rv:1.8.1.6) Gecko/20070803 SeaMonkey/1.1.4 +Mozilla/5.0 (X11; U; Linux x86_64; fr-fr) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux x86_64; fr-fr) AppleWebKit/531.2+ (KHTML, like Gecko) Safari/531.2+ Epiphany/2.29.91 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.6) Gecko/20040115 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.7.12) Gecko/20050922 Fedora/1.0.7-1.1.fc4 Firefox/1.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.7.12) Gecko/20051010 Epiphany/1.8.2 (Ubuntu) (Ubuntu package 1.0.7) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.8) Gecko/20051231 Firefox/1.5 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.8.1.1) Gecko/20060601 Firefox/2.0.0.1 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.8.1.16) Gecko/20080715 Fedora/2.0.0.16-1.fc8 Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-1) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.8.1.3) Gecko/20070310 Iceweasel/2.0.0.3 (Debian-2.0.0.3-2) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.8.1.3) Gecko/20070322 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9) Gecko/2008061017 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.1) Gecko/2008070400 SUSE/3.0.1-1.1 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.1) Gecko/2008071222 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.11) Gecko/2009060309 Ubuntu/9.04 (jaunty) Firefox/3.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.11) Gecko/2009061208 Iceweasel/3.0.9 (Debian-3.0.9-1) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.14) Gecko/2009090216 Ubuntu/8.04 (hardy) Firefox/3.0.14 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.19) Gecko/2010051407 CentOS/3.0.19-1.el5.centos Firefox/3.0.19 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.19) Gecko/2010072022 Iceweasel/3.0.6 (Debian-3.0.6-3) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.2) Gecko/2008092213 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.7) Gecko/2009030423 Ubuntu/8.10 (intrepid) Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.7) Gecko/2009030810 Iceweasel/3.0.7 (Debian-3.0.7-1) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.7) Gecko/2009031819 Iceweasel/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.7) Gecko/2009032813 Iceweasel/3.0.6 Firefox/3.0.6 (Debian-3.0.6-1) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.9) Gecko/2009042114 Ubuntu/9.04 (jaunty) Firefox/3.0.9 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.16) Gecko/20101206 Lightning/1.0b1 SeaMonkey/2.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.16) Gecko/20120511 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.16) Gecko/20120714 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.18) Gecko/20110412 Lightning/1.0b1 SeaMonkey/2.0.13 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.5) Gecko/20091109 Ubuntu/9.10 (karmic) Firefox/3.5.3pre +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.5) Gecko/20091109 Ubuntu/9.10 (karmic) Firefox/3.5.5 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.9) Gecko/20100317 SUSE/3.5.9-0.1.1 Firefox/3.5.9 GTB7.0 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.9) Gecko/20100428 Lightning/1.0b1 SeaMonkey/2.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.2.13) Gecko/20101203 IceCat/3.6.13-g1 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.2.13) Gecko/20101203 Iceweasel/3.6.7 (like Firefox/3.6.13) +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.2.13) Gecko/20110103 Fedora/3.6.13-1.fc14 Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.2.14pre) Gecko/20101224 Ubuntu/10.04 (lucid) Namoroka/3.6.14pre +Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.2.3) Gecko/20100403 Fedora/3.6.3-4.fc13 Firefox/3.6.3 +Mozilla/5.0 (X11; U; Linux x86_64; hu-HU; rv:1.9.1.16) Gecko/20110107 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; hu-HU; rv:1.9.2.18pre) Gecko/20110515 Ubuntu/10.10 (maverick) Namoroka/3.6.18pre +Mozilla/5.0 (X11; U; Linux x86_64; hu-hu) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux x86_64; hu; rv:1.8.1.14) Gecko/20080416 Fedora/2.0.0.14-1.fc7 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; Linux x86_64; it-it) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux x86_64; it-it) AppleWebKit/534.26+ (KHTML, like Gecko) Ubuntu/11.04 Epiphany/2.30.6 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.8.1.2) Gecko/20060601 Firefox/2.0.0.2 (Ubuntu-edgy) +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9) Gecko/2008061017 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.0.1) Gecko/2008071717 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.0.14) Gecko/2009090216 Ubuntu/8.04 (hardy) Firefox/3.0.14 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.0.3) Gecko/2008092813 Gentoo Firefox/3.0.3 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.10 (intrepid) Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.0.8) Gecko/2009032712 Ubuntu/8.10 (intrepid) Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.0.8) Gecko/2009033100 Ubuntu/9.04 (jaunty) Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.15) Gecko/20101027 Fedora/3.5.15-1.fc12 Firefox/3.5.15 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.16) Gecko/20111108 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.16) Gecko/20120602 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.16) Gecko/20120714 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.16) Gecko/20120921 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.9) Gecko/20100330 Fedora/3.5.9-2.fc12 Firefox/3.5.9 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.9) Gecko/20100402 Ubuntu/9.10 (karmic) Firefox/3.5.9 (.NET CLR 3.5.30729) +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13 (.NET CLR 3.5.30729) +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.2.20) Gecko/20110805 Ubuntu/10.04 (lucid) Firefox/3.6.20 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.2.24) Gecko/20111101 SUSE/3.6.24-0.2.1 Firefox/3.6.24 +Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.2.9pre) Gecko/20100818 Ubuntu/10.04 (lucid) Namoroka/3.6.9pre +Mozilla/5.0 (X11; U; Linux x86_64; ja-JP; rv:1.9.2.16) Gecko/20110323 Ubuntu/10.10 (maverick) Firefox/3.6.16 +Mozilla/5.0 (X11; U; Linux x86_64; ja; rv:1.9.1.4) Gecko/20091016 SUSE/3.5.4-1.1.2 Firefox/3.5.4 +Mozilla/5.0 (X11; U; Linux x86_64; ja; rv:1.9.1.8) Gecko/20100324 Iceweasel/3.5.8 (like Firefox/3.5.8) +Mozilla/5.0 (X11; U; Linux x86_64; ko-KR; rv:1.9.0.1) Gecko/2008071717 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; nb-NO; rv:1.9.0.8) Gecko/2009032600 SUSE/3.0.8-1.2 Firefox/3.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; nb-NO; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; nl-NL; rv:1.7.6) Gecko/20050318 Firefox/1.0.2 +Mozilla/5.0 (X11; U; Linux x86_64; nl-nl) AppleWebKit/531.2+ (KHTML, like Gecko) Safari/531.2+ Epiphany/2.29.91 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.8) Gecko/20051128 SUSE/1.5-0.1 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.8.1.13) Gecko/20080325 Ubuntu/7.10 (gutsy) Firefox/2.0.0.13 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.8.1.2pre) Gecko/20061023 SUSE/2.0.0.1-0.1 Firefox/2.0.0.2pre +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9) Gecko/2008060309 Firefox/3.0 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.0.1) Gecko/2008071222 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.0.1) Gecko/2008071222 Ubuntu (hardy) Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.0.1) Gecko/2008071222 Ubuntu/hardy Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.0.2) Gecko/2008092213 Ubuntu/8.04 (hardy) Firefox/3.0.2 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.0.5) Gecko/2008121623 Ubuntu/8.10 (intrepid) Firefox/3.0.5 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13 +Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:2.0) Gecko/20110307 Firefox/4.0 +Mozilla/5.0 (X11; U; Linux x86_64; pl; rv:1.8.1.4) Gecko/20070611 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; Linux x86_64; pl; rv:1.8.1.7) Gecko/20071009 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; pl; rv:1.9.1.2) Gecko/20090911 Slackware Firefox/3.5.2 +Mozilla/5.0 (X11; U; Linux x86_64; pt-BR; rv:1.9.0.14) Gecko/2009090217 Ubuntu/9.04 (jaunty) Firefox/3.0.14 +Mozilla/5.0 (X11; U; Linux x86_64; pt-BR; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux x86_64; pt-BR; rv:1.9b5) Gecko/2008041515 Firefox/3.0b5 +Mozilla/5.0 (X11; U; Linux x86_64; ru-RU) AppleWebKit/533.3 (KHTML, like Gecko) Leechcraft/0.3.95-1-g84cc6b7 Safari/533.3 +Mozilla/5.0 (X11; U; Linux x86_64; ru-RU) AppleWebKit/533.3 (KHTML, like Gecko) Leechcraft/0.4.55-13-g2230d9f Safari/533.3 +Mozilla/5.0 (X11; U; Linux x86_64; ru-RU; rv:1.8.1.16) Gecko/20080716 Fedora/1.1.11-1.fc9 SeaMonkey/1.1.11 +Mozilla/5.0 (X11; U; Linux x86_64; ru-ru) AppleWebKit/525.1+ (KHTML, like Gecko, Safari/525.1+) midori +Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.8.1.14) Gecko/20080404 Iceweasel/2.0.0.14 (Debian-2.0.0.14-2) +Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.8.1.8) Gecko/20071022 Ubuntu/7.10 (gutsy) Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.0.14) Gecko/2009090217 Ubuntu/9.04 (jaunty) Firefox/3.0.14 (.NET CLR 3.5.30729) +Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8 +Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.2.11) Gecko/20101028 CentOS/3.6-2.el5.centos Firefox/3.6.11 +Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.2.18) Gecko/20110628 Ubuntu/10.10 (maverick) Firefox/3.6.18 +Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.2.18pre) Gecko/20110419 Ubuntu/10.04 (lucid) Namoroka/3.6.18pre +Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.3a4pre) Gecko/20100319 Minefield/3.7a4pre +Mozilla/5.0 (X11; U; Linux x86_64; rv:1.9.0.1) Gecko/2008072820 Firefox/3.0.1 +Mozilla/5.0 (X11; U; Linux x86_64; rv:1.9.1.1) Gecko/20090716 Linux Firefox/3.5.1 +Mozilla/5.0 (X11; U; Linux x86_64; sv-SE; rv:1.9.0.7) Gecko/2009030423 Ubuntu/8.10 (intrepid) Firefox/3.0.7 +Mozilla/5.0 (X11; U; Linux x86_64; sv-SE; rv:1.9.1.16) Gecko/20120714 Iceweasel/3.5.16 (like Firefox/3.5.16) +Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10 +Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.9pre) Gecko/20100811 Ubuntu/10.04 (lucid) Namoroka/3.6.9pre GTB7.0 +Mozilla/5.0 (X11; U; Linux x86_64; zh-TW; rv:1.8.1.11) Gecko/20071204 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; Linux x86_64; zh-TW; rv:1.9.0.13) Gecko/2009080315 Ubuntu/9.04 (jaunty) Firefox/3.0.13 +Mozilla/5.0 (X11; U; Linux x86_64; zh-TW; rv:1.9.0.8) Gecko/2009032712 Ubuntu/8.04 (hardy) Firefox/3.0.8 GTB5 +Mozilla/5.0 (X11; U; Linux x86_64; zh-cn) AppleWebKit/531.2+ (KHTML, like Gecko) Safari/531.2+ Epiphany/2.28.0 SUSE/2.28.0-2.4 +Mozilla/5.0 (X11; U; Linux x86_64; zh-cn) AppleWebKit/531.2+ (KHTML, like Gecko) Safari/531.2+ Epiphany/2.28.2 SUSE/2.28.0-2.4 +Mozilla/5.0 (X11; U; Linux; cs-CZ) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 (Change: 333 41e3bc6) +Mozilla/5.0 (X11; U; Linux; de-DE) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 (Change: 0 ) +Mozilla/5.0 (X11; U; Linux; de-DE) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 +Mozilla/5.0 (X11; U; Linux; de-DE) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.8.0 +Mozilla/5.0 (X11; U; Linux; en-GB) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 +Mozilla/5.0 (X11; U; Linux; en-GB) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 (Change: 388 835b3b6) +Mozilla/5.0 (X11; U; Linux; en-GB) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 239 52c6958) +Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 (Change: 0 ) +Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 (Change: 189 35c14e0) +Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 +Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6 +Mozilla/5.0 (X11; U; Linux; en-US; rv:1.8.1.2) Gecko/20070219 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; Linux; en-US; rv:1.9.1.11) Gecko/20100720 Firefox/3.5.11 +Mozilla/5.0 (X11; U; Linux; en-us; rv:1.8.1) Gecko/20061010 Firefox/2.0 Midori/0.1.6 +Mozilla/5.0 (X11; U; Linux; es-CR) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 (Change: 0 ) +Mozilla/5.0 (X11; U; Linux; es-ES) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 (Change: 388 835b3b6) +Mozilla/5.0 (X11; U; Linux; fi-FI) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6 (Change: 754 46b659a) +Mozilla/5.0 (X11; U; Linux; fr-FR) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 +Mozilla/5.0 (X11; U; Linux; fr-fr) AppleWebKit/532+ (KHTML, like Gecko) Safari/419.3 Midori/0.1.7 +Mozilla/5.0 (X11; U; Linux; fr; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 +Mozilla/5.0 (X11; U; Linux; hu-HU) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 +Mozilla/5.0 (X11; U; Linux; hu-HU) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 (Change: 388 835b3b6) +Mozilla/5.0 (X11; U; Linux; i686; en-US; rv:1.6) Gecko Epiphany/1.2.5 +Mozilla/5.0 (X11; U; Linux; i686; en-US; rv:1.6) Gecko Galeon/1.3.14 +Mozilla/5.0 (X11; U; Linux; it-IT) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 +Mozilla/5.0 (X11; U; Linux; it-IT) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.4 (Change: 413 12f13f8) +Mozilla/5.0 (X11; U; Linux; it-IT; rv:1.9.1) Gecko/20080913 Firefox/2.0 Midori/0.1.6 +Mozilla/5.0 (X11; U; Linux; it-it) AppleWebKit/531+ (KHTML, like Gecko) Safari/531.2+ Midori/0.2 +Mozilla/5.0 (X11; U; Linux; nb-NO) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 (Change: 0 ) +Mozilla/5.0 (X11; U; Linux; nb-NO) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.4 +Mozilla/5.0 (X11; U; Linux; pl-PL) AppleWebKit/532.4 (KHTML, like Gecko) Arora/0.10.2 Safari/532.4 +Mozilla/5.0 (X11; U; Linux; pt-PT) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.4 +Mozilla/5.0 (X11; U; Linux; pt-br) AppleWebKit/531+ (KHTML, like Gecko) Safari/531.2+ Midori/0.3 +Mozilla/5.0 (X11; U; Linux; ru-RU) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6 (Change: 802 025a17d) +Mozilla/5.0 (X11; U; Linux; sk-SK) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 (Change: 0 ) +Mozilla/5.0 (X11; U; Mac OSX; it; rv:1.9.0.7) Gecko/2009030422 Firefox/3.0.7 +Mozilla/5.0 (X11; U; NetBSD alpha; en-US; rv:1.8.1.6) Gecko/20080115 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; NetBSD amd64; fr-FR; rv:1.8.0.7) Gecko/20061102 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.8) Gecko/20060104 Firefox/1.5 +Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.8.0.5) Gecko/20060818 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.9.2.12) Gecko/20101030 Firefox/3.6.12 +Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.9.2.3) Gecko/20100403 Namoroka/3.6.3 +Mozilla/5.0 (X11; U; NetBSD sparc64; fr-FR; rv:1.8.1.6) Gecko/20070822 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; OSF1 alpha; en-US; rv:0.9.4.1) Gecko/20020517 Netscape6/6.2.3 +Mozilla/5.0 (X11; U; OpenBSD amd64; en-US; rv:1.8.0.9) Gecko/20070101 Firefox/1.5.0.9 +Mozilla/5.0 (X11; U; OpenBSD amd64; en-US; rv:1.8.1.6) Gecko/20070817 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; OpenBSD amd64; en-US; rv:1.9.0.1) Gecko/2008081402 Firefox/3.0.1 +Mozilla/5.0 (X11; U; OpenBSD amd64; en; rv:1.8.1.6) Gecko/20070817 Epiphany/2.18 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; OpenBSD arm; en-us) AppleWebKit/531.2+ (KHTML, like Gecko) Safari/531.2+ Epiphany/2.30.0 +Mozilla/5.0 (X11; U; OpenBSD i386; de-DE; rv:1.8.1.6) Gecko/20080429 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.359.0 Safari/533.3 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.7.0.13) Gecko/20060901 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.7.10) Gecko/20050919 (No IDN) Firefox/1.0.6 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.7.13) Gecko/20060901 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.0.1) Gecko/20060213 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.0.4) Gecko/20060628 Firefox/1.5.0.4 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.0.5) Gecko/20060819 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.0.7) Gecko/20060920 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.0.7) Gecko/20061017 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.0.8) Gecko/20061110 Firefox/1.5.0.8 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.1.16) Gecko/20080812 Firefox/2.0.0.16 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.1.3) Gecko/20070505 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.1.4) Gecko/20070704 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.1.4) Gecko/20070704 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.1.4) Gecko/20071127 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.1.6) Gecko/20070819 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.1.7) Gecko/20070930 Firefox/2.0.0.7 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.20 +Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.9.2.8) Gecko/20101230 Firefox/3.6.8 +Mozilla/5.0 (X11; U; OpenBSD ppc; en-US; rv:1.8.0.10) Gecko/20070223 Firefox/1.5.0.10 +Mozilla/5.0 (X11; U; OpenBSD ppc; en-US; rv:1.8.1.4) Gecko/20070223 BonEcho/2.0.0.4 +Mozilla/5.0 (X11; U; OpenBSD ppc; en-US; rv:1.8.1.9) Gecko/20070223 BonEcho/2.0.0.9 +Mozilla/5.0 (X11; U; OpenBSD sparc64; en-AU; rv:1.8.1.6) Gecko/20071225 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; OpenBSD sparc64; en-CA; rv:1.8.0.2) Gecko/20060429 Firefox/1.5.0.2 +Mozilla/5.0 (X11; U; OpenBSD sparc64; en-US; rv:1.8.1.6) Gecko/20070816 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; OpenBSD sparc64; pl-PL; rv:1.8.0.2) Gecko/20060429 Firefox/1.5.0.2 +Mozilla/5.0 (X11; U; Slackware Linux i686; en-US; rv:1.9.0.10) Gecko/2009042315 Firefox/3.0.10 +Mozilla/5.0 (X11; U; Slackware Linux x86_64; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.30 Safari/532.5 +Mozilla/5.0 (X11; U; SunOS 5.11; en-US; rv:1.8.0.2) Gecko/20050405 Epiphany/1.7.1 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7) Gecko/20041221 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7) Gecko/20050502 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7) Gecko/20051027 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7) Gecko/20051122 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7) Gecko/20060627 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7.12) Gecko/20051121 Firefox/1.0.7 (Nexenta package 1.0.7) +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.8.0.5) Gecko/20060728 Firefox/1.5.0.5 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.8.1) Gecko/20061024 Firefox/2.0 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.8.1) Gecko/20061211 Firefox/2.0 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.8.1.3) Gecko/20070423 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.8.1.4) Gecko/20070622 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.9.0.4) Gecko/2008111710 Firefox/3.0.4 +Mozilla/5.0 (X11; U; SunOS i86pc; en-ZW; rv:1.8.1.6) Gecko/20071125 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; SunOS i86pc; fr; rv:1.9.0.4) Gecko/2008111710 Firefox/3.0.4 +Mozilla/5.0 (X11; U; SunOS sun4u; de-DE; rv:0.9.4.1) Gecko/20020518 Netscape6/6.2.3 +Mozilla/5.0 (X11; U; SunOS sun4u; de-DE; rv:1.7) Gecko/20070606 +Mozilla/5.0 (X11; U; SunOS sun4u; de-DE; rv:1.8.1.6) Gecko/20070805 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; SunOS sun4u; de-DE; rv:1.9.1b4) Gecko/20090428 Firefox/2.0.0.0 +Mozilla/5.0 (X11; U; SunOS sun4u; en-GB; rv:1.8.0.1) Gecko/20060206 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:0.9.2) Gecko/20011002 Netscape6/6.1 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:0.9.4) Gecko/20011206 Netscape6/6.2.1 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:0.9.4.1) Gecko/20020406 Netscape6/6.2.2 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:0.9.4.1) Gecko/20020518 Netscape6/6.2.3 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.0) Gecko/20020611 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020719 Netscape/7.0 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020920 Netscape/7.0 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020921 Netscape/7.0 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.1) Gecko/20020827 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.1) Gecko/20020909 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.1) Gecko/20020925 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.2.1) Gecko/20021205 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.2.1) Gecko/20021212 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.2.1) Gecko/20021217 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.2.1) Gecko/20030711 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.3) Gecko/20030318 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.3.1) Gecko/20030509 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4) Gecko/20041224 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4a) Gecko/20030318 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4b) Gecko/20030517 Mozilla Firebird/0.6 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5a) Gecko/20030729 Mozilla Firebird/0.6.1 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20060120 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20060629 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.11) Gecko/20050802 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.12) Gecko/20050922 Firefox/1.0.7 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.12) Gecko/20050927 Firefox/1.0.7 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.13) Gecko/20060509 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20041221 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20050105 Epiphany/1.4.8 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.7) Gecko/20050421 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.8) Gecko/20050512 Firefox/1.0.4 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8) Gecko/20051130 Firefox/1.5 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.0.1) Gecko/20060206 Firefox/1.5.0.1 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.0.7) Gecko/20060915 Firefox/1.5.0.7 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1) Gecko/20061024 Firefox/2.0 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1) Gecko/20061228 Firefox/2.0 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1.11) Gecko/20080118 Firefox/2.0.0.11 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1.12) Gecko/20080210 Firefox/2.0.0.12 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1.14) Gecko/20080418 Firefox/2.0.0.14 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1.2) Gecko/20070226 Firefox/2.0.0.2 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1.20) Gecko/20090108 Firefox/2.0.0.20 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1.3) Gecko/20070321 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1.4) Gecko/20070531 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1.4) Gecko/20070622 Firefox/2.0.0.4 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8.1.9) Gecko/20071102 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.9b5) Gecko/2008032620 Firefox/3.0b5 +Mozilla/5.0 (X11; U; SunOS sun4u; fr-FR; rv:1.7) Gecko/20040621 +Mozilla/5.0 (X11; U; SunOS sun4u; it-IT; ) Gecko/20080000 Firefox/3.0 +Mozilla/5.0 (X11; U; SunOS sun4u; pl-PL; rv:1.8.1.6) Gecko/20071217 Firefox/2.0.0.6 +Mozilla/5.0 (X11; U; SunOS sun4v; en-US; rv:1.7) Gecko/20060120 +Mozilla/5.0 (X11; U; SunOS sun4v; en-US; rv:1.8.1.3) Gecko/20070321 Firefox/2.0.0.3 +Mozilla/5.0 (X11; U; SunOS sun4v; es-ES; rv:1.8.1.9) Gecko/20071127 Firefox/2.0.0.9 +Mozilla/5.0 (X11; U; SunOS5.10 sun4u; ja-JP; rv:1.5) Gecko/20031022 +Mozilla/5.0 (X11; U; Win95; en-US; rv:1.8.1) Gecko/20061125 BonEcho/2.0 +Mozilla/5.0 (X11; U; Windows NT 5.0; en-US; rv:1.9b4) Gecko/2008030318 Firefox/3.0b4 +Mozilla/5.0 (X11; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7 +Mozilla/5.0 (X11; U; Windows NT 6; en-US) AppleWebKit/534.12 (KHTML, like Gecko) Chrome/9.0.587.0 Safari/534.12 +Mozilla/5.0 (X11; U; Windows NT i686; fr; rv:1.9.0.1) Gecko/2008070206 Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; x86_64 Linux; en_GB, en_US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.358.0 Safari/533.3 +Mozilla/5.0 (X11; U; x86_64 Linux; en_GB, en_US; rv:1.9.2) Gecko/20100115 Firefox/3.6 +Mozilla/5.0 (X11; U; x86_64 Linux; en_US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7 +Mozilla/5.0 (X11; U; x86_64 Linux; en_US; rv:1.8.16) Gecko/20071015 Firefox/2.0.0.8 +Mozilla/5.0 (X11; U; x86_64 Linux; en_US; rv:1.9.0.5) Gecko/2008120121 Firefox/3.0.5 +Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:14.0) Gecko/20100101 Firefox/14.0.1 +Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1 +Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:14.0) Gecko/20100101 Firefox/14.0.1 +Mozilla/5.0 (X11; debian; Linux x86_64; rv:15.0) Gecko/20100101 Iceweasel/15.0 +Mozilla/5.0 (X11;U; Linux i686; en-GB; rv:1.9.1) Gecko/20090624 Ubuntu/9.04 (jaunty) Firefox/3.5 +Mozilla/5.0 (X11;U;Linux i686;en-US;rv:1.8.1) Gecko/2006101022 Firefox/2.0 +Mozilla/5.0 (ZX-81; U; CP/M86; en-US; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1 +Mozilla/5.0 (compatible; ABrowse 0.4; Syllable) +Mozilla/5.0 (compatible; IBrowse 3.0; AmigaOS4.0) +Mozilla/5.0 (compatible; Konqueror/2.1.1; X11) +Mozilla/5.0 (compatible; Konqueror/2.1.2; X11) +Mozilla/5.0 (compatible; Konqueror/2.2-11; Linux) +Mozilla/5.0 (compatible; Konqueror/2.2-12; Linux) +Mozilla/5.0 (compatible; Konqueror/2.2.1; Linux) +Mozilla/5.0 (compatible; Konqueror/2.2.2) +Mozilla/5.0 (compatible; Konqueror/2.2.2-3; Linux) +Mozilla/5.0 (compatible; Konqueror/2.2.2; Linux 2.4.14-xfs; X11; i686) +Mozilla/5.0 (compatible; Konqueror/2.2.2; Linux) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020217) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020319) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020515) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020523) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020703) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020704) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020705) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020723) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020726) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020801) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020807) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020808) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020906) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020911) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020917) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20021026) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20021103) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20021118) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20021206) +Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20021208) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020105) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020106) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020107) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020108) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020110) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020213) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020219) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020226) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020323) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020424) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020505) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020602) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020606) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020702) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20020809) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20021008) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20021118) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20021127) +Mozilla/5.0 (compatible; Konqueror/3.0-rc2; i686 Linux; 20021221) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020412) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020426) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020506) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020517) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020519) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020605) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020608) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020624) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020626) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020703) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020724) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020812) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020818) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020910) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020914) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20021013) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20021018) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20021025) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20021123) +Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20021125) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020420) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020504) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020517) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020519) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020609) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020622) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020628) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020707) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020721) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020802) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020818) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020821) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020915) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020920) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020923) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020926) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20021004) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20021016) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20021028) +Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20021117) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20020628) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20020703) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20020724) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20020821) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20020822) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20020901) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20020910) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20020913) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20020921) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021015) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021020) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021026) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021105) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021109) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021120) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021121) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021208) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021210) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021213) +Mozilla/5.0 (compatible; Konqueror/3.0-rc5; i686 Linux; 20021226) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020312) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020512) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020520) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020522) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020613) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020614) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020624) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020718) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020723) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020817) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020827) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020908) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020912) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020918) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20020923) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20021012) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20021027) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20021106) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20021115) +Mozilla/5.0 (compatible; Konqueror/3.0-rc6; i686 Linux; 20021127) +Mozilla/5.0 (compatible; Konqueror/3.0.0-10; Linux) +Mozilla/5.0 (compatible; Konqueror/3.0.0; Linux) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020423) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020502) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020510) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020511) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020603) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020608) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020707) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020716) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020728) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020809) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020817) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020823) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020825) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020914) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20020927) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20021006) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20021012) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20021107) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20021117) +Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20021219) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020510) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020515) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020520) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020608) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020618) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020620) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020703) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020711) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020718) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020722) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020723) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020816) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020823) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20020919) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20021008) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20021022) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20021113) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20021120) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20021221) +Mozilla/5.0 (compatible; Konqueror/3.1-rc1; i686 Linux; 20021226) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020509) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020513) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020605) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020612) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020614) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020619) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020721) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020808) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020809) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020818) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020820) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020905) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020917) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20020925) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20021011) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20021014) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20021020) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20021119) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20021128) +Mozilla/5.0 (compatible; Konqueror/3.1-rc2; i686 Linux; 20021221) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020421) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020426) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020510) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020515) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020520) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020607) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020709) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020716) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020725) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020818) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020912) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020915) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020926) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20021004) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20021025) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20021110) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20021125) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20021204) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20021210) +Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20021223) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020420) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020511) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020521) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020602) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020714) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020718) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020808) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020811) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020824) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020827) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020901) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020912) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020913) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020928) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20021026) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20021114) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20021124) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20021204) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20021208) +Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20021217) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020524) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020601) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020606) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020615) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020621) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020625) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020712) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020809) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020819) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020823) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020906) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020910) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020913) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020927) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20021001) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20021112) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20021127) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20021212) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20021219) +Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20021224) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20020607) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20020614) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20020624) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20020626) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20020815) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20020822) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20020828) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20020905) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20020907) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20020915) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20021002) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20021006) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20021019) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20021105) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20021113) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20021119) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20021124) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20021203) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20021219) +Mozilla/5.0 (compatible; Konqueror/3.1-rc6; i686 Linux; 20021224) +Mozilla/5.0 (compatible; Konqueror/3.1; Linux) +Mozilla/5.0 (compatible; Konqueror/3.1; Linux; X11; i686) +Mozilla/5.0 (compatible; Konqueror/3.1; Linux; en) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20020712) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20020720) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20020810) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20020811) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20020817) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20020913) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20020928) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021001) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021006) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021007) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021027) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021102) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021103) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021105) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021106) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021113) +Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021128) +Mozilla/5.0 (compatible; Konqueror/3.2; FreeBSD) (KHTML, like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.2) (KHTML, like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; en_US) (KHTML, like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3) (KHTML, like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3) KHTML/3.3.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.4.22-xfs; X11) KHTML/3.3.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.4.27; X11) (KHTML, like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.11) KHTML/3.3.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.11.12-whnetz-xenU; X11; i686; en_US) KHTML/3.3.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.11; X11) KHTML/3.3.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.11; X11; i686) KHTML/3.3.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.11; X11; i686; de) KHTML/3.3.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.9-1.667) (KHTML, like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; Linux) (KHTML, like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; Linux) KHTML/3.3.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.3; SunOS) (KHTML, like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.4) KHTML/3.4.0 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.4) KHTML/3.4.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux 2.6.11; X11) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux 2.6.11; X11) KHTML/3.4.0 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux 2.6.12.6; X11; i686; en_US) KHTML/3.4.3 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux 2.6.12; X11) KHTML/3.4.1 (like Gecko) (Debian package 4:3.4.1-1) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.0 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.1 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.2 (like Gecko) (Debian package 4:3.4.2-4) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.3 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.3 (like Gecko) (Debian package 4:3.4.3-2) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.3 (like Gecko) (Kubuntu package 4:3.4.3-0ubuntu1) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.3 (like Gecko) (Kubuntu package 4:3.4.3-0ubuntu2) +Mozilla/5.0 (compatible; Konqueror/3.4; Linux; de, en_US) KHTML/3.4.2 (like Gecko) (Debian package 4:3.4.2-4) +Mozilla/5.0 (compatible; Konqueror/3.4; SunOS) KHTML/3.4.1 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.6 (like Gecko) (Kubuntu) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.7 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.7 (like Gecko) (Debian) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.7 (like Gecko) (Kubuntu) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.7 (like Gecko) SUSE +Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.9 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux; X11) KHTML/3.5.3 (like Gecko) Kubuntu 6.06 Dapper +Mozilla/5.0 (compatible; Konqueror/3.5; Linux; X11; i686; en_US) KHTML/3.5.6 (like Gecko) (Debian) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux; de) KHTML/3.5.5 (like Gecko) (Debian) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux; en_US) KHTML/3.5.6 (like Gecko) (Kubuntu) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux; i686; U; it-IT) KHTML/3.5.5 (like Gecko) (Debian) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux; x86_64) KHTML/3.5.5 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux; x86_64) KHTML/3.5.5 (like Gecko) (Debian) +Mozilla/5.0 (compatible; Konqueror/3.5; Linux; x86_64; en_US) KHTML/3.5.10 (like Gecko) SUSE +Mozilla/5.0 (compatible; Konqueror/3.5; NetBSD 3.0; X11) KHTML/3.5.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.5; NetBSD 4.0_RC3; X11) KHTML/3.5.7 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.5; SunOS) +Mozilla/5.0 (compatible; Konqueror/3.5; SunOS) KHTML/3.5.0 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.5; SunOS) KHTML/3.5.1 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/3.5; Windows NT 6.0) KHTML/3.5.6 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.0; Linux) KHTML/4.0.82 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.0; Linux; x86_64) KHTML/4.0.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.0; Windows) KHTML/4.0.83 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.0; X11) KHTML/4.0.3 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.1; DragonFly) KHTML/4.1.4 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.1; Linux 2.6.27.7-134.fc10.x86_64; X11; x86_64) KHTML/4.1.3 (like Gecko) Fedora/4.1.3-4.fc10 +Mozilla/5.0 (compatible; Konqueror/4.1; Linux) KHTML/4.1.3 (like Gecko) Fedora/4.1.3-3.fc10 +Mozilla/5.0 (compatible; Konqueror/4.1; Linux) KHTML/4.1.4 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.1; OpenBSD) KHTML/4.1.4 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.2) KHTML/4.2.4 (like Gecko) Fedora/4.2.4-2.fc11 +Mozilla/5.0 (compatible; Konqueror/4.2; Linux) KHTML/4.2.1 (like Gecko) Fedora/4.2.1-4.fc11 +Mozilla/5.0 (compatible; Konqueror/4.2; Linux) KHTML/4.2.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.2; Linux) KHTML/4.2.4 (like Gecko) Fedora/4.2.4-2.fc11 +Mozilla/5.0 (compatible; Konqueror/4.2; Linux) KHTML/4.2.4 (like Gecko) Slackware/13.0 +Mozilla/5.0 (compatible; Konqueror/4.2; Linux) KHTML/4.2.96 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.2; Linux) KHTML/4.2.98 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.2; Linux; X11; x86_64) KHTML/4.2.4 (like Gecko) Fedora/4.2.4-2.fc11 +Mozilla/5.0 (compatible; Konqueror/4.3; Linux 2.6.31-16-generic; X11) KHTML/4.3.2 (like Gecko) +Mozilla/5.0 (compatible; Konqueror/4.3; Linux) KHTML/4.3.1 (like Gecko) Fedora/4.3.1-3.fc11 +Mozilla/5.0 (compatible; Konqueror/4.4; Linux 2.6.32-22-generic; X11; en_US) KHTML/4.4.3 (like Gecko) Kubuntu +Mozilla/5.0 (compatible; Konqueror/4.4; Linux) KHTML/4.4.1 (like Gecko) Fedora/4.4.1-1.fc12 +Mozilla/5.0 (compatible; Konqueror/4.5; FreeBSD) KHTML/4.5.4 (like Gecko) +Mozilla/5.0 (compatible; MSIE 10.0; Macintosh; Intel Mac OS X 10_7_3; Trident/6.0) +Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/4.0; InfoPath.2; SV1; .NET CLR 2.0.50727; WOW64) +Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/5.0) +Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0) +Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0) +Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0 +Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1) +Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4325) +Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727) +Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; zh-cn) Opera 8.65 +Mozilla/5.0 (compatible; MSIE 7.0; Windows 98; SpamBlockerUtility 6.3.91; SpamBlockerUtility 6.2.91; .NET CLR 4.1.89;GB) +Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 5.0; Trident/4.0; FBSMTWB; .NET CLR 2.0.34861; .NET CLR 3.0.3746.3218; .NET CLR 3.5.33652; msn OptimizedIE8;ENUS) +Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 5.2; WOW64; .NET CLR 2.0.50727) +Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; c .NET CLR 3.0.04506; .NET CLR 3.5.30707; InfoPath.1; el-GR) +Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; c .NET CLR 3.0.04506; .NET CLR 3.5.30707; InfoPath.1; el-GR) +Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; en-US) +Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; fr-FR) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.0; Trident/4.0; InfoPath.1; SV1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 3.0.04506.30) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.1; SLCC1; .NET CLR 1.1.4322) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Maxthon; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 3.0.04320) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 1.1.4322) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; Media Center PC 4.0; SLCC1; .NET CLR 3.0.04320) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; Trident/4.0; Media Center PC 4.0; SLCC1; .NET CLR 3.0.04320; Maxthon 2.0) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; SV1; Crazy Browser 9.0.04) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; .NET CLR 2.7.58687; SLCC2; Media Center PC 5.0; Zune 3.4; Tablet PC 3.6; InfoPath.3) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; InfoPath.1; SV1; .NET CLR 3.8.36217; WOW64; en-US) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322) +Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB7.4; InfoPath.2; SV1; .NET CLR 3.3.69573; WOW64; en-US) +Mozilla/5.0 (compatible; MSIE 9.0; AOL 9.0; Windows NT 6.0; Trident/5.0) +Mozilla/5.0 (compatible; MSIE 9.0; AOL 9.1; AOLBuild 4334.5012; Windows NT 6.0; WOW64; Trident/5.0) +Mozilla/5.0 (compatible; MSIE 9.0; AOL 9.7; AOLBuild 4343.19; Windows NT 6.1; WOW64; Trident/5.0; FunWebProducts) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/4.0; GTB7.4; InfoPath.3; SV1; .NET CLR 3.1.76908; WOW64; en-US) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/4.0; Maxthon; SV1; .NET CLR 1.1.4322; .NET CLR 2.4.84947; SLCC1; Media Center PC 4.0; Zune 3.5; Tablet PC 3.5; InfoPath.3) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; Sleipnir/2.9.7) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; TheWorld) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; chromeframe/11.0.696.57) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/4.0; GTB7.4; InfoPath.1; SV1; .NET CLR 2.8.52393; WOW64; en-US) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/4.0; WOW64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0; Maxthon 2.0) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/4.0; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Zune 4.0; InfoPath.3; MS-RTC LM 8; .NET4.0C; .NET4.0E; Maxthon 2.0) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) chromeframe/10.0.648.205 +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; FunWebProducts) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET CLR 1.1.4322; .NET4.0C; Tablet PC 2.0) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; chromeframe/11.0.696.57) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; chromeframe/13.0.782.215) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; yie8) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; Maxthon/3.0) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Lunascape 6.7.1.25446) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Zune 4.0; InfoPath.3; MS-RTC LM 8; .NET4.0C; .NET4.0E) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; Media Center PC 6.0; InfoPath.3; MS-RTC LM 8; Zune 4.7 +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; Media Center PC 6.0; InfoPath.3; MS-RTC LM 8; Zune 4.7) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; chromeframe/12.0.742.112) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0 +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Zune 4.0; Tablet PC 2.0; InfoPath.3; .NET4.0C; .NET4.0E) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; de) Opera 11.51 +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0) +Mozilla/5.0 (compatible; Sundance/0.9x) +Mozilla/5.0 (compatible; U; ABrowse 0.6; Syllable) AppleWebKit/420+ (KHTML, like Gecko) +Mozilla/5.0 (compatible; Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070219 +Mozilla/5.0 (compatible; Windows; U; Windows NT 6.2; WOW64; en-US; rv:12.0) Gecko/20120403211507 Firefox/12.0 +Mozilla/5.0 (compatible; iCab 3.0.2; Macintosh; U; PPC Mac OS X) +Mozilla/5.0 (compatible; iCab 3.0.2; Macintosh; U; PPC Mac OS) +Mozilla/5.0 (compatible; iCab 3.0.3; Macintosh; U; PPC Mac OS X) +Mozilla/5.0 (compatible; iCab 3.0.3; Macintosh; U; PPC Mac OS) +Mozilla/5.0 (compatible; iCab 3.0.5; Macintosh; U; PPC Mac OS X) +Mozilla/5.0 (compatible; iCab 3.0.5; Macintosh; U; PPC Mac OS) +Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko ) Version/5.1 Mobile/9B176 Safari/7534.48.3 +Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25 +Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; es-es) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B360 Safari/531.21.10 +Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; es-es) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10 +Mozilla/5.0 (iPad; U; CPU OS 3_2_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B500 Safari/53 +Mozilla/5.0 (iPad;U;CPU OS 3_2_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B500 Safari/531.21.10 +Mozilla/5.0 (iPhone Simulator; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7D11 Safari/531.21.10 +Mozilla/5.0 (iPhone; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10 +Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7 +Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B5097d Safari/6531.22.7 +Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; nb-no) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148a Safari/6533.18.5 +Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; ru-ru) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5 +Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3 like Mac OS X; en-gb) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8F190 Safari/6533.18.5 +Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3 like Mac OS X; fr-fr) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8F190 Safari/6533.18.5 +Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3 like Mac OS X; pl-pl) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8F190 Safari/6533.18.5 +Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_1 like Mac OS X; zh-tw) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8G4 Safari/6533.18.5 +Mozilla/5.0 (iPhone; U; Linux i686; pt-br) AppleWebKit/532+ (KHTML, like Gecko) Version/3.0 Mobile/1A538b Safari/419.3 Midori/0.2.0 +Mozilla/5.0 (iPhone; U; fr; CPU iPhone OS 4_2_1 like Mac OS X; fr) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148a Safari/6533.18.5 +Mozilla/5.0 (iPhone; U; ru; CPU iPhone OS 4_2_1 like Mac OS X; fr) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148a Safari/6533.18.5 +Mozilla/5.0 (iPhone; U; ru; CPU iPhone OS 4_2_1 like Mac OS X; ru) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148a Safari/6533.18.5 +Mozilla/5.0 (iPod; U; CPU iPhone OS 4_2_1 like Mac OS X; he-il) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5 +Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8G4 Safari/6533.18.5 +Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5 +Mozilla/5.0 (ipad Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.6 (KHTML, like Gecko) Chrome/7.0.498.0 Safari/534.6 +Mozilla/5.0 ArchLinux (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 +Mozilla/5.0 ArchLinux (X11; U; Linux x86_64; en-US) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 +Mozilla/5.0 ArchLinux (X11; U; Linux x86_64; en-US) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30 +Mozilla/5.0 ArchLinux (X11; U; Linux x86_64; en-US) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.60 Safari/534.30 +Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U;) Gecko/0 +Mozilla/5.0 Galeon/1.2.5 (X11; Linux i586; U;) Gecko/20020623 Debian/1.2.5-0.woody.1 +Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/0 +Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/20020610 Debian/1.2.5-1 +Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/20020623 Debian/1.2.5-0.woody.1 +Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/20020809 +Mozilla/5.0 Galeon/1.2.6 (X11; Linux i586; U;) Gecko/20020916 +Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20020827 +Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20020830 +Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20020913 Debian/1.2.6-2 +Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20020916 +Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20021226 Debian/1.2.7-6 +Mozilla/5.0 Galeon/1.2.8 (X11; Linux i686; U;) Gecko/20030212 +Mozilla/5.0 Galeon/1.2.8 (X11; Linux i686; U;) Gecko/20030317 +Mozilla/5.0 Galeon/1.2.9 (X11; Linux i686; U;) Gecko/20021213 Debian/1.2.9-0.bunk +Mozilla/5.0 Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.13) Firefox/3.6.13 +Mozilla/5.0 Slackware/13.37 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/11.0.696.50 +Mozilla/5.0 Slackware/13.37 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/12.0.742.91 +Mozilla/5.0 Slackware/13.37 (X11; U; Linux x86_64; en-US) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 +Mozilla/5.0(Compatible; Windows; U; en-US;) Sundance/0.9 +Mozilla/5.0(Compatible; Windows; U; en-US;) Sundance/0.9.0.33 +Mozilla/5.0(Windows; U; Windows NT 5.2; rv:1.9.2) Gecko/20100101 Firefox/3.6 +Mozilla/5.0(Windows; U; Windows NT 7.0; rv:1.9.2) Gecko/20100101 Firefox/3.6 +Mozilla/5.0(X11;U;Linux(x86_64);en;rv:1.9a8)Gecko/2007100619;GranParadiso/3.1 +Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/123 +Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10 +Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10gin_lib.cc +Mozilla/5.001 (Macintosh; N; PPC; ja) Gecko/25250101 +Mozilla/5.001 (X11; U; Linux i686; rv:1.8.1.6; de-ch) Gecko/25250101 (ubuntu-feisty) +Mozilla/6.0 (Future Star Technologies Corp. Star-Blade OS; U; en-US) iNet Browser 2.5 +Mozilla/6.0 (Macintosh; I; Intel Mac OS X 11_7_9; de-LI; rv:1.9b4) Gecko/2012010317 Firefox/10.0a4 +Mozilla/6.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:2.0.0.0) Gecko/20061028 Firefox/3.0 +Mozilla/6.0 (Windows; U; Windows NT 6.0; en-US) Gecko/2009032609 (KHTML, like Gecko) Chrome/2.0.172.6 Safari/530.7 +Mozilla/6.0 (Windows; U; Windows NT 6.0; en-US) Gecko/2009032609 Chrome/2.0.172.6 Safari/530.7 +Mozilla/6.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8 +Mozilla/6.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8 (.NET CLR 3.5.30729) +Mozilla/6.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.27 Safari/532.0 +Mozilla/6.0 (Windows; U; Windows NT 7.0; en-US; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.9 (.NET CLR 3.5.30729) +Mozilla/6.0 (X11; U; Linux x86_64; en-US; rv:2.9.0.3) Gecko/2009022510 FreeBSD/ Sunrise/4.0.1/like Safari +Opera 9.4 (Windows NT 5.3; U; en) +Opera 9.4 (Windows NT 6.1; U; en) +Opera 9.60 +Opera 9.7 (Windows NT 5.2; U; en) +Opera/10.50 (Windows NT 6.1; U; en-GB) Presto/2.2.2 +Opera/10.60 (Windows NT 5.1; U; en-US) Presto/2.6.30 Version/10.60 +Opera/10.60 (Windows NT 5.1; U; zh-cn) Presto/2.6.30 Version/10.60 +Opera/4.02 (Windows 98; U) [en] +Opera/5.0 (SunOS 5.8 sun4u; U) [en] +Opera/5.0 (Ubuntu; U; Windows NT 6.1; es; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 +Opera/5.02 (Macintosh; U; id) +Opera/5.02 (Windows 98; U) [en] +Opera/5.02 (Windows NT 5.0; U) [en] +Opera/5.11 (Windows 98; U) [en] +Opera/5.12 (Windows 98; U) [en] +Opera/5.12 (Windows NT 5.1; U) [de] +Opera/6.0 (Macintosh; PPC Mac OS X; U) +Opera/6.0 (Windows 2000; U) [de] +Opera/6.0 (Windows 2000; U) [fr] +Opera/6.0 (Windows ME; U) [de] +Opera/6.0 (Windows XP; U) [de] +Opera/6.01 (Windows 2000; U) [de] +Opera/6.01 (Windows 2000; U) [en] +Opera/6.01 (Windows 98; U) [de] +Opera/6.01 (Windows 98; U) [en] +Opera/6.01 (Windows XP; U) [de] +Opera/6.01 (X11; U; nn) +Opera/6.02 (Windows NT 4.0; U) [de] +Opera/6.03 (Linux 2.4.18-18.7.x i686; U) [en] +Opera/6.03 (Windows 2000; U) [en] +Opera/6.03 (Windows 98; U) [en] +Opera/6.03 (Windows NT 4.0; U) [en] +Opera/6.04 (Windows 2000; U) [de] +Opera/6.04 (Windows 2000; U) [en] +Opera/6.04 (Windows 98; U) [en-GB] +Opera/6.04 (Windows NT 4.0; U) [de] +Opera/6.04 (Windows NT 4.0; U) [en] +Opera/6.04 (Windows XP; U) [de] +Opera/6.04 (Windows XP; U) [en] +Opera/6.05 (Windows 2000; U) [de] +Opera/6.05 (Windows 2000; U) [en] +Opera/6.05 (Windows 2000; U) [fr] +Opera/6.05 (Windows 2000; U) [it] +Opera/6.05 (Windows 2000; U) [ja] +Opera/6.05 (Windows 2000; U) [oc] +Opera/6.05 (Windows 98; U) [de] +Opera/6.05 (Windows 98; U) [en] +Opera/6.05 (Windows 98; U) [fr] +Opera/6.05 (Windows ME; U) [de] +Opera/6.05 (Windows ME; U) [fr] +Opera/6.05 (Windows NT 4.0; U) [de] +Opera/6.05 (Windows NT 4.0; U) [fr] +Opera/6.05 (Windows NT 4.0; U) [ro] +Opera/6.05 (Windows XP; U) [de] +Opera/6.05 (Windows XP; U) [en] +Opera/6.11 (FreeBSD 4.7-RELEASE i386; U) [en] +Opera/6.11 (Linux 2.4.10-4GB i686; U) [en] +Opera/6.11 (Linux 2.4.18-4GB i686; U) [en] +Opera/6.11 (Linux 2.4.18-bf2.4 i686; U) [en] +Opera/6.12 (Linux 2.4.18-14cpq i686; U) [en] +Opera/6.12 (Linux 2.4.20-4GB i686; U) [en] +Opera/7.0 (Windows 2000; U) [de] +Opera/7.0 (Windows 2000; U) [en] +Opera/7.0 (Windows 98; U) [en] +Opera/7.0 (Windows NT 4.0; U) [de] +Opera/7.0 (Windows NT 4.0; U) [en] +Opera/7.0 (Windows NT 5.1; U) [en] +Opera/7.01 (Windows 98; U) [en] +Opera/7.01 (Windows 98; U) [fr] +Opera/7.01 (Windows NT 5.0; U) [en] +Opera/7.01 (Windows NT 5.1; U) [en] +Opera/7.02 (Windows 98; U) [en] +Opera/7.02 (Windows NT 5.1; U) [fr] +Opera/7.03 (Windows 98; U) [de] +Opera/7.03 (Windows 98; U) [en] +Opera/7.03 (Windows NT 4.0; U) [en] +Opera/7.03 (Windows NT 5.0; U) [de] +Opera/7.03 (Windows NT 5.0; U) [en] +Opera/7.03 (Windows NT 5.1; U) [de] +Opera/7.03 (Windows NT 5.1; U) [en] +Opera/7.10 (Linux Debian;en-US) +Opera/7.10 (Windows NT 4.0; U) [de] +Opera/7.10 (Windows NT 5.0; U) [en] +Opera/7.10 (Windows NT 5.1; U) [en] +Opera/7.11 (Linux 2.6.0-test4 i686; U) [en] +Opera/7.11 (Windows 98; U) [de] +Opera/7.11 (Windows 98; U) [en] +Opera/7.11 (Windows NT 5.0; U) [de] +Opera/7.11 (Windows NT 5.0; U) [en] +Opera/7.11 (Windows NT 5.1; U) [de] +Opera/7.11 (Windows NT 5.1; U) [en] +Opera/7.11 (Windows NT 5.1; U) [pl] +Opera/7.20 (Windows NT 5.1; U) [en] +Opera/7.21 (Windows NT 5.1; U) [en] +Opera/7.22 (Windows NT 5.1; U) [de] +Opera/7.23 (Windows 98; U) [en] +Opera/7.23 (Windows NT 5.0; U) [en] +Opera/7.23 (Windows NT 5.0; U) [fr] +Opera/7.23 (Windows NT 5.1; U; sv) +Opera/7.23 (Windows NT 6.0; U) [zh-cn] +Opera/7.50 (Windows NT 5.1; U) [en] +Opera/7.50 (Windows XP; U) +Opera/7.51 (Linux) [en] +Opera/7.51 (Windows NT 5.1; U) [en] +Opera/7.51 (X11; SunOS sun4u; U) [de] +Opera/7.52 (Windows NT 5.1; U) [en] +Opera/7.53 (Windows NT 5.1; U) [en] +Opera/7.53 (X11; Linux i686; U) [en_US] +Opera/7.54 (Windows 98; U) [de] +Opera/7.54 (Windows NT 5.0; U) [de] +Opera/7.54 (Windows NT 5.0; U) [en] +Opera/7.54 (Windows NT 5.1; U) [de] +Opera/7.54 (Windows NT 5.1; U) [en] +Opera/7.54 (Windows NT 5.1; U) [it] +Opera/7.54 (X11; Linux i686; U) [en] +Opera/8.0 (Windows NT 5.1; U; en) +Opera/8.0 (X11; Linux i686; U; cs) +Opera/8.00 (Windows NT 5.1; U; en) +Opera/8.01 (Macintosh; PPC Mac OS X; U; en) +Opera/8.01 (Macintosh; U; PPC Mac OS; en) +Opera/8.01 (Windows NT 5.0; U; de) +Opera/8.01 (Windows NT 5.1; U; de) +Opera/8.01 (Windows NT 5.1; U; en) +Opera/8.01 (Windows NT 5.1; U; fr) +Opera/8.01 (Windows NT 5.1; U; pl) +Opera/8.02 (Windows NT 5.1; U; de) +Opera/8.02 (Windows NT 5.1; U; en) +Opera/8.02 (Windows NT 5.1; U; ru) +Opera/8.10 (Windows NT 5.1; U; en) +Opera/8.50 (Windows 98; U; en) +Opera/8.50 (Windows 98; U; ru) +Opera/8.50 (Windows ME; U; en) +Opera/8.50 (Windows NT 4.0; U; zh-cn) +Opera/8.50 (Windows NT 5.0; U; de) +Opera/8.50 (Windows NT 5.0; U; en) +Opera/8.50 (Windows NT 5.0; U; fr) +Opera/8.50 (Windows NT 5.1; U; de) +Opera/8.50 (Windows NT 5.1; U; en) +Opera/8.50 (Windows NT 5.1; U; es-ES) +Opera/8.50 (Windows NT 5.1; U; fr) +Opera/8.50 (Windows NT 5.1; U; pl) +Opera/8.50 (Windows NT 5.1; U; ru) +Opera/8.51 (FreeBSD 5.1; U; en) +Opera/8.51 (Macintosh; PPC Mac OS X; U; de) +Opera/8.51 (Windows 98; U; en) +Opera/8.51 (Windows NT 5.0; U; en) +Opera/8.51 (Windows NT 5.1; U; de) +Opera/8.51 (Windows NT 5.1; U; en) +Opera/8.51 (Windows NT 5.1; U; fr) +Opera/8.51 (Windows NT 5.1; U; nb) +Opera/8.51 (Windows NT 5.1; U; pl) +Opera/8.51 (X11; Linux i686; U; en) +Opera/8.51 (X11; Linux x86_64; U; en) +Opera/8.51 (X11; U; Linux i686; en-US; rv:1.8) +Opera/8.52 (Windows ME; U; en) +Opera/8.52 (Windows NT 5.0; U; en) +Opera/8.52 (Windows NT 5.1; U; en) +Opera/8.52 (Windows NT 5.1; U; ru) +Opera/8.52 (X11; Linux i686; U; en) +Opera/8.52 (X11; Linux x86_64; U; en) +Opera/8.53 (Windows 98; U; en) +Opera/8.53 (Windows NT 5.0; U; en) +Opera/8.53 (Windows NT 5.1; U; de) +Opera/8.53 (Windows NT 5.1; U; en) +Opera/8.53 (Windows NT 5.1; U; pt) +Opera/8.53 (Windows NT 5.2; U; en) +Opera/8.54 (Windows 98; U; en) +Opera/8.54 (Windows NT 4.0; U; zh-cn) +Opera/8.54 (Windows NT 5.0; U; de) +Opera/8.54 (Windows NT 5.0; U; en) +Opera/8.54 (Windows NT 5.1; U; en) +Opera/8.54 (Windows NT 5.1; U; pl) +Opera/8.54 (Windows NT 5.1; U; ru) +Opera/8.54 (X11; Linux i686; U; de) +Opera/8.54 (X11; Linux i686; U; pl) +Opera/9.00 (Macintosh; PPC Mac OS X; U; es) +Opera/9.00 (Nintendo Wii; U; ; 1038-58; Wii Internet Channel/1.0; en) +Opera/9.00 (Windows NT 5.0; U; en) +Opera/9.00 (Windows NT 5.1; U; de) +Opera/9.00 (Windows NT 5.1; U; en) +Opera/9.00 (Windows NT 5.1; U; es-es) +Opera/9.00 (Windows NT 5.1; U; fi) +Opera/9.00 (Windows NT 5.1; U; fr) +Opera/9.00 (Windows NT 5.1; U; it) +Opera/9.00 (Windows NT 5.1; U; ja) +Opera/9.00 (Windows NT 5.1; U; nl) +Opera/9.00 (Windows NT 5.1; U; pl) +Opera/9.00 (Windows NT 5.1; U; ru) +Opera/9.00 (Windows NT 5.2; U; en) +Opera/9.00 (Windows NT 5.2; U; pl) +Opera/9.00 (Windows NT 5.2; U; ru) +Opera/9.00 (Windows; U) +Opera/9.00 (X11; Linux i686; U; de) +Opera/9.00 (X11; Linux i686; U; en) +Opera/9.00 (X11; Linux i686; U; pl) +Opera/9.01 (Macintosh; PPC Mac OS X; U; en) +Opera/9.01 (Macintosh; PPC Mac OS X; U; it) +Opera/9.01 (Windows NT 5.0; U; de) +Opera/9.01 (Windows NT 5.0; U; en) +Opera/9.01 (Windows NT 5.1) +Opera/9.01 (Windows NT 5.1; U; bg) +Opera/9.01 (Windows NT 5.1; U; cs) +Opera/9.01 (Windows NT 5.1; U; da) +Opera/9.01 (Windows NT 5.1; U; de) +Opera/9.01 (Windows NT 5.1; U; en) +Opera/9.01 (Windows NT 5.1; U; es-es) +Opera/9.01 (Windows NT 5.1; U; ja) +Opera/9.01 (Windows NT 5.1; U; pl) +Opera/9.01 (Windows NT 5.1; U; ru) +Opera/9.01 (Windows NT 5.2; U; en) +Opera/9.01 (Windows NT 5.2; U; ru) +Opera/9.01 (X11; FreeBSD 6 i386; U; en) +Opera/9.01 (X11; FreeBSD 6 i386; U;pl) +Opera/9.01 (X11; Linux i686; U; en) +Opera/9.01 (X11; OpenBSD i386; U; en) +Opera/9.02 (Windows NT 5.0; U; en) +Opera/9.02 (Windows NT 5.0; U; pl) +Opera/9.02 (Windows NT 5.0; U; sv) +Opera/9.02 (Windows NT 5.1; U; de) +Opera/9.02 (Windows NT 5.1; U; en) +Opera/9.02 (Windows NT 5.1; U; fi) +Opera/9.02 (Windows NT 5.1; U; ja) +Opera/9.02 (Windows NT 5.1; U; nb) +Opera/9.02 (Windows NT 5.1; U; pl) +Opera/9.02 (Windows NT 5.1; U; pt-br) +Opera/9.02 (Windows NT 5.1; U; ru) +Opera/9.02 (Windows NT 5.1; U; zh-cn) +Opera/9.02 (Windows NT 5.2; U; de) +Opera/9.02 (Windows NT 5.2; U; en) +Opera/9.02 (Windows XP; U; ru) +Opera/9.02 (Windows; U; nl) +Opera/9.02 (X11; Linux i686; U; de) +Opera/9.02 (X11; Linux i686; U; en) +Opera/9.02 (X11; Linux i686; U; hu) +Opera/9.02 (X11; Linux i686; U; pl) +Opera/9.10 (Windows NT 5.1; U; MEGAUPLOAD 1.0; pl) +Opera/9.10 (Windows NT 5.1; U; es-es) +Opera/9.10 (Windows NT 5.1; U; fi) +Opera/9.10 (Windows NT 5.1; U; hu) +Opera/9.10 (Windows NT 5.1; U; it) +Opera/9.10 (Windows NT 5.1; U; nl) +Opera/9.10 (Windows NT 5.1; U; pl) +Opera/9.10 (Windows NT 5.1; U; pt) +Opera/9.10 (Windows NT 5.1; U; sv) +Opera/9.10 (Windows NT 5.1; U; zh-tw) +Opera/9.10 (Windows NT 5.2; U; de) +Opera/9.10 (Windows NT 5.2; U; en) +Opera/9.10 (Windows NT 6.0; U; en) +Opera/9.10 (Windows NT 6.0; U; it-IT) +Opera/9.10 (X11; Linux i386; U; en) +Opera/9.10 (X11; Linux i686; U; en) +Opera/9.10 (X11; Linux i686; U; kubuntu;pl) +Opera/9.10 (X11; Linux i686; U; pl) +Opera/9.10 (X11; Linux x86_64; U; en) +Opera/9.10 (X11; Linux; U; en) +Opera/9.12 (Windows NT 5.0; U) +Opera/9.12 (Windows NT 5.0; U; ru) +Opera/9.12 (X11; Linux i686; U; en) (Ubuntu) +Opera/9.20 (Windows NT 5.1; U; MEGAUPLOAD=1.0; es-es) +Opera/9.20 (Windows NT 5.1; U; en) +Opera/9.20 (Windows NT 5.1; U; es-AR) +Opera/9.20 (Windows NT 5.1; U; es-es) +Opera/9.20 (Windows NT 5.1; U; it) +Opera/9.20 (Windows NT 5.1; U; nb) +Opera/9.20 (Windows NT 5.1; U; zh-tw) +Opera/9.20 (Windows NT 5.2; U; en) +Opera/9.20 (Windows NT 6.0; U; de) +Opera/9.20 (Windows NT 6.0; U; en) +Opera/9.20 (Windows NT 6.0; U; es-es) +Opera/9.20 (X11; Linux i586; U; en) +Opera/9.20 (X11; Linux i686; U; en) +Opera/9.20 (X11; Linux i686; U; es-es) +Opera/9.20 (X11; Linux i686; U; pl) +Opera/9.20 (X11; Linux i686; U; ru) +Opera/9.20 (X11; Linux i686; U; tr) +Opera/9.20 (X11; Linux ppc; U; en) +Opera/9.20 (X11; Linux x86_64; U; en) +Opera/9.20(Windows NT 5.1; U; en) +Opera/9.21 (Macintosh; Intel Mac OS X; U; en) +Opera/9.21 (Macintosh; PPC Mac OS X; U; en) +Opera/9.21 (Windows 98; U; en) +Opera/9.21 (Windows NT 5.0; U; de) +Opera/9.21 (Windows NT 5.1; U; MEGAUPLOAD 1.0; en) +Opera/9.21 (Windows NT 5.1; U; SV1; MEGAUPLOAD 1.0; ru) +Opera/9.21 (Windows NT 5.1; U; de) +Opera/9.21 (Windows NT 5.1; U; en) +Opera/9.21 (Windows NT 5.1; U; fr) +Opera/9.21 (Windows NT 5.1; U; nl) +Opera/9.21 (Windows NT 5.1; U; pl) +Opera/9.21 (Windows NT 5.1; U; pt-br) +Opera/9.21 (Windows NT 5.1; U; ru) +Opera/9.21 (Windows NT 5.2; U; en) +Opera/9.21 (Windows NT 6.0; U; en) +Opera/9.21 (Windows NT 6.0; U; nb) +Opera/9.21 (X11; Linux i686; U; de) +Opera/9.21 (X11; Linux i686; U; en) +Opera/9.21 (X11; Linux i686; U; es-es) +Opera/9.21 (X11; Linux x86_64; U; en) +Opera/9.22 (Windows NT 5.1; U; SV1; MEGAUPLOAD 1.0; ru) +Opera/9.22 (Windows NT 5.1; U; SV1; MEGAUPLOAD 2.0; ru) +Opera/9.22 (Windows NT 5.1; U; en) +Opera/9.22 (Windows NT 5.1; U; fr) +Opera/9.22 (Windows NT 5.1; U; pl) +Opera/9.22 (Windows NT 6.0; U; en) +Opera/9.22 (Windows NT 6.0; U; ru) +Opera/9.22 (X11; Linux i686; U; de) +Opera/9.22 (X11; Linux i686; U; en) +Opera/9.22 (X11; OpenBSD i386; U; en) +Opera/9.23 (Mac OS X; fr) +Opera/9.23 (Mac OS X; ru) +Opera/9.23 (Macintosh; Intel Mac OS X; U; ja) +Opera/9.23 (Nintendo Wii; U; ; 1038-58; Wii Internet Channel/1.0; en) +Opera/9.23 (Windows NT 5.0; U; de) +Opera/9.23 (Windows NT 5.0; U; en) +Opera/9.23 (Windows NT 5.1; U; SV1; MEGAUPLOAD 1.0; ru) +Opera/9.23 (Windows NT 5.1; U; da) +Opera/9.23 (Windows NT 5.1; U; de) +Opera/9.23 (Windows NT 5.1; U; en) +Opera/9.23 (Windows NT 5.1; U; fi) +Opera/9.23 (Windows NT 5.1; U; it) +Opera/9.23 (Windows NT 5.1; U; ja) +Opera/9.23 (Windows NT 5.1; U; pt) +Opera/9.23 (Windows NT 5.1; U; zh-cn) +Opera/9.23 (Windows NT 6.0; U; de) +Opera/9.23 (X11; Linux i686; U; en) +Opera/9.23 (X11; Linux i686; U; es-es) +Opera/9.23 (X11; Linux x86_64; U; en) +Opera/9.24 (Macintosh; PPC Mac OS X; U; en) +Opera/9.24 (Windows NT 5.0; U; ru) +Opera/9.24 (Windows NT 5.1; U; ru) +Opera/9.24 (Windows NT 5.1; U; tr) +Opera/9.24 (X11; Linux i686; U; de) +Opera/9.24 (X11; SunOS i86pc; U; en) +Opera/9.25 (Macintosh; Intel Mac OS X; U; en) +Opera/9.25 (Macintosh; PPC Mac OS X; U; en) +Opera/9.25 (OpenSolaris; U; en) +Opera/9.25 (Windows NT 4.0; U; en) +Opera/9.25 (Windows NT 5.0; U; cs) +Opera/9.25 (Windows NT 5.0; U; en) +Opera/9.25 (Windows NT 5.1; U; MEGAUPLOAD 1.0; pt-br) +Opera/9.25 (Windows NT 5.1; U; de) +Opera/9.25 (Windows NT 5.1; U; lt) +Opera/9.25 (Windows NT 5.1; U; ru) +Opera/9.25 (Windows NT 5.1; U; zh-cn) +Opera/9.25 (Windows NT 5.2; U; en) +Opera/9.25 (Windows NT 6.0; U; MEGAUPLOAD 1.0; ru) +Opera/9.25 (Windows NT 6.0; U; SV1; MEGAUPLOAD 2.0; ru) +Opera/9.25 (Windows NT 6.0; U; en-US) +Opera/9.25 (Windows NT 6.0; U; ru) +Opera/9.25 (Windows NT 6.0; U; sv) +Opera/9.25 (X11; Linux i686; U; en) +Opera/9.25 (X11; Linux i686; U; fr) +Opera/9.25 (X11; Linux i686; U; fr-ca) +Opera/9.26 (Macintosh; PPC Mac OS X; U; en) +Opera/9.26 (Windows NT 5.1; U; MEGAUPLOAD 2.0; en) +Opera/9.26 (Windows NT 5.1; U; de) +Opera/9.26 (Windows NT 5.1; U; nl) +Opera/9.26 (Windows NT 5.1; U; pl) +Opera/9.26 (Windows NT 5.1; U; zh-cn) +Opera/9.26 (Windows; U; pl) +Opera/9.27 (Macintosh; Intel Mac OS X; U; sv) +Opera/9.27 (Windows NT 5.1; U; ja) +Opera/9.27 (Windows NT 5.2; U; en) +Opera/9.27 (X11; Linux i686; U; en) +Opera/9.27 (X11; Linux i686; U; fr) +Opera/9.30 (Nintendo Wii; U; ; 2047-7; de) +Opera/9.30 (Nintendo Wii; U; ; 2047-7; fr) +Opera/9.30 (Nintendo Wii; U; ; 2047-7;en) +Opera/9.30 (Nintendo Wii; U; ; 2047-7;es) +Opera/9.30 (Nintendo Wii; U; ; 2047-7;pt-br) +Opera/9.30 (Nintendo Wii; U; ; 2071; Wii Shop Channel/1.0; en) +Opera/9.5 (Windows NT 5.1; U; fr) +Opera/9.5 (Windows NT 6.0; U; en) +Opera/9.50 (Macintosh; Intel Mac OS X; U; de) +Opera/9.50 (Macintosh; Intel Mac OS X; U; en) +Opera/9.50 (Windows NT 5.1; U; es-ES) +Opera/9.50 (Windows NT 5.1; U; it) +Opera/9.50 (Windows NT 5.1; U; nl) +Opera/9.50 (Windows NT 5.1; U; nn) +Opera/9.50 (Windows NT 5.1; U; ru) +Opera/9.50 (Windows NT 5.2; U; it) +Opera/9.50 (X11; Linux i686; U; es-ES) +Opera/9.50 (X11; Linux ppc; U; en) +Opera/9.50 (X11; Linux x86_64; U; nb) +Opera/9.50 (X11; Linux x86_64; U; pl) +Opera/9.51 (Macintosh; Intel Mac OS X; U; en) +Opera/9.51 (Windows NT 5.1; U; da) +Opera/9.51 (Windows NT 5.1; U; en) +Opera/9.51 (Windows NT 5.1; U; en-GB) +Opera/9.51 (Windows NT 5.1; U; es-AR) +Opera/9.51 (Windows NT 5.1; U; es-LA) +Opera/9.51 (Windows NT 5.1; U; fr) +Opera/9.51 (Windows NT 5.1; U; nn) +Opera/9.51 (Windows NT 5.2; U; en) +Opera/9.51 (Windows NT 6.0; U; en) +Opera/9.51 (Windows NT 6.0; U; es) +Opera/9.51 (Windows NT 6.0; U; sv) +Opera/9.51 (X11; Linux i686; U; Linux Mint; en) +Opera/9.51 (X11; Linux i686; U; de) +Opera/9.51 (X11; Linux i686; U; fr) +Opera/9.52 (Macintosh; Intel Mac OS X; U; pt) +Opera/9.52 (Macintosh; Intel Mac OS X; U; pt-BR) +Opera/9.52 (Macintosh; PPC Mac OS X; U; fr) +Opera/9.52 (Macintosh; PPC Mac OS X; U; ja) +Opera/9.52 (Windows NT 5.0; U; en) +Opera/9.52 (Windows NT 5.2; U; ru) +Opera/9.52 (Windows NT 6.0; U; Opera/9.52 (X11; Linux x86_64; U); en) +Opera/9.52 (Windows NT 6.0; U; de) +Opera/9.52 (Windows NT 6.0; U; en) +Opera/9.52 (Windows NT 6.0; U; fr) +Opera/9.52 (X11; Linux i686; U; cs) +Opera/9.52 (X11; Linux i686; U; en) +Opera/9.52 (X11; Linux i686; U; fr) +Opera/9.52 (X11; Linux ppc; U; de) +Opera/9.52 (X11; Linux x86_64; U) +Opera/9.52 (X11; Linux x86_64; U; en) +Opera/9.52 (X11; Linux x86_64; U; ru) +Opera/9.60 (Windows NT 5.0; U; en) Presto/2.1.1 +Opera/9.60 (Windows NT 5.1; U; en-GB) Presto/2.1.1 +Opera/9.60 (Windows NT 5.1; U; es-ES) Presto/2.1.1 +Opera/9.60 (Windows NT 5.1; U; sv) Presto/2.1.1 +Opera/9.60 (Windows NT 5.1; U; tr) Presto/2.1.1 +Opera/9.60 (Windows NT 6.0; U; bg) Presto/2.1.1 +Opera/9.60 (Windows NT 6.0; U; de) Presto/2.1.1 +Opera/9.60 (Windows NT 6.0; U; pl) Presto/2.1.1 +Opera/9.60 (Windows NT 6.0; U; ru) Presto/2.1.1 +Opera/9.60 (Windows NT 6.0; U; uk) Presto/2.1.1 +Opera/9.60 (X11; Linux i686; U; en-GB) Presto/2.1.1 +Opera/9.60 (X11; Linux i686; U; ru) Presto/2.1.1 +Opera/9.60 (X11; Linux x86_64; U) +Opera/9.61 (Macintosh; Intel Mac OS X; U; de) Presto/2.1.1 +Opera/9.61 (Windows NT 5.1; U; cs) Presto/2.1.1 +Opera/9.61 (Windows NT 5.1; U; de) Presto/2.1.1 +Opera/9.61 (Windows NT 5.1; U; en) Presto/2.1.1 +Opera/9.61 (Windows NT 5.1; U; en-GB) Presto/2.1.1 +Opera/9.61 (Windows NT 5.1; U; fr) Presto/2.1.1 +Opera/9.61 (Windows NT 5.1; U; ru) Presto/2.1.1 +Opera/9.61 (Windows NT 5.1; U; zh-cn) Presto/2.1.1 +Opera/9.61 (Windows NT 5.1; U; zh-tw) Presto/2.1.1 +Opera/9.61 (Windows NT 5.2; U; en) Presto/2.1.1 +Opera/9.61 (Windows NT 6.0; U; en) Presto/2.1.1 +Opera/9.61 (Windows NT 6.0; U; http://lucideer.com; en-GB) Presto/2.1.1 +Opera/9.61 (Windows NT 6.0; U; pt-BR) Presto/2.1.1 +Opera/9.61 (Windows NT 6.0; U; ru) Presto/2.1.1 +Opera/9.61 (X11; Linux i686; U; de) Presto/2.1.1 +Opera/9.61 (X11; Linux i686; U; en) Presto/2.1.1 +Opera/9.61 (X11; Linux i686; U; pl) Presto/2.1.1 +Opera/9.61 (X11; Linux i686; U; ru) Presto/2.1.1 +Opera/9.61 (X11; Linux x86_64; U; fr) Presto/2.1.1 +Opera/9.62 (Windows NT 5.1; U; pt-BR) Presto/2.1.1 +Opera/9.62 (Windows NT 5.1; U; ru) Presto/2.1.1 +Opera/9.62 (Windows NT 5.1; U; tr) Presto/2.1.1 +Opera/9.62 (Windows NT 5.1; U; zh-cn) Presto/2.1.1 +Opera/9.62 (Windows NT 5.1; U; zh-tw) Presto/2.1.1 +Opera/9.62 (Windows NT 5.2; U; en) Presto/2.1.1 +Opera/9.62 (Windows NT 6.0; U; de) Presto/2.1.1 +Opera/9.62 (Windows NT 6.0; U; en) Presto/2.1.1 +Opera/9.62 (Windows NT 6.0; U; en-GB) Presto/2.1.1 +Opera/9.62 (Windows NT 6.0; U; nb) Presto/2.1.1 +Opera/9.62 (Windows NT 6.0; U; pl) Presto/2.1.1 +Opera/9.62 (Windows NT 6.1; U; de) Presto/2.1.1 +Opera/9.62 (Windows NT 6.1; U; en) Presto/2.1.1 +Opera/9.62 (X11; Linux i686; U; Linux Mint; en) Presto/2.1.1 +Opera/9.62 (X11; Linux i686; U; en) Presto/2.1.1 +Opera/9.62 (X11; Linux i686; U; fi) Presto/2.1.1 +Opera/9.62 (X11; Linux i686; U; it) Presto/2.1.1 +Opera/9.62 (X11; Linux i686; U; pt-BR) Presto/2.1.1 +Opera/9.62 (X11; Linux x86_64; U; en_GB, en_US) Presto/2.1.1 +Opera/9.62 (X11; Linux x86_64; U; ru) Presto/2.1.1 +Opera/9.63 (Windows NT 5.1; U; pt-BR) Presto/2.1.1 +Opera/9.63 (Windows NT 5.2; U; de) Presto/2.1.1 +Opera/9.63 (Windows NT 5.2; U; en) Presto/2.1.1 +Opera/9.63 (Windows NT 6.0; U; cs) Presto/2.1.1 +Opera/9.63 (Windows NT 6.0; U; en) Presto/2.1.1 +Opera/9.63 (Windows NT 6.0; U; fr) Presto/2.1.1 +Opera/9.63 (Windows NT 6.0; U; nb) Presto/2.1.1 +Opera/9.63 (Windows NT 6.0; U; pl) Presto/2.1.1 +Opera/9.63 (Windows NT 6.1; U; de) Presto/2.1.1 +Opera/9.63 (Windows NT 6.1; U; en) Presto/2.1.1 +Opera/9.63 (Windows NT 6.1; U; hu) Presto/2.1.1 +Opera/9.63 (X11; FreeBSD 7.1-RELEASE i386; U; en) Presto/2.1.1 +Opera/9.63 (X11; Linux i686) +Opera/9.63 (X11; Linux i686; U; de) Presto/2.1.1 +Opera/9.63 (X11; Linux i686; U; en) +Opera/9.63 (X11; Linux i686; U; nb) Presto/2.1.1 +Opera/9.63 (X11; Linux i686; U; ru) +Opera/9.63 (X11; Linux i686; U; ru) Presto/2.1.1 +Opera/9.63 (X11; Linux x86_64; U; cs) Presto/2.1.1 +Opera/9.63 (X11; Linux x86_64; U; ru) Presto/2.1.1 +Opera/9.64 (Windows NT 6.0; U; pl) Presto/2.1.1 +Opera/9.64 (Windows NT 6.0; U; zh-cn) Presto/2.1.1 +Opera/9.64 (Windows NT 6.1; U; MRA 5.5 (build 02842); ru) Presto/2.1.1 +Opera/9.64 (Windows NT 6.1; U; de) Presto/2.1.1 +Opera/9.64 (X11; Linux i686; U; Linux Mint; it) Presto/2.1.1 +Opera/9.64 (X11; Linux i686; U; Linux Mint; nb) Presto/2.1.1 +Opera/9.64 (X11; Linux i686; U; da) Presto/2.1.1 +Opera/9.64 (X11; Linux i686; U; de) Presto/2.1.1 +Opera/9.64 (X11; Linux i686; U; en) Presto/2.1.1 +Opera/9.64 (X11; Linux i686; U; nb) Presto/2.1.1 +Opera/9.64 (X11; Linux i686; U; pl) Presto/2.1.1 +Opera/9.64 (X11; Linux i686; U; sv) Presto/2.1.1 +Opera/9.64 (X11; Linux i686; U; tr) Presto/2.1.1 +Opera/9.64 (X11; Linux x86_64; U; cs) Presto/2.1.1 +Opera/9.64 (X11; Linux x86_64; U; de) Presto/2.1.1 +Opera/9.64 (X11; Linux x86_64; U; en) Presto/2.1.1 +Opera/9.64 (X11; Linux x86_64; U; en-GB) Presto/2.1.1 +Opera/9.64 (X11; Linux x86_64; U; hr) Presto/2.1.1 +Opera/9.64 (X11; Linux x86_64; U; pl) Presto/2.1.1 +Opera/9.64(Windows NT 5.1; U; en) Presto/2.1.1 +Opera/9.70 (Linux i686 ; U; ; en) Presto/2.2.1 +Opera/9.70 (Linux i686 ; U; en) Presto/2.2.0 +Opera/9.70 (Linux i686 ; U; en) Presto/2.2.1 +Opera/9.70 (Linux i686 ; U; en-us) Presto/2.2.0 +Opera/9.70 (Linux i686 ; U; zh-cn) Presto/2.2.0 +Opera/9.70 (Linux ppc64 ; U; en) Presto/2.2.1 +Opera/9.80 (J2ME/MIDP; Opera Mini/5.0 (Windows; U; Windows NT 5.1; en) AppleWebKit/886; U; en) Presto/2.4.15 +Opera/9.80 (Linux i686; U; en) Presto/2.5.22 Version/10.51 +Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; de) Presto/2.9.168 Version/11.52 +Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52 +Opera/9.80 (Macintosh; Intel Mac OS X; U; nl) Presto/2.6.30 Version/10.61 +Opera/9.80 (S60; SymbOS; Opera Tablet/9174; U; en) Presto/2.7.81 Version/10.5 +Opera/9.80 (Windows 98; U; de) Presto/2.6.30 Version/10.61 +Opera/9.80 (Windows NT 5.1; U; MRA 5.5 (build 02842); ru) Presto/2.7.62 Version/11.00 +Opera/9.80 (Windows NT 5.1; U; MRA 5.6 (build 03278); ru) Presto/2.6.30 Version/10.63 +Opera/9.80 (Windows NT 5.1; U; cs) Presto/2.2.15 Version/10.10 +Opera/9.80 (Windows NT 5.1; U; cs) Presto/2.7.62 Version/11.01 +Opera/9.80 (Windows NT 5.1; U; de) Presto/2.2.15 Version/10.10 +Opera/9.80 (Windows NT 5.1; U; en) Presto/2.9.168 Version/11.51 +Opera/9.80 (Windows NT 5.1; U; it) Presto/2.7.62 Version/11.00 +Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.6.30 Version/10.62 +Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.2.15 Version/10.00 +Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.22 Version/10.50 +Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.7.39 Version/11.00 +Opera/9.80 (Windows NT 5.1; U; sk) Presto/2.5.22 Version/10.50 +Opera/9.80 (Windows NT 5.1; U; zh-cn) Presto/2.2.15 Version/10.00 +Opera/9.80 (Windows NT 5.1; U; zh-sg) Presto/2.9.181 Version/12.00 +Opera/9.80 (Windows NT 5.1; U; zh-tw) Presto/2.8.131 Version/11.10 +Opera/9.80 (Windows NT 5.1; U;) Presto/2.7.62 Version/11.01 +Opera/9.80 (Windows NT 5.2; U; en) Presto/2.2.15 Version/10.00 +Opera/9.80 (Windows NT 5.2; U; en) Presto/2.6.30 Version/10.63 +Opera/9.80 (Windows NT 5.2; U; ru) Presto/2.5.22 Version/10.51 +Opera/9.80 (Windows NT 5.2; U; ru) Presto/2.6.30 Version/10.61 +Opera/9.80 (Windows NT 5.2; U; ru) Presto/2.7.62 Version/11.01 +Opera/9.80 (Windows NT 5.2; U; zh-cn) Presto/2.6.30 Version/10.63 +Opera/9.80 (Windows NT 6.0; U; Gecko/20100115; pl) Presto/2.2.15 Version/10.10 +Opera/9.80 (Windows NT 6.0; U; cs) Presto/2.5.22 Version/10.51 +Opera/9.80 (Windows NT 6.0; U; de) Presto/2.2.15 Version/10.00 +Opera/9.80 (Windows NT 6.0; U; en) Presto/2.2.15 Version/10.00 +Opera/9.80 (Windows NT 6.0; U; en) Presto/2.2.15 Version/10.10 +Opera/9.80 (Windows NT 6.0; U; en) Presto/2.7.39 Version/11.00 +Opera/9.80 (Windows NT 6.0; U; en) Presto/2.8.99 Version/11.10 +Opera/9.80 (Windows NT 6.0; U; it) Presto/2.6.30 Version/10.61 +Opera/9.80 (Windows NT 6.0; U; nl) Presto/2.6.30 Version/10.60 +Opera/9.80 (Windows NT 6.0; U; pl) Presto/2.10.229 Version/11.62 +Opera/9.80 (Windows NT 6.0; U; pl) Presto/2.7.62 Version/11.01 +Opera/9.80 (Windows NT 6.0; U; zh-cn) Presto/2.5.22 Version/10.50 +Opera/9.80 (Windows NT 6.1 x64; U; en) Presto/2.7.62 Version/11.00 +Opera/9.80 (Windows NT 6.1; Opera Tablet/15165; U; en) Presto/2.8.149 Version/11.1 +Opera/9.80 (Windows NT 6.1; U; cs) Presto/2.2.15 Version/10.00 +Opera/9.80 (Windows NT 6.1; U; cs) Presto/2.7.62 Version/11.01 +Opera/9.80 (Windows NT 6.1; U; de) Presto/2.2.15 Version/10.00 +Opera/9.80 (Windows NT 6.1; U; de) Presto/2.2.15 Version/10.10 +Opera/9.80 (Windows NT 6.1; U; en) Presto/2.2.15 Version/10.00 +Opera/9.80 (Windows NT 6.1; U; en) Presto/2.5.22 Version/10.51 +Opera/9.80 (Windows NT 6.1; U; en) Presto/2.6.30 Version/10.61 +Opera/9.80 (Windows NT 6.1; U; en-GB) Presto/2.7.62 Version/11.00 +Opera/9.80 (Windows NT 6.1; U; en-US) Presto/2.7.62 Version/11.01 +Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00 +Opera/9.80 (Windows NT 6.1; U; fi) Presto/2.2.15 Version/10.00 +Opera/9.80 (Windows NT 6.1; U; fi) Presto/2.7.62 Version/11.00 +Opera/9.80 (Windows NT 6.1; U; fr) Presto/2.5.24 Version/10.52 +Opera/9.80 (Windows NT 6.1; U; ja) Presto/2.5.22 Version/10.50 +Opera/9.80 (Windows NT 6.1; U; ko) Presto/2.7.62 Version/11.00 +Opera/9.80 (Windows NT 6.1; U; pl) Presto/2.6.31 Version/10.70 +Opera/9.80 (Windows NT 6.1; U; pl) Presto/2.7.62 Version/11.00 +Opera/9.80 (Windows NT 6.1; U; sk) Presto/2.6.22 Version/10.50 +Opera/9.80 (Windows NT 6.1; U; sv) Presto/2.7.62 Version/11.01 +Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.2.15 Version/10.00 +Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.5.22 Version/10.50 +Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.6.30 Version/10.61 +Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.6.37 Version/11.00 +Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.7.62 Version/11.01 +Opera/9.80 (Windows NT 6.1; U; zh-tw) Presto/2.5.22 Version/10.50 +Opera/9.80 (Windows NT 6.1; U; zh-tw) Presto/2.7.62 Version/11.01 +Opera/9.80 (Windows NT 6.1; WOW64; U; pt) Presto/2.10.229 Version/11.62 +Opera/9.80 (X11; Linux i686; U; Debian; pl) Presto/2.2.15 Version/10.00 +Opera/9.80 (X11; Linux i686; U; de) Presto/2.2.15 Version/10.00 +Opera/9.80 (X11; Linux i686; U; en) Presto/2.2.15 Version/10.00 +Opera/9.80 (X11; Linux i686; U; en) Presto/2.5.27 Version/10.60 +Opera/9.80 (X11; Linux i686; U; en-GB) Presto/2.2.15 Version/10.00 +Opera/9.80 (X11; Linux i686; U; en-GB) Presto/2.5.24 Version/10.53 +Opera/9.80 (X11; Linux i686; U; es-ES) Presto/2.6.30 Version/10.61 +Opera/9.80 (X11; Linux i686; U; es-ES) Presto/2.8.131 Version/11.11 +Opera/9.80 (X11; Linux i686; U; fr) Presto/2.7.62 Version/11.01 +Opera/9.80 (X11; Linux i686; U; hu) Presto/2.9.168 Version/11.50 +Opera/9.80 (X11; Linux i686; U; it) Presto/2.5.24 Version/10.54 +Opera/9.80 (X11; Linux i686; U; it) Presto/2.7.62 Version/11.00 +Opera/9.80 (X11; Linux i686; U; ja) Presto/2.7.62 Version/11.01 +Opera/9.80 (X11; Linux i686; U; nb) Presto/2.2.15 Version/10.00 +Opera/9.80 (X11; Linux i686; U; pl) Presto/2.2.15 Version/10.00 +Opera/9.80 (X11; Linux i686; U; pl) Presto/2.6.30 Version/10.61 +Opera/9.80 (X11; Linux i686; U; pt-BR) Presto/2.2.15 Version/10.00 +Opera/9.80 (X11; Linux i686; U; ru) Presto/2.2.15 Version/10.00 +Opera/9.80 (X11; Linux i686; U; ru) Presto/2.8.131 Version/11.11 +Opera/9.80 (X11; Linux x86_64; U; Ubuntu/10.10 (maverick); pl) Presto/2.7.62 Version/11.01 +Opera/9.80 (X11; Linux x86_64; U; bg) Presto/2.8.131 Version/11.10 +Opera/9.80 (X11; Linux x86_64; U; de) Presto/2.2.15 Version/10.00 +Opera/9.80 (X11; Linux x86_64; U; en) Presto/2.2.15 Version/10.00 +Opera/9.80 (X11; Linux x86_64; U; en-GB) Presto/2.2.15 Version/10.01 +Opera/9.80 (X11; Linux x86_64; U; fr) Presto/2.9.168 Version/11.50 +Opera/9.80 (X11; Linux x86_64; U; it) Presto/2.2.15 Version/10.10 +Opera/9.80 (X11; Linux x86_64; U; pl) Presto/2.7.62 Version/11.00 +Opera/9.80 (X11; U; Linux i686; en-US; rv:1.9.2.3) Presto/2.2.15 Version/10.10 +Opera/9.99 (Windows NT 5.1; U; pl) Presto/9.9.9 \ No newline at end of file diff --git a/src/assets_linux_tor.qrc b/src/assets_linux_tor.qrc new file mode 100644 index 0000000..4539da6 --- /dev/null +++ b/src/assets_linux_tor.qrc @@ -0,0 +1,5 @@ + + + tor/tor + + diff --git a/src/assets_macos_tor.qrc b/src/assets_macos_tor.qrc new file mode 100644 index 0000000..4539da6 --- /dev/null +++ b/src/assets_macos_tor.qrc @@ -0,0 +1,5 @@ + + + tor/tor + + diff --git a/src/assets_windows_tor.qrc b/src/assets_windows_tor.qrc new file mode 100644 index 0000000..70e0369 --- /dev/null +++ b/src/assets_windows_tor.qrc @@ -0,0 +1,5 @@ + + + tor/tor.exe + + diff --git a/src/calcwidget.cpp b/src/calcwidget.cpp new file mode 100644 index 0000000..cde1d8c --- /dev/null +++ b/src/calcwidget.cpp @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include + +#include "calcwidget.h" +#include "ui_calcwidget.h" +#include "utils/config.h" +#include "mainwindow.h" + +CalcWidget::CalcWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::CalcWidget) +{ + ui->setupUi(this); + + ui->imageExchange->setBackgroundRole(QPalette::Base); + QPixmap pm(":/assets/images/exchange.png"); + ui->imageExchange->setPixmap(pm); + ui->imageExchange->setScaledContents(true); + ui->imageExchange->setFixedSize(26, 26); + + // validator/locale for input + QLocale lo(QLocale::C); + lo.setNumberOptions(QLocale::RejectGroupSeparator); + auto dv = new QDoubleValidator(0.0, 2147483647, 10, this); // [0, 32bit max], 10 decimals of precision + dv->setNotation(QDoubleValidator::StandardNotation); + dv->setLocale(lo); + ui->lineFrom->setValidator(dv); + ui->lineTo->setValidator(dv); + + connect(AppContext::prices, &Prices::fiatPricesUpdated, this, &CalcWidget::initFiat); + connect(AppContext::prices, &Prices::cryptoPricesUpdated, this, &CalcWidget::initCrypto); +} + +void CalcWidget::fromChanged(const QString &data) { + if(!this->m_comboBoxInit) return; + if(this->m_changing){ + this->m_changing = false; + return; + } + + QString symbolFrom = ui->comboCalcFrom->itemText(ui->comboCalcFrom->currentIndex()); + QString symbolTo = ui->comboCalcTo->itemText(ui->comboCalcTo->currentIndex()); + + if(symbolFrom == symbolTo){ + ui->lineTo->setText(data); + return; + } + + QString amount_str = ui->lineFrom->text(); + if(amount_str.startsWith('.')){ + ui->lineFrom->setText(ui->lineTo->text()); + return; + } + + double amount = amount_str.toDouble(); + double result = AppContext::prices->convert(symbolFrom, symbolTo, amount); + + this->m_changing = true; + + int precision = 10; + if(AppContext::prices->rates.contains(symbolTo)) + precision = 2; + + ui->lineTo->setText(QString::number(result, 'f', precision)); +} + +void CalcWidget::toChanged(const QString &data) { + if(!this->m_comboBoxInit) return; + if(this->m_changing){ + this->m_changing = false; + return; + } + + QString symbolFrom = ui->comboCalcFrom->itemText( + ui->comboCalcFrom->currentIndex()); + QString symbolTo = ui->comboCalcTo->itemText( + ui->comboCalcTo->currentIndex()); + + if(symbolFrom == symbolTo){ + ui->lineTo->setText(ui->lineFrom->text()); + return; + } + + QString amount_str = ui->lineTo->text(); + if(amount_str.startsWith('.')){ + ui->lineTo->setText(""); + return; + } + + double amount = amount_str.toDouble(); + double result = AppContext::prices->convert(symbolTo, symbolFrom, amount); + + this->m_changing = true; + + int precision = 10; + if(AppContext::prices->rates.contains(symbolFrom)) + precision = 2; + + ui->lineFrom->setText(QString::number(result, 'f', precision)); +} + +void CalcWidget::toComboChanged(const QString &data) { + this->fromChanged(data); +} + +void CalcWidget::initCrypto() { + if (this->m_ctx == nullptr) + this->m_ctx = MainWindow::getContext(); + + this->initComboBox(); +} + +void CalcWidget::initFiat() { + if(this->m_ctx == nullptr) + this->m_ctx = MainWindow::getContext(); + + this->initComboBox(); +} + +void CalcWidget::initComboBox() { + if(m_comboBoxInit || this->m_ctx == nullptr) return; + QList marketsKeys = AppContext::prices->markets.keys(); + QList ratesKeys = AppContext::prices->rates.keys(); + if(marketsKeys.count() <= 0 || ratesKeys.count() <= 0) return; + + ui->comboCalcFrom->addItems(marketsKeys); + ui->comboCalcFrom->insertSeparator(marketsKeys.count()); + ui->comboCalcFrom->addItems(ratesKeys); + ui->comboCalcFrom->setCurrentIndex(marketsKeys.indexOf("XMR")); + + ui->comboCalcTo->addItems(marketsKeys); + ui->comboCalcTo->insertSeparator(marketsKeys.count()); + ui->comboCalcTo->addItems(ratesKeys); + + auto preferredFiat = config()->get(Config::preferredFiatCurrency).toString(); + ui->comboCalcTo->setCurrentText(preferredFiat); + + this->m_comboBoxInit = true; +} + +CalcWidget::~CalcWidget() { + delete ui; +} diff --git a/src/calcwidget.h b/src/calcwidget.h new file mode 100644 index 0000000..8bd6c50 --- /dev/null +++ b/src/calcwidget.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef CALC_H +#define CALC_H + +#include +#include "appcontext.h" + +namespace Ui { + class CalcWidget; +} + +class CalcWidget : public QWidget +{ +Q_OBJECT + +public: + explicit CalcWidget(QWidget *parent = nullptr); + ~CalcWidget(); + +signals: + void closed(); + +public slots: + void fromChanged(const QString& data); + void toChanged(const QString& data); + void toComboChanged(const QString& data); + void initFiat(); + void initCrypto(); + +private: + Ui::CalcWidget *ui; + AppContext *m_ctx = nullptr; + bool m_comboBoxInit = false; + void initComboBox(); + bool m_changing = false; +}; + +#endif // CALC_H diff --git a/src/calcwidget.ui b/src/calcwidget.ui new file mode 100644 index 0000000..674516b --- /dev/null +++ b/src/calcwidget.ui @@ -0,0 +1,234 @@ + + + CalcWidget + + + + 0 + 0 + 737 + 153 + + + + MainWindow + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + 9 + + + + + Crypto/fiat and fiat/fiat calculator. + + + + + + + Qt::Horizontal + + + + + + + + + 18 + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + From... + + + + + + + + + + + + exchange image + + + + + + + 0 + + + + + + 0 + 0 + + + + false + + + To... + + + + + + + + + + + + + + + + Exchange rates are updated every 2 minutes. + + + + + + + Qt::Vertical + + + + 20 + 170 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + lineFrom + textChanged(QString) + CalcWidget + fromChanged(QString) + + + 119 + 77 + + + 427 + -1 + + + + + lineTo + textChanged(QString) + CalcWidget + toChanged(QString) + + + 463 + 86 + + + 640 + -4 + + + + + comboCalcFrom + currentIndexChanged(QString) + CalcWidget + fromChanged(QString) + + + 196 + 77 + + + 330 + -9 + + + + + comboCalcTo + currentIndexChanged(QString) + CalcWidget + toComboChanged(QString) + + + 574 + 82 + + + 265 + -5 + + + + + + fromChanged(QString) + toChanged(QString) + toComboChanged(QString) + + diff --git a/src/calcwindow.cpp b/src/calcwindow.cpp new file mode 100644 index 0000000..f422c03 --- /dev/null +++ b/src/calcwindow.cpp @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "calcwindow.h" +#include "mainwindow.h" + +#include "ui_calcwindow.h" + +CalcWindow::CalcWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::CalcWindow) +{ + Qt::WindowFlags flags = this->windowFlags(); + this->setWindowFlags(flags|Qt::WindowStaysOnTopHint); // on top + + ui->setupUi(this); + this->setWindowIcon(QIcon("://assets/images/coldcard.png")); + + connect(AppContext::prices, &Prices::fiatPricesUpdated, this, &CalcWindow::initFiat); + connect(AppContext::prices, &Prices::cryptoPricesUpdated, this, &CalcWindow::initCrypto); +} + +void CalcWindow::initFiat() { + this->ui->calcWidget->initFiat(); +} + +void CalcWindow::initCrypto() { + this->ui->calcWidget->initCrypto(); +} + +void CalcWindow::closeEvent(QCloseEvent *foo) { + emit closed(); +} + +CalcWindow::~CalcWindow() { + delete ui; +} diff --git a/src/calcwindow.h b/src/calcwindow.h new file mode 100644 index 0000000..2b5b9ac --- /dev/null +++ b/src/calcwindow.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef CalcWindow_H +#define CalcWindow_H + +#include + +namespace Ui { + class CalcWindow; +} + +class CalcWindow : public QMainWindow +{ +Q_OBJECT + +public: + explicit CalcWindow(QWidget *parent = nullptr); + ~CalcWindow() override; + +signals: + void closed(); + +public slots: + void initFiat(); + void initCrypto(); + +private: + void closeEvent(QCloseEvent *bar) override; + +private: + Ui::CalcWindow *ui; +}; + +#endif // CalcWindow_H diff --git a/src/calcwindow.ui b/src/calcwindow.ui new file mode 100644 index 0000000..1d490cf --- /dev/null +++ b/src/calcwindow.ui @@ -0,0 +1,49 @@ + + + CalcWindow + + + + 0 + 0 + 520 + 108 + + + + Calculator + + + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + + + + + CalcWidget + QWidget +
calcwidget.h
+ 1 +
+
+ + + + stayOnTop(int) + +
diff --git a/src/cli.cpp b/src/cli.cpp new file mode 100644 index 0000000..db2d4ba --- /dev/null +++ b/src/cli.cpp @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "cli.h" + +// libwalletqt +#include "Wallet.h" +#include "libwalletqt/TransactionHistory.h" +#include "libwalletqt/SubaddressAccount.h" +#include "libwalletqt/Subaddress.h" +#include "libwalletqt/AddressBook.h" +#include "libwalletqt/Coins.h" +#include "model/AddressBookModel.h" +#include "model/TransactionHistoryModel.h" +#include "model/SubaddressAccountModel.h" +#include "model/SubaddressModel.h" +#include "model/CoinsModel.h" + +CLI::CLI(AppContext *ctx, QObject *parent) : + QObject(parent), + ctx(ctx) { + connect(this->ctx, &AppContext::walletOpened, this, &CLI::onWalletOpened); + connect(this->ctx, &AppContext::walletOpenedError, this, &CLI::onWalletOpenedError); + connect(this->ctx, &AppContext::walletOpenPasswordNeeded, this, &CLI::onWalletOpenPasswordRequired); +} + +void CLI::run() { + if(mode == CLIMode::CLIModeExportContacts || + mode == CLIMode::CLIModeExportTxHistory) { + if(!ctx->cmdargs->isSet("wallet-file")) return this->finishedError("--wallet-file argument missing"); + if(!ctx->cmdargs->isSet("password")) return this->finishedError("--password argument missing"); + ctx->onOpenWallet(ctx->cmdargs->value("wallet-file"), ctx->cmdargs->value("password")); + } +} + +void CLI::onWalletOpened() { + if(mode == CLIMode::CLIModeExportContacts){ + auto *model = ctx->currentWallet->addressBookModel(); + auto fn = ctx->cmdargs->value("export-contacts"); + if(model->writeCSV(fn)) + this->finished(QString("Address book exported to %1").arg(fn)); + else + this->finishedError("Address book export failure"); + } else if(mode == CLIModeExportTxHistory) { + ctx->currentWallet->history()->refresh(ctx->currentWallet->currentSubaddressAccount()); + auto *model = ctx->currentWallet->history(); + auto fn = ctx->cmdargs->value("export-txhistory"); + if(model->writeCSV(fn)) + this->finished(QString("Transaction history exported to %1").arg(fn)); + else + this->finishedError("Transaction history export failure"); + } +} + +void CLI::onWalletOpenedError(const QString &err) { + if(mode == CLIMode::CLIModeExportContacts || + mode == CLIMode::CLIModeExportTxHistory) + return this->finishedError(err); +} + +void CLI::onWalletOpenPasswordRequired(bool invalidPassword) { + if(mode == CLIMode::CLIModeExportContacts || + mode == CLIMode::CLIModeExportTxHistory) + return this->finishedError("invalid password"); +} + +void CLI::finished(const QString &msg){ + qInfo() << msg; + emit closeApplication(); +} + +void CLI::finishedError(const QString &err) { + qCritical() << err; + emit closeApplication(); +} + +CLI::~CLI() { + ctx->disconnect(); + delete ctx; +} diff --git a/src/cli.h b/src/cli.h new file mode 100644 index 0000000..5398c31 --- /dev/null +++ b/src/cli.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_CLI_H +#define FEATHER_CLI_H + +#include +#include "appcontext.h" + +enum CLIMode { + CLIModeExportContacts, + CLIModeExportTxHistory +}; + +class CLI : public QObject +{ + Q_OBJECT +public: + CLIMode mode; + explicit CLI(AppContext *ctx, QObject *parent = nullptr); + ~CLI() override; + +public slots: + void run(); + + //libwalletqt + void onWalletOpened(); + void onWalletOpenedError(const QString& err); + void onWalletOpenPasswordRequired(bool invalidPassword); + +private: + AppContext *ctx; + +private slots: + void finished(const QString &msg); + void finishedError(const QString &err); + +signals: + void closeApplication(); +}; + +#endif //FEATHER_CLI_H diff --git a/src/coinswidget.cpp b/src/coinswidget.cpp new file mode 100644 index 0000000..60dfe72 --- /dev/null +++ b/src/coinswidget.cpp @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "coinswidget.h" +#include "ui_coinswidget.h" +#include "model/ModelUtils.h" +#include "utils/utils.h" +#include "dialog/outputinfodialog.h" +#include "dialog/outputsweepdialog.h" + +#include +#include +#include +#include +#include + +CoinsWidget::CoinsWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::CoinsWidget) + , m_headerMenu(new QMenu(this)) + , m_copyMenu(new QMenu("Copy",this)) +{ + ui->setupUi(this); + + // header context menu + ui->coins->header()->setContextMenuPolicy(Qt::CustomContextMenu); + m_showSpentAction = m_headerMenu->addAction("Show spent outputs", this, &CoinsWidget::setShowSpent); + m_showSpentAction->setCheckable(true); + connect(ui->coins->header(), &QHeaderView::customContextMenuRequested, this, &CoinsWidget::showHeaderMenu); + + // copy menu + m_copyMenu->setIcon(QIcon(":/assets/images/copy.png")); + m_copyMenu->addAction("Public key", this, [this]{copy(copyField::PubKey);}); + m_copyMenu->addAction("Key Image", this, [this]{copy(copyField::KeyImage);}); + m_copyMenu->addAction("Transaction ID", this, [this]{copy(copyField::TxID);}); + m_copyMenu->addAction("Address", this, [this]{copy(copyField::Address);}); + m_copyMenu->addAction("Height", this, [this]{copy(copyField::Height);}); + m_copyMenu->addAction("Amount", this, [this]{copy(copyField::Amount);}); + + // context menu + ui->coins->setContextMenuPolicy(Qt::CustomContextMenu); + + m_thawOutputAction = new QAction("Thaw output"); + m_freezeOutputAction = new QAction("Freeze output"); + + m_freezeAllSelectedAction = new QAction("Freeze selected"); + m_thawAllSelectedAction = new QAction("Thaw selected"); + + m_viewOutputAction = new QAction(QIcon(":/assets/images/info.png"), "Details"); + m_sweepOutputAction = new QAction("Sweep output"); + connect(m_freezeOutputAction, &QAction::triggered, this, &CoinsWidget::freezeOutput); + connect(m_thawOutputAction, &QAction::triggered, this, &CoinsWidget::thawOutput); + connect(m_viewOutputAction, &QAction::triggered, this, &CoinsWidget::viewOutput); + connect(m_sweepOutputAction, &QAction::triggered, this, &CoinsWidget::onSweepOutput); + + connect(m_freezeAllSelectedAction, &QAction::triggered, this, &CoinsWidget::freezeAllSelected); + connect(m_thawAllSelectedAction, &QAction::triggered, this, &CoinsWidget::thawAllSelected); + + connect(ui->coins, &QTreeView::customContextMenuRequested, this, &CoinsWidget::showContextMenu); +} + +void CoinsWidget::setModel(CoinsModel * model, Coins * coins) { + m_coins = coins; + m_model = model; + m_proxyModel = new CoinsProxyModel; + m_proxyModel->setSourceModel(m_model); + ui->coins->setModel(m_proxyModel); + ui->coins->setColumnHidden(CoinsModel::Spent, true); + ui->coins->setColumnHidden(CoinsModel::SpentHeight, true); + ui->coins->setColumnHidden(CoinsModel::Frozen, true); + + ui->coins->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui->coins->header()->setSectionResizeMode(CoinsModel::AddressLabel, QHeaderView::Stretch); + ui->coins->header()->setSortIndicator(CoinsModel::BlockHeight, Qt::DescendingOrder); + ui->coins->setSortingEnabled(true); +} + +void CoinsWidget::showContextMenu(const QPoint &point) { + QModelIndexList list = ui->coins->selectionModel()->selectedRows(); + + auto *menu = new QMenu(ui->coins); + if (list.size() > 1) { + menu->addAction(m_freezeAllSelectedAction); + menu->addAction(m_thawAllSelectedAction); + } + else { + QModelIndex index = ui->coins->indexAt(point); + if (!index.isValid()) { + return; + } + + int row = m_proxyModel->mapToSource(index).row(); + + bool isSpent, isFrozen, isUnlocked; + m_coins->coin(row, [&isSpent, &isFrozen, &isUnlocked](CoinsInfo &c) { + isSpent = c.spent(); + isFrozen = c.frozen(); + isUnlocked = c.unlocked(); + }); + + menu->addMenu(m_copyMenu); + + if (!isSpent) { + isFrozen ? menu->addAction(m_thawOutputAction) : menu->addAction(m_freezeOutputAction); + } + if (!isFrozen && isUnlocked) { + menu->addAction(m_sweepOutputAction); + } + menu->addAction(m_viewOutputAction); + } + + menu->popup(ui->coins->viewport()->mapToGlobal(point)); +} + +void CoinsWidget::showHeaderMenu(const QPoint& position) +{ + m_headerMenu->popup(QCursor::pos()); +} + +void CoinsWidget::setShowSpent(bool show) +{ + if(!m_proxyModel) return; + m_proxyModel->setShowSpent(show); +} + +void CoinsWidget::freezeOutput() { + QModelIndex index = ui->coins->currentIndex(); + emit freeze(m_proxyModel->mapToSource(index).row()); +} + +void CoinsWidget::freezeAllSelected() { + QModelIndexList list = ui->coins->selectionModel()->selectedRows(); + + QVector indexes; + for (QModelIndex index: list) { + indexes.push_back(m_proxyModel->mapToSource(index).row()); // todo: will segfault if index get invalidated + } + emit freezeMulti(indexes); +} + +void CoinsWidget::thawOutput() { + QModelIndex index = ui->coins->currentIndex(); + emit thaw(m_proxyModel->mapToSource(index).row()); +} + +void CoinsWidget::thawAllSelected() { + QModelIndexList list = ui->coins->selectionModel()->selectedRows(); + + QVector indexes; + for (QModelIndex index: list) { + indexes.push_back(m_proxyModel->mapToSource(index).row()); + } + emit thawMulti(indexes); +} + +void CoinsWidget::viewOutput() { + QModelIndex index = ui->coins->currentIndex(); + + int row = m_proxyModel->mapToSource(index).row(); + QPointer c; + m_coins->coin(row, [&c](CoinsInfo &cInfo) { + c = &cInfo; + }); + + if (c) { + auto * dialog = new OutputInfoDialog(c, this); + dialog->show(); + } +} + +void CoinsWidget::onSweepOutput() { + QModelIndex index = ui->coins->currentIndex(); + int row = m_proxyModel->mapToSource(index).row(); + + QString keyImage; + bool keyImageKnown; + m_coins->coin(row, [&keyImage, &keyImageKnown](CoinsInfo &c) { + keyImageKnown = c.keyImageKnown(); + keyImage = c.keyImage(); + }); + + qCritical() << "key image: " << keyImage; + + if (!keyImageKnown) { + Utils::showMessageBox("Unable to sweep output", "Unable to sweep output: key image unknown", true); + return; + } + + auto * dialog = new OutputSweepDialog(this); + int ret = dialog->exec(); + if (!ret) return; + + qCritical() << "key image: " << keyImage; + + emit sweepOutput(keyImage, dialog->address(), dialog->churn(), dialog->outputs()); +} + +void CoinsWidget::copy(copyField field) { + QModelIndex index = ui->coins->currentIndex(); + int row = m_proxyModel->mapToSource(index).row(); + + QString data; + m_coins->coin(row, [field, &data](CoinsInfo &c) { + switch (field) { + case PubKey: + data = c.pubKey(); + break; + case KeyImage: + data = c.keyImage(); + break; + case TxID: + data = c.hash(); + break; + case Address: + data = c.address(); + break; + case Height: + data = QString::number(c.blockHeight()); + break; + case Amount: + data = c.displayAmount(); + break; + } + }); + + Utils::copyToClipboard(data); +} + +CoinsWidget::~CoinsWidget() { + delete ui; +} diff --git a/src/coinswidget.h b/src/coinswidget.h new file mode 100644 index 0000000..0ff1d8e --- /dev/null +++ b/src/coinswidget.h @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_COINSWIDGET_H +#define FEATHER_COINSWIDGET_H + +#include "appcontext.h" +#include "model/CoinsModel.h" +#include "model/CoinsProxyModel.h" +#include "libwalletqt/Coins.h" + +#include +#include + +namespace Ui { + class CoinsWidget; +} + +class CoinsWidget : public QWidget +{ +Q_OBJECT + +public: + explicit CoinsWidget(QWidget *parent = nullptr); + void setModel(CoinsModel * model, Coins * coins); + ~CoinsWidget() override; + +private slots: + void showHeaderMenu(const QPoint& position); + void setShowSpent(bool show); + void freezeOutput(); + void freezeAllSelected(); + void thawOutput(); + void thawAllSelected(); + void viewOutput(); + void onSweepOutput(); + +signals: + void freeze(int index); + void freezeMulti(QVector); + void thaw(int index); + void thawMulti(QVector); + void sweepOutput(const QString &keyImage, const QString &address, bool isChurn, int outputs); + +private: + enum copyField { + PubKey = 0, + KeyImage, + TxID, + Address, + Height, + Amount + }; + + Ui::CoinsWidget *ui; + + QMenu *m_contextMenu; + QMenu *m_copyMenu; + QAction *m_showSpentAction; + QMenu *m_headerMenu; + QAction *m_freezeOutputAction; + QAction *m_freezeAllSelectedAction; + QAction *m_thawOutputAction; + QAction *m_thawAllSelectedAction; + QAction *m_viewOutputAction; + QAction *m_sweepOutputAction; + Coins *m_coins; + CoinsModel * m_model; + CoinsProxyModel * m_proxyModel; + + void showContextMenu(const QPoint & point); + void copy(copyField field); +}; + + +#endif //FEATHER_COINSWIDGET_H diff --git a/src/coinswidget.ui b/src/coinswidget.ui new file mode 100644 index 0000000..cddca31 --- /dev/null +++ b/src/coinswidget.ui @@ -0,0 +1,49 @@ + + + CoinsWidget + + + + 0 + 0 + 782 + 444 + + + + Form + + + + 7 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::ExtendedSelection + + + false + + + false + + + + + + + + diff --git a/src/components.cpp b/src/components.cpp new file mode 100644 index 0000000..0fc5e39 --- /dev/null +++ b/src/components.cpp @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "components.h" + +#include + +StatusBarButton::StatusBarButton(const QIcon &icon, const QString &tooltip, QWidget *parent) : QPushButton(parent) { + setIcon(icon); + setToolTip(tooltip); + setFlat(true); + setMaximumWidth(20); + setIconSize(QSize(20,20)); + setCursor(QCursor(Qt::PointingHandCursor)); +} + +WWLabel::WWLabel(const QString& text, QWidget *parent) : QLabel(text, parent){ + setWordWrap(true); + setTextInteractionFlags(Qt::TextSelectableByMouse); +} + +PasswordLineEdit::PasswordLineEdit(QWidget *parent) : QLineEdit(parent) { + setEchoMode(Password); +} + +Buttons::Buttons(QPushButton* arr[], int size, QWidget *parent) : QHBoxLayout(parent) { + addStretch(); + for (int n=0; n < size; n++) { + addWidget(arr[n]); + } +} + +OkButton::OkButton(QDialog *dialog, const QString& label = nullptr, QWidget *parent) : QPushButton(parent){ + setText(label == nullptr ? label : "OK"); + connect(this, &OkButton::clicked, dialog, &QDialog::accept); + setDefault(true); +} + +CloseButton::CloseButton(QDialog *dialog, QWidget *parent) : QPushButton(parent) { + setText("Close"); + connect(this, &CloseButton::clicked, dialog, &QDialog::close); + setDefault(true); +} + +ButtonsTextEdit::ButtonsTextEdit(const QString &text) : QPlainTextEdit(text) { + +} + +void ButtonsTextEdit::setText(const QString &text) { + this->setPlainText(text); +} + +QString ButtonsTextEdit::text(){ + return this->toPlainText(); +} + +void HelpLabel::setHelpText(const QString &text) +{ + this->help_text = text; +} + +HelpLabel::HelpLabel(QWidget *parent) : QLabel(parent) +{ + this->help_text = "help_text"; + this->font = QFont(); +} + +void HelpLabel::mouseReleaseEvent(QMouseEvent *event) +{ + Q_UNUSED(event) + QMessageBox msgBox(QApplication::activeWindow()); + msgBox.setText(this->help_text); + msgBox.exec(); +} + +void HelpLabel::enterEvent(QEvent *event) +{ + font.setUnderline(true); + setFont(font); + QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor)); + return QLabel::enterEvent(event); +} + +void HelpLabel::leaveEvent(QEvent *event) +{ + font.setUnderline(false); + setFont(font); + QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); + return QLabel::leaveEvent(event); +} + +ClickableLabel::ClickableLabel(QWidget* parent, Qt::WindowFlags f) + : QLabel(parent) { +} + +ClickableLabel::~ClickableLabel() = default; + +void ClickableLabel::mousePressEvent(QMouseEvent* event) { + emit clicked(); +} \ No newline at end of file diff --git a/src/components.h b/src/components.h new file mode 100644 index 0000000..5a9772f --- /dev/null +++ b/src/components.h @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef COMP_H +#define COMP_H + +#include +#include +#include +#include +#include +#include + +class StatusBarButton : public QPushButton +{ + Q_OBJECT + +public: + explicit StatusBarButton(const QIcon &icon, const QString &tooltip, QWidget *parent = nullptr); +}; + +class WWLabel : public QLabel +{ + Q_OBJECT + +public: + explicit WWLabel(const QString& label="", QWidget *parent = nullptr); +}; + +class PasswordLineEdit : public QLineEdit +{ + Q_OBJECT + +public: + explicit PasswordLineEdit(QWidget *parent = nullptr); +}; + +class Buttons : public QHBoxLayout +{ + Q_OBJECT + +public: + explicit Buttons(QPushButton* arr[], int size, QWidget *parent = nullptr); +}; + + +class CloseButton : public QPushButton +{ +Q_OBJECT + +public: + explicit CloseButton(QDialog *dialog, QWidget *parent = nullptr); +}; + +class OkButton : public QPushButton +{ +Q_OBJECT + +public: + explicit OkButton(QDialog *dialog, const QString& label, QWidget *parent = nullptr); +}; + + +class ButtonsTextEdit : public QPlainTextEdit +{ + Q_OBJECT + +public: + void setText(const QString &text); + QString text(); + + explicit ButtonsTextEdit(const QString &text = ""); +}; + +class HelpLabel : public QLabel +{ + Q_OBJECT + +public: + QString help_text; + QFont font; + void setHelpText(const QString &text); + + explicit HelpLabel(QWidget * parent); + +protected: + void mouseReleaseEvent(QMouseEvent *event) override; + void enterEvent(QEvent *event) override; + void leaveEvent(QEvent *event) override; +}; + +class ClickableLabel : public QLabel { +Q_OBJECT + +public: + explicit ClickableLabel(QWidget* parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()); + ~ClickableLabel() override; + +signals: + void clicked(); + +protected: + void mousePressEvent(QMouseEvent* event) override; + +}; +#endif diff --git a/src/contactswidget.cpp b/src/contactswidget.cpp new file mode 100644 index 0000000..8093fc6 --- /dev/null +++ b/src/contactswidget.cpp @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "contactswidget.h" +#include "ui_contactswidget.h" +#include "dialog/contactsdialog.h" +#include "model/ModelUtils.h" +#include "utils/utils.h" + +#include +#include +#include + +ContactsWidget::ContactsWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::ContactsWidget) +{ + ui->setupUi(this); + + // header context menu + ui->contacts->header()->setContextMenuPolicy(Qt::CustomContextMenu); + m_headerMenu = new QMenu(this); + m_showFullAddressesAction = m_headerMenu->addAction("Show full addresses", this, &ContactsWidget::setShowFullAddresses); + m_showFullAddressesAction->setCheckable(true); + + connect(ui->contacts->header(), &QHeaderView::customContextMenuRequested, this, &ContactsWidget::showHeaderMenu); + + // context menu + ui->contacts->setContextMenuPolicy(Qt::CustomContextMenu); + m_contextMenu = new QMenu(ui->contacts); + m_contextMenu->addAction(QIcon(":/assets/images/person.svg"), "New contact", this, &ContactsWidget::newContact); + + + // row context menu + m_rowMenu = new QMenu(ui->contacts); + m_rowMenu->addAction(QIcon(":/assets/images/copy.png"), "Copy address", this, &ContactsWidget::copyAddress); + m_rowMenu->addAction(QIcon(":/assets/images/copy.png"), "Copy name", this, &ContactsWidget::copyName); + m_rowMenu->addAction(QIcon(":/assets/images/appicons/128x128.png"), "Pay to", this, &ContactsWidget::payTo); + m_deleteEntryAction = m_rowMenu->addAction("Delete", this, &ContactsWidget::deleteContact); + + connect(ui->contacts, &QTreeView::customContextMenuRequested, [=](const QPoint & point){ + QModelIndex index = ui->contacts->indexAt(point); + if (index.isValid()) { + m_rowMenu->exec(ui->contacts->viewport()->mapToGlobal(point)); + } + else { + m_contextMenu->exec(ui->contacts->viewport()->mapToGlobal(point)); + } + }); + + connect(ui->search, &QLineEdit::textChanged, this, &ContactsWidget::setSearchFilter); +} + +void ContactsWidget::copyAddress() { + QModelIndex index = ui->contacts->currentIndex(); + ModelUtils::copyColumn(&index, AddressBookModel::Address); +} + +void ContactsWidget::copyName() { + QModelIndex index = ui->contacts->currentIndex(); + ModelUtils::copyColumn(&index, AddressBookModel::Description); +} + +void ContactsWidget::payTo() { + QModelIndex index = ui->contacts->currentIndex(); + QString address = index.model()->data(index.siblingAtColumn(AddressBookModel::Address), Qt::UserRole).toString(); + emit fillAddress(address); +} + +void ContactsWidget::setModel(AddressBookModel *model) +{ + m_model = model; + m_proxyModel = new AddressBookProxyModel; + m_proxyModel->setSourceModel(m_model); + ui->contacts->setModel(m_proxyModel); + + ui->contacts->setSortingEnabled(true); + ui->contacts->header()->setSectionResizeMode(AddressBookModel::Address, QHeaderView::Stretch); + ui->contacts->header()->setSectionResizeMode(AddressBookModel::Description, QHeaderView::ResizeToContents); + ui->contacts->header()->setMinimumSectionSize(200); +} + +void ContactsWidget::setShowFullAddresses(bool show) { + m_model->setShowFullAddresses(show); +} + +void ContactsWidget::setSearchFilter(const QString &filter) { + if(!m_proxyModel) return; + m_proxyModel->setSearchFilter(filter); +} + +void ContactsWidget::showHeaderMenu(const QPoint& position) +{ + m_showFullAddressesAction->setChecked(m_model->isShowFullAddresses()); + m_headerMenu->exec(QCursor::pos()); +} + +void ContactsWidget::newContact() +{ + auto * dialog = new ContactsDialog(this); + int ret = dialog->exec(); + if (!ret) return; + + QString address = dialog->getAddress(); + QString name = dialog->getName(); + + emit addContact(address, name); +} + +void ContactsWidget::deleteContact() +{ + QModelIndex index = ui->contacts->currentIndex(); + m_model->deleteRow(m_proxyModel->mapToSource(index).row()); +} + +ContactsWidget::~ContactsWidget() +{ + delete ui; +} diff --git a/src/contactswidget.h b/src/contactswidget.h new file mode 100644 index 0000000..3859d15 --- /dev/null +++ b/src/contactswidget.h @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef CONTACTSWIDGET_H +#define CONTACTSWIDGET_H + +#include "model/AddressBookModel.h" +#include "model/AddressBookProxyModel.h" + +#include +#include + +namespace Ui { +class ContactsWidget; +} + +class ContactsWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ContactsWidget(QWidget *parent = nullptr); + void setModel(AddressBookModel * model); + ~ContactsWidget(); + +public slots: + void copyAddress(); + void copyName(); + void payTo(); + void newContact(); + void deleteContact(); + void setShowFullAddresses(bool show); + void setSearchFilter(const QString &filter); + +signals: + void addContact(QString &address, QString &name); + void fillAddress(QString &address); + +private slots: + void showHeaderMenu(const QPoint& position); + +private: + Ui::ContactsWidget *ui; + + QAction *m_showFullAddressesAction; + QAction *m_deleteEntryAction; + QMenu *m_rowMenu; + QMenu *m_contextMenu; + QMenu *m_headerMenu; + AddressBookModel * m_model; + AddressBookProxyModel * m_proxyModel; +}; + +#endif // CONTACTSWIDGET_H diff --git a/src/contactswidget.ui b/src/contactswidget.ui new file mode 100644 index 0000000..69151e6 --- /dev/null +++ b/src/contactswidget.ui @@ -0,0 +1,53 @@ + + + ContactsWidget + + + + 0 + 0 + 589 + 416 + + + + Form + + + + 9 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Search contacts... + + + + + + + false + + + false + + + + + + + + diff --git a/src/dialog/aboutdialog.cpp b/src/dialog/aboutdialog.cpp new file mode 100644 index 0000000..5563425 --- /dev/null +++ b/src/dialog/aboutdialog.cpp @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "aboutdialog.h" +#include "ui_aboutdialog.h" +#include "utils/utils.h" +#include "config-feather.h" + +AboutDialog::AboutDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::AboutDialog) +{ + ui->setupUi(this); + this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png")); + // cute fox (c) Diego "rehrar" Salazar :-D + QPixmap p(":assets/images/cutexmrfox.png"); + ui->aboutImage->setPixmap(p.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + auto about = Utils::fileOpenQRC(":assets/about.txt"); + auto about_text = Utils::barrayToString(about); + about_text = about_text.replace("", FEATHER_VERSION); + about_text = about_text.replace("", FEATHER_BRANCH); + about_text = about_text.replace("", QString::number(QDate::currentDate().year())); + ui->copyrightText->setPlainText(about_text); + + auto ack = Utils::fileOpenQRC(":assets/ack.txt"); + auto ack_text = Utils::barrayToString(ack); + ui->ackText->setText(ack_text); + + auto sm = QApplication::font(); + auto font = QApplication::font(); + sm.setPointSize(sm.pointSize() - 2); + this->m_model = new QStandardItemModel(this); + this->m_model->setHorizontalHeaderItem(0, Utils::qStandardItem("Name", sm)); + this->m_model->setHorizontalHeaderItem(1, Utils::qStandardItem("Email", sm)); + ui->authorView->setModel(this->m_model); + + int i = 0; + auto contributors = Utils::barrayToString(Utils::fileOpenQRC(":assets/contributors.txt")); + for(const auto &line: contributors.split("\n")){ + // too lazy for regex #sorry #notsorry + auto name = line.left(line.indexOf("<")).trimmed(); + auto nameItem = Utils::qStandardItem(name, font); + auto email = line.mid(line.indexOf("<")+1, line.length()).replace(">", "").trimmed(); + auto emailItem = Utils::qStandardItem(email, font); + + this->m_model->setItem(i, 0, nameItem); + this->m_model->setItem(i, 1, emailItem); + i++; + } + + ui->authorView->header()->setSectionResizeMode(QHeaderView::Stretch); + + this->adjustSize(); +} + +AboutDialog::~AboutDialog() { + delete ui; +} + diff --git a/src/dialog/aboutdialog.h b/src/dialog/aboutdialog.h new file mode 100644 index 0000000..6dbce29 --- /dev/null +++ b/src/dialog/aboutdialog.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef ABOUT_H +#define ABOUT_H + +#include +#include +#include + +namespace Ui { + class AboutDialog; +} + +class AboutDialog : public QDialog +{ +Q_OBJECT + +public: + explicit AboutDialog(QWidget *parent = nullptr); + ~AboutDialog() override; + +private: + QStandardItemModel *m_model; + Ui::AboutDialog *ui; +}; + +#endif // ABOUT_H diff --git a/src/dialog/aboutdialog.ui b/src/dialog/aboutdialog.ui new file mode 100644 index 0000000..e68c094 --- /dev/null +++ b/src/dialog/aboutdialog.ui @@ -0,0 +1,111 @@ + + + AboutDialog + + + + 0 + 0 + 750 + 623 + + + + + 750 + 0 + + + + About + + + + + + 0 + + + + Feather + + + + + + image + + + Qt::AlignCenter + + + + + + + a free, open-source Monero wallet + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 420 + + + + true + + + + + + + + Authors + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + + + + + + Acknowledgements + + + + + + true + + + + + + + + + + + + diff --git a/src/dialog/contactsdialog.cpp b/src/dialog/contactsdialog.cpp new file mode 100644 index 0000000..bf0e207 --- /dev/null +++ b/src/dialog/contactsdialog.cpp @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "ui_contactsdialog.h" +#include "contactsdialog.h" + +ContactsDialog::ContactsDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::ContactsDialog) +{ + ui->setupUi(this); + setMinimumWidth(400); + + connect(ui->buttonBox, &QDialogButtonBox::accepted, [&](){ + m_address = ui->lineEdit_address->text(); + m_name = ui->lineEdit_name->text(); + }); + + this->adjustSize(); +} + +ContactsDialog::~ContactsDialog() +{ + delete ui; +} + +QString ContactsDialog::getAddress() { + return m_address; +} + +QString ContactsDialog::getName() { + return m_name; +} \ No newline at end of file diff --git a/src/dialog/contactsdialog.h b/src/dialog/contactsdialog.h new file mode 100644 index 0000000..1bb231e --- /dev/null +++ b/src/dialog/contactsdialog.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_CONTACTSDIALOG_H +#define FEATHER_CONTACTSDIALOG_H + +#include + +namespace Ui { + class ContactsDialog; +} + +class ContactsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ContactsDialog(QWidget *parent = nullptr); + ~ContactsDialog() override; + + QString getAddress(); + QString getName(); + +private: + Ui::ContactsDialog *ui; + + QString m_address; + QString m_name; +}; + +#endif //FEATHER_CONTACTSDIALOG_H diff --git a/src/dialog/contactsdialog.ui b/src/dialog/contactsdialog.ui new file mode 100644 index 0000000..1ec06bb --- /dev/null +++ b/src/dialog/contactsdialog.ui @@ -0,0 +1,88 @@ + + + ContactsDialog + + + + 0 + 0 + 400 + 136 + + + + New Contact + + + + + + + + Address + + + + + + + Name + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + ContactsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ContactsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialog/debuginfodialog.cpp b/src/dialog/debuginfodialog.cpp new file mode 100644 index 0000000..aa3c1ae --- /dev/null +++ b/src/dialog/debuginfodialog.cpp @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "debuginfodialog.h" +#include "ui_debuginfodialog.h" +#include "config-feather.h" +#include "utils/utils.h" + +#include +#include + +DebugInfoDialog::DebugInfoDialog(AppContext *ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::DebugInfoDialog) +{ + ui->setupUi(this); + + QString torStatus; + if(ctx->isTorSocks) + torStatus = "Torsocks"; + else if(ctx->tor->localTor) + torStatus = "Local (assumed to be running)"; + else if(ctx->tor->torConnected) + torStatus = "Running"; + else + torStatus = "Unknown"; + + ui->label_featherVersion->setText(QString("%1-%2").arg(FEATHER_VERSION, FEATHER_BRANCH)); + ui->label_moneroVersion->setText(QString("%1-%2").arg(MONERO_VERSION, MONERO_BRANCH)); + + ui->label_walletHeight->setText(QString::number(ctx->currentWallet->blockChainHeight())); + ui->label_daemonHeight->setText(QString::number(ctx->currentWallet->daemonBlockChainHeight())); + ui->label_restoreHeight->setText(QString::number(ctx->currentWallet->getWalletCreationHeight())); + ui->label_synchronized->setText(ctx->currentWallet->synchronized() ? "True" : "False"); + + auto node = ctx->nodes->connection(); + ui->label_remoteNode->setText(node.full); + ui->label_walletStatus->setText(this->statusToString(ctx->currentWallet->connected())); + ui->label_torStatus->setText(torStatus); + ui->label_websocketStatus->setText(Utils::QtEnumToString(ctx->ws->webSocket.state())); + + ui->label_netType->setText(Utils::QtEnumToString(ctx->currentWallet->nettype())); + ui->label_seedType->setText(ctx->currentWallet->getCacheAttribute("feather.seed").isEmpty() ? "25 word" : "14 word"); + ui->label_viewOnly->setText(ctx->currentWallet->viewOnly() ? "True" : "False"); + + ui->label_OS->setText(QSysInfo::prettyProductName()); + ui->label_timestamp->setText(QString::number(QDateTime::currentSecsSinceEpoch())); + + connect(ui->btn_Copy, &QPushButton::clicked, this, &DebugInfoDialog::copyToClipboad); + + this->adjustSize(); +} + +QString DebugInfoDialog::statusToString(Wallet::ConnectionStatus status) { + switch (status) { + case Wallet::ConnectionStatus_Disconnected: + return "Disconnected"; + case Wallet::ConnectionStatus_Connected: + return "Connected"; + case Wallet::ConnectionStatus_WrongVersion: + return "Daemon wrong version"; + case Wallet::ConnectionStatus_Connecting: + return "Connecting"; + default: + return "Unknown"; + } +} + +void DebugInfoDialog::copyToClipboad() { + QString text = ""; + text += QString("Feather version: %1\n").arg(ui->label_featherVersion->text()); + text += QString("Monero version: %1\n").arg(ui->label_moneroVersion->text()); + + text += QString("Wallet height: %1\n").arg(ui->label_walletHeight->text()); + text += QString("Daemon height: %1\n").arg(ui->label_daemonHeight->text()); + text += QString("Restore height: %1\n").arg(ui->label_restoreHeight->text()); + text += QString("Synchronized: %1\n").arg(ui->label_synchronized->text()); + + text += QString("Remote node: %1\n").arg(ui->label_remoteNode->text()); + text += QString("Wallet status: %1\n").arg(ui->label_walletStatus->text()); + text += QString("Tor status: %1\n").arg(ui->label_torStatus->text()); + text += QString("Websocket status: %1\n").arg(ui->label_websocketStatus->text()); + + text += QString("Network type: %1\n").arg(ui->label_netType->text()); + text += QString("Seed type: %1\n").arg(ui->label_seedType->text()); + text += QString("View only: %1\n").arg(ui->label_viewOnly->text()); + + text += QString("Operating system: %1\n").arg(ui->label_OS->text()); + text += QString("Timestamp: %1\n").arg(ui->label_timestamp->text()); + + Utils::copyToClipboard(text); +} + +DebugInfoDialog::~DebugInfoDialog() { + delete ui; +} diff --git a/src/dialog/debuginfodialog.h b/src/dialog/debuginfodialog.h new file mode 100644 index 0000000..2443df1 --- /dev/null +++ b/src/dialog/debuginfodialog.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_DEBUGINFODIALOG_H +#define FEATHER_DEBUGINFODIALOG_H + +#include +#include "appcontext.h" +#include "libwalletqt/Wallet.h" + +namespace Ui { + class DebugInfoDialog; +} + +class DebugInfoDialog : public QDialog +{ + Q_OBJECT + +public: + explicit DebugInfoDialog(AppContext *ctx, QWidget *parent = nullptr); + ~DebugInfoDialog() override; + +private: + QString statusToString(Wallet::ConnectionStatus status); + void copyToClipboad(); + + Ui::DebugInfoDialog *ui; +}; + +#endif //FEATHER_DEBUGINFODIALOG_H diff --git a/src/dialog/debuginfodialog.ui b/src/dialog/debuginfodialog.ui new file mode 100644 index 0000000..646dd4d --- /dev/null +++ b/src/dialog/debuginfodialog.ui @@ -0,0 +1,359 @@ + + + DebugInfoDialog + + + + 0 + 0 + 693 + 580 + + + + Debug Info + + + + + + + + Feather version: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Monero version: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Qt::Horizontal + + + + + + + Wallet height: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Daemon height: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Restore height: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Synchronized: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Qt::Horizontal + + + + + + + Remote node: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Wallet status: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Tor status: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Websocket status: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Qt::Horizontal + + + + + + + Network type: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Seed type: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + View only: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Timestamp: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Operating system: + + + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + + + + + + + + Copy + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + DebugInfoDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + DebugInfoDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialog/keysdialog.cpp b/src/dialog/keysdialog.cpp new file mode 100644 index 0000000..11fffb5 --- /dev/null +++ b/src/dialog/keysdialog.cpp @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "keysdialog.h" +#include "ui_keysdialog.h" + +KeysDialog::KeysDialog(AppContext *ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::KeysDialog) +{ + ui->setupUi(this); + + ui->label_restoreHeight->setText(QString::number(ctx->currentWallet->getWalletCreationHeight())); + ui->label_primaryAddress->setText(ctx->currentWallet->address(0, 0)); + ui->label_secretSpendKey->setText(ctx->currentWallet->getSecretSpendKey()); + ui->label_secretViewKey->setText(ctx->currentWallet->getSecretViewKey()); + ui->label_publicSpendKey->setText(ctx->currentWallet->getPublicSpendKey()); + ui->label_publicViewKey->setText(ctx->currentWallet->getPublicViewKey()); + + this->adjustSize(); +} + +KeysDialog::~KeysDialog() +{ + delete ui; +} diff --git a/src/dialog/keysdialog.h b/src/dialog/keysdialog.h new file mode 100644 index 0000000..8a89605 --- /dev/null +++ b/src/dialog/keysdialog.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_KEYSDIALOG_H +#define FEATHER_KEYSDIALOG_H + +#include +#include "appcontext.h" + +namespace Ui { + class KeysDialog; +} + +class KeysDialog : public QDialog +{ +Q_OBJECT + +public: + explicit KeysDialog(AppContext *ctx, QWidget *parent = nullptr); + ~KeysDialog() override; + +private: + Ui::KeysDialog *ui; +}; + + +#endif //FEATHER_KEYSDIALOG_H diff --git a/src/dialog/keysdialog.ui b/src/dialog/keysdialog.ui new file mode 100644 index 0000000..84a90b9 --- /dev/null +++ b/src/dialog/keysdialog.ui @@ -0,0 +1,178 @@ + + + KeysDialog + + + + 0 + 0 + 747 + 543 + + + + Keys + + + + + + Restore height + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + Primary address + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + Secret spend key + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + Secret view key + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + Public spend key + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + Public view key + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + KeysDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + KeysDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialog/outputinfodialog.cpp b/src/dialog/outputinfodialog.cpp new file mode 100644 index 0000000..800b1c8 --- /dev/null +++ b/src/dialog/outputinfodialog.cpp @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "outputinfodialog.h" +#include "ui_outputinfodialog.h" +#include "model/ModelUtils.h" +#include "libwalletqt/CoinsInfo.h" +#include "utils/utils.h" + +#include + +OutputInfoDialog::OutputInfoDialog(CoinsInfo *cInfo, QWidget *parent) + : QDialog(parent) + , ui(new Ui::OutputInfoDialog) +{ + ui->setupUi(this); + + QFont font = ModelUtils::getMonospaceFont(); + ui->label_pubKey->setFont(font); + ui->label_keyImage->setFont(font); + ui->label_txid->setFont(font); + ui->label_address->setFont(font); + + ui->label_pubKey->setText(cInfo->pubKey()); + ui->label_keyImage->setText(cInfo->keyImage()); + ui->label_txid->setText(cInfo->hash()); + ui->label_address->setText(cInfo->address()); + + QString status = cInfo->spent() ? "spent" : (cInfo->frozen() ? "frozen" : "unspent"); + ui->label_status->setText(status); + ui->label_amount->setText(QString("%1 XMR").arg(cInfo->displayAmount())); + ui->label_creationHeight->setText(QString::number(cInfo->blockHeight())); + ui->label_globalIndex->setText(QString::number(cInfo->globalOutputIndex())); + ui->label_internalIndex->setText(QString::number(cInfo->internalOutputIndex())); + + QString spentHeight = QVariant(cInfo->spentHeight()).toString(); + if (spentHeight == "0") spentHeight = "n/a"; + ui->label_spentHeight->setText(spentHeight); + + this->adjustSize(); +} + +OutputInfoDialog::~OutputInfoDialog() { + delete ui; +} diff --git a/src/dialog/outputinfodialog.h b/src/dialog/outputinfodialog.h new file mode 100644 index 0000000..481e81b --- /dev/null +++ b/src/dialog/outputinfodialog.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_OUTPUTINFODIALOG_H +#define FEATHER_OUTPUTINFODIALOG_H + +#include +#include "libwalletqt/Coins.h" +#include "libwalletqt/CoinsInfo.h" + +namespace Ui { + class OutputInfoDialog; +} + +class OutputInfoDialog : public QDialog +{ +Q_OBJECT + +public: + explicit OutputInfoDialog(CoinsInfo *cInfo, QWidget *parent = nullptr); + ~OutputInfoDialog() override; + +private: + Ui::OutputInfoDialog *ui; +}; + + +#endif //FEATHER_OUTPUTINFODIALOG_H diff --git a/src/dialog/outputinfodialog.ui b/src/dialog/outputinfodialog.ui new file mode 100644 index 0000000..ed1086f --- /dev/null +++ b/src/dialog/outputinfodialog.ui @@ -0,0 +1,234 @@ + + + OutputInfoDialog + + + + 0 + 0 + 865 + 474 + + + + Output + + + + + + Public Key: + + + + + + pubkey + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + Key Image: + + + + + + false + + + key image + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + Created in tx: + + + + + + txid + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + Address: + + + + + + address + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + + + + + Status: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Global index: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Amount: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + Qt::Vertical + + + + + + + + + Spent height: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Creation height: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Tx index: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + diff --git a/src/dialog/outputsweepdialog.cpp b/src/dialog/outputsweepdialog.cpp new file mode 100644 index 0000000..1b4bcaf --- /dev/null +++ b/src/dialog/outputsweepdialog.cpp @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "ui_outputsweepdialog.h" +#include "outputsweepdialog.h" + +OutputSweepDialog::OutputSweepDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::OutputSweepDialog) +{ + ui->setupUi(this); + + connect(ui->checkBox_churn, &QCheckBox::toggled, [&](bool toggled){ + ui->lineEdit_address->setEnabled(!toggled); + }); + + connect(ui->buttonBox, &QDialogButtonBox::accepted, [&](){ + m_address = ui->lineEdit_address->text(); + m_churn = ui->checkBox_churn->isChecked(); + m_outputs = ui->spinBox_numOutputs->value(); + }); + + this->adjustSize(); +} + +OutputSweepDialog::~OutputSweepDialog() +{ + delete ui; +} + +QString OutputSweepDialog::address() { + return m_address; +} + +bool OutputSweepDialog::churn() const { + return m_churn; +} + +int OutputSweepDialog::outputs() const { + return m_outputs; +} \ No newline at end of file diff --git a/src/dialog/outputsweepdialog.h b/src/dialog/outputsweepdialog.h new file mode 100644 index 0000000..ecfbe8d --- /dev/null +++ b/src/dialog/outputsweepdialog.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_OUTPUTSWEEPDIALOG_H +#define FEATHER_OUTPUTSWEEPDIALOG_H + +#include + +namespace Ui { + class OutputSweepDialog; +} + +class OutputSweepDialog : public QDialog +{ +Q_OBJECT + +public: + explicit OutputSweepDialog(QWidget *parent = nullptr); + ~OutputSweepDialog() override; + + QString address(); + bool churn() const; + int outputs() const; + +private: + Ui::OutputSweepDialog *ui; + + QString m_address; + bool m_churn; + int m_outputs; +}; + + +#endif //FEATHER_OUTPUTSWEEPDIALOG_H diff --git a/src/dialog/outputsweepdialog.ui b/src/dialog/outputsweepdialog.ui new file mode 100644 index 0000000..e6abab4 --- /dev/null +++ b/src/dialog/outputsweepdialog.ui @@ -0,0 +1,130 @@ + + + OutputSweepDialog + + + + 0 + 0 + 623 + 231 + + + + Sweep output + + + + + + + + Address: + + + + + + + true + + + + 500 + 0 + + + + + + + + + + Send to self (churn) + + + + + + + Advanced options + + + true + + + false + + + + QFormLayout::ExpandingFieldsGrow + + + + + Number of outputs: + + + + + + + 1 + + + 16 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + OutputSweepDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + OutputSweepDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialog/passwordchangedialog.cpp b/src/dialog/passwordchangedialog.cpp new file mode 100644 index 0000000..175d86e --- /dev/null +++ b/src/dialog/passwordchangedialog.cpp @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "passwordchangedialog.h" +#include "ui_passwordchangedialog.h" + +#include + +PasswordChangeDialog::PasswordChangeDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::PasswordChangeDialog) +{ + ui->setupUi(this); + ui->icon->setPixmap(QPixmap(":/assets/images/lock.png").scaledToWidth(32, Qt::SmoothTransformation)); + + connect(ui->lineEdit_newPassword, &QLineEdit::textChanged, this, &PasswordChangeDialog::passwordsMatch); + connect(ui->lineEdit_confirmPassword, &QLineEdit::textChanged, this, &PasswordChangeDialog::passwordsMatch); + + this->adjustSize(); +} + +PasswordChangeDialog::~PasswordChangeDialog() +{ + delete ui; +} + +QString PasswordChangeDialog::getCurrentPassword() { + return ui->lineEdit_currentPassword->text(); +} + +QString PasswordChangeDialog::getNewPassword() { + return ui->lineEdit_newPassword->text(); +} + +void PasswordChangeDialog::passwordsMatch() { + bool match = ui->lineEdit_newPassword->text() == ui->lineEdit_confirmPassword->text(); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(match); +} \ No newline at end of file diff --git a/src/dialog/passwordchangedialog.h b/src/dialog/passwordchangedialog.h new file mode 100644 index 0000000..64cc7ce --- /dev/null +++ b/src/dialog/passwordchangedialog.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_PASSWORDCHANGEDIALOG_H +#define FEATHER_PASSWORDCHANGEDIALOG_H + +#include + +namespace Ui { + class PasswordChangeDialog; +} + +class PasswordChangeDialog : public QDialog +{ +Q_OBJECT + +public: + explicit PasswordChangeDialog(QWidget *parent = nullptr); + ~PasswordChangeDialog() override; + + QString getCurrentPassword(); + QString getNewPassword(); + +private: + Ui::PasswordChangeDialog *ui; + + void passwordsMatch(); +}; + +#endif //FEATHER_PASSWORDCHANGEDIALOG_H diff --git a/src/dialog/passwordchangedialog.ui b/src/dialog/passwordchangedialog.ui new file mode 100644 index 0000000..88db6af --- /dev/null +++ b/src/dialog/passwordchangedialog.ui @@ -0,0 +1,142 @@ + + + PasswordChangeDialog + + + + 0 + 0 + 500 + 237 + + + + + 0 + 0 + + + + Change Password + + + + + + + + TextLabel + + + + + + + Your wallet is password protected and encrypted. Use this dialog to change your password. + + + true + + + + + + + + + + + New Password: + + + + + + + QLineEdit::Password + + + + + + + QLineEdit::Password + + + + + + + Current Password: + + + + + + + Confirm Password: + + + + + + + QLineEdit::Password + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + lineEdit_currentPassword + lineEdit_newPassword + lineEdit_confirmPassword + + + + + buttonBox + accepted() + PasswordChangeDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PasswordChangeDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialog/qrcodedialog.cpp b/src/dialog/qrcodedialog.cpp new file mode 100644 index 0000000..02742be --- /dev/null +++ b/src/dialog/qrcodedialog.cpp @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "qrcodedialog.h" +#include "ui_qrcodedialog.h" +#include "qrcode/QrCode.h" + +#include +#include +#include + +QrCodeDialog::QrCodeDialog(QWidget *parent, const QString &text, const QString &title) + : QDialog(parent) + , ui(new Ui::QrCodeDialog) +{ + ui->setupUi(this); + this->setWindowTitle(title); + + m_qrc = new QrCode(text, QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::HIGH); + m_pixmap = m_qrc->toPixmap(1).scaled(500, 500, Qt::KeepAspectRatio); + ui->QrCode->setPixmap(m_pixmap); + + connect(ui->btn_CopyImage, &QPushButton::clicked, this, &QrCodeDialog::copyImage); + connect(ui->btn_Save, &QPushButton::clicked, this, &QrCodeDialog::saveImage); + connect(ui->btn_Close, &QPushButton::clicked, [this](){ + accept(); + }); + + this->adjustSize(); +} + +QrCodeDialog::~QrCodeDialog() +{ + delete ui; + delete m_qrc; +} + +void QrCodeDialog::copyImage() { + QApplication::clipboard()->setPixmap(m_pixmap); + QMessageBox::information(this, "Information", "QR code copied to clipboard"); +} + +void QrCodeDialog::saveImage() { + QString filename = QFileDialog::getSaveFileName(this, "Select where to save file", "qrcode.png"); + if (filename.isEmpty()) { + return; + } + + QFile file(filename); + file.open(QIODevice::WriteOnly); + m_pixmap.save(&file, "PNG"); + QMessageBox::information(this, "Information", "QR code saved to file"); +} \ No newline at end of file diff --git a/src/dialog/qrcodedialog.h b/src/dialog/qrcodedialog.h new file mode 100644 index 0000000..cb0d1a2 --- /dev/null +++ b/src/dialog/qrcodedialog.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_QRCODEDIALOG_H +#define FEATHER_QRCODEDIALOG_H +#include + +#include "qrcode/QrCode.h" + +namespace Ui { + class QrCodeDialog; +} + +class QrCodeDialog : public QDialog +{ +Q_OBJECT + +public: + explicit QrCodeDialog(QWidget *parent, const QString &text, const QString &title = "Qr Code"); + ~QrCodeDialog() override; + +private: + void copyImage(); + void saveImage(); + + Ui::QrCodeDialog *ui; + QrCode *m_qrc; + QPixmap m_pixmap; +}; + + +#endif //FEATHER_QRCODEDIALOG_H diff --git a/src/dialog/qrcodedialog.ui b/src/dialog/qrcodedialog.ui new file mode 100644 index 0000000..c160dc9 --- /dev/null +++ b/src/dialog/qrcodedialog.ui @@ -0,0 +1,93 @@ + + + QrCodeDialog + + + + 0 + 0 + 522 + 562 + + + + Dialog + + + + + + + 0 + 0 + + + + + 500 + 500 + + + + QrCode + + + + + + + QLayout::SetDefaultConstraint + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Copy Image + + + false + + + + + + + Save + + + false + + + + + + + Close + + + false + + + true + + + + + + + + + + diff --git a/src/dialog/restoredialog.cpp b/src/dialog/restoredialog.cpp new file mode 100644 index 0000000..e6363bb --- /dev/null +++ b/src/dialog/restoredialog.cpp @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "restoredialog.h" +#include "ui_restoredialog.h" +#include "utils/utils.h" +#include "appcontext.h" + +RestoreDialog::RestoreDialog(AppContext *ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::RestoreDialog) + , m_ctx(ctx) +{ + ui->setupUi(this); + this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png")); + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &RestoreDialog::accepted); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &RestoreDialog::rejected); + + if(m_ctx->networkType == NetworkType::Type::TESTNET) { + ui->restoreHeightWidget->hideSlider(); + } else { + // load restoreHeight lookup db + ui->restoreHeightWidget->initRestoreHeights(m_ctx->restoreHeights[m_ctx->networkType]); + } +} + +unsigned int RestoreDialog::getHeight() { + return ui->restoreHeightWidget->getHeight(); +} + +void RestoreDialog::initRestoreHeights(RestoreHeightLookup *lookup) { + ui->restoreHeightWidget->initRestoreHeights(lookup); +} + +RestoreDialog::~RestoreDialog() { + delete ui; +} + diff --git a/src/dialog/restoredialog.h b/src/dialog/restoredialog.h new file mode 100644 index 0000000..d45ae05 --- /dev/null +++ b/src/dialog/restoredialog.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef RESTOREDIALOG_H +#define RESTOREDIALOG_H + +#include +#include +#include +#include +#include + +#include "utils/seeds.h" +#include "appcontext.h" + +namespace Ui { + class RestoreDialog; +} + +class RestoreDialog : public QDialog +{ +Q_OBJECT + +public: + explicit RestoreDialog(AppContext *ctx, QWidget *parent = nullptr); + void initRestoreHeights(RestoreHeightLookup *lookup); + unsigned int getHeight(); + ~RestoreDialog() override; + +signals: + void accepted(); + void rejected(); + +private: + AppContext *m_ctx; + Ui::RestoreDialog *ui; +}; + +#endif // RESTOREDIALOG_H diff --git a/src/dialog/restoredialog.ui b/src/dialog/restoredialog.ui new file mode 100644 index 0000000..5c914bb --- /dev/null +++ b/src/dialog/restoredialog.ui @@ -0,0 +1,56 @@ + + + RestoreDialog + + + + 0 + 0 + 584 + 99 + + + + specify restore height + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + RestoreHeightWidget + QWidget +
widgets/restoreheightwidget.h
+ 1 +
+
+ + +
diff --git a/src/dialog/seeddialog.cpp b/src/dialog/seeddialog.cpp new file mode 100644 index 0000000..bd1a537 --- /dev/null +++ b/src/dialog/seeddialog.cpp @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "ui_seeddialog.h" +#include "seeddialog.h" + +SeedDialog::SeedDialog(const QString &seed, QWidget *parent) + : QDialog(parent) + , ui(new Ui::SeedDialog) +{ + ui->setupUi(this); + ui->label_seedIcon->setPixmap(QPixmap(":/assets/images/seed.png").scaledToWidth(64, Qt::SmoothTransformation)); + ui->seed->setPlainText(seed); + + int words = seed.split(" ").size(); + ui->label_warning->setText(QString("

Please save these %1 words on paper (order is important). " + "This seed will allow you to recover your wallet in case " + "of computer failure." + "

" + "WARNING:" + "
    " + "
  • Never disclose your seed.
  • " + "
  • Never type it on a website
  • " + "
  • Do not store it electronically
  • " + "
").arg(words)); + + this->adjustSize(); +} + +SeedDialog::~SeedDialog() +{ + delete ui; +} \ No newline at end of file diff --git a/src/dialog/seeddialog.h b/src/dialog/seeddialog.h new file mode 100644 index 0000000..a26fee4 --- /dev/null +++ b/src/dialog/seeddialog.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_SEEDDIALOG_H +#define FEATHER_SEEDDIALOG_H + +#include + +namespace Ui { + class SeedDialog; +} + +class SeedDialog : public QDialog +{ +Q_OBJECT + +public: + explicit SeedDialog(const QString& seed, QWidget *parent = nullptr); + ~SeedDialog() override; + +private: + Ui::SeedDialog *ui; +}; + + +#endif //FEATHER_SEEDDIALOG_H diff --git a/src/dialog/seeddialog.ui b/src/dialog/seeddialog.ui new file mode 100644 index 0000000..1288fac --- /dev/null +++ b/src/dialog/seeddialog.ui @@ -0,0 +1,117 @@ + + + SeedDialog + + + + 0 + 0 + 542 + 244 + + + + Seed + + + + + + Your wallet generation seed is: + + + + + + + + + seed + + + false + + + + + + + true + + + + 0 + 0 + + + + + 16777215 + 125 + + + + true + + + + + + + + + warning + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SeedDialog + accept() + + + 270 + 211 + + + 157 + 274 + + + + + buttonBox + rejected() + SeedDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialog/signverifydialog.cpp b/src/dialog/signverifydialog.cpp new file mode 100644 index 0000000..2176b2e --- /dev/null +++ b/src/dialog/signverifydialog.cpp @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "signverifydialog.h" +#include "ui_signverifydialog.h" +#include "utils/utils.h" + +#include + +SignVerifyDialog::SignVerifyDialog(Wallet *wallet, QWidget *parent) + : QDialog(parent) + , m_wallet(wallet) + , ui(new Ui::SignVerifyDialog) +{ + ui->setupUi(this); + + connect(ui->btn_Sign, &QPushButton::clicked, this, &SignVerifyDialog::signMessage); + connect(ui->btn_Verify, &QPushButton::clicked, this, &SignVerifyDialog::verifyMessage); + connect(ui->btn_Copy, &QPushButton::clicked, this, &SignVerifyDialog::copyToClipboard); + + connect(ui->message, &QPlainTextEdit::textChanged, [this](){ui->btn_Copy->setVisible(false);}); + connect(ui->address, &QLineEdit::textEdited, [this](){ui->btn_Copy->setVisible(false);}); + connect(ui->signature, &QLineEdit::textEdited, [this](){ui->btn_Copy->setVisible(false);}); + + ui->address->setText(m_wallet->address(0, 0)); + ui->address->setCursorPosition(0); + + ui->btn_Copy->setVisible(false); +} + +void SignVerifyDialog::signMessage() { + QString signature = m_wallet->signMessage(ui->message->toPlainText(), false, ui->address->text()); + + if (signature.isEmpty()) { + QMessageBox::information(this, "Information", m_wallet->errorString()); + return; + } + + ui->signature->setText(signature); + ui->btn_Copy->setVisible(true); +} + +void SignVerifyDialog::verifyMessage() { + bool verified = m_wallet->verifySignedMessage(ui->message->toPlainText(), ui->address->text(), ui->signature->text()); + verified ? QMessageBox::information(this, "Information", "Signature is valid") + : QMessageBox::warning(this, "Warning", "Signature failed to verify"); +} + +void SignVerifyDialog::copyToClipboard() { + QStringList sig; + sig << ui->message->toPlainText() << ui->address->text() << ui->signature->text(); + Utils::copyToClipboard(sig.join("\n")); +} + +SignVerifyDialog::~SignVerifyDialog() +{ + delete ui; +} \ No newline at end of file diff --git a/src/dialog/signverifydialog.h b/src/dialog/signverifydialog.h new file mode 100644 index 0000000..e4c5700 --- /dev/null +++ b/src/dialog/signverifydialog.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_SIGNVERIFYDIALOG_H +#define FEATHER_SIGNVERIFYDIALOG_H + +#include +#include "libwalletqt/Wallet.h" + +namespace Ui { + class SignVerifyDialog; +} + +class SignVerifyDialog : public QDialog +{ +Q_OBJECT + +public: + explicit SignVerifyDialog(Wallet *wallet, QWidget *parent = nullptr); + ~SignVerifyDialog() override; + +private: + Ui::SignVerifyDialog *ui; + Wallet *m_wallet; + +private slots: + void signMessage(); + void verifyMessage(); + void copyToClipboard(); +}; + + +#endif //FEATHER_SIGNVERIFYDIALOG_H diff --git a/src/dialog/signverifydialog.ui b/src/dialog/signverifydialog.ui new file mode 100644 index 0000000..935cada --- /dev/null +++ b/src/dialog/signverifydialog.ui @@ -0,0 +1,89 @@ + + + SignVerifyDialog + + + + 0 + 0 + 1102 + 269 + + + + Sign / Verify + + + + + + Address + + + + + + + Signature + + + + + + + Message + + + + + + + + + + + + + + + Sign + + + + + + + Verify + + + + + + + Copy to clipboard + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + diff --git a/src/dialog/torinfodialog.cpp b/src/dialog/torinfodialog.cpp new file mode 100644 index 0000000..85e8474 --- /dev/null +++ b/src/dialog/torinfodialog.cpp @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "torinfodialog.h" +#include "ui_torinfodialog.h" + +#include + +TorInfoDialog::TorInfoDialog(AppContext *ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::TorInfoDialog) + , m_ctx(ctx) +{ + ui->setupUi(this); + + if (!m_ctx->tor->torConnected && !m_ctx->tor->errorMsg.isEmpty()) { + ui->message->setText(m_ctx->tor->errorMsg); + } else { + ui->message->setText(QString("Currently using Tor instance: %1:%2").arg(Tor::torHost).arg(Tor::torPort)); + } + + if (m_ctx->tor->localTor) { + ui->logs->setHidden(true); + } else { + ui->logs->setPlainText(m_ctx->tor->torLogs); + } + + this->adjustSize(); +} + +void TorInfoDialog::onLogsUpdated() { + ui->logs->setPlainText(m_ctx->tor->torLogs); +} + +TorInfoDialog::~TorInfoDialog() { + delete ui; +} diff --git a/src/dialog/torinfodialog.h b/src/dialog/torinfodialog.h new file mode 100644 index 0000000..9c44db1 --- /dev/null +++ b/src/dialog/torinfodialog.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_TORINFODIALOG_H +#define FEATHER_TORINFODIALOG_H + +#include + +#include "appcontext.h" + +namespace Ui { + class TorInfoDialog; +} + +class TorInfoDialog : public QDialog +{ + Q_OBJECT + +public: + explicit TorInfoDialog(AppContext *ctx, QWidget *parent = nullptr); + ~TorInfoDialog() override; + +public slots: + void onLogsUpdated(); + +private: + Ui::TorInfoDialog *ui; + AppContext *m_ctx; +}; + + +#endif //FEATHER_TORINFODIALOG_H diff --git a/src/dialog/torinfodialog.ui b/src/dialog/torinfodialog.ui new file mode 100644 index 0000000..d31d1e7 --- /dev/null +++ b/src/dialog/torinfodialog.ui @@ -0,0 +1,84 @@ + + + TorInfoDialog + + + + 0 + 0 + 618 + 386 + + + + Tor information + + + + + + Message + + + + + + + + 600 + 0 + + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + TorInfoDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + TorInfoDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialog/transactioninfodialog.cpp b/src/dialog/transactioninfodialog.cpp new file mode 100644 index 0000000..d773c14 --- /dev/null +++ b/src/dialog/transactioninfodialog.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "transactioninfodialog.h" +#include "ui_transactioninfodialog.h" + +#include "libwalletqt/CoinsInfo.h" +#include "libwalletqt/WalletManager.h" +#include + +TransactionInfoDialog::TransactionInfoDialog(Coins *coins, TransactionInfo *txInfo, QWidget *parent) + : QDialog(parent) + , ui(new Ui::TransactionInfoDialog) + , m_coins(coins) + , m_txInfo(txInfo) +{ + ui->setupUi(this); + + ui->txid->setText(QString(txInfo->hash())); + ui->txid->setCursorPosition(0); + + ui->label_status->setText(QString("Status: %1 confirmations").arg(txInfo->confirmations())); + ui->label_date->setText(QString("Date: %1").arg(txInfo->timestamp().toString("yyyy-MM-dd HH:mm"))); + ui->label_blockHeight->setText(QString("Block height: %1").arg(txInfo->blockHeight())); + + QString direction = txInfo->direction() == TransactionInfo::Direction_In ? "received" : "sent"; + ui->label_amount->setText(QString("Amount %1: %2").arg(direction, txInfo->displayAmount())); + + QString fee = txInfo->fee().isEmpty() ? "n/a" : txInfo->fee(); + ui->label_fee->setText(QString("Fee: %1").arg(txInfo->isCoinbase() ? WalletManager::displayAmount(0) : fee)); + ui->label_unlockTime->setText(QString("Unlock time: %1 (height)").arg(txInfo->unlockTime())); + + qDebug() << m_coins->coins_from_txid(txInfo->hash()); + + QString destinations = txInfo->destinations_formatted(); + if (destinations.isEmpty()) { + ui->destinations->setHidden(true); + ui->label_destinations->setHidden(true); + ui->line_2->setHidden(true); + } else { + ui->destinations->setText(destinations); + } + + this->adjustSize(); +} + +TransactionInfoDialog::~TransactionInfoDialog() { + delete ui; +} diff --git a/src/dialog/transactioninfodialog.h b/src/dialog/transactioninfodialog.h new file mode 100644 index 0000000..26feaa7 --- /dev/null +++ b/src/dialog/transactioninfodialog.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_TRANSACTIONINFODIALOG_H +#define FEATHER_TRANSACTIONINFODIALOG_H + +#include +#include +#include "libwalletqt/Coins.h" +#include "libwalletqt/TransactionInfo.h" + +namespace Ui { + class TransactionInfoDialog; +} + +class TransactionInfoDialog : public QDialog +{ +Q_OBJECT + +public: + explicit TransactionInfoDialog(Coins *coins, TransactionInfo *txInfo, QWidget *parent = nullptr); + ~TransactionInfoDialog() override; + +private: + Ui::TransactionInfoDialog *ui; + + TransactionInfo *m_txInfo; + Coins *m_coins; +}; + +#endif //FEATHER_TRANSACTIONINFODIALOG_H diff --git a/src/dialog/transactioninfodialog.ui b/src/dialog/transactioninfodialog.ui new file mode 100644 index 0000000..8026b6e --- /dev/null +++ b/src/dialog/transactioninfodialog.ui @@ -0,0 +1,169 @@ + + + TransactionInfoDialog + + + + 0 + 0 + 547 + 332 + + + + Transaction + + + + + + Transaction ID: + + + + + + + + 0 + 0 + + + + + 525 + 0 + + + + txid + + + true + + + + + + + + + + + Status: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Date: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Block height: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + Qt::Vertical + + + + + + + + + Amount received: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Fee: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Unlock time: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + + Qt::Horizontal + + + + + + + Destinations: + + + + + + + + 16777215 + 100 + + + + true + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + diff --git a/src/dialog/txconfdialog.cpp b/src/dialog/txconfdialog.cpp new file mode 100644 index 0000000..b72c437 --- /dev/null +++ b/src/dialog/txconfdialog.cpp @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "txconfdialog.h" +#include "ui_txconfdialog.h" +#include "appcontext.h" +#include "utils/config.h" +#include "model/ModelUtils.h" + +#include + +TxConfDialog::TxConfDialog(PendingTransaction *tx, const QString &address, const QString &description, int mixin, QWidget *parent) + : QDialog(parent) + , ui(new Ui::TxConfDialog) + , m_tx(tx) + , m_address(address) + , m_description(description) + , m_mixin(mixin) +{ + ui->setupUi(this); + + ui->label_warning->setText("You are about to send a transaction.\nVerify the information below."); + + QString preferredCur = config()->get(Config::preferredFiatCurrency).toString(); + + auto convert = [preferredCur](double amount){ + return QString::number(AppContext::prices->convert("XMR", preferredCur, amount), 'f', 2); + }; + + QString amount = WalletManager::displayAmount(tx->amount()); + QString amount_fiat = convert(tx->amount() / AppContext::cdiv); + ui->label_amount->setText(QString("%1 (%2 %3)").arg(amount, amount_fiat, preferredCur)); + + QString fee = WalletManager::displayAmount(tx->fee()); + QString fee_fiat = convert(tx->fee() / AppContext::cdiv); + ui->label_fee->setText(QString("%1 (%2 %3)").arg(fee, fee_fiat, preferredCur)); + + QString total = WalletManager::displayAmount(tx->amount() + tx->fee()); + QString total_fiat = convert((tx->amount() + tx->fee()) / AppContext::cdiv); + ui->label_total->setText(QString("%1 (%2 %3)").arg(total, total_fiat, preferredCur)); + + ui->label_address->setText(ModelUtils::displayAddress(address, 2)); + ui->label_address->setFont(ModelUtils::getMonospaceFont()); + ui->label_address->setToolTip(address); + + connect(ui->btn_Advanced, &QPushButton::clicked, this, &TxConfDialog::showAdvanced); + + this->adjustSize(); +} + +void TxConfDialog::showAdvanced() { + const auto amount = m_tx->amount() / AppContext::cdiv; + const auto fee = m_tx->fee() / AppContext::cdiv; + + QString body = QString("Address: %2\n").arg(m_address.left(60)); + body += m_address.mid(60) + "\n"; + if(!m_description.isEmpty()) + body = QString("%1Description: %2\n").arg(body, m_description); + body = QString("%1Amount: %2 XMR\n").arg(body, QString::number(amount)); + body = QString("%1Fee: %2 XMR\n").arg(body, QString::number(fee)); + body = QString("%1Ringsize: %2").arg(body, QString::number(m_mixin + 1)); + + auto subaddrIndices = m_tx->subaddrIndices(); + for (int i = 0; i < subaddrIndices.count(); ++i){ + body = QString("%1\nSpending address index: %2").arg(body, QString::number(subaddrIndices.at(i).toInt())); + } + + QMessageBox::information(this, "Transaction information", body); +} + +TxConfDialog::~TxConfDialog() { + delete ui; +} diff --git a/src/dialog/txconfdialog.h b/src/dialog/txconfdialog.h new file mode 100644 index 0000000..7a2b02a --- /dev/null +++ b/src/dialog/txconfdialog.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_TXCONFDIALOG_H +#define FEATHER_TXCONFDIALOG_H + +#include +#include "libwalletqt/PendingTransaction.h" +#include "libwalletqt/WalletManager.h" + +namespace Ui { + class TxConfDialog; +} + +class TxConfDialog : public QDialog +{ +Q_OBJECT + +public: + explicit TxConfDialog(PendingTransaction *tx, const QString &address, const QString &description, int mixin, QWidget *parent = nullptr); + ~TxConfDialog() override; + +private: + void showAdvanced(); + + Ui::TxConfDialog *ui; + PendingTransaction *m_tx; + QString m_address; + QString m_description; + int m_mixin; +}; + +#endif //FEATHER_TXCONFDIALOG_H diff --git a/src/dialog/txconfdialog.ui b/src/dialog/txconfdialog.ui new file mode 100644 index 0000000..1269b12 --- /dev/null +++ b/src/dialog/txconfdialog.ui @@ -0,0 +1,175 @@ + + + TxConfDialog + + + + 0 + 0 + 655 + 232 + + + + Confirm transaction + + + + 15 + + + + + warning + + + + + + + + + 15 + + + 7 + + + + + Address: + + + + + + + address + + + + + + + Amount: + + + + + + + amount + + + + + + + Fee: + + + + + + + fee + + + + + + + Qt::Horizontal + + + + + + + Total: + + + + + + + total + + + + + + + + + + + + + Advanced + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + TxConfDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + TxConfDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialog/verifyproofdialog.cpp b/src/dialog/verifyproofdialog.cpp new file mode 100644 index 0000000..291b977 --- /dev/null +++ b/src/dialog/verifyproofdialog.cpp @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "verifyproofdialog.h" +#include "ui_verifyproofdialog.h" + +#include "utils/utils.h" +#include "libwalletqt/WalletManager.h" + +#include + +VerifyProofDialog::VerifyProofDialog(Wallet *wallet, QWidget *parent) + : QDialog(parent) + , m_wallet(wallet) + , ui(new Ui::VerifyProofDialog) +{ + ui->setupUi(this); + + connect(ui->btn_verifySpendProof, &QPushButton::clicked, this, &VerifyProofDialog::checkSpendProof); + connect(ui->btn_verifyOutProof, &QPushButton::clicked, this, &VerifyProofDialog::checkOutProof); + connect(ui->btn_verifyInProof, &QPushButton::clicked, this, &VerifyProofDialog::checkInProof); + + connect(ui->btn_spendClear, &QPushButton::clicked, [this](){ + ui->lineEdit_spendTxID->clear(); + ui->lineEdit_spendMessage->clear(); + ui->input_SpendProof->clear(); + }); + connect(ui->btn_outClear, &QPushButton::clicked, [this](){ + ui->lineEdit_outTxID->clear(); + ui->lineEdit_outAddress->clear(); + ui->lineEdit_outMessage->clear(); + ui->input_OutProof->clear(); + }); + connect(ui->btn_inClear, &QPushButton::clicked, [this](){ + ui->lineEdit_inTxID->clear(); + ui->lineEdit_inAddress->clear(); + ui->lineEdit_inMessage->clear(); + ui->input_InProof->clear(); + }); +} + +VerifyProofDialog::~VerifyProofDialog() +{ + delete ui; +} + +void VerifyProofDialog::checkSpendProof() { + auto r = m_wallet->checkSpendProof(ui->lineEdit_spendTxID->text(), ui->lineEdit_spendMessage->text(), ui->input_SpendProof->toPlainText()); + + if (!r.first) { + QMessageBox::information(this, "Information", m_wallet->errorString()); + return; + } + + r.second ? QMessageBox::information(this, "Information", "Proof is valid") + : QMessageBox::warning(this, "Warning", "Proof is invalid"); +} + +void VerifyProofDialog::checkOutProof() { + this->checkTxProof(ui->lineEdit_outTxID->text(), ui->lineEdit_outAddress->text(), ui->lineEdit_outMessage->text(), ui->input_OutProof->toPlainText()); +} + +void VerifyProofDialog::checkInProof() { + this->checkTxProof(ui->lineEdit_inTxID->text(), ui->lineEdit_inAddress->text(), ui->lineEdit_inMessage->text(), ui->input_InProof->toPlainText()); +} + +void VerifyProofDialog::checkTxProof(const QString &txId, const QString &address, const QString &message, + const QString &signature) { + TxProofResult r = m_wallet->checkTxProof(txId, address, message, signature); + + if (!r.success) { + QMessageBox::information(this, "Information", m_wallet->errorString()); + return; + } + + if (!r.good) { + QMessageBox::warning(this, "Warning", "Proof is invalid"); + return; + } + + QString msg = QString("This address received %1 monero, with %2 confirmation(s)").arg(WalletManager::displayAmount(r.received), QString::number(r.confirmations)); + QMessageBox::information(this, "Information", QString("Proof is valid.\n\n%1").arg(msg)); +} \ No newline at end of file diff --git a/src/dialog/verifyproofdialog.h b/src/dialog/verifyproofdialog.h new file mode 100644 index 0000000..28b22a7 --- /dev/null +++ b/src/dialog/verifyproofdialog.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_VERIFYPROOFDIALOG_H +#define FEATHER_VERIFYPROOFDIALOG_H + +#include +#include "libwalletqt/Wallet.h" + +namespace Ui { + class VerifyProofDialog; +} + +class VerifyProofDialog : public QDialog +{ +Q_OBJECT + +public: + explicit VerifyProofDialog(Wallet *wallet, QWidget *parent = nullptr); + ~VerifyProofDialog() override; + +private slots: + void checkSpendProof(); + void checkOutProof(); + void checkInProof(); + +private: + void checkTxProof(const QString &txId, const QString &address, const QString &message, const QString &signature); + + Ui::VerifyProofDialog *ui; + Wallet *m_wallet; +}; + +#endif //FEATHER_VERIFYPROOFDIALOG_H diff --git a/src/dialog/verifyproofdialog.ui b/src/dialog/verifyproofdialog.ui new file mode 100644 index 0000000..6ff55bf --- /dev/null +++ b/src/dialog/verifyproofdialog.ui @@ -0,0 +1,373 @@ + + + VerifyProofDialog + + + + 0 + 0 + 1123 + 413 + + + + Verify transaction proof + + + + + + Select proof to verify: + + + + + + + 2 + + + + SpendProof + + + + + + A SpendProof proves authorship of a transaction. + + + + + + + + + Transaction ID: + + + + + + + + + + Message: + + + + + + + SpendProof: + + + + + + + Optional message against which the signature is signed + + + + + + + false + + + SpendProof.. + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Clear + + + + + + + Verify + + + + + + + + + + OutProof + + + + + + An OutProof shows the prover sent an output to an address. + + + + + + + + + OutProof: + + + + + + + + + + Address: + + + + + + + + + + Address of recipient + + + + + + + Transaction ID: + + + + + + + Message: + + + + + + + Optional message against which the signature is signed + + + + + + + OutProof.. + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Clear + + + + + + + Verify + + + + + + + + + + InProof + + + + + + An InProof proves ownership of an output. + + + + + + + + + InProof: + + + + + + + Transaction ID: + + + + + + + Address: + + + + + + + Output owner's address + + + + + + + Transaction that created the output + + + + + + + Message: + + + + + + + Optional message against which the signature is signed + + + + + + + InProof.. + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Clear + + + + + + + Verify + + + + + + + + + + + + + + diff --git a/src/dialog/walletinfodialog.cpp b/src/dialog/walletinfodialog.cpp new file mode 100644 index 0000000..9996c9f --- /dev/null +++ b/src/dialog/walletinfodialog.cpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "walletinfodialog.h" +#include "ui_walletinfodialog.h" + +#include + +WalletInfoDialog::WalletInfoDialog(AppContext *ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::WalletInfoDialog) + , m_ctx(ctx) +{ + ui->setupUi(this); + + QFileInfo keys(ctx->walletPath); + QFileInfo cache(ctx->currentWallet->path()); + + ui->label_walletName->setText(keys.fileName().replace(".keys", "")); + ui->label_netType->setText(Utils::QtEnumToString(ctx->currentWallet->nettype())); + ui->label_seedType->setText(ctx->currentWallet->getCacheAttribute("feather.seed").isEmpty() ? "25 word" : "14 word"); + ui->label_viewOnly->setText(ctx->currentWallet->viewOnly() ? "True" : "False"); + ui->label_path->setText(ctx->walletPath); + ui->label_cacheSize->setText(QString("%1 MB").arg(QString::number(cache.size() / 1e6, 'f', 2))); + + connect(ui->btn_openWalletDir, &QPushButton::clicked, this, &WalletInfoDialog::openWalletDir); + + this->adjustSize(); +} + +void WalletInfoDialog::openWalletDir() { + QFileInfo file(m_ctx->walletPath); + + QDesktopServices::openUrl(file.absolutePath()); +} + +WalletInfoDialog::~WalletInfoDialog() { + delete ui; +} diff --git a/src/dialog/walletinfodialog.h b/src/dialog/walletinfodialog.h new file mode 100644 index 0000000..b30b7c7 --- /dev/null +++ b/src/dialog/walletinfodialog.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_WALLETINFODIALOG_H +#define FEATHER_WALLETINFODIALOG_H + +#include + +#include "appcontext.h" + +namespace Ui { + class WalletInfoDialog; +} + +class WalletInfoDialog : public QDialog +{ +Q_OBJECT + +public: + explicit WalletInfoDialog(AppContext *ctx, QWidget *parent = nullptr); + ~WalletInfoDialog() override; + +private: + void openWalletDir(); + + Ui::WalletInfoDialog *ui; + AppContext *m_ctx; +}; + +#endif //FEATHER_WALLETINFODIALOG_H diff --git a/src/dialog/walletinfodialog.ui b/src/dialog/walletinfodialog.ui new file mode 100644 index 0000000..8b1f0d5 --- /dev/null +++ b/src/dialog/walletinfodialog.ui @@ -0,0 +1,181 @@ + + + WalletInfoDialog + + + + 0 + 0 + 701 + 252 + + + + Wallet Information + + + + + + + + Wallet name: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Network type: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Seed type: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + View only: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Path: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Cache size: + + + + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + + Open wallet directory + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + WalletInfoDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + WalletInfoDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialog/xmrtoinfodialog.cpp b/src/dialog/xmrtoinfodialog.cpp new file mode 100644 index 0000000..0400a96 --- /dev/null +++ b/src/dialog/xmrtoinfodialog.cpp @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "xmrtoinfodialog.h" +#include "ui_xmrtoinfodialog.h" + +#include + +XmrToInfoDialog::XmrToInfoDialog(XmrToOrder *oInfo, QWidget *parent) + : QDialog(parent) + , ui(new Ui::XmrToInfoDialog) + , m_oInfo(oInfo) +{ + ui->setupUi(this); + + ui->status->setText(XmrTo::stateMap[(OrderState) oInfo->state]); + ui->xmrto_id->setText(!oInfo->uuid.isEmpty() ? oInfo->uuid : ""); + + ui->error_code->setText(!oInfo->errorCode.isEmpty() ? oInfo->errorCode : ""); + ui->error_msg->setText(!oInfo->errorMsg.isEmpty() ? oInfo->errorMsg : ""); + + ui->xmr_amount->setText(QString::number(oInfo->incoming_amount_total)); + ui->btc_amount->setText(QString::number(oInfo->btc_amount)); + ui->rate->setText(oInfo->incoming_price_btc > 0 ? QString::number(oInfo->incoming_price_btc) : ""); + + ui->xmr_txid->setText(oInfo->xmr_txid); + ui->xmr_address->setText(oInfo->receiving_subaddress); + + ui->btc_txid->setText(oInfo->btc_txid); + ui->btc_address->setText(oInfo->btc_dest_address); + + this->adjustSize(); +} + +XmrToInfoDialog::~XmrToInfoDialog() { + delete ui; +} diff --git a/src/dialog/xmrtoinfodialog.h b/src/dialog/xmrtoinfodialog.h new file mode 100644 index 0000000..03fd3c5 --- /dev/null +++ b/src/dialog/xmrtoinfodialog.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_XMRTOINFODIALOG_H +#define FEATHER_XMRTOINFODIALOG_H + +#include +#include "utils/xmrto.h" + +namespace Ui { + class XmrToInfoDialog; +} + +class XmrToInfoDialog : public QDialog +{ +Q_OBJECT + +public: + explicit XmrToInfoDialog(XmrToOrder *oInfo, QWidget *parent = nullptr); + ~XmrToInfoDialog() override; + +private: + Ui::XmrToInfoDialog *ui; + + XmrToOrder *m_oInfo; +}; + +#endif //FEATHER_XMRTOINFODIALOG_H diff --git a/src/dialog/xmrtoinfodialog.ui b/src/dialog/xmrtoinfodialog.ui new file mode 100644 index 0000000..cb38077 --- /dev/null +++ b/src/dialog/xmrtoinfodialog.ui @@ -0,0 +1,256 @@ + + + XmrToInfoDialog + + + + 0 + 0 + 689 + 581 + + + + Xmr.to Order + + + + + + + + + + Status: + + + + + + + XMR.to ID: + + + + + + + Error code: + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + + + Qt::Vertical + + + + + + + + + XMR amount: + + + + + + + BTC amount: + + + + + + + Rate: + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + + + + + + + Message: + + + + + + + true + + + + + + + Qt::Horizontal + + + + + + + XMR.to address: + + + + + + + true + + + + + + + XMR txid: + + + + + + + true + + + + + + + Qt::Horizontal + + + + + + + BTC address: + + + + + + + true + + + + + + + BTC txid: + + + + + + + true + + + + + + + + + Qt::Horizontal + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Copy support template + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/historywidget.cpp b/src/historywidget.cpp new file mode 100644 index 0000000..48c5334 --- /dev/null +++ b/src/historywidget.cpp @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "historywidget.h" +#include "ui_historywidget.h" +#include "dialog/transactioninfodialog.h" +#include "libwalletqt/TransactionHistory.h" +#include "model/TransactionHistoryProxyModel.h" + +#include + +HistoryWidget::HistoryWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::HistoryWidget) + , m_contextMenu(new QMenu(this)) + , m_copyMenu(new QMenu("Copy", this)) +{ + ui->setupUi(this); + m_contextMenu->addMenu(m_copyMenu); + m_contextMenu->addAction(QIcon(":/assets/images/info.png"), "Show details", this, &HistoryWidget::showTxDetails); + m_contextMenu->addAction(QIcon(":/assets/images/network.png"), "View on block explorer", this, &HistoryWidget::onViewOnBlockExplorer); + + // copy menu + m_copyMenu->setIcon(QIcon(":/assets/images/copy.png")); + m_copyMenu->addAction("Transaction ID", this, [this]{copy(copyField::TxID);}); + m_copyMenu->addAction("Date", this, [this]{copy(copyField::Date);}); + m_copyMenu->addAction("Amount", this, [this]{copy(copyField::Amount);}); + m_copyMenu->addAction("Spend proof", this, &HistoryWidget::getSpendProof); + + ui->history->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->history, &QTreeView::customContextMenuRequested, [=](const QPoint & point){ + QModelIndex index = ui->history->indexAt(point); + if (index.isValid()) { + m_contextMenu->exec(ui->history->viewport()->mapToGlobal(point)); + } + }); + connect(ui->search, &QLineEdit::textChanged, this, &HistoryWidget::setSearchFilter); +} + +void HistoryWidget::setModel(Coins *coins, TransactionHistoryProxyModel *model, TransactionHistory *txHistory) +{ + m_coins = coins; + m_model = model; + m_txHistory = txHistory; + ui->history->setModel(m_model); + + ui->history->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui->history->header()->setSectionResizeMode(TransactionHistoryModel::Description, QHeaderView::Stretch); + ui->history->hideColumn(TransactionHistoryModel::TxID); +} + +void HistoryWidget::showTxDetails() { + QModelIndex index = ui->history->currentIndex(); + + TransactionInfo *i = nullptr; + m_txHistory->transaction(m_model->mapToSource(index).row(), [&i](TransactionInfo &tInfo) { + i = &tInfo; + }); + + if (i != nullptr) { + auto * dialog = new TransactionInfoDialog(m_coins, i, this); + dialog->exec(); + } +} + +void HistoryWidget::onViewOnBlockExplorer() { + QModelIndex index = ui->history->currentIndex(); + + QString txid; + m_txHistory->transaction(m_model->mapToSource(index).row(), [&txid](TransactionInfo &tInfo) { + txid = tInfo.hash(); + }); + emit viewOnBlockExplorer(txid); +} + +void HistoryWidget::getSpendProof() { + QModelIndex index = ui->history->currentIndex(); + + m_txHistory->transaction(m_model->mapToSource(index).row(), [this](TransactionInfo &tInfo) { + emit spendProof(tInfo.hash()); + }); +} + +void HistoryWidget::setSearchText(const QString &text) { + ui->search->setText(text); +} + +void HistoryWidget::setSearchFilter(const QString &filter) { + if(!m_model) return; + m_model->setSearchFilter(filter); +} + +void HistoryWidget::copy(copyField field) { + QModelIndex index = ui->history->currentIndex(); + + QString data; + m_txHistory->transaction(m_model->mapToSource(index).row(), [field, &data](TransactionInfo &tInfo) { + switch(field) { + case copyField::TxID: + data = tInfo.hash(); + break; + case copyField::Date: + data = tInfo.timestamp().toString("yyyy-MM-dd HH:mm"); + break; + case copyField::Amount: + data = tInfo.displayAmount(); + break; + } + }); + + Utils::copyToClipboard(data); +} + +HistoryWidget::~HistoryWidget() { + delete ui; +} diff --git a/src/historywidget.h b/src/historywidget.h new file mode 100644 index 0000000..ffd1200 --- /dev/null +++ b/src/historywidget.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_HISTORYWIDGET_H +#define FEATHER_HISTORYWIDGET_H + +#include "model/TransactionHistoryModel.h" +#include "model/TransactionHistoryProxyModel.h" +#include "libwalletqt/Coins.h" + +#include +#include + +namespace Ui { + class HistoryWidget; +} + +class HistoryWidget : public QWidget +{ +Q_OBJECT + +public: + explicit HistoryWidget(QWidget *parent = nullptr); + void setModel(Coins * coins, TransactionHistoryProxyModel * model, TransactionHistory * txHistory); + ~HistoryWidget() override; + +public slots: + void setSearchText(const QString &text); + +signals: + void spendProof(QString txid); + void viewOnBlockExplorer(QString txid); + +private slots: + void showTxDetails(); + void onViewOnBlockExplorer(); + void getSpendProof(); + void setSearchFilter(const QString &filter); + +private: + enum copyField { + TxID = 0, + Date, + Amount + }; + + void copy(copyField field); + + Ui::HistoryWidget *ui; + QMenu *m_contextMenu; + QMenu *m_copyMenu; + TransactionHistory *m_txHistory; + TransactionHistoryProxyModel *m_model; + Coins *m_coins; +}; + +#endif //FEATHER_HISTORYWIDGET_H diff --git a/src/historywidget.ui b/src/historywidget.ui new file mode 100644 index 0000000..c333a69 --- /dev/null +++ b/src/historywidget.ui @@ -0,0 +1,53 @@ + + + HistoryWidget + + + + 0 + 0 + 959 + 507 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Search txid, description.. + + + + + + + false + + + true + + + false + + + + + + + + diff --git a/src/libwalletqt/AddressBook.cpp b/src/libwalletqt/AddressBook.cpp new file mode 100644 index 0000000..decfa3a --- /dev/null +++ b/src/libwalletqt/AddressBook.cpp @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "AddressBook.h" +#include "AddressBookInfo.h" +#include + +AddressBook::AddressBook(Monero::AddressBook *abImpl,QObject *parent) + : QObject(parent), m_addressBookImpl(abImpl) +{ + getAll(); +} + +QString AddressBook::errorString() const +{ + return QString::fromStdString(m_addressBookImpl->errorString()); +} + +int AddressBook::errorCode() const +{ + return m_addressBookImpl->errorCode(); +} + +void AddressBook::getAll() +{ + emit refreshStarted(); + + { + QWriteLocker locker(&m_lock); + + qDeleteAll(m_rows); + + m_addresses.clear(); + m_rows.clear(); + + for (auto &abr: m_addressBookImpl->getAll()) { + m_addresses.insert(QString::fromStdString(abr->getAddress()), m_rows.size()); + + m_rows.append(new AddressBookInfo(abr, this)); + } + } + + emit refreshFinished(); +} + +bool AddressBook::getRow(int index, std::function callback) const +{ + QReadLocker locker(&m_lock); + + if (index < 0 || index >= m_rows.size()) + { + return false; + } + + callback(*m_rows.value(index)); + return true; +} + +bool AddressBook::addRow(const QString &address, const QString &payment_id, const QString &description) +{ + // virtual bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) = 0; + bool result; + + { + QWriteLocker locker(&m_lock); + + result = m_addressBookImpl->addRow(address.toStdString(), payment_id.toStdString(), description.toStdString()); + } + + if (result) + { + getAll(); + } + + return result; +} + +void AddressBook::setDescription(int index, const QString &description) { + bool result; + + { + QWriteLocker locker(&m_lock); + + result = m_addressBookImpl->setDescription(index, description.toStdString()); + } + + if (result) + { + getAll(); + emit descriptionChanged(); + } +} + +bool AddressBook::deleteRow(int rowId) +{ + bool result; + + { + QWriteLocker locker(&m_lock); + + result = m_addressBookImpl->deleteRow(rowId); + } + + // Fetch new data from wallet2. + if (result) + { + getAll(); + } + + return result; +} + +quint64 AddressBook::count() const +{ + QReadLocker locker(&m_lock); + + return m_rows.size(); +} + +int AddressBook::lookupPaymentID(const QString &payment_id) const +{ + QReadLocker locker(&m_lock); + + return m_addressBookImpl->lookupPaymentID(payment_id.toStdString()); +} + +QString AddressBook::getDescription(const QString &address) const +{ + QReadLocker locker(&m_lock); + + const QMap::const_iterator it = m_addresses.find(address); + if (it == m_addresses.end()) + { + return {}; + } + return m_rows.value(*it)->description(); +} diff --git a/src/libwalletqt/AddressBook.h b/src/libwalletqt/AddressBook.h new file mode 100644 index 0000000..6c8fefd --- /dev/null +++ b/src/libwalletqt/AddressBook.h @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef ADDRESSBOOK_H +#define ADDRESSBOOK_H + +#include +#include "AddressBookInfo.h" +#include +#include +#include +#include +#include + +namespace Monero { +struct AddressBook; +} +class AddressBookRow; + +class AddressBook : public QObject +{ + Q_OBJECT +public: + Q_INVOKABLE bool getRow(int index, std::function callback) const; + Q_INVOKABLE bool addRow(const QString &address, const QString &payment_id, const QString &description); + Q_INVOKABLE bool deleteRow(int rowId); + Q_INVOKABLE void setDescription(int index, const QString &label); + quint64 count() const; + Q_INVOKABLE QString errorString() const; + Q_INVOKABLE int errorCode() const; + Q_INVOKABLE int lookupPaymentID(const QString &payment_id) const; + Q_INVOKABLE QString getDescription(const QString &address) const; + + enum ErrorCode { + Status_Ok, + General_Error, + Invalid_Address, + Invalid_Payment_Id + }; + + Q_ENUM(ErrorCode); + +private: + void getAll(); + +signals: + void refreshStarted() const; + void refreshFinished() const; + void descriptionChanged() const; + + +public slots: + +private: + explicit AddressBook(Monero::AddressBook * abImpl, QObject *parent); + friend class Wallet; + Monero::AddressBook * m_addressBookImpl; + mutable QReadWriteLock m_lock; + QList m_rows; + QMap m_addresses; +}; + +#endif // ADDRESSBOOK_H diff --git a/src/libwalletqt/AddressBookInfo.cpp b/src/libwalletqt/AddressBookInfo.cpp new file mode 100644 index 0000000..c6e33ec --- /dev/null +++ b/src/libwalletqt/AddressBookInfo.cpp @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "AddressBookInfo.h" + +QString AddressBookInfo::address() const { + return m_address; +} + +QString AddressBookInfo::description() const { + return m_description; +} + +AddressBookInfo::AddressBookInfo(const Monero::AddressBookRow *pimpl, QObject *parent) + : QObject(parent) + , m_address(QString::fromStdString(pimpl->getAddress())) + , m_description(QString::fromStdString(pimpl->getDescription())) +{ + +} diff --git a/src/libwalletqt/AddressBookInfo.h b/src/libwalletqt/AddressBookInfo.h new file mode 100644 index 0000000..af9c609 --- /dev/null +++ b/src/libwalletqt/AddressBookInfo.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef FEATHER_ADDRESSBOOKINFO_H +#define FEATHER_ADDRESSBOOKINFO_H + +#include +#include + +class AddressBookInfo : public QObject { + Q_OBJECT + Q_PROPERTY(QString address READ address); + Q_PROPERTY(QString description READ description); + +public: + QString address() const; + QString description() const; + +private: + explicit AddressBookInfo(const Monero::AddressBookRow *pimpl, QObject *parent = nullptr); + + friend class AddressBook; + QString m_address; + QString m_description; +}; + + +#endif //FEATHER_ADDRESSBOOKINFO_H diff --git a/src/libwalletqt/CMakeLists.txt b/src/libwalletqt/CMakeLists.txt new file mode 100644 index 0000000..7d16b0f --- /dev/null +++ b/src/libwalletqt/CMakeLists.txt @@ -0,0 +1,2 @@ +file(GLOB_RECURSE SRC_SOURCES *.cpp) +file(GLOB_RECURSE SRC_HEADERS *.h) diff --git a/src/libwalletqt/Coins.cpp b/src/libwalletqt/Coins.cpp new file mode 100644 index 0000000..4c1a9e5 --- /dev/null +++ b/src/libwalletqt/Coins.cpp @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "Coins.h" + +#include + +#include "Coins.h" +#include "CoinsInfo.h" +#include + +#include +#include +#include +#include +#include + + +bool Coins::coin(int index, std::function callback) +{ + QReadLocker locker(&m_lock); + + if (index < 0 || index >= m_tinfo.size()) { + qCritical("%s: no transaction info for index %d", __FUNCTION__, index); + qCritical("%s: there's %d transactions in backend", __FUNCTION__, m_pimpl->count()); + return false; + } + + callback(*m_tinfo.value(index)); + return true; +} + +void Coins::refresh(quint32 accountIndex) +{ + emit refreshStarted(); + + { + QWriteLocker locker(&m_lock); + + qDeleteAll(m_tinfo); + m_tinfo.clear(); + + m_pimpl->refresh(); + for (const auto i : m_pimpl->getAll()) { + if (i->subaddrAccount() != accountIndex) { + continue; + } + + m_tinfo.append(new CoinsInfo(i, this)); + } + } + + emit refreshFinished(); +} + +void Coins::refreshUnlocked() +{ + QWriteLocker locker(&m_lock); + + for (CoinsInfo* c : m_tinfo) { + if (!c->unlocked()) { + bool unlocked = m_pimpl->isTransferUnlocked(c->unlockTime(), c->blockHeight()); + c->setUnlocked(unlocked); + } + } +} + +quint64 Coins::count() const +{ + QReadLocker locker(&m_lock); + + return m_tinfo.count(); +} + +void Coins::freeze(int index) const +{ + m_pimpl->setFrozen(index); + emit coinFrozen(); +} + +void Coins::thaw(int index) const +{ + m_pimpl->thaw(index); + emit coinThawed(); +} + +QStringList Coins::coins_from_txid(const QString &txid) +{ + QStringList keyimages; + + for (int i = 0; i < this->count(); i++) { + this->coin(i, [&keyimages, &txid](const CoinsInfo &x) { + if (x.hash() == txid) { + keyimages += x.keyImage(); + } + }); + } + return keyimages; +} + +Coins::Coins(Monero::Coins *pimpl, QObject *parent) + : QObject(parent) + , m_pimpl(pimpl) +{ + +} \ No newline at end of file diff --git a/src/libwalletqt/Coins.h b/src/libwalletqt/Coins.h new file mode 100644 index 0000000..66a0166 --- /dev/null +++ b/src/libwalletqt/Coins.h @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_COINS_H +#define FEATHER_COINS_H + +#include + +#include +#include +#include +#include +#include + +namespace Monero { + struct TransactionHistory; +} + +class CoinsInfo; + +class Coins : public QObject +{ +Q_OBJECT + Q_PROPERTY(int count READ count) + +public: + Q_INVOKABLE bool coin(int index, std::function callback); + Q_INVOKABLE void refresh(quint32 accountIndex); + Q_INVOKABLE void refreshUnlocked(); + Q_INVOKABLE void freeze(int index) const; + Q_INVOKABLE void thaw(int index) const; + Q_INVOKABLE QStringList coins_from_txid(const QString &txid); // Todo: return CoinsInfo vector + + quint64 count() const; + +signals: + void refreshStarted() const; + void refreshFinished() const; + void coinFrozen() const; + void coinThawed() const; + +private: + explicit Coins(Monero::Coins * pimpl, QObject *parent = nullptr); + +private: + friend class Wallet; + mutable QReadWriteLock m_lock; + Monero::Coins * m_pimpl; + mutable QList m_tinfo; +}; + +#endif //FEATHER_COINS_H diff --git a/src/libwalletqt/CoinsInfo.cpp b/src/libwalletqt/CoinsInfo.cpp new file mode 100644 index 0000000..01a0ae8 --- /dev/null +++ b/src/libwalletqt/CoinsInfo.cpp @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "CoinsInfo.h" +#include "libwalletqt/WalletManager.h" +#include "Transfer.h" +#include +#include + +quint64 CoinsInfo::blockHeight() const +{ + return m_blockHeight; +} + +QString CoinsInfo::hash() const +{ + return m_hash; +} + +quint64 CoinsInfo::internalOutputIndex() const +{ + return m_internalOutputIndex; +} + +quint64 CoinsInfo::globalOutputIndex() const +{ + return m_globalOutputIndex; +} + +bool CoinsInfo::spent() const +{ + return m_spent; +} + +bool CoinsInfo::frozen() const +{ + return m_frozen; +} + +quint64 CoinsInfo::spentHeight() const +{ + return m_spentHeight; +} + +quint64 CoinsInfo::amount() const { + return m_amount; +} + +QString CoinsInfo::displayAmount() const +{ + return WalletManager::displayAmount(m_amount); +} + +bool CoinsInfo::rct() const { + return m_rct; +} + +bool CoinsInfo::keyImageKnown() const { + return m_keyImageKnown; +} + +quint64 CoinsInfo::pkIndex() const { + return m_pkIndex; +} + +quint32 CoinsInfo::subaddrIndex() const { + return m_subaddrIndex; +} + +quint32 CoinsInfo::subaddrAccount() const { + return m_subaddrAccount; +} + +QString CoinsInfo::address() const { + return m_address; +} + +QString CoinsInfo::addressLabel() const { + return m_addressLabel; +} + +QString CoinsInfo::keyImage() const { + return m_keyImage; +} + +quint64 CoinsInfo::unlockTime() const { + return m_unlockTime; +} + +bool CoinsInfo::unlocked() const { + return m_unlocked; +} + +void CoinsInfo::setUnlocked(bool unlocked) { + m_unlocked = unlocked; +} + +QString CoinsInfo::pubKey() const { + return m_pubKey; +} + +bool CoinsInfo::coinbase() const { + return m_coinbase; +} + +CoinsInfo::CoinsInfo(const Monero::CoinsInfo *pimpl, QObject *parent) + : QObject(parent) + , m_blockHeight(pimpl->blockHeight()) + , m_hash(QString::fromStdString(pimpl->hash())) + , m_internalOutputIndex(pimpl->internalOutputIndex()) + , m_globalOutputIndex(pimpl->globalOutputIndex()) + , m_spent(pimpl->spent()) + , m_frozen(pimpl->frozen()) + , m_spentHeight(pimpl->spentHeight()) + , m_amount(pimpl->amount()) + , m_rct(pimpl->rct()) + , m_keyImageKnown(pimpl->keyImageKnown()) + , m_pkIndex(pimpl->pkIndex()) + , m_subaddrIndex(pimpl->subaddrIndex()) + , m_subaddrAccount(pimpl->subaddrAccount()) + , m_address(QString::fromStdString(pimpl->address())) + , m_addressLabel(QString::fromStdString(pimpl->addressLabel())) + , m_keyImage(QString::fromStdString(pimpl->keyImage())) + , m_unlockTime(pimpl->unlockTime()) + , m_unlocked(pimpl->unlocked()) + , m_pubKey(QString::fromStdString(pimpl->pubKey())) + , m_coinbase(pimpl->coinbase()) +{ + +} diff --git a/src/libwalletqt/CoinsInfo.h b/src/libwalletqt/CoinsInfo.h new file mode 100644 index 0000000..4739ea9 --- /dev/null +++ b/src/libwalletqt/CoinsInfo.h @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_COINSINFO_H +#define FEATHER_COINSINFO_H + +#include +#include +#include +#include + +class Coins; + +class CoinsInfo : public QObject +{ +Q_OBJECT + Q_PROPERTY(quint64 blockHeight READ blockHeight) + Q_PROPERTY(QString hash READ hash) + Q_PROPERTY(quint64 internalOutputIndex READ internalOutputIndex) + Q_PROPERTY(quint64 globalOutputIndex READ globalOutputIndex) + Q_PROPERTY(bool spent READ spent) + Q_PROPERTY(bool frozen READ frozen) + Q_PROPERTY(quint64 spentHeight READ spentHeight) + Q_PROPERTY(quint64 amount READ amount) + Q_PROPERTY(QString displayAmount READ displayAmount) + Q_PROPERTY(bool rct READ rct) + Q_PROPERTY(bool keyImageKnown READ keyImageKnown) + Q_PROPERTY(quint64 pkIndex READ pkIndex) + Q_PROPERTY(quint32 subaddrIndex READ subaddrIndex) + Q_PROPERTY(quint32 subaddrAccount READ subaddrAccount) + Q_PROPERTY(QString address READ address) + Q_PROPERTY(QString addressLabel READ addressLabel) + Q_PROPERTY(QString keyImage READ keyImage) + Q_PROPERTY(quint64 unlockTime READ unlockTime) + Q_PROPERTY(bool unlocked READ unlocked) + Q_PROPERTY(QString pubKey READ pubKey) + Q_PROPERTY(bool coinbase READ coinbase) + +public: + quint64 blockHeight() const; + QString hash() const; + quint64 internalOutputIndex() const; + quint64 globalOutputIndex() const; + bool spent() const; + bool frozen() const; + quint64 spentHeight() const; + quint64 amount() const; + QString displayAmount() const; + bool rct() const; + bool keyImageKnown() const; + quint64 pkIndex() const; + quint32 subaddrIndex() const; + quint32 subaddrAccount() const; + QString address() const; + QString addressLabel() const; + QString keyImage() const; + quint64 unlockTime() const; + bool unlocked() const; + QString pubKey() const; + bool coinbase() const; + + void setUnlocked(bool unlocked); + +private: + explicit CoinsInfo(const Monero::CoinsInfo *pimpl, QObject *parent = nullptr); +private: + friend class Coins; + + quint64 m_blockHeight; + QString m_hash; + quint64 m_internalOutputIndex; + quint64 m_globalOutputIndex; + bool m_spent; + bool m_frozen; + quint64 m_spentHeight; + quint64 m_amount; + bool m_rct; + bool m_keyImageKnown; + quint64 m_pkIndex; + quint32 m_subaddrIndex; + quint32 m_subaddrAccount; + QString m_address; + QString m_addressLabel; + QString m_keyImage; + quint64 m_unlockTime; + bool m_unlocked; + QString m_pubKey; + bool m_coinbase; +}; + +#endif //FEATHER_COINSINFO_H diff --git a/src/libwalletqt/PassphraseHelper.cpp b/src/libwalletqt/PassphraseHelper.cpp new file mode 100644 index 0000000..f4cea92 --- /dev/null +++ b/src/libwalletqt/PassphraseHelper.cpp @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "PassphraseHelper.h" +#include +#include + +Monero::optional PassphraseHelper::onDevicePassphraseRequest(bool & on_device) +{ + qDebug() << __FUNCTION__; + QMutexLocker locker(&m_mutex_pass); + m_passphrase_on_device = true; + m_passphrase_abort = false; + + if (m_prompter != nullptr){ + m_prompter->onWalletPassphraseNeeded(on_device); + } + + m_cond_pass.wait(&m_mutex_pass); + + if (m_passphrase_abort) + { + throw std::runtime_error("Passphrase entry abort"); + } + + on_device = m_passphrase_on_device; + if (!on_device) { + auto tmpPass = m_passphrase.toStdString(); + m_passphrase = QString(); + return Monero::optional(tmpPass); + } else { + return Monero::optional(); + } +} + +void PassphraseHelper::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) +{ + qDebug() << __FUNCTION__; + QMutexLocker locker(&m_mutex_pass); + m_passphrase = passphrase; + m_passphrase_abort = entry_abort; + m_passphrase_on_device = enter_on_device; + + m_cond_pass.wakeAll(); +} diff --git a/src/libwalletqt/PassphraseHelper.h b/src/libwalletqt/PassphraseHelper.h new file mode 100644 index 0000000..2cd1c8c --- /dev/null +++ b/src/libwalletqt/PassphraseHelper.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef MONERO_GUI_PASSPHRASEHELPER_H +#define MONERO_GUI_PASSPHRASEHELPER_H + +#include +#include +#include +#include +#include +#include + +/** + * Implements component responsible for showing entry prompt to the user, + * typically Wallet / Wallet manager. + */ +class PassprasePrompter { +public: + virtual void onWalletPassphraseNeeded(bool onDevice) = 0; +}; + +/** + * Implements receiver of the passphrase responsible for passing it back to the wallet, + * typically wallet listener. + */ +class PassphraseReceiver { +public: + virtual void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) = 0; +}; + +class PassphraseHelper { +public: + PassphraseHelper(PassprasePrompter * prompter=nullptr): m_prompter(prompter) {}; + PassphraseHelper(const PassphraseHelper & h): PassphraseHelper(h.m_prompter) {}; + Monero::optional onDevicePassphraseRequest(bool & on_device); + void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort); + +private: + PassprasePrompter * m_prompter; + QWaitCondition m_cond_pass; + QMutex m_mutex_pass; + QString m_passphrase; + bool m_passphrase_abort; + bool m_passphrase_on_device; + +}; + +#endif //MONERO_GUI_PASSPHRASEHELPER_H diff --git a/src/libwalletqt/PendingTransaction.cpp b/src/libwalletqt/PendingTransaction.cpp new file mode 100644 index 0000000..7c9aeb5 --- /dev/null +++ b/src/libwalletqt/PendingTransaction.cpp @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "PendingTransaction.h" + + +PendingTransaction::Status PendingTransaction::status() const +{ + return static_cast(m_pimpl->status()); +} + +QString PendingTransaction::errorString() const +{ + return QString::fromStdString(m_pimpl->errorString()); +} + +bool PendingTransaction::commit() +{ + // Save transaction to file if fileName is set. + if(!m_fileName.isEmpty()) + return m_pimpl->commit(m_fileName.toStdString()); + return m_pimpl->commit(m_fileName.toStdString()); +} + +quint64 PendingTransaction::amount() const +{ + return m_pimpl->amount(); +} + +quint64 PendingTransaction::dust() const +{ + return m_pimpl->dust(); +} + +quint64 PendingTransaction::fee() const +{ + return m_pimpl->fee(); +} + + +QStringList PendingTransaction::txid() const +{ + QStringList list; + std::vector txid = m_pimpl->txid(); + for (const auto &t: txid) + list.append(QString::fromStdString(t)); + return list; +} + + +quint64 PendingTransaction::txCount() const +{ + return m_pimpl->txCount(); +} + +QList PendingTransaction::subaddrIndices() const +{ + std::vector> subaddrIndices = m_pimpl->subaddrIndices(); + QList result; + for (const auto& x : subaddrIndices) + for (uint32_t i : x) + result.push_back(i); + return result; +} + +void PendingTransaction::setFilename(const QString &fileName) +{ + m_fileName = fileName; +} + +PendingTransaction::PendingTransaction(Monero::PendingTransaction *pt, QObject *parent) + : QObject(parent), m_pimpl(pt) +{ + +} diff --git a/src/libwalletqt/PendingTransaction.h b/src/libwalletqt/PendingTransaction.h new file mode 100644 index 0000000..5b60bab --- /dev/null +++ b/src/libwalletqt/PendingTransaction.h @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef PENDINGTRANSACTION_H +#define PENDINGTRANSACTION_H + +#include +#include +#include + +#include + +//namespace Monero { +//class PendingTransaction; +//} + +class PendingTransaction : public QObject +{ + Q_OBJECT + Q_PROPERTY(Status status READ status) + Q_PROPERTY(QString errorString READ errorString) + Q_PROPERTY(quint64 amount READ amount) + Q_PROPERTY(quint64 dust READ dust) + Q_PROPERTY(quint64 fee READ fee) + Q_PROPERTY(QStringList txid READ txid) + Q_PROPERTY(quint64 txCount READ txCount) + Q_PROPERTY(QList subaddrIndices READ subaddrIndices) + +public: + enum Status { + Status_Ok = Monero::PendingTransaction::Status_Ok, + Status_Error = Monero::PendingTransaction::Status_Error, + Status_Critical = Monero::PendingTransaction::Status_Critical + }; + Q_ENUM(Status) + + enum Priority { + Priority_Low = Monero::PendingTransaction::Priority_Low, + Priority_Medium = Monero::PendingTransaction::Priority_Medium, + Priority_High = Monero::PendingTransaction::Priority_High + }; + Q_ENUM(Priority) + + + Status status() const; + QString errorString() const; + Q_INVOKABLE bool commit(); + quint64 amount() const; + quint64 dust() const; + quint64 fee() const; + QStringList txid() const; + quint64 txCount() const; + QList subaddrIndices() const; + Q_INVOKABLE void setFilename(const QString &fileName); + +private: + explicit PendingTransaction(Monero::PendingTransaction * pt, QObject *parent = 0); + +private: + friend class Wallet; + Monero::PendingTransaction * m_pimpl; + QString m_fileName; +}; + +#endif // PENDINGTRANSACTION_H diff --git a/src/libwalletqt/Ring.h b/src/libwalletqt/Ring.h new file mode 100644 index 0000000..95fc34e --- /dev/null +++ b/src/libwalletqt/Ring.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_RINGS_H +#define FEATHER_RINGS_H + +#include +#include +#include +#include + +class Ring : public QObject +{ +Q_OBJECT + Q_PROPERTY(QString keyImage READ keyImage) + Q_PROPERTY(std::vector ringMembers READ ringMembers) +private: + explicit Ring(QString _keyImage, std::vector _ringMembers, QObject *parent = nullptr): QObject(parent), m_keyImage(std::move(_keyImage)), m_ringMembers(std::move(_ringMembers)) {}; +private: + friend class TransactionInfo; + QString m_keyImage; + std::vector m_ringMembers; +public: + QString keyImage() const { return m_keyImage; } + std::vector ringMembers() const { return m_ringMembers; } +}; + +#endif //FEATHER_RINGS_H diff --git a/src/libwalletqt/Subaddress.cpp b/src/libwalletqt/Subaddress.cpp new file mode 100644 index 0000000..d046676 --- /dev/null +++ b/src/libwalletqt/Subaddress.cpp @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "Subaddress.h" +#include + +Subaddress::Subaddress(Monero::Subaddress *subaddressImpl, QObject *parent) + : QObject(parent), m_subaddressImpl(subaddressImpl), m_unusedLookahead(0) +{ + getAll(); +} + +void Subaddress::getAll() const +{ + emit refreshStarted(); + + { + QWriteLocker locker(&m_lock); + + m_unusedLookahead = 0; + + m_rows.clear(); + for (auto &row: m_subaddressImpl->getAll()) { + m_rows.append(row); + + if (row->isUsed()) + m_unusedLookahead = 0; + else + m_unusedLookahead += 1; + } + } + + emit refreshFinished(); +} + +bool Subaddress::getRow(int index, std::function callback) const +{ + QReadLocker locker(&m_lock); + + if (index < 0 || index >= m_rows.size()) + { + return false; + } + + callback(*m_rows.value(index)); + return true; +} + +void Subaddress::addRow(quint32 accountIndex, const QString &label) const +{ + m_subaddressImpl->addRow(accountIndex, label.toStdString()); + getAll(); +} + +void Subaddress::setLabel(quint32 accountIndex, quint32 addressIndex, const QString &label) const +{ + m_subaddressImpl->setLabel(accountIndex, addressIndex, label.toStdString()); + getAll(); + emit labelChanged(); +} + +void Subaddress::refresh(quint32 accountIndex) const +{ + m_subaddressImpl->refresh(accountIndex); + getAll(); +} + +quint64 Subaddress::unusedLookahead() const +{ + QReadLocker locker(&m_lock); + + return m_unusedLookahead; +} + +quint64 Subaddress::count() const +{ + QReadLocker locker(&m_lock); + + return m_rows.size(); +} diff --git a/src/libwalletqt/Subaddress.h b/src/libwalletqt/Subaddress.h new file mode 100644 index 0000000..ec86bc2 --- /dev/null +++ b/src/libwalletqt/Subaddress.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef SUBADDRESS_H +#define SUBADDRESS_H + +#include + +#include +#include +#include +#include +#include + +class Subaddress : public QObject +{ + Q_OBJECT +public: + Q_INVOKABLE void getAll() const; + Q_INVOKABLE bool getRow(int index, std::function callback) const; + Q_INVOKABLE void addRow(quint32 accountIndex, const QString &label) const; + Q_INVOKABLE void setLabel(quint32 accountIndex, quint32 addressIndex, const QString &label) const; + Q_INVOKABLE void refresh(quint32 accountIndex) const; + Q_INVOKABLE quint64 unusedLookahead() const; + quint64 count() const; + +signals: + void refreshStarted() const; + void refreshFinished() const; + void labelChanged() const; + +public slots: + +private: + explicit Subaddress(Monero::Subaddress * subaddressImpl, QObject *parent); + friend class Wallet; + mutable QReadWriteLock m_lock; + Monero::Subaddress * m_subaddressImpl; + mutable QList m_rows; + mutable quint64 m_unusedLookahead; +}; + +#endif // SUBADDRESS_H diff --git a/src/libwalletqt/SubaddressAccount.cpp b/src/libwalletqt/SubaddressAccount.cpp new file mode 100644 index 0000000..82e19d2 --- /dev/null +++ b/src/libwalletqt/SubaddressAccount.cpp @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "SubaddressAccount.h" +#include + +SubaddressAccount::SubaddressAccount(Monero::SubaddressAccount *subaddressAccountImpl, QObject *parent) + : QObject(parent), m_subaddressAccountImpl(subaddressAccountImpl) +{ + getAll(); +} + +void SubaddressAccount::getAll() const +{ + emit refreshStarted(); + + { + QWriteLocker locker(&m_lock); + m_rows.clear(); + for (auto &row: m_subaddressAccountImpl->getAll()) { + m_rows.append(row); + } + } + + emit refreshFinished(); +} + +bool SubaddressAccount::getRow(int index, std::function callback) const +{ + QReadLocker locker(&m_lock); + + if (index < 0 || index >= m_rows.size()) + { + return false; + } + + callback(*m_rows.value(index)); + return true; +} + +void SubaddressAccount::addRow(const QString &label) const +{ + m_subaddressAccountImpl->addRow(label.toStdString()); + getAll(); +} + +void SubaddressAccount::setLabel(quint32 accountIndex, const QString &label) const +{ + m_subaddressAccountImpl->setLabel(accountIndex, label.toStdString()); + getAll(); +} + +void SubaddressAccount::refresh() const +{ + m_subaddressAccountImpl->refresh(); + getAll(); +} + +quint64 SubaddressAccount::count() const +{ + QReadLocker locker(&m_lock); + + return m_rows.size(); +} diff --git a/src/libwalletqt/SubaddressAccount.h b/src/libwalletqt/SubaddressAccount.h new file mode 100644 index 0000000..ca04afc --- /dev/null +++ b/src/libwalletqt/SubaddressAccount.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef SUBADDRESSACCOUNT_H +#define SUBADDRESSACCOUNT_H + +#include + +#include +#include +#include +#include +#include + +class SubaddressAccount : public QObject +{ + Q_OBJECT +public: + Q_INVOKABLE void getAll() const; + Q_INVOKABLE bool getRow(int index, std::function callback) const; + Q_INVOKABLE void addRow(const QString &label) const; + Q_INVOKABLE void setLabel(quint32 accountIndex, const QString &label) const; + Q_INVOKABLE void refresh() const; + quint64 count() const; + +signals: + void refreshStarted() const; + void refreshFinished() const; + +public slots: + +private: + explicit SubaddressAccount(Monero::SubaddressAccount * subaddressAccountImpl, QObject *parent); + friend class Wallet; + mutable QReadWriteLock m_lock; + Monero::SubaddressAccount * m_subaddressAccountImpl; + mutable QList m_rows; +}; + +#endif // SUBADDRESSACCOUNT_H diff --git a/src/libwalletqt/TransactionHistory.cpp b/src/libwalletqt/TransactionHistory.cpp new file mode 100644 index 0000000..38c086c --- /dev/null +++ b/src/libwalletqt/TransactionHistory.cpp @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "TransactionHistory.h" +#include "TransactionInfo.h" +#include "utils/utils.h" +#include "appcontext.h" +#include + +#include +#include +#include +#include +#include + + +bool TransactionHistory::transaction(int index, std::function callback) +{ + QReadLocker locker(&m_lock); + + if (index < 0 || index >= m_tinfo.size()) { + qCritical("%s: no transaction info for index %d", __FUNCTION__, index); + qCritical("%s: there's %d transactions in backend", __FUNCTION__, m_pimpl->count()); + return false; + } + + callback(*m_tinfo.value(index)); + return true; +} + +TransactionInfo* TransactionHistory::transaction(const QString &id) +{ + QReadLocker locker(&m_lock); + + auto itr = std::find_if(m_tinfo.begin(), m_tinfo.end(), + [&](const TransactionInfo * ti) { + return ti->hash() == id; + }); + return itr != m_tinfo.end() ? *itr : nullptr; +} + +void TransactionHistory::refresh(quint32 accountIndex) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + QDateTime firstDateTime = QDate(2014, 4, 18).startOfDay(); +#else + QDateTime firstDateTime = QDateTime(QDate(2014, 4, 18)); // the genesis block +#endif + QDateTime lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones) + + emit refreshStarted(); + + { + QWriteLocker locker(&m_lock); + + qDeleteAll(m_tinfo); + m_tinfo.clear(); + + quint64 lastTxHeight = 0; + m_locked = false; + m_minutesToUnlock = 0; + + m_pimpl->refresh(); + for (const auto i : m_pimpl->getAll()) { + if (i->subaddrAccount() != accountIndex) { + continue; + } + + m_tinfo.append(new TransactionInfo(i, this)); + + const TransactionInfo *ti = m_tinfo.back(); + // looking for transactions timestamp scope + if (ti->timestamp() >= lastDateTime) { + lastDateTime = ti->timestamp(); + } + if (ti->timestamp() <= firstDateTime) { + firstDateTime = ti->timestamp(); + } + quint64 requiredConfirmations = (ti->blockHeight() < ti->unlockTime()) ? ti->unlockTime() - ti->blockHeight() : 10; + // store last tx height + if (ti->confirmations() < requiredConfirmations && ti->blockHeight() >= lastTxHeight) { + lastTxHeight = ti->blockHeight(); + // TODO: Fetch block time and confirmations needed from wallet2? + m_minutesToUnlock = (requiredConfirmations - ti->confirmations()) * 2; + m_locked = true; + } + } + } + + emit refreshFinished(); + + if (m_firstDateTime != firstDateTime) { + m_firstDateTime = firstDateTime; + emit firstDateTimeChanged(); + } + if (m_lastDateTime != lastDateTime) { + m_lastDateTime = lastDateTime; + emit lastDateTimeChanged(); + } +} + +void TransactionHistory::setTxNote(const QString &txid, const QString ¬e) +{ + m_pimpl->setTxNote(txid.toStdString(), note.toStdString()); + this->refresh(0); // todo: get actual account index + emit txNoteChanged(); +} + +quint64 TransactionHistory::count() const +{ + QReadLocker locker(&m_lock); + + return m_tinfo.count(); +} + +QDateTime TransactionHistory::firstDateTime() const +{ + return m_firstDateTime; +} + +QDateTime TransactionHistory::lastDateTime() const +{ + return m_lastDateTime; +} + +quint64 TransactionHistory::minutesToUnlock() const +{ + return m_minutesToUnlock; +} + +bool TransactionHistory::TransactionHistory::locked() const +{ + return m_locked; +} + + +TransactionHistory::TransactionHistory(Monero::TransactionHistory *pimpl, QObject *parent) + : QObject(parent), m_pimpl(pimpl), m_minutesToUnlock(0), m_locked(false) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + m_firstDateTime = QDate(2014, 4, 18).startOfDay(); +#else + m_firstDateTime = QDateTime(QDate(2014, 4, 18)); // the genesis block +#endif + m_lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones) +} + +bool TransactionHistory::writeCSV(const QString &path) { + auto data = QString(""); + QReadLocker locker(&m_lock); + for (const auto &tx : m_pimpl->getAll()) { + if (tx->subaddrAccount() != 0) { // only account 0 + continue; + } + + TransactionInfo info(tx, this); + + // collect column data + QDateTime timeStamp = info.timestamp(); + double amount = info.amount(); + + // calc historical fiat price + QString fiatAmount; + QString preferredFiatSymbol = config()->get(Config::preferredFiatCurrency).toString(); + const double usd_price = AppContext::txFiatHistory->get(timeStamp.toString("yyyyMMdd")); + double fiat_price = usd_price * amount; + + if(preferredFiatSymbol != "USD") + fiat_price = AppContext::prices->convert("USD", preferredFiatSymbol, fiat_price); + double fiat_rounded = ceil(Utils::roundSignificant(fiat_price, 3) * 100.0) / 100.0; + if(fiat_price != 0) + fiatAmount = QString("%1 %2").arg(QString::number(fiat_rounded)).arg(preferredFiatSymbol); + + // collect some more column data + quint64 atomicAmount = info.atomicAmount(); + quint32 subaddrAccount = info.subaddrAccount(); + QString fee = info.fee(); + QString direction = QString(""); + TransactionInfo::Direction _direction = info.direction(); + if(_direction == TransactionInfo::Direction_In) + direction = QString("in"); + else if(_direction == TransactionInfo::Direction_Out) + direction = QString("out"); + else + continue; // skip TransactionInfo::Direction_Both + + QString label = info.label(); + label.remove(QChar('"')); // reserved + quint64 blockHeight = info.blockHeight(); + QString date = info.date() + " " + info.time(); + uint epoch = timeStamp.toTime_t(); + QString displayAmount = info.displayAmount(); + QString paymentId = info.paymentId(); + if(paymentId == "0000000000000000") + paymentId = ""; + + // format and write + QString line = QString("%1,%2,%3,%4,%5,\"%6\",%7,%8,%9,\"%10\",%11,%12\n") + .arg(QString::number(blockHeight), QString::number(epoch), date) + .arg(direction, QString::number(amount), fiatAmount, QString::number(atomicAmount)) + .arg(info.fee(), info.hash(), label, QString::number(subaddrAccount)) + .arg(paymentId); + data += line; + } + + if(data.isEmpty()) + return false; + + data = QString("blockHeight,epoch,date,direction,amount,fiat,atomicAmount,fee,txid,label,subaddrAccount,paymentId\n%1").arg(data); + return Utils::fileWrite(path, data); +} diff --git a/src/libwalletqt/TransactionHistory.h b/src/libwalletqt/TransactionHistory.h new file mode 100644 index 0000000..e37cf2b --- /dev/null +++ b/src/libwalletqt/TransactionHistory.h @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef TRANSACTIONHISTORY_H +#define TRANSACTIONHISTORY_H + +#include + +#include +#include +#include +#include + +namespace Monero { +struct TransactionHistory; +} + +class TransactionInfo; + +class TransactionHistory : public QObject +{ + Q_OBJECT + Q_PROPERTY(int count READ count) + Q_PROPERTY(QDateTime firstDateTime READ firstDateTime NOTIFY firstDateTimeChanged) + Q_PROPERTY(QDateTime lastDateTime READ lastDateTime NOTIFY lastDateTimeChanged) + Q_PROPERTY(int minutesToUnlock READ minutesToUnlock) + Q_PROPERTY(bool locked READ locked) + +public: + Q_INVOKABLE bool transaction(int index, std::function callback); + Q_INVOKABLE TransactionInfo * transaction(const QString &id); + Q_INVOKABLE void refresh(quint32 accountIndex); + Q_INVOKABLE void setTxNote(const QString &txid, const QString ¬e); + Q_INVOKABLE bool writeCSV(const QString &path); + quint64 count() const; + QDateTime firstDateTime() const; + QDateTime lastDateTime() const; + quint64 minutesToUnlock() const; + bool locked() const; + +signals: + void refreshStarted() const; + void refreshFinished() const; + void firstDateTimeChanged() const; + void lastDateTimeChanged() const; + void txNoteChanged() const; + +private: + explicit TransactionHistory(Monero::TransactionHistory * pimpl, QObject *parent = nullptr); + +private: + friend class Wallet; + mutable QReadWriteLock m_lock; + Monero::TransactionHistory * m_pimpl; + mutable QList m_tinfo; + mutable QDateTime m_firstDateTime; + mutable QDateTime m_lastDateTime; + mutable int m_minutesToUnlock; + // history contains locked transfers + mutable bool m_locked; + +}; + +#endif // TRANSACTIONHISTORY_H diff --git a/src/libwalletqt/TransactionInfo.cpp b/src/libwalletqt/TransactionInfo.cpp new file mode 100644 index 0000000..3352198 --- /dev/null +++ b/src/libwalletqt/TransactionInfo.cpp @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "TransactionInfo.h" +#include "libwalletqt/WalletManager.h" +#include "Transfer.h" +#include "Ring.h" +#include +#include + +TransactionInfo::Direction TransactionInfo::direction() const +{ + return m_direction; +} + +bool TransactionInfo::isPending() const +{ + return m_pending; +} + +bool TransactionInfo::isFailed() const +{ + return m_failed; +} + +bool TransactionInfo::isCoinbase() const +{ + return m_coinbase; +} + +double TransactionInfo::amount() const +{ + // there's no unsigned uint64 for JS, so better use double + return displayAmount().toDouble(); +} + +quint64 TransactionInfo::atomicAmount() const +{ + return m_amount; +} + +QString TransactionInfo::displayAmount() const +{ + return WalletManager::displayAmount(m_amount); +} + +QString TransactionInfo::fee() const +{ + if(m_fee == 0) + return ""; + return WalletManager::displayAmount(m_fee); +} + +quint64 TransactionInfo::blockHeight() const +{ + return m_blockHeight; +} + +QString TransactionInfo::description() const +{ + return m_description; +} + +QSet TransactionInfo::subaddrIndex() const +{ + return m_subaddrIndex; +} + +quint32 TransactionInfo::subaddrAccount() const +{ + return m_subaddrAccount; +} + +QString TransactionInfo::label() const +{ + return m_label; +} + +quint64 TransactionInfo::confirmations() const +{ + return m_confirmations; +} + +quint64 TransactionInfo::confirmationsRequired() const +{ + return (m_blockHeight < m_unlockTime) ? m_unlockTime - m_blockHeight : 10; +} + +quint64 TransactionInfo::unlockTime() const +{ + return m_unlockTime; +} + +QString TransactionInfo::hash() const +{ + return m_hash; +} + +QDateTime TransactionInfo::timestamp() const +{ + return m_timestamp; +} + +QString TransactionInfo::date() const +{ + return timestamp().date().toString(Qt::ISODate); +} + +QString TransactionInfo::time() const +{ + return timestamp().time().toString(Qt::ISODate); +} + +QString TransactionInfo::paymentId() const +{ + return m_paymentId; +} + +QString TransactionInfo::destinations_formatted() const +{ + QString destinations; + for (auto const& t: m_transfers) { + if (!destinations.isEmpty()) + destinations += "
"; + destinations += WalletManager::displayAmount(t->amount()) + ": " + t->address(); + } + return destinations; +} + +QString TransactionInfo::rings_formatted() const +{ + QString rings; + for (auto const& r: m_rings) { + rings += r->keyImage() + ": \n"; + for (uint64_t m : r->ringMembers()){ + rings += QString::number(m) + " "; + } + rings += "\n\n"; + } + return rings; +} + +TransactionInfo::TransactionInfo(const Monero::TransactionInfo *pimpl, QObject *parent) + : QObject(parent) + , m_amount(pimpl->amount()) + , m_blockHeight(pimpl->blockHeight()) + , m_description(QString::fromStdString(pimpl->description())) + , m_confirmations(pimpl->confirmations()) + , m_direction(static_cast(pimpl->direction())) + , m_failed(pimpl->isFailed()) + , m_fee(pimpl->fee()) + , m_hash(QString::fromStdString(pimpl->hash())) + , m_label(QString::fromStdString(pimpl->label())) + , m_paymentId(QString::fromStdString(pimpl->paymentId())) + , m_pending(pimpl->isPending()) + , m_subaddrAccount(pimpl->subaddrAccount()) + , m_timestamp(QDateTime::fromSecsSinceEpoch(pimpl->timestamp())) + , m_unlockTime(pimpl->unlockTime()) + , m_coinbase(pimpl->isCoinbase()) +{ + for (auto const &t: pimpl->transfers()) + { + Transfer *transfer = new Transfer(t.amount, QString::fromStdString(t.address), this); + m_transfers.append(transfer); + } + for (auto const &r: pimpl->rings()) + { + Ring *ring = new Ring(QString::fromStdString(r.first), r.second, this); + m_rings.append(ring); + } + for (uint32_t i : pimpl->subaddrIndex()) + { + m_subaddrIndex.insert(i); + } +} diff --git a/src/libwalletqt/TransactionInfo.h b/src/libwalletqt/TransactionInfo.h new file mode 100644 index 0000000..98dece9 --- /dev/null +++ b/src/libwalletqt/TransactionInfo.h @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef TRANSACTIONINFO_H +#define TRANSACTIONINFO_H + +#include +#include +#include +#include + +class Transfer; +class Ring; + +class TransactionInfo : public QObject +{ + Q_OBJECT + Q_PROPERTY(Direction direction READ direction) + Q_PROPERTY(bool isPending READ isPending) + Q_PROPERTY(bool isFailed READ isFailed) + Q_PROPERTY(bool isCoinbase READ isCoinbase) + Q_PROPERTY(double amount READ amount) + Q_PROPERTY(quint64 atomicAmount READ atomicAmount) + Q_PROPERTY(QString displayAmount READ displayAmount) + Q_PROPERTY(QString fee READ fee) + Q_PROPERTY(quint64 blockHeight READ blockHeight) + Q_PROPERTY(QString description READ description) + Q_PROPERTY(QSet subaddrIndex READ subaddrIndex) + Q_PROPERTY(quint32 subaddrAccount READ subaddrAccount) + Q_PROPERTY(QString label READ label) + Q_PROPERTY(quint64 confirmations READ confirmations) + Q_PROPERTY(quint64 confirmationsRequired READ confirmationsRequired) + Q_PROPERTY(quint64 unlockTime READ unlockTime) + Q_PROPERTY(QString hash READ hash) + Q_PROPERTY(QDateTime timestamp READ timestamp) + Q_PROPERTY(QString date READ date) + Q_PROPERTY(QString time READ time) + Q_PROPERTY(QString paymentId READ paymentId) + Q_PROPERTY(QString destinations_formatted READ destinations_formatted) + Q_PROPERTY(QString rings_formatted READ rings_formatted) + +public: + enum Direction { + Direction_In = Monero::TransactionInfo::Direction_In, + Direction_Out = Monero::TransactionInfo::Direction_Out, + Direction_Both // invalid direction value, used for filtering + }; + + Q_ENUM(Direction) + + Direction direction() const; + bool isPending() const; + bool isFailed() const; + bool isCoinbase() const; + double amount() const; + quint64 atomicAmount() const; + QString displayAmount() const; + QString fee() const; + quint64 blockHeight() const; + QString description() const; + QSet subaddrIndex() const; + quint32 subaddrAccount() const; + QString label() const; + quint64 confirmations() const; + quint64 confirmationsRequired() const; + quint64 unlockTime() const; + //! transaction_id + QString hash() const; + QDateTime timestamp() const; + QString date() const; + QString time() const; + QString paymentId() const; + //! only applicable for output transactions + //! used in tx details popup + QString destinations_formatted() const; + QString rings_formatted() const; + +private: + explicit TransactionInfo(const Monero::TransactionInfo *pimpl, QObject *parent = nullptr); +private: + friend class TransactionHistory; + mutable QList m_transfers; + mutable QList m_rings; + quint64 m_amount; + quint64 m_blockHeight; + QString m_description; + quint64 m_confirmations; + quint64 m_confirmationsRequired; + Direction m_direction; + bool m_failed; + quint64 m_fee; + QString m_hash; + QString m_label; + QString m_paymentId; + bool m_pending; + quint32 m_subaddrAccount; + QSet m_subaddrIndex; + QDateTime m_timestamp; + quint64 m_unlockTime; + bool m_coinbase; +}; + +#endif // TRANSACTIONINFO_H diff --git a/src/libwalletqt/Transfer.h b/src/libwalletqt/Transfer.h new file mode 100644 index 0000000..3f81d0c --- /dev/null +++ b/src/libwalletqt/Transfer.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef TRANSFER_H +#define TRANSFER_H + +#include +#include +#include + +class Transfer : public QObject +{ + Q_OBJECT + Q_PROPERTY(quint64 amount READ amount) + Q_PROPERTY(QString address READ address) +private: + explicit Transfer(uint64_t _amount, QString _address, QObject *parent = 0): QObject(parent), m_amount(_amount), m_address(std::move(_address)) {}; +private: + friend class TransactionInfo; + quint64 m_amount; + QString m_address; +public: + quint64 amount() const { return m_amount; } + QString address() const { return m_address; } + +}; + +#endif // TRANSACTIONINFO_H diff --git a/src/libwalletqt/UnsignedTransaction.cpp b/src/libwalletqt/UnsignedTransaction.cpp new file mode 100644 index 0000000..7cbe9b4 --- /dev/null +++ b/src/libwalletqt/UnsignedTransaction.cpp @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "UnsignedTransaction.h" +#include +#include + +UnsignedTransaction::Status UnsignedTransaction::status() const +{ + return static_cast(m_pimpl->status()); +} + +QString UnsignedTransaction::errorString() const +{ + return QString::fromStdString(m_pimpl->errorString()); +} + +quint64 UnsignedTransaction::amount(size_t index) const +{ + std::vector arr = m_pimpl->amount(); + if(index > arr.size() - 1) + return 0; + return arr[index]; +} + +quint64 UnsignedTransaction::fee(size_t index) const +{ + std::vector arr = m_pimpl->fee(); + if(index > arr.size() - 1) + return 0; + return arr[index]; +} + +quint64 UnsignedTransaction::mixin(size_t index) const +{ + std::vector arr = m_pimpl->mixin(); + if(index > arr.size() - 1) + return 0; + return arr[index]; +} + +quint64 UnsignedTransaction::txCount() const +{ + return m_pimpl->txCount(); +} + +quint64 UnsignedTransaction::minMixinCount() const +{ + return m_pimpl->minMixinCount(); +} + +QString UnsignedTransaction::confirmationMessage() const +{ + return QString::fromStdString(m_pimpl->confirmationMessage()); +} + +QStringList UnsignedTransaction::paymentId() const +{ + QList list; + for (const auto &t: m_pimpl->paymentId()) + list.append(QString::fromStdString(t)); + return list; +} + +QStringList UnsignedTransaction::recipientAddress() const +{ + QList list; + for (const auto &t: m_pimpl->recipientAddress()) + list.append(QString::fromStdString(t)); + return list; +} + +bool UnsignedTransaction::sign(const QString &fileName) const +{ + if(!m_pimpl->sign(fileName.toStdString())) + return false; + // export key images + return m_walletImpl->exportKeyImages(fileName.toStdString() + "_keyImages"); +} + +void UnsignedTransaction::setFilename(const QString &fileName) +{ + m_fileName = fileName; +} + +UnsignedTransaction::UnsignedTransaction(Monero::UnsignedTransaction *pt, Monero::Wallet *walletImpl, QObject *parent) + : QObject(parent), m_pimpl(pt), m_walletImpl(walletImpl) +{ + +} + +UnsignedTransaction::~UnsignedTransaction() +{ + delete m_pimpl; +} diff --git a/src/libwalletqt/UnsignedTransaction.h b/src/libwalletqt/UnsignedTransaction.h new file mode 100644 index 0000000..c0906bf --- /dev/null +++ b/src/libwalletqt/UnsignedTransaction.h @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef UNSIGNEDTRANSACTION_H +#define UNSIGNEDTRANSACTION_H + +#include + +#include + +class UnsignedTransaction : public QObject +{ + Q_OBJECT + Q_PROPERTY(Status status READ status) + Q_PROPERTY(QString errorString READ errorString) + // Q_PROPERTY(QList amount READ amount) + // Q_PROPERTY(QList fee READ fee) + Q_PROPERTY(quint64 txCount READ txCount) + Q_PROPERTY(QString confirmationMessage READ confirmationMessage) + Q_PROPERTY(QStringList recipientAddress READ recipientAddress) + Q_PROPERTY(QStringList paymentId READ paymentId) + Q_PROPERTY(quint64 minMixinCount READ minMixinCount) + +public: + enum Status { + Status_Ok = Monero::UnsignedTransaction::Status_Ok, + Status_Error = Monero::UnsignedTransaction::Status_Error, + Status_Critical = Monero::UnsignedTransaction::Status_Critical + }; + Q_ENUM(Status) + + Status status() const; + QString errorString() const; + Q_INVOKABLE quint64 amount(size_t index) const; + Q_INVOKABLE quint64 fee(size_t index) const; + Q_INVOKABLE quint64 mixin(size_t index) const; + QStringList recipientAddress() const; + QStringList paymentId() const; + quint64 txCount() const; + QString confirmationMessage() const; + quint64 minMixinCount() const; + Q_INVOKABLE bool sign(const QString &fileName) const; + Q_INVOKABLE void setFilename(const QString &fileName); + +private: + explicit UnsignedTransaction(Monero::UnsignedTransaction * pt, Monero::Wallet *walletImpl, QObject *parent = 0); + ~UnsignedTransaction(); +private: + friend class Wallet; + Monero::UnsignedTransaction * m_pimpl; + QString m_fileName; + Monero::Wallet * m_walletImpl; +}; + +#endif // UNSIGNEDTRANSACTION_H diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp new file mode 100644 index 0000000..51d4d58 --- /dev/null +++ b/src/libwalletqt/Wallet.cpp @@ -0,0 +1,1074 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "Wallet.h" +#include "PendingTransaction.h" +#include "UnsignedTransaction.h" +#include "TransactionHistory.h" +#include "AddressBook.h" +#include "Subaddress.h" +#include "SubaddressAccount.h" +#include "Coins.h" +#include "model/TransactionHistoryModel.h" +#include "model/TransactionHistoryProxyModel.h" +#include "model/AddressBookModel.h" +#include "model/SubaddressModel.h" +#include "model/SubaddressAccountModel.h" +#include "model/CoinsModel.h" +#include "wallet/api/wallet2_api.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 5; + static const int DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS = 30; + static const int WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS = 5; + + static constexpr char ATTRIBUTE_SUBADDRESS_ACCOUNT[] ="gui.subaddress_account"; +} + +Wallet::Wallet(QObject * parent) + : Wallet(nullptr, parent) +{ +} + +QString Wallet::getSeed() const +{ + return QString::fromStdString(m_walletImpl->seed()); +} + +QString Wallet::getSeedLanguage() const +{ + return QString::fromStdString(m_walletImpl->getSeedLanguage()); +} + +void Wallet::setSeedLanguage(const QString &lang) +{ + m_walletImpl->setSeedLanguage(lang.toStdString()); +} + +Wallet::Status Wallet::status() const +{ + return static_cast(m_walletImpl->status()); +} + +NetworkType::Type Wallet::nettype() const +{ + return static_cast(m_walletImpl->nettype()); +} + + +void Wallet::updateConnectionStatusAsync() +{ + m_scheduler.run([this] { + if (m_connectionStatus == Wallet::ConnectionStatus_Disconnected) + { + setConnectionStatus(ConnectionStatus_Connecting); + } + ConnectionStatus newStatus = static_cast(m_walletImpl->connected()); + if (newStatus != m_connectionStatus || !m_initialized) { + m_initialized = true; + setConnectionStatus(newStatus); + } + // Release lock + m_connectionStatusRunning = false; + }); +} + +Wallet::ConnectionStatus Wallet::connected(bool forceCheck) +{ + // cache connection status + if (forceCheck || !m_initialized || (m_connectionStatusTime.elapsed() / 1000 > m_connectionStatusTtl && !m_connectionStatusRunning) || m_connectionStatusTime.elapsed() > 30000) { + m_connectionStatusRunning = true; + m_connectionStatusTime.restart(); + updateConnectionStatusAsync(); + } + + return m_connectionStatus; +} + +bool Wallet::disconnected() const +{ + return m_disconnected; +} + +void Wallet::setConnectionStatus(ConnectionStatus value) +{ + if (m_connectionStatus == value) + { + return; + } + + m_connectionStatus = value; + emit connectionStatusChanged(m_connectionStatus); + + bool disconnected = m_connectionStatus == Wallet::ConnectionStatus_Connecting || + m_connectionStatus == Wallet::ConnectionStatus_Disconnected; + + if (m_disconnected != disconnected) + { + m_disconnected = disconnected; + emit disconnectedChanged(); + } +} + +bool Wallet::synchronized() const +{ + return m_walletImpl->synchronized(); +} + +QString Wallet::errorString() const +{ + return QString::fromStdString(m_walletImpl->errorString()); +} + +bool Wallet::setPassword(const QString &password) +{ + return m_walletImpl->setPassword(password.toStdString()); +} + +QString Wallet::address(quint32 accountIndex, quint32 addressIndex) const +{ + return QString::fromStdString(m_walletImpl->address(accountIndex, addressIndex)); +} + +QString Wallet::path() const +{ + return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->path())); +} + + + +//void Wallet::storeAsync(const QVariant &callback, const QString &path /* = "" */) +//{ +// const auto future = m_scheduler.run( +// [this, path] { +// QMutexLocker locker(&m_storeMutex); + +// return QVariantList({m_walletImpl->store(path.toStdString())}); +// }, +// callback); +// if (!future.first) +// { +// QVariant(callback).call(QVariantList({false})); +// } +//} + +void Wallet::store(const QString &path) +{ + m_walletImpl->store(path.toStdString()); +} + +bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight) +{ + qDebug() << "init non async"; + if (isRecovering){ + qDebug() << "RESTORING"; + m_walletImpl->setRecoveringFromSeed(true); + } + if (isRecoveringFromDevice){ + qDebug() << "RESTORING FROM DEVICE"; + m_walletImpl->setRecoveringFromDevice(true); + } + if (isRecovering || isRecoveringFromDevice) { + m_walletImpl->setRefreshFromBlockHeight(restoreHeight); + } + m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString()); + setTrustedDaemon(trustedDaemon); + return true; +} + +void Wallet::setDaemonLogin(const QString &daemonUsername, const QString &daemonPassword) +{ + // store daemon login + m_daemonUsername = daemonUsername; + m_daemonPassword = daemonPassword; +} + +void Wallet::initAsync(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight) +{ + qDebug() << "initAsync: " + daemonAddress; + const auto future = m_scheduler.run([this, daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight] { + bool success = init(daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight); + if (success) + { + emit walletCreationHeightChanged(); + qDebug() << "init async finished - starting refresh"; + connected(true); + m_walletImpl->startRefresh(); + } + }); + if (future.first) + { + setConnectionStatus(Wallet::ConnectionStatus_Connecting); + } +} + +bool Wallet::isHwBacked() const +{ + return m_walletImpl->getDeviceType() != Monero::Wallet::Device_Software; +} + +bool Wallet::isLedger() const +{ + return m_walletImpl->getDeviceType() == Monero::Wallet::Device_Ledger; +} + +bool Wallet::isTrezor() const +{ + return m_walletImpl->getDeviceType() == Monero::Wallet::Device_Trezor; +} + +//! create a view only wallet +bool Wallet::createViewOnly(const QString &path, const QString &password) const +{ + // Create path + QDir d = QFileInfo(path).absoluteDir(); + d.mkpath(d.absolutePath()); + return m_walletImpl->createWatchOnly(path.toStdString(),password.toStdString(),m_walletImpl->getSeedLanguage()); +} + +bool Wallet::connectToDaemon() +{ + return m_walletImpl->connectToDaemon(); +} + +void Wallet::setTrustedDaemon(bool arg) +{ + m_walletImpl->setTrustedDaemon(arg); +} + +bool Wallet::viewOnly() const +{ + return m_walletImpl->watchOnly(); +} + +quint64 Wallet::balance() const +{ + return balance(m_currentSubaddressAccount); +} + +quint64 Wallet::balance(quint32 accountIndex) const +{ + return m_walletImpl->balance(accountIndex); +} + +quint64 Wallet::balanceAll() const +{ + return m_walletImpl->balanceAll(); +} + +quint64 Wallet::unlockedBalance() const +{ + return unlockedBalance(m_currentSubaddressAccount); +} + +quint64 Wallet::unlockedBalance(quint32 accountIndex) const +{ + return m_walletImpl->unlockedBalance(accountIndex); +} + +quint64 Wallet::unlockedBalanceAll() const +{ + return m_walletImpl->unlockedBalanceAll(); +} + +quint32 Wallet::currentSubaddressAccount() const +{ + return m_currentSubaddressAccount; +} +void Wallet::switchSubaddressAccount(quint32 accountIndex) +{ + if (accountIndex < numSubaddressAccounts()) + { + m_currentSubaddressAccount = accountIndex; + if (!setCacheAttribute(ATTRIBUTE_SUBADDRESS_ACCOUNT, QString::number(m_currentSubaddressAccount))) + { + qWarning() << "failed to set " << ATTRIBUTE_SUBADDRESS_ACCOUNT << " cache attribute"; + } + m_subaddress->refresh(m_currentSubaddressAccount); + m_history->refresh(m_currentSubaddressAccount); + emit currentSubaddressAccountChanged(); + } +} +void Wallet::addSubaddressAccount(const QString& label) +{ + m_walletImpl->addSubaddressAccount(label.toStdString()); + switchSubaddressAccount(numSubaddressAccounts() - 1); +} +quint32 Wallet::numSubaddressAccounts() const +{ + return m_walletImpl->numSubaddressAccounts(); +} +quint32 Wallet::numSubaddresses(quint32 accountIndex) const +{ + return m_walletImpl->numSubaddresses(accountIndex); +} +void Wallet::addSubaddress(const QString& label) +{ + m_walletImpl->addSubaddress(currentSubaddressAccount(), label.toStdString()); +} +QString Wallet::getSubaddressLabel(quint32 accountIndex, quint32 addressIndex) const +{ + return QString::fromStdString(m_walletImpl->getSubaddressLabel(accountIndex, addressIndex)); +} +void Wallet::setSubaddressLabel(quint32 accountIndex, quint32 addressIndex, const QString &label) +{ + m_walletImpl->setSubaddressLabel(accountIndex, addressIndex, label.toStdString()); + emit currentSubaddressAccountChanged(); +} +void Wallet::deviceShowAddressAsync(quint32 accountIndex, quint32 addressIndex, const QString &paymentId) +{ + m_scheduler.run([this, accountIndex, addressIndex, paymentId] { + m_walletImpl->deviceShowAddress(accountIndex, addressIndex, paymentId.toStdString()); + emit deviceShowAddressShowed(); + }); +} + +void Wallet::refreshHeightAsync() +{ + m_scheduler.run([this] { + quint64 daemonHeight; + QPair> daemonHeightFuture = m_scheduler.run([this, &daemonHeight] { + daemonHeight = daemonBlockChainHeight(); + }); + if (!daemonHeightFuture.first) + { + return; + } + + quint64 targetHeight; + QPair> targetHeightFuture = m_scheduler.run([this, &targetHeight] { + targetHeight = daemonBlockChainTargetHeight(); + }); + if (!targetHeightFuture.first) + { + return; + } + + quint64 walletHeight = blockChainHeight(); + daemonHeightFuture.second.waitForFinished(); + targetHeightFuture.second.waitForFinished(); + + emit heightRefreshed(walletHeight, daemonHeight, targetHeight); + }); +} + +quint64 Wallet::blockChainHeight() const +{ + return m_walletImpl->blockChainHeight(); +} + +quint64 Wallet::daemonBlockChainHeight() const +{ + // cache daemon blockchain height for some time (60 seconds by default) + + if (m_daemonBlockChainHeight == 0 + || m_daemonBlockChainHeightTime.elapsed() / 1000 > m_daemonBlockChainHeightTtl) { + m_daemonBlockChainHeight = m_walletImpl->daemonBlockChainHeight(); + m_daemonBlockChainHeightTime.restart(); + } + return m_daemonBlockChainHeight; +} + +quint64 Wallet::daemonBlockChainTargetHeight() const +{ + if (m_daemonBlockChainTargetHeight <= 1 + || m_daemonBlockChainTargetHeightTime.elapsed() / 1000 > m_daemonBlockChainTargetHeightTtl) { + m_daemonBlockChainTargetHeight = m_walletImpl->daemonBlockChainTargetHeight(); + + // Target height is set to 0 if daemon is synced. + // Use current height from daemon when target height < current height + if (m_daemonBlockChainTargetHeight < m_daemonBlockChainHeight){ + m_daemonBlockChainTargetHeight = m_daemonBlockChainHeight; + } + m_daemonBlockChainTargetHeightTime.restart(); + } + + return m_daemonBlockChainTargetHeight; +} + +bool Wallet::exportKeyImages(const QString& path) +{ + return m_walletImpl->exportKeyImages(path.toStdString()); +} + +bool Wallet::importKeyImages(const QString& path) +{ + return m_walletImpl->importKeyImages(path.toStdString()); +} + +bool Wallet::refresh() +{ + bool result = m_walletImpl->refresh(); + m_history->refresh(currentSubaddressAccount()); + m_subaddress->refresh(currentSubaddressAccount()); + m_coins->refresh(currentSubaddressAccount()); + m_subaddressAccount->getAll(); + if (result) + emit updated(); + return result; +} + +void Wallet::refreshAsync() +{ + qDebug() << "refresh async"; + m_walletImpl->refreshAsync(); +} + +void Wallet::setAutoRefreshInterval(int seconds) +{ + m_walletImpl->setAutoRefreshInterval(seconds); +} + +int Wallet::autoRefreshInterval() const +{ + return m_walletImpl->autoRefreshInterval(); +} + +void Wallet::startRefresh() const +{ + m_walletImpl->startRefresh(); +} + +void Wallet::pauseRefresh() const +{ + m_walletImpl->pauseRefresh(); +} + +PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id, + quint64 amount, quint32 mixin_count, + PendingTransaction::Priority priority) +{ + std::set subaddr_indices; + Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction( + dst_addr.toStdString(), payment_id.toStdString(), amount, mixin_count, + static_cast(priority), currentSubaddressAccount(), subaddr_indices); + PendingTransaction * result = new PendingTransaction(ptImpl,0); + return result; +} + +void Wallet::createTransactionAsync(const QString &dst_addr, const QString &payment_id, + quint64 amount, quint32 mixin_count, + PendingTransaction::Priority priority) +{ + m_scheduler.run([this, dst_addr, payment_id, amount, mixin_count, priority] { + PendingTransaction *tx = createTransaction(dst_addr, payment_id, amount, mixin_count, priority); + emit transactionCreated(tx, dst_addr, payment_id, mixin_count); + }); +} + +PendingTransaction *Wallet::createTransactionAll(const QString &dst_addr, const QString &payment_id, + quint32 mixin_count, PendingTransaction::Priority priority) +{ + std::set subaddr_indices; + Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction( + dst_addr.toStdString(), payment_id.toStdString(), Monero::optional(), mixin_count, + static_cast(priority), currentSubaddressAccount(), subaddr_indices); + PendingTransaction * result = new PendingTransaction(ptImpl, this); + return result; +} + +void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &payment_id, + quint32 mixin_count, + PendingTransaction::Priority priority) +{ + m_scheduler.run([this, dst_addr, payment_id, mixin_count, priority] { + PendingTransaction *tx = createTransactionAll(dst_addr, payment_id, mixin_count, priority); + emit transactionCreated(tx, dst_addr, payment_id, mixin_count); + }); +} + +PendingTransaction *Wallet::createTransactionSingle(const QString &key_image, const QString &dst_addr, const size_t outputs, + PendingTransaction::Priority priority) +{ + Monero::PendingTransaction * ptImpl = m_walletImpl->createTransactionSingle(key_image.toStdString(), dst_addr.toStdString(), + outputs, static_cast(priority)); + PendingTransaction * result = new PendingTransaction(ptImpl, this); + return result; +} + +void Wallet::createTransactionSingleAsync(const QString &key_image, const QString &dst_addr, const size_t outputs, + PendingTransaction::Priority priority) +{ + m_scheduler.run([this, key_image, dst_addr, outputs, priority] { + PendingTransaction *tx = createTransactionSingle(key_image, dst_addr, outputs, priority); + emit transactionCreated(tx, dst_addr, "", 0); // todo: return true mixincount + }); +} + +PendingTransaction *Wallet::createSweepUnmixableTransaction() +{ + Monero::PendingTransaction * ptImpl = m_walletImpl->createSweepUnmixableTransaction(); + PendingTransaction * result = new PendingTransaction(ptImpl, this); + return result; +} + +void Wallet::createSweepUnmixableTransactionAsync() +{ + m_scheduler.run([this] { + PendingTransaction *tx = createSweepUnmixableTransaction(); + emit transactionCreated(tx, "", "", 0); + }); +} + +UnsignedTransaction * Wallet::loadTxFile(const QString &fileName) +{ + qDebug() << "Trying to sign " << fileName; + Monero::UnsignedTransaction * ptImpl = m_walletImpl->loadUnsignedTx(fileName.toStdString()); + UnsignedTransaction * result = new UnsignedTransaction(ptImpl, m_walletImpl, this); + return result; +} + +bool Wallet::submitTxFile(const QString &fileName) const +{ + qDebug() << "Trying to submit " << fileName; + if (!m_walletImpl->submitTransaction(fileName.toStdString())) + return false; + // import key images + return m_walletImpl->importKeyImages(fileName.toStdString() + "_keyImages"); +} + +void Wallet::commitTransactionAsync(PendingTransaction *t) +{ + m_scheduler.run([this, t] { + auto txIdList = t->txid(); // retrieve before commit + emit transactionCommitted(t->commit(), t, txIdList); + }); +} + +void Wallet::disposeTransaction(PendingTransaction *t) +{ + m_walletImpl->disposeTransaction(t->m_pimpl); + delete t; +} + +void Wallet::disposeTransaction(UnsignedTransaction *t) +{ + delete t; +} + +// @ TODO: QJSValue could probably be QVARIANT +//void Wallet::estimateTransactionFeeAsync(const QString &destination, +// quint64 amount, +// PendingTransaction::Priority priority, +// const QJSValue &callback) +//{ +// m_scheduler.run([this, destination, amount, priority] { +// const uint64_t fee = m_walletImpl->estimateTransactionFee( +// {std::make_pair(destination.toStdString(), amount)}, +// static_cast(priority)); +// return QJSValueList({QString::fromStdString(Monero::Wallet::displayAmount(fee))}); +// }, callback); +//} + +TransactionHistory *Wallet::history() const +{ + return m_history; +} + +TransactionHistoryProxyModel *Wallet::historyModel() const +{ + if (!m_historyModel) { + Wallet * w = const_cast(this); + m_historyModel = new TransactionHistoryModel(w); + m_historyModel->setTransactionHistory(this->history()); + m_historySortFilterModel = new TransactionHistoryProxyModel(w); + m_historySortFilterModel->setSourceModel(m_historyModel); + m_historySortFilterModel->setSortRole(TransactionHistoryModel::Date); + m_historySortFilterModel->sort(0, Qt::DescendingOrder); + } + + return m_historySortFilterModel; +} + +TransactionHistoryModel *Wallet::transactionHistoryModel() const +{ + return m_historyModel; +} + +AddressBook *Wallet::addressBook() const +{ + return m_addressBook; +} + +AddressBookModel *Wallet::addressBookModel() const +{ + + if (!m_addressBookModel) { + Wallet * w = const_cast(this); + m_addressBookModel = new AddressBookModel(w,m_addressBook); + } + + return m_addressBookModel; +} + +Subaddress *Wallet::subaddress() +{ + return m_subaddress; +} + +SubaddressModel *Wallet::subaddressModel() +{ + if (!m_subaddressModel) { + m_subaddressModel = new SubaddressModel(this, m_subaddress); + } + return m_subaddressModel; +} + +SubaddressAccount *Wallet::subaddressAccount() const +{ + return m_subaddressAccount; +} + +SubaddressAccountModel *Wallet::subaddressAccountModel() const +{ + if (!m_subaddressAccountModel) { + Wallet * w = const_cast(this); + m_subaddressAccountModel = new SubaddressAccountModel(w,m_subaddressAccount); + } + return m_subaddressAccountModel; +} + +Coins *Wallet::coins() const +{ + return m_coins; +} + +CoinsModel *Wallet::coinsModel() const +{ + if (!m_coinsModel) { + Wallet * w = const_cast(this); + m_coinsModel = new CoinsModel(w, m_coins); + } + return m_coinsModel; +} + +QString Wallet::generatePaymentId() const +{ + return QString::fromStdString(Monero::Wallet::genPaymentId()); +} + +QString Wallet::integratedAddress(const QString &paymentId) const +{ + return QString::fromStdString(m_walletImpl->integratedAddress(paymentId.toStdString())); +} + +QString Wallet::paymentId() const +{ + return m_paymentId; +} + +void Wallet::setPaymentId(const QString &paymentId) +{ + m_paymentId = paymentId; +} + +QString Wallet::getCacheAttribute(const QString &key) const { + return QString::fromStdString(m_walletImpl->getCacheAttribute(key.toStdString())); +} + +bool Wallet::setCacheAttribute(const QString &key, const QString &val) +{ + return m_walletImpl->setCacheAttribute(key.toStdString(), val.toStdString()); +} + +bool Wallet::setUserNote(const QString &txid, const QString ¬e) +{ + return m_walletImpl->setUserNote(txid.toStdString(), note.toStdString()); +} + +QString Wallet::getUserNote(const QString &txid) const +{ + return QString::fromStdString(m_walletImpl->getUserNote(txid.toStdString())); +} + +QString Wallet::getTxKey(const QString &txid) const +{ + return QString::fromStdString(m_walletImpl->getTxKey(txid.toStdString())); +} + +//void Wallet::getTxKeyAsync(const QString &txid, const QJSValue &callback) +//{ +// m_scheduler.run([this, txid] { +// return QJSValueList({txid, getTxKey(txid)}); +// }, callback); +//} + +QString Wallet::checkTxKey(const QString &txid, const QString &tx_key, const QString &address) +{ + uint64_t received; + bool in_pool; + uint64_t confirmations; + bool success = m_walletImpl->checkTxKey(txid.toStdString(), tx_key.toStdString(), address.toStdString(), received, in_pool, confirmations); + std::string result = std::string(success ? "true" : "false") + "|" + QString::number(received).toStdString() + "|" + std::string(in_pool ? "true" : "false") + "|" + QString::number(confirmations).toStdString(); + return QString::fromStdString(result); +} + +QString Wallet::getTxProof(const QString &txid, const QString &address, const QString &message) const +{ + std::string result = m_walletImpl->getTxProof(txid.toStdString(), address.toStdString(), message.toStdString()); + if (result.empty()) + result = "error|" + m_walletImpl->errorString(); + return QString::fromStdString(result); +} + +//void Wallet::getTxProofAsync(const QString &txid, const QString &address, const QString &message, const QJSValue &callback) +//{ +// m_scheduler.run([this, txid, address, message] { +// return QJSValueList({txid, getTxProof(txid, address, message)}); +// }, callback); +//} + +TxProofResult Wallet::checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature) +{ + bool good; + uint64_t received; + bool in_pool; + uint64_t confirmations; + bool success = m_walletImpl->checkTxProof(txid.toStdString(), address.toStdString(), message.toStdString(), signature.toStdString(), good, received, in_pool, confirmations); + return {success, good, received, in_pool, confirmations}; +} + +Q_INVOKABLE QString Wallet::getSpendProof(const QString &txid, const QString &message) const +{ + std::string result = m_walletImpl->getSpendProof(txid.toStdString(), message.toStdString()); + if (result.empty()) + result = "error|" + m_walletImpl->errorString(); + return QString::fromStdString(result); +} + +//void Wallet::getSpendProofAsync(const QString &txid, const QString &message, const QJSValue &callback) +//{ +// m_scheduler.run([this, txid, message] { +// return QJSValueList({txid, getSpendProof(txid, message)}); +// }, callback); +//} + +Q_INVOKABLE QPair Wallet::checkSpendProof(const QString &txid, const QString &message, + const QString &signature) const { + bool good; + bool success = m_walletImpl->checkSpendProof(txid.toStdString(), message.toStdString(), signature.toStdString(), good); + return {success, good}; +} + +QString Wallet::signMessage(const QString &message, bool filename, const QString &address) const +{ + if (filename) { + QFile file(message); + uchar *data = NULL; + + try { + if (!file.open(QIODevice::ReadOnly)) + return ""; + quint64 size = file.size(); + if (size == 0) { + file.close(); + return QString::fromStdString(m_walletImpl->signMessage(std::string())); + } + data = file.map(0, size); + if (!data) { + file.close(); + return ""; + } + std::string signature = m_walletImpl->signMessage(std::string(reinterpret_cast(data), size), address.toStdString()); + file.unmap(data); + file.close(); + return QString::fromStdString(signature); + } + catch (const std::exception &e) { + if (data) + file.unmap(data); + file.close(); + return ""; + } + } + else { + return QString::fromStdString(m_walletImpl->signMessage(message.toStdString(), address.toStdString())); + } +} + +bool Wallet::verifySignedMessage(const QString &message, const QString &address, const QString &signature, bool filename) const +{ + if (filename) { + QFile file(message); + uchar *data = NULL; + + try { + if (!file.open(QIODevice::ReadOnly)) + return false; + quint64 size = file.size(); + if (size == 0) { + file.close(); + return m_walletImpl->verifySignedMessage(std::string(), address.toStdString(), signature.toStdString()); + } + data = file.map(0, size); + if (!data) { + file.close(); + return false; + } + bool ret = m_walletImpl->verifySignedMessage(std::string(reinterpret_cast(data), size), address.toStdString(), signature.toStdString()); + file.unmap(data); + file.close(); + return ret; + } + catch (const std::exception &e) { + if (data) + file.unmap(data); + file.close(); + return false; + } + } + else { + return m_walletImpl->verifySignedMessage(message.toStdString(), address.toStdString(), signature.toStdString()); + } +} + +bool Wallet::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector &unknown_parameters, QString &error) +{ + std::string s_address, s_payment_id, s_tx_description, s_recipient_name, s_error; + std::vector s_unknown_parameters; + bool res= m_walletImpl->parse_uri(uri.toStdString(), s_address, s_payment_id, amount, s_tx_description, s_recipient_name, s_unknown_parameters, s_error); + if(res) + { + address = QString::fromStdString(s_address); + payment_id = QString::fromStdString(s_payment_id); + tx_description = QString::fromStdString(s_tx_description); + recipient_name = QString::fromStdString(s_recipient_name); + for( const auto &p : s_unknown_parameters ) + unknown_parameters.append(QString::fromStdString(p)); + } + error = QString::fromStdString(s_error); + return res; +} + +bool Wallet::rescanSpent() +{ + return m_walletImpl->rescanSpent(); +} + +bool Wallet::useForkRules(quint8 required_version, quint64 earlyBlocks) const +{ + if(m_connectionStatus == Wallet::ConnectionStatus_Disconnected) + return false; + try { + return m_walletImpl->useForkRules(required_version,earlyBlocks); + } catch (const std::exception &e) { + qDebug() << e.what(); + return false; + } +} + +void Wallet::setWalletCreationHeight(quint64 height) +{ + m_walletImpl->setRefreshFromBlockHeight(height); + emit walletCreationHeightChanged(); +} + +QString Wallet::getDaemonLogPath() const +{ + return QString::fromStdString(m_walletImpl->getDefaultDataDir()) + "/bitmonero.log"; +} + +bool Wallet::blackballOutput(const QString &amount, const QString &offset) +{ + return m_walletImpl->blackballOutput(amount.toStdString(), offset.toStdString()); +} + +bool Wallet::blackballOutputs(const QList &pubkeys, bool add) +{ + std::vector std_pubkeys; + foreach (const QString &pubkey, pubkeys) { + std_pubkeys.push_back(pubkey.toStdString()); + } + return m_walletImpl->blackballOutputs(std_pubkeys, add); +} + +bool Wallet::blackballOutputs(const QString &filename, bool add) +{ + QFile file(filename); + + try { + if (!file.open(QIODevice::ReadOnly)) + return false; + QList outputs; + QTextStream in(&file); + while (!in.atEnd()) { + outputs.push_back(in.readLine()); + } + file.close(); + return blackballOutputs(outputs, add); + } + catch (const std::exception &e) { + file.close(); + return false; + } +} + +bool Wallet::unblackballOutput(const QString &amount, const QString &offset) +{ + return m_walletImpl->unblackballOutput(amount.toStdString(), offset.toStdString()); +} + +QString Wallet::getRing(const QString &key_image) +{ + std::vector cring; + if (!m_walletImpl->getRing(key_image.toStdString(), cring)) + return ""; + QString ring = ""; + for (uint64_t out: cring) + { + if (!ring.isEmpty()) + ring = ring + " "; + QString s; + s.setNum(out); + ring = ring + s; + } + return ring; +} + +QString Wallet::getRings(const QString &txid) +{ + std::vector>> crings; + if (!m_walletImpl->getRings(txid.toStdString(), crings)) + return ""; + QString ring = ""; + for (const auto &cring: crings) + { + if (!ring.isEmpty()) + ring = ring + "|"; + ring = ring + QString::fromStdString(cring.first) + " absolute"; + for (uint64_t out: cring.second) + { + ring = ring + " "; + QString s; + s.setNum(out); + ring = ring + s; + } + } + return ring; +} + +bool Wallet::setRing(const QString &key_image, const QString &ring, bool relative) +{ + std::vector cring; + QStringList strOuts = ring.split(" "); + foreach(QString str, strOuts) + { + uint64_t out; + bool ok; + out = str.toULong(&ok); + if (ok) + cring.push_back(out); + } + return m_walletImpl->setRing(key_image.toStdString(), cring, relative); +} + +void Wallet::segregatePreForkOutputs(bool segregate) +{ + m_walletImpl->segregatePreForkOutputs(segregate); +} + +void Wallet::segregationHeight(quint64 height) +{ + m_walletImpl->segregationHeight(height); +} + +void Wallet::keyReuseMitigation2(bool mitigation) +{ + m_walletImpl->keyReuseMitigation2(mitigation); +} + +void Wallet::onWalletPassphraseNeeded(bool on_device) +{ + emit this->walletPassphraseNeeded(on_device); +} + +void Wallet::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) +{ + if (m_walletListener != nullptr) + { + m_walletListener->onPassphraseEntered(passphrase, enter_on_device, entry_abort); + } +} + +Wallet::Wallet(Monero::Wallet *w, QObject *parent) + : QObject(parent) + , m_walletImpl(w) + , m_history(nullptr) + , m_historyModel(nullptr) + , m_addressBook(nullptr) + , m_addressBookModel(nullptr) + , m_daemonBlockChainHeight(0) + , m_daemonBlockChainHeightTtl(DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS) + , m_daemonBlockChainTargetHeight(0) + , m_daemonBlockChainTargetHeightTtl(DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS) + , m_connectionStatus(Wallet::ConnectionStatus_Disconnected) + , m_connectionStatusTtl(WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS) + , m_disconnected(true) + , m_currentSubaddressAccount(0) + , m_subaddress(nullptr) + , m_subaddressModel(nullptr) + , m_subaddressAccount(nullptr) + , m_subaddressAccountModel(nullptr) + , m_coinsModel(nullptr) + , m_scheduler(this) +{ + m_history = new TransactionHistory(m_walletImpl->history(), this); + m_addressBook = new AddressBook(m_walletImpl->addressBook(), this); + m_subaddress = new Subaddress(m_walletImpl->subaddress(), this); + m_subaddressAccount = new SubaddressAccount(m_walletImpl->subaddressAccount(), this); + m_coins = new Coins(m_walletImpl->coins(), this); + m_walletListener = new WalletListenerImpl(this); + m_walletImpl->setListener(m_walletListener); + m_currentSubaddressAccount = getCacheAttribute(ATTRIBUTE_SUBADDRESS_ACCOUNT).toUInt(); + // start cache timers + m_connectionStatusTime.start(); + m_daemonBlockChainHeightTime.start(); + m_daemonBlockChainTargetHeightTime.start(); + m_initialized = false; + m_connectionStatusRunning = false; + m_daemonUsername = ""; + m_daemonPassword = ""; +} + +Wallet::~Wallet() +{ + qDebug() << "~Wallet: Closing wallet"; + + m_scheduler.shutdownWaitForFinished(); + + delete m_addressBook; + m_addressBook = NULL; + + delete m_history; + m_history = NULL; + delete m_addressBook; + m_addressBook = NULL; + delete m_subaddress; + m_subaddress = NULL; + delete m_subaddressAccount; + m_subaddressAccount = NULL; + delete m_coins; + m_coins = NULL; + //Monero::WalletManagerFactory::getWalletManager()->closeWallet(m_walletImpl); + if(status() == Status_Critical) + qDebug("Not storing wallet cache"); + else if( m_walletImpl->store("")) + qDebug("Wallet cache stored successfully"); + else + qDebug("Error storing wallet cache"); + delete m_walletImpl; + m_walletImpl = NULL; + delete m_walletListener; + m_walletListener = NULL; + qDebug("m_walletImpl deleted"); +} diff --git a/src/libwalletqt/Wallet.h b/src/libwalletqt/Wallet.h new file mode 100644 index 0000000..39ccee7 --- /dev/null +++ b/src/libwalletqt/Wallet.h @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef WALLET_H +#define WALLET_H + +#include +#include +#include +#include +//#include +#include + +#include "wallet/api/wallet2_api.h" // we need to have an access to the Monero::Wallet::Status enum here; +#include "utils/scheduler.h" +#include "PendingTransaction.h" // we need to have an access to the PendingTransaction::Priority enum here; +#include "UnsignedTransaction.h" +#include "utils/networktype.h" +#include "PassphraseHelper.h" +#include "WalletListenerImpl.h" + +namespace Monero { +struct Wallet; // forward declaration +} + + +class TransactionHistory; +class TransactionHistoryModel; +class TransactionHistoryProxyModel; +class TransactionHistorySortFilterModel; +class AddressBook; +class AddressBookModel; +class Subaddress; +class SubaddressModel; +class SubaddressAccount; +class SubaddressAccountModel; +class Coins; +class CoinsModel; + +struct TxProofResult { + TxProofResult(bool success, bool good, uint64_t received, bool in_pool, uint64_t confirmations) + : success(success), good(good), received(received), in_pool(in_pool), confirmations(confirmations){} + + bool success; + bool good; + uint64_t received; + bool in_pool; + uint64_t confirmations; +}; + +class Wallet : public QObject, public PassprasePrompter +{ + Q_OBJECT + Q_PROPERTY(bool disconnected READ disconnected NOTIFY disconnectedChanged) + Q_PROPERTY(QString seed READ getSeed) + Q_PROPERTY(QString seedLanguage READ getSeedLanguage) + Q_PROPERTY(Status status READ status) + Q_PROPERTY(NetworkType::Type nettype READ nettype) + Q_PROPERTY(ConnectionStatus connected READ connected) + Q_PROPERTY(quint32 currentSubaddressAccount READ currentSubaddressAccount NOTIFY currentSubaddressAccountChanged) + Q_PROPERTY(bool synchronized READ synchronized) + Q_PROPERTY(QString errorString READ errorString) + Q_PROPERTY(TransactionHistory * history READ history) + Q_PROPERTY(QString paymentId READ paymentId WRITE setPaymentId) + Q_PROPERTY(TransactionHistoryProxyModel * historyModel READ historyModel NOTIFY historyModelChanged) + Q_PROPERTY(QString path READ path) + Q_PROPERTY(AddressBookModel * addressBookModel READ addressBookModel) + Q_PROPERTY(AddressBook * addressBook READ addressBook NOTIFY addressBookChanged) + Q_PROPERTY(SubaddressModel * subaddressModel READ subaddressModel) + Q_PROPERTY(Subaddress * subaddress READ subaddress) + Q_PROPERTY(SubaddressAccountModel * subaddressAccountModel READ subaddressAccountModel) + Q_PROPERTY(SubaddressAccount * subaddressAccount READ subaddressAccount) + Q_PROPERTY(bool viewOnly READ viewOnly) + Q_PROPERTY(QString secretViewKey READ getSecretViewKey) + Q_PROPERTY(QString publicViewKey READ getPublicViewKey) + Q_PROPERTY(QString secretSpendKey READ getSecretSpendKey) + Q_PROPERTY(QString publicSpendKey READ getPublicSpendKey) + Q_PROPERTY(QString daemonLogPath READ getDaemonLogPath CONSTANT) + Q_PROPERTY(quint64 walletCreationHeight READ getWalletCreationHeight WRITE setWalletCreationHeight NOTIFY walletCreationHeightChanged) + +public: + + + enum Status { + Status_Ok = Monero::Wallet::Status_Ok, + Status_Error = Monero::Wallet::Status_Error, + Status_Critical = Monero::Wallet::Status_Critical + }; + + Q_ENUM(Status) + + enum ConnectionStatus { + ConnectionStatus_Disconnected = Monero::Wallet::ConnectionStatus_Disconnected, + ConnectionStatus_Connected = Monero::Wallet::ConnectionStatus_Connected, + ConnectionStatus_WrongVersion = Monero::Wallet::ConnectionStatus_WrongVersion, + ConnectionStatus_Connecting + }; + + Q_ENUM(ConnectionStatus) + + //! returns mnemonic seed + QString getSeed() const; + + //! returns seed language + QString getSeedLanguage() const; + + //! set seed language + Q_INVOKABLE void setSeedLanguage(const QString &lang); + + //! returns last operation's status + Status status() const; + + //! returns network type of the wallet. + NetworkType::Type nettype() const; + + //! returns whether the wallet is connected, and version status + Q_INVOKABLE ConnectionStatus connected(bool forceCheck = false); + void updateConnectionStatusAsync(); + + //! returns true if wallet was ever synchronized + bool synchronized() const; + + //! returns last operation's error message + QString errorString() const; + + //! changes the password using existing parameters (path, seed, seed lang) + Q_INVOKABLE bool setPassword(const QString &password); + + //! returns wallet's public address + Q_INVOKABLE QString address(quint32 accountIndex, quint32 addressIndex) const; + + //! returns wallet file's path + QString path() const; + + //! saves wallet to the file by given path + //! empty path stores in current location + Q_INVOKABLE void store(const QString &path = ""); + // Q_INVOKABLE void storeAsync(const QJSValue &callback, const QString &path = ""); + + //! initializes wallet asynchronously + Q_INVOKABLE void initAsync(const QString &daemonAddress, bool trustedDaemon = false, quint64 upperTransactionLimit = 0, bool isRecovering = false, bool isRecoveringFromDevice = false, quint64 restoreHeight = 0); + + // Set daemon rpc user/pass + Q_INVOKABLE void setDaemonLogin(const QString &daemonUsername = "", const QString &daemonPassword = ""); + + //! create a view only wallet + Q_INVOKABLE bool createViewOnly(const QString &path, const QString &password) const; + + //! connects to daemon + Q_INVOKABLE bool connectToDaemon(); + + //! indicates id daemon is trusted + Q_INVOKABLE void setTrustedDaemon(bool arg); + + //! returns balance + Q_INVOKABLE quint64 balance() const; + Q_INVOKABLE quint64 balance(quint32 accountIndex) const; + Q_INVOKABLE quint64 balanceAll() const; + + //! returns unlocked balance + Q_INVOKABLE quint64 unlockedBalance() const; + Q_INVOKABLE quint64 unlockedBalance(quint32 accountIndex) const; + Q_INVOKABLE quint64 unlockedBalanceAll() const; + + //! account/address management + quint32 currentSubaddressAccount() const; + Q_INVOKABLE void switchSubaddressAccount(quint32 accountIndex); + Q_INVOKABLE void addSubaddressAccount(const QString& label); + Q_INVOKABLE quint32 numSubaddressAccounts() const; + Q_INVOKABLE quint32 numSubaddresses(quint32 accountIndex) const; + Q_INVOKABLE void addSubaddress(const QString& label); + Q_INVOKABLE QString getSubaddressLabel(quint32 accountIndex, quint32 addressIndex) const; + Q_INVOKABLE void setSubaddressLabel(quint32 accountIndex, quint32 addressIndex, const QString &label); + Q_INVOKABLE void deviceShowAddressAsync(quint32 accountIndex, quint32 addressIndex, const QString &paymentId); + + //! hw-device backed wallets + Q_INVOKABLE bool isHwBacked() const; + Q_INVOKABLE bool isLedger() const; + Q_INVOKABLE bool isTrezor() const; + + //! returns if view only wallet + Q_INVOKABLE bool viewOnly() const; + + Q_INVOKABLE void refreshHeightAsync(); + + //! export/import key images + Q_INVOKABLE bool exportKeyImages(const QString& path); + Q_INVOKABLE bool importKeyImages(const QString& path); + + //! refreshes the wallet + Q_INVOKABLE bool refresh(); + + //! refreshes the wallet asynchronously + Q_INVOKABLE void refreshAsync(); + + //! setup auto-refresh interval in seconds + Q_INVOKABLE void setAutoRefreshInterval(int seconds); + + //! return auto-refresh interval in seconds + Q_INVOKABLE int autoRefreshInterval() const; + + // pause/resume refresh + Q_INVOKABLE void startRefresh() const; + Q_INVOKABLE void pauseRefresh() const; + + //! returns current wallet's block height + //! (can be less than daemon's blockchain height when wallet sync in progress) + Q_INVOKABLE quint64 blockChainHeight() const; + + //! returns daemon's blockchain height + Q_INVOKABLE quint64 daemonBlockChainHeight() const; + + //! returns daemon's blockchain target height + Q_INVOKABLE quint64 daemonBlockChainTargetHeight() const; + + //! creates transaction + Q_INVOKABLE PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id, + quint64 amount, quint32 mixin_count, + PendingTransaction::Priority priority); + + //! creates async transaction + Q_INVOKABLE void createTransactionAsync(const QString &dst_addr, const QString &payment_id, + quint64 amount, quint32 mixin_count, + PendingTransaction::Priority priority); + + //! creates transaction with all outputs + Q_INVOKABLE PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id, + quint32 mixin_count, PendingTransaction::Priority priority); + + //! creates async transaction with all outputs + Q_INVOKABLE void createTransactionAllAsync(const QString &dst_addr, const QString &payment_id, + quint32 mixin_count, PendingTransaction::Priority priority); + + //! creates transaction with single input + Q_INVOKABLE PendingTransaction * createTransactionSingle(const QString &key_image, const QString &dst_addr, + size_t outputs, PendingTransaction::Priority priority); + + //! creates async transaction with single input + Q_INVOKABLE void createTransactionSingleAsync(const QString &key_image, const QString &dst_addr, + size_t outputs, PendingTransaction::Priority priority); + + //! creates sweep unmixable transaction + Q_INVOKABLE PendingTransaction * createSweepUnmixableTransaction(); + + //! creates async sweep unmixable transaction + Q_INVOKABLE void createSweepUnmixableTransactionAsync(); + + //! Sign a transfer from file + Q_INVOKABLE UnsignedTransaction * loadTxFile(const QString &fileName); + + //! Submit a transfer from file + Q_INVOKABLE bool submitTxFile(const QString &fileName) const; + + //! asynchronous transaction commit + Q_INVOKABLE void commitTransactionAsync(PendingTransaction * t); + + //! deletes transaction and frees memory + Q_INVOKABLE void disposeTransaction(PendingTransaction * t); + + //! deletes unsigned transaction and frees memory + Q_INVOKABLE void disposeTransaction(UnsignedTransaction * t); + +// Q_INVOKABLE void estimateTransactionFeeAsync(const QString &destination, +// quint64 amount, +// PendingTransaction::Priority priority, +// const QJSValue &callback); + + //! returns transaction history + TransactionHistory * history() const; + + //! returns transaction history model + TransactionHistoryProxyModel *historyModel() const; + + //! returns transaction history model (the real one) + TransactionHistoryModel *transactionHistoryModel() const; + + //! returns Address book + AddressBook *addressBook() const; + + //! returns adress book model + AddressBookModel *addressBookModel() const; + + //! returns subaddress + Subaddress *subaddress(); + + //! returns subadress model + SubaddressModel *subaddressModel(); + + //! returns subaddress account + SubaddressAccount *subaddressAccount() const; + + //! returns subadress account model + SubaddressAccountModel *subaddressAccountModel() const; + + //! returns coins + Coins *coins() const; + + //! return coins model + CoinsModel *coinsModel() const; + + //! generate payment id + Q_INVOKABLE QString generatePaymentId() const; + + //! integrated address + Q_INVOKABLE QString integratedAddress(const QString &paymentId) const; + + //! signing a message + Q_INVOKABLE QString signMessage(const QString &message, bool filename = false, const QString &address = "") const; + + //! verify a signed message + Q_INVOKABLE bool verifySignedMessage(const QString &message, const QString &address, const QString &signature, bool filename = false) const; + + //! Parse URI + Q_INVOKABLE bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector &unknown_parameters, QString &error); + + //! saved payment id + QString paymentId() const; + + void setPaymentId(const QString &paymentId); + + //! Namespace your cacheAttribute keys to avoid collisions + Q_INVOKABLE bool setCacheAttribute(const QString &key, const QString &val); + Q_INVOKABLE QString getCacheAttribute(const QString &key) const; + + Q_INVOKABLE bool setUserNote(const QString &txid, const QString ¬e); + Q_INVOKABLE QString getUserNote(const QString &txid) const; + Q_INVOKABLE QString getTxKey(const QString &txid) const; + //Q_INVOKABLE void getTxKeyAsync(const QString &txid, const QJSValue &callback); + Q_INVOKABLE QString checkTxKey(const QString &txid, const QString &tx_key, const QString &address); + Q_INVOKABLE QString getTxProof(const QString &txid, const QString &address, const QString &message) const; + // Q_INVOKABLE void getTxProofAsync(const QString &txid, const QString &address, const QString &message, const QJSValue &callback); + //Q_INVOKABLE QString checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature); + Q_INVOKABLE TxProofResult checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature); + Q_INVOKABLE QString getSpendProof(const QString &txid, const QString &message) const; + // Q_INVOKABLE void getSpendProofAsync(const QString &txid, const QString &message, const QJSValue &callback); + Q_INVOKABLE QPair checkSpendProof(const QString &txid, const QString &message, const QString &signature) const; + // Rescan spent outputs + Q_INVOKABLE bool rescanSpent(); + + // check if fork rules should be used + Q_INVOKABLE bool useForkRules(quint8 version, quint64 earlyBlocks = 0) const; + + //! Get wallet keys + QString getSecretViewKey() const {return QString::fromStdString(m_walletImpl->secretViewKey());} + QString getPublicViewKey() const {return QString::fromStdString(m_walletImpl->publicViewKey());} + QString getSecretSpendKey() const {return QString::fromStdString(m_walletImpl->secretSpendKey());} + QString getPublicSpendKey() const {return QString::fromStdString(m_walletImpl->publicSpendKey());} + + quint64 getWalletCreationHeight() const {return m_walletImpl->getRefreshFromBlockHeight();} + void setWalletCreationHeight(quint64 height); + + QString getDaemonLogPath() const; + QString getWalletLogPath() const; + + // Blackalled outputs + Q_INVOKABLE bool blackballOutput(const QString &amount, const QString &offset); + Q_INVOKABLE bool blackballOutputs(const QList &outputs, bool add); + Q_INVOKABLE bool blackballOutputs(const QString &filename, bool add); + Q_INVOKABLE bool unblackballOutput(const QString &amount, const QString &offset); + + // Rings + Q_INVOKABLE QString getRing(const QString &key_image); + Q_INVOKABLE QString getRings(const QString &txid); + Q_INVOKABLE bool setRing(const QString &key_image, const QString &ring, bool relative); + + // key reuse mitigation options + Q_INVOKABLE void segregatePreForkOutputs(bool segregate); + Q_INVOKABLE void segregationHeight(quint64 height); + Q_INVOKABLE void keyReuseMitigation2(bool mitigation); + + // Passphrase entry for hardware wallets + Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false); + virtual void onWalletPassphraseNeeded(bool on_device) override; + + // TODO: setListenter() when it implemented in API +signals: + // emitted on every event happened with wallet + // (money sent/received, new block) + void updated(); + + // emitted when refresh process finished (could take a long time) + // signalling only after we + void refreshed(); + + void moneySpent(const QString &txId, quint64 amount); + void moneyReceived(const QString &txId, quint64 amount); + void unconfirmedMoneyReceived(const QString &txId, quint64 amount); + void newBlock(quint64 height, quint64 targetHeight); + void addressBookChanged() const; + void historyModelChanged() const; + void walletCreationHeightChanged(); + void deviceButtonRequest(quint64 buttonCode); + void deviceButtonPressed(); + void walletPassphraseNeeded(bool onDevice); + void transactionCommitted(bool status, PendingTransaction *t, const QStringList& txid); + void heightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) const; + void deviceShowAddressShowed(); + + // emitted when transaction is created async + void transactionCreated(PendingTransaction * transaction, QString address, QString paymentId, quint32 mixinCount); + + void connectionStatusChanged(int status) const; + void currentSubaddressAccountChanged() const; + void disconnectedChanged() const; + +private: + Wallet(QObject * parent = nullptr); + Wallet(Monero::Wallet *w, QObject * parent = 0); + ~Wallet(); + + //! initializes wallet + bool init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight); + + bool disconnected() const; + void setConnectionStatus(ConnectionStatus value); + +private: + friend class WalletManager; + friend class WalletListenerImpl; + //! libwallet's + Monero::Wallet * m_walletImpl; + // history lifetime managed by wallet; + TransactionHistory * m_history; + // Used for UI history view + mutable TransactionHistoryModel * m_historyModel; + mutable TransactionHistoryProxyModel * m_historySortFilterModel; + QString m_paymentId; + AddressBook * m_addressBook; + mutable AddressBookModel * m_addressBookModel; + mutable QElapsedTimer m_daemonBlockChainHeightTime; + mutable quint64 m_daemonBlockChainHeight; + int m_daemonBlockChainHeightTtl; + mutable QElapsedTimer m_daemonBlockChainTargetHeightTime; + mutable quint64 m_daemonBlockChainTargetHeight; + int m_daemonBlockChainTargetHeightTtl; + mutable ConnectionStatus m_connectionStatus; + int m_connectionStatusTtl; + mutable QElapsedTimer m_connectionStatusTime; + bool m_disconnected; + mutable bool m_initialized; + uint32_t m_currentSubaddressAccount; + Subaddress * m_subaddress; + mutable SubaddressModel * m_subaddressModel; + SubaddressAccount * m_subaddressAccount; + mutable SubaddressAccountModel * m_subaddressAccountModel; + Coins * m_coins; + mutable CoinsModel * m_coinsModel; + QMutex m_connectionStatusMutex; + bool m_connectionStatusRunning; + QString m_daemonUsername; + QString m_daemonPassword; + WalletListenerImpl *m_walletListener; + FutureScheduler m_scheduler; + QMutex m_storeMutex; +}; + + + +#endif // WALLET_H diff --git a/src/libwalletqt/WalletListenerImpl.cpp b/src/libwalletqt/WalletListenerImpl.cpp new file mode 100644 index 0000000..d857b9e --- /dev/null +++ b/src/libwalletqt/WalletListenerImpl.cpp @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "WalletListenerImpl.h" +#include "Wallet.h" + +WalletListenerImpl::WalletListenerImpl(Wallet * w) + : m_wallet(w) + , m_phelper(w) +{ + +} + +void WalletListenerImpl::moneySpent(const std::string &txId, uint64_t amount) +{ + qDebug() << __FUNCTION__; + emit m_wallet->moneySpent(QString::fromStdString(txId), amount); +} + +void WalletListenerImpl::moneyReceived(const std::string &txId, uint64_t amount) +{ + qDebug() << __FUNCTION__; + emit m_wallet->moneyReceived(QString::fromStdString(txId), amount); +} + +void WalletListenerImpl::unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) +{ + qDebug() << __FUNCTION__; + emit m_wallet->unconfirmedMoneyReceived(QString::fromStdString(txId), amount); +} + +void WalletListenerImpl::newBlock(uint64_t height) +{ + // qDebug() << __FUNCTION__; + emit m_wallet->newBlock(height, m_wallet->daemonBlockChainTargetHeight()); +} + +void WalletListenerImpl::updated() +{ + emit m_wallet->updated(); +} + +// called when wallet refreshed by background thread or explicitly +void WalletListenerImpl::refreshed() +{ + qDebug() << __FUNCTION__; + emit m_wallet->refreshed(); +} + +void WalletListenerImpl::onDeviceButtonRequest(uint64_t code) +{ + qDebug() << __FUNCTION__; + emit m_wallet->deviceButtonRequest(code); +} + +void WalletListenerImpl::onDeviceButtonPressed() +{ + qDebug() << __FUNCTION__; + emit m_wallet->deviceButtonPressed(); +} + +void WalletListenerImpl::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) +{ + qDebug() << __FUNCTION__; + m_phelper.onPassphraseEntered(passphrase, enter_on_device, entry_abort); +} + +Monero::optional WalletListenerImpl::onDevicePassphraseRequest(bool & on_device) +{ + qDebug() << __FUNCTION__; + return m_phelper.onDevicePassphraseRequest(on_device); +} diff --git a/src/libwalletqt/WalletListenerImpl.h b/src/libwalletqt/WalletListenerImpl.h new file mode 100644 index 0000000..120ddf4 --- /dev/null +++ b/src/libwalletqt/WalletListenerImpl.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef MONERO_GUI_WALLETLISTENERIMPL_H +#define MONERO_GUI_WALLETLISTENERIMPL_H + +#include "wallet/api/wallet2_api.h" +#include "PassphraseHelper.h" + +class Wallet; + +class WalletListenerImpl : public Monero::WalletListener, public PassphraseReceiver +{ +public: + WalletListenerImpl(Wallet * w); + + virtual void moneySpent(const std::string &txId, uint64_t amount) override; + + virtual void moneyReceived(const std::string &txId, uint64_t amount) override; + + virtual void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override; + + virtual void newBlock(uint64_t height) override; + + virtual void updated() override; + + // called when wallet refreshed by background thread or explicitly + virtual void refreshed() override; + + virtual void onDeviceButtonRequest(uint64_t code) override; + + virtual void onDeviceButtonPressed() override; + + virtual void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) override; + + virtual Monero::optional onDevicePassphraseRequest(bool & on_device) override; + +private: + Wallet * m_wallet; + PassphraseHelper m_phelper; +}; + +#endif //MONERO_GUI_WALLETLISTENERIMPL_H diff --git a/src/libwalletqt/WalletManager.cpp b/src/libwalletqt/WalletManager.cpp new file mode 100644 index 0000000..d0caa6e --- /dev/null +++ b/src/libwalletqt/WalletManager.cpp @@ -0,0 +1,487 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "libwalletqt/WalletManager.h" +#include "Wallet.h" +#include "wallet/api/wallet2_api.h" +#include +#include +#include +#include +#include +#include +#include +#include + +//#include "qt/updater.h" +#include "utils/ScopeGuard.h" + +class WalletPassphraseListenerImpl : public Monero::WalletListener, public PassphraseReceiver +{ +public: + WalletPassphraseListenerImpl(WalletManager * mgr): m_mgr(mgr), m_phelper(mgr) {} + + virtual void moneySpent(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; }; + virtual void moneyReceived(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; }; + virtual void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; }; + virtual void newBlock(uint64_t height) override { (void) height; }; + virtual void updated() override {}; + virtual void refreshed() override {}; + + virtual void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) override + { + qDebug() << __FUNCTION__; + m_phelper.onPassphraseEntered(passphrase, enter_on_device, entry_abort); + } + +// virtual Monero::optional onDevicePassphraseRequest(bool & on_device) override +// { +// qDebug() << __FUNCTION__; +// return m_phelper.onDevicePassphraseRequest(on_device); +// } +// +// virtual void onDeviceButtonRequest(uint64_t code) override +// { +// qDebug() << __FUNCTION__; +// emit m_mgr->deviceButtonRequest(code); +// } +// +// virtual void onDeviceButtonPressed() override +// { +// qDebug() << __FUNCTION__; +// emit m_mgr->deviceButtonPressed(); +// } + +private: + WalletManager * m_mgr; + PassphraseHelper m_phelper; +}; + +WalletManager * WalletManager::m_instance = nullptr; + +WalletManager *WalletManager::instance() +{ + if (!m_instance) { + m_instance = new WalletManager; + } + + return m_instance; +} + +Wallet *WalletManager::createWallet(const QString &path, const QString &password, + const QString &language, NetworkType::Type nettype, quint64 kdfRounds) +{ + QMutexLocker locker(&m_mutex); + if (m_currentWallet) { + qDebug() << "Closing open m_currentWallet" << m_currentWallet; + delete m_currentWallet; + } + Monero::Wallet * w = m_pimpl->createWallet(path.toStdString(), password.toStdString(), + language.toStdString(), static_cast(nettype), kdfRounds); + m_currentWallet = new Wallet(w); + return m_currentWallet; +} + +Wallet *WalletManager::openWallet(const QString &path, const QString &password, NetworkType::Type nettype, quint64 kdfRounds) +{ + QMutexLocker locker(&m_mutex); + WalletPassphraseListenerImpl tmpListener(this); + m_mutex_passphraseReceiver.lock(); + m_passphraseReceiver = &tmpListener; + m_mutex_passphraseReceiver.unlock(); + const auto cleanup = sg::make_scope_guard([this]() noexcept { + QMutexLocker passphrase_locker(&m_mutex_passphraseReceiver); + this->m_passphraseReceiver = nullptr; + }); + + if (m_currentWallet) { + qDebug() << "Closing open m_currentWallet" << m_currentWallet; + delete m_currentWallet; + } + qDebug() << QString("%1: opening wallet at %2, nettype = %3 ").arg(__PRETTY_FUNCTION__).arg(qPrintable(path)).arg(nettype); + + Monero::Wallet * w = m_pimpl->openWallet(path.toStdString(), password.toStdString(), static_cast(nettype), kdfRounds, &tmpListener); + w->setListener(nullptr); + + qDebug() << QString("%1: opened wallet: %2, status: %3").arg(__PRETTY_FUNCTION__).arg(w->address(0, 0).c_str()).arg(w->status()); + m_currentWallet = new Wallet(w); + + // move wallet to the GUI thread. Otherwise it wont be emitting signals + if (m_currentWallet->thread() != qApp->thread()) { + m_currentWallet->moveToThread(qApp->thread()); + } + + return m_currentWallet; +} + +void WalletManager::openWalletAsync(const QString &path, const QString &password, NetworkType::Type nettype, quint64 kdfRounds) +{ + m_scheduler.run([this, path, password, nettype, kdfRounds] { + emit walletOpened(openWallet(path, password, nettype, kdfRounds)); + }); +} + + +Wallet *WalletManager::recoveryWallet(const QString &path, const QString &password, const QString &seed, const QString &seed_offset, NetworkType::Type nettype, quint64 restoreHeight, quint64 kdfRounds) +{ + QMutexLocker locker(&m_mutex); + if (m_currentWallet) { + qDebug() << "Closing open m_currentWallet" << m_currentWallet; + delete m_currentWallet; + } + Monero::Wallet * w = m_pimpl->recoveryWallet(path.toStdString(), password.toStdString(), seed.toStdString(), static_cast(nettype), restoreHeight, kdfRounds, seed_offset.toStdString()); + m_currentWallet = new Wallet(w); + return m_currentWallet; +} + +Wallet *WalletManager::createWalletFromKeys(const QString &path, const QString &language, NetworkType::Type nettype, + const QString &address, const QString &viewkey, const QString &spendkey, + quint64 restoreHeight, quint64 kdfRounds) +{ + QMutexLocker locker(&m_mutex); + if (m_currentWallet) { + qDebug() << "Closing open m_currentWallet" << m_currentWallet; + delete m_currentWallet; + m_currentWallet = NULL; + } + Monero::Wallet * w = m_pimpl->createWalletFromKeys(path.toStdString(), "", language.toStdString(), static_cast(nettype), restoreHeight, + address.toStdString(), viewkey.toStdString(), spendkey.toStdString(), kdfRounds); + m_currentWallet = new Wallet(w); + return m_currentWallet; +} + +Wallet *WalletManager::createDeterministicWalletFromSpendKey(const QString &path, const QString &password, const QString &language, NetworkType::Type nettype, + const QString &spendkey, quint64 restoreHeight, quint64 kdfRounds) +{ + QMutexLocker locker(&m_mutex); + if (m_currentWallet) { + qDebug() << "Closing open m_currentWallet" << m_currentWallet; + delete m_currentWallet; + m_currentWallet = NULL; + } + Monero::Wallet * w = m_pimpl->createDeterministicWalletFromSpendKey(path.toStdString(), "", language.toStdString(), static_cast(nettype), restoreHeight, + spendkey.toStdString(), kdfRounds); + m_currentWallet = new Wallet(w); + return m_currentWallet; +} + +Wallet *WalletManager::createWalletFromDevice(const QString &path, const QString &password, NetworkType::Type nettype, + const QString &deviceName, quint64 restoreHeight, const QString &subaddressLookahead) +{ + QMutexLocker locker(&m_mutex); + WalletPassphraseListenerImpl tmpListener(this); + m_mutex_passphraseReceiver.lock(); + m_passphraseReceiver = &tmpListener; + m_mutex_passphraseReceiver.unlock(); + const auto cleanup = sg::make_scope_guard([this]() noexcept { + QMutexLocker passphrase_locker(&m_mutex_passphraseReceiver); + this->m_passphraseReceiver = nullptr; + }); + + if (m_currentWallet) { + qDebug() << "Closing open m_currentWallet" << m_currentWallet; + delete m_currentWallet; + m_currentWallet = NULL; + } + Monero::Wallet * w = m_pimpl->createWalletFromDevice(path.toStdString(), password.toStdString(), static_cast(nettype), + deviceName.toStdString(), restoreHeight, subaddressLookahead.toStdString(), 1, &tmpListener); + w->setListener(nullptr); + + m_currentWallet = new Wallet(w); + + // move wallet to the GUI thread. Otherwise it wont be emitting signals + if (m_currentWallet->thread() != qApp->thread()) { + m_currentWallet->moveToThread(qApp->thread()); + } + + return m_currentWallet; +} + + +void WalletManager::createWalletFromDeviceAsync(const QString &path, const QString &password, NetworkType::Type nettype, + const QString &deviceName, quint64 restoreHeight, const QString &subaddressLookahead) +{ + m_scheduler.run([this, path, password, nettype, deviceName, restoreHeight, subaddressLookahead] { + Wallet *wallet = createWalletFromDevice(path, password, nettype, deviceName, restoreHeight, subaddressLookahead); + emit walletCreated(wallet); + }); +} + +QString WalletManager::closeWallet() +{ + QMutexLocker locker(&m_mutex); + QString result; + if (m_currentWallet) { + result = m_currentWallet->address(0, 0); + delete m_currentWallet; + } else { + qCritical() << "Trying to close non existing wallet " << m_currentWallet; + result = "0"; + } + return result; +} + +// @TODO: fix +//void WalletManager::closeWalletAsync(const QJSValue& callback) +//{ +// m_scheduler.run([this] { +// return QJSValueList({closeWallet()}); +// }, callback); +//} + +bool WalletManager::walletExists(const QString &path) const +{ + return m_pimpl->walletExists(path.toStdString()); +} + +QStringList WalletManager::findWallets(const QString &path) +{ + std::vector found_wallets = m_pimpl->findWallets(path.toStdString()); + QStringList result; + for (const auto &w : found_wallets) { + result.append(QString::fromStdString(w)); + } + return result; +} + +QString WalletManager::errorString() const +{ + return tr("Unknown error"); +} + +quint64 WalletManager::maximumAllowedAmount() const +{ + return Monero::Wallet::maximumAllowedAmount(); +} + +QString WalletManager::maximumAllowedAmountAsString() const +{ + return WalletManager::displayAmount(WalletManager::maximumAllowedAmount()); +} + +QString WalletManager::displayAmount(quint64 amount) +{ + return QString::fromStdString(Monero::Wallet::displayAmount(amount)); +} + +quint64 WalletManager::amountFromString(const QString &amount) const +{ + return Monero::Wallet::amountFromString(amount.toStdString()); +} + +quint64 WalletManager::amountFromDouble(double amount) const +{ + return Monero::Wallet::amountFromDouble(amount); +} + +bool WalletManager::paymentIdValid(const QString &payment_id) const +{ + return Monero::Wallet::paymentIdValid(payment_id.toStdString()); +} + +bool WalletManager::addressValid(const QString &address, NetworkType::Type nettype) +{ + return Monero::Wallet::addressValid(address.toStdString(), static_cast(nettype)); +} + +bool WalletManager::keyValid(const QString &key, const QString &address, bool isViewKey, NetworkType::Type nettype) const +{ + std::string error; + if(!Monero::Wallet::keyValid(key.toStdString(), address.toStdString(), isViewKey, static_cast(nettype), error)){ + qDebug() << QString::fromStdString(error); + return false; + } + return true; +} + +QString WalletManager::paymentIdFromAddress(const QString &address, NetworkType::Type nettype) const +{ + return QString::fromStdString(Monero::Wallet::paymentIdFromAddress(address.toStdString(), static_cast(nettype))); +} + +void WalletManager::setDaemonAddressAsync(const QString &address) +{ + m_scheduler.run([this, address] { + m_pimpl->setDaemonAddress(address.toStdString()); + }); +} + +bool WalletManager::connected() const +{ + return m_pimpl->connected(); +} + +quint64 WalletManager::networkDifficulty() const +{ + return m_pimpl->networkDifficulty(); +} + +quint64 WalletManager::blockchainHeight() const +{ + return m_pimpl->blockchainHeight(); +} + +quint64 WalletManager::blockchainTargetHeight() const +{ + return m_pimpl->blockchainTargetHeight(); +} + +double WalletManager::miningHashRate() const +{ + return m_pimpl->miningHashRate(); +} + +bool WalletManager::isMining() const +{ + { + QMutexLocker locker(&m_mutex); + if (m_currentWallet == nullptr || !m_currentWallet->connected()) + { + return false; + } + } + + return m_pimpl->isMining(); +} + +void WalletManager::miningStatusAsync() +{ + m_scheduler.run([this] { + emit miningStatus(isMining()); + }); +} + +bool WalletManager::startMining(const QString &address, quint32 threads, bool backgroundMining, bool ignoreBattery) +{ + if(threads == 0) + threads = 1; + return m_pimpl->startMining(address.toStdString(), threads, backgroundMining, ignoreBattery); +} + +bool WalletManager::stopMining() +{ + return m_pimpl->stopMining(); +} + +bool WalletManager::localDaemonSynced() const +{ + return blockchainHeight() > 1 && blockchainHeight() >= blockchainTargetHeight(); +} + +bool WalletManager::isDaemonLocal(const QString &daemon_address) const +{ + return daemon_address.isEmpty() ? false : Monero::Utils::isAddressLocal(daemon_address.toStdString()); +} + +QString WalletManager::resolveOpenAlias(const QString &address) const +{ + bool dnssec_valid = false; + std::string res = m_pimpl->resolveOpenAlias(address.toStdString(), dnssec_valid); + res = std::string(dnssec_valid ? "true" : "false") + "|" + res; + return QString::fromStdString(res); +} +bool WalletManager::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector &unknown_parameters, QString &error) const +{ + QMutexLocker locker(&m_mutex); + if (m_currentWallet) + return m_currentWallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); + return false; +} + +QVariantMap WalletManager::parse_uri_to_object(const QString &uri) const +{ + QString address; + QString payment_id; + uint64_t amount = 0; + QString tx_description; + QString recipient_name; + QVector unknown_parameters; + QString error; + + QVariantMap result; + if (this->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error)) { + result.insert("address", address); + result.insert("payment_id", payment_id); + result.insert("amount", amount > 0 ? displayAmount(amount) : ""); + result.insert("tx_description", tx_description); + result.insert("recipient_name", recipient_name); + } else { + result.insert("error", error); + } + + return result; +} + +void WalletManager::setLogLevel(int logLevel) +{ + Monero::WalletManagerFactory::setLogLevel(logLevel); +} + +void WalletManager::setLogCategories(const QString &categories) +{ + Monero::WalletManagerFactory::setLogCategories(categories.toStdString()); +} + +QString WalletManager::urlToLocalPath(const QUrl &url) const +{ + return QDir::toNativeSeparators(url.toLocalFile()); +} + +QUrl WalletManager::localPathToUrl(const QString &path) const +{ + return QUrl::fromLocalFile(path); +} + +QString WalletManager::checkUpdates(const QString &software, const QString &subdir) const +{ + qDebug() << "Checking for updates"; + const std::tuple result = Monero::WalletManager::checkUpdates(software.toStdString(), subdir.toStdString()); + if (!std::get<0>(result)) + return QString(""); + return QString::fromStdString(std::get<1>(result) + "|" + std::get<2>(result) + "|" + std::get<3>(result) + "|" + std::get<4>(result)); +} + +bool WalletManager::clearWalletCache(const QString &wallet_path) const +{ + + QString fileName = wallet_path; + // Make sure wallet file is not .keys + fileName.replace(".keys",""); + QFile walletCache(fileName); + QString suffix = ".old_cache"; + QString newFileName = fileName + suffix; + + // create unique file name + for (int i = 1; QFile::exists(newFileName); i++) { + newFileName = QString("%1%2.%3").arg(fileName).arg(suffix).arg(i); + } + + return walletCache.rename(newFileName); +} + +WalletManager::WalletManager(QObject *parent) + : QObject(parent) + , m_passphraseReceiver(nullptr) + , m_scheduler(this) +{ + m_pimpl = Monero::WalletManagerFactory::getWalletManager(); +} + +WalletManager::~WalletManager() +{ + m_scheduler.shutdownWaitForFinished(); +} + +void WalletManager::onWalletPassphraseNeeded(bool on_device) +{ + emit this->walletPassphraseNeeded(on_device); +} + +void WalletManager::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) +{ + QMutexLocker locker(&m_mutex_passphraseReceiver); + if (m_passphraseReceiver != nullptr) + { + m_passphraseReceiver->onPassphraseEntered(passphrase, enter_on_device, entry_abort); + } +} diff --git a/src/libwalletqt/WalletManager.h b/src/libwalletqt/WalletManager.h new file mode 100644 index 0000000..28b84e3 --- /dev/null +++ b/src/libwalletqt/WalletManager.h @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef WALLETMANAGER_H +#define WALLETMANAGER_H + +#include +#include +#include +#include +#include +#include +#include +#include "utils/scheduler.h" +#include "utils/networktype.h" +#include "PassphraseHelper.h" + +class Wallet; +namespace Monero { +struct WalletManager; +} + +class WalletManager : public QObject, public PassprasePrompter +{ + Q_OBJECT + Q_PROPERTY(bool connected READ connected) + +public: + enum LogLevel { + LogLevel_Silent = Monero::WalletManagerFactory::LogLevel_Silent, + LogLevel_0 = Monero::WalletManagerFactory::LogLevel_0, + LogLevel_1 = Monero::WalletManagerFactory::LogLevel_1, + LogLevel_2 = Monero::WalletManagerFactory::LogLevel_2, + LogLevel_3 = Monero::WalletManagerFactory::LogLevel_3, + LogLevel_4 = Monero::WalletManagerFactory::LogLevel_4, + LogLevel_Min = Monero::WalletManagerFactory::LogLevel_Min, + LogLevel_Max = Monero::WalletManagerFactory::LogLevel_Max, + }; + + static WalletManager * instance(); + // wizard: createWallet path; + Q_INVOKABLE Wallet * createWallet(const QString &path, const QString &password, + const QString &language, NetworkType::Type nettype = NetworkType::MAINNET, quint64 kdfRounds = 1); + + /*! + * \brief openWallet - opens wallet by given path + * \param path - wallet filename + * \param password - wallet password. Empty string in wallet isn't password protected + * \param nettype - type of network the wallet is running on + * \return wallet object pointer + */ + Q_INVOKABLE Wallet * openWallet(const QString &path, const QString &password, NetworkType::Type nettype = NetworkType::MAINNET, quint64 kdfRounds = 1); + + /*! + * \brief openWalletAsync - asynchronous version of "openWallet". Returns immediately. "walletOpened" signal + * emitted when wallet opened; + */ + Q_INVOKABLE void openWalletAsync(const QString &path, const QString &password, NetworkType::Type nettype = NetworkType::MAINNET, quint64 kdfRounds = 1); + + // wizard: recoveryWallet path; hint: internally it recorvers wallet and set password = "" + Q_INVOKABLE Wallet * recoveryWallet(const QString &path, const QString &password, const QString &seed, const QString &seed_offset, + NetworkType::Type nettype = NetworkType::MAINNET, quint64 restoreHeight = 0, quint64 kdfRounds = 1); + + Q_INVOKABLE Wallet * createWalletFromKeys(const QString &path, + const QString &language, + NetworkType::Type nettype, + const QString &address, + const QString &viewkey, + const QString &spendkey = "", + quint64 restoreHeight = 0, + quint64 kdfRounds = 1); + + Q_INVOKABLE Wallet * createDeterministicWalletFromSpendKey(const QString &path, + const QString &password, + const QString &language, + NetworkType::Type nettype, + const QString &spendkey, + quint64 restoreHeight, + quint64 kdfRounds); + + Q_INVOKABLE Wallet * createWalletFromDevice(const QString &path, + const QString &password, + NetworkType::Type nettype, + const QString &deviceName, + quint64 restoreHeight = 0, + const QString &subaddressLookahead = ""); + + Q_INVOKABLE void createWalletFromDeviceAsync(const QString &path, + const QString &password, + NetworkType::Type nettype, + const QString &deviceName, + quint64 restoreHeight = 0, + const QString &subaddressLookahead = ""); + /*! + * \brief closeWallet - closes current open wallet and frees memory + * \return wallet address + */ + Q_INVOKABLE QString closeWallet(); + + /*! + * \brief closeWalletAsync - asynchronous version of "closeWallet" + */ + //Q_INVOKABLE void closeWalletAsync(const QJSValue& callback); + + //! checks is given filename is a wallet; + Q_INVOKABLE bool walletExists(const QString &path) const; + + //! returns list with wallet's filenames, if found by given path + Q_INVOKABLE QStringList findWallets(const QString &path); + + //! returns error description in human language + Q_INVOKABLE QString errorString() const; + + //! since we can't call static method from QML, move it to this class + Q_INVOKABLE static QString displayAmount(quint64 amount); + Q_INVOKABLE quint64 amountFromString(const QString &amount) const; + Q_INVOKABLE quint64 amountFromDouble(double amount) const; + Q_INVOKABLE quint64 maximumAllowedAmount() const; + + // QML JS engine doesn't support unsigned integers + Q_INVOKABLE QString maximumAllowedAmountAsString() const; + + Q_INVOKABLE bool paymentIdValid(const QString &payment_id) const; + Q_INVOKABLE static bool addressValid(const QString &address, NetworkType::Type nettype); + Q_INVOKABLE bool keyValid(const QString &key, const QString &address, bool isViewKey, NetworkType::Type nettype) const; + + Q_INVOKABLE QString paymentIdFromAddress(const QString &address, NetworkType::Type nettype) const; + + Q_INVOKABLE void setDaemonAddressAsync(const QString &address); + Q_INVOKABLE bool connected() const; + Q_INVOKABLE quint64 networkDifficulty() const; + Q_INVOKABLE quint64 blockchainHeight() const; + Q_INVOKABLE quint64 blockchainTargetHeight() const; + Q_INVOKABLE double miningHashRate() const; + Q_INVOKABLE bool localDaemonSynced() const; + Q_INVOKABLE bool isDaemonLocal(const QString &daemon_address) const; + + Q_INVOKABLE void miningStatusAsync(); + Q_INVOKABLE bool startMining(const QString &address, quint32 threads, bool backgroundMining, bool ignoreBattery); + Q_INVOKABLE bool stopMining(); + + // QML missing such functionality, implementing these helpers here + Q_INVOKABLE QString urlToLocalPath(const QUrl &url) const; + Q_INVOKABLE QUrl localPathToUrl(const QString &path) const; + + Q_INVOKABLE void setLogLevel(int logLevel); + Q_INVOKABLE void setLogCategories(const QString &categories); + + Q_INVOKABLE quint64 add(quint64 x, quint64 y) const { return x + y; } + Q_INVOKABLE quint64 sub(quint64 x, quint64 y) const { return x - y; } + Q_INVOKABLE qint64 addi(qint64 x, qint64 y) const { return x + y; } + Q_INVOKABLE qint64 subi(qint64 x, qint64 y) const { return x - y; } + + Q_INVOKABLE QString resolveOpenAlias(const QString &address) const; + Q_INVOKABLE bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector &unknown_parameters, QString &error) const; + Q_INVOKABLE QVariantMap parse_uri_to_object(const QString &uri) const; +// Q_INVOKABLE bool saveQrCode(const QString &, const QString &) const; +// Q_INVOKABLE void checkUpdatesAsync( +// const QString &software, +// const QString &subdir, +// const QString &buildTag, +// const QString &version); + Q_INVOKABLE QString checkUpdates(const QString &software, const QString &subdir) const; + + // clear/rename wallet cache + Q_INVOKABLE bool clearWalletCache(const QString &fileName) const; + + Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false); + virtual void onWalletPassphraseNeeded(bool on_device) override; + +signals: + + void walletOpened(Wallet * wallet); + void walletCreated(Wallet * wallet); + void walletPassphraseNeeded(bool onDevice); + void deviceButtonRequest(quint64 buttonCode); + void deviceButtonPressed(); + void checkUpdatesComplete( + const QString &version, + const QString &downloadUrl, + const QString &hash, + const QString &firstSigner, + const QString &secondSigner) const; + void miningStatus(bool isMining) const; + +public slots: +private: + friend class WalletPassphraseListenerImpl; + + explicit WalletManager(QObject *parent = 0); + ~WalletManager(); + + bool isMining() const; + + static WalletManager * m_instance; + Monero::WalletManager * m_pimpl; + mutable QMutex m_mutex; + QPointer m_currentWallet; + PassphraseReceiver * m_passphraseReceiver; + QMutex m_mutex_passphraseReceiver; + FutureScheduler m_scheduler; +}; + +#endif // WALLETMANAGER_H diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..bcabcef --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include + +#include "config-feather.h" +#include "mainwindow.h" +#include "cli.h" +#include "utils/utils.h" +#include "appcontext.h" + +#include + +#if defined(Q_OS_LINUX) +Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) +#endif + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(assets); + +#if defined(Q_OS_MAC) && defined(BUILD_TOR) + Q_INIT_RESOURCE(assets_macos_tor); +#elif defined(Q_OS_LINUX) && defined(BUILD_TOR) + Q_INIT_RESOURCE(assets_linux_tor); +#elif defined(Q_OS_WIN) && defined(BUILD_TOR) + Q_INIT_RESOURCE(assets_windows_tor); +#endif + + QStringList argv_; + for(int i = 0; i != argc; i++){ + argv_ << QString::fromStdString(argv[i]); + } + + QCommandLineParser parser; + parser.setApplicationDescription("feather"); + parser.addHelpOption(); + parser.addVersionOption(); + + QCommandLineOption useLocalTorOption(QStringList() << "use-local-tor", "Use system wide installed Tor instead of the bundled."); + parser.addOption(useLocalTorOption); + + QCommandLineOption torPortOption(QStringList() << "tor-port", "Port of running Tor instance.", "torPort"); + parser.addOption(torPortOption); + + QCommandLineOption debugModeOption(QStringList() << "debug", "Run program in debug mode."); + parser.addOption(debugModeOption); + + QCommandLineOption quietModeOption(QStringList() << "quiet", "Limit console output"); + parser.addOption(quietModeOption); + + QCommandLineOption stagenetOption(QStringList() << "stagenet", "Stagenet is for development purposes only."); + parser.addOption(stagenetOption); + + QCommandLineOption testnetOption(QStringList() << "testnet", "Testnet is for development purposes only."); + parser.addOption(testnetOption); + + QCommandLineOption walletPathOption(QStringList() << "wallet-file", "Path to wallet keys file.", "file"); + parser.addOption(walletPathOption); + + QCommandLineOption walletPasswordOption(QStringList() << "password", "Wallet password (escape/quote as needed)", "password"); + parser.addOption(walletPasswordOption); + + QCommandLineOption daemonAddressOption(QStringList() << "daemon-address", "Daemon address (IPv4:port)", "daemonAddress"); + parser.addOption(daemonAddressOption); + + QCommandLineOption exportContactsOption(QStringList() << "export-contacts", "Output wallet contacts as CSV to specified path.", "file"); + parser.addOption(exportContactsOption); + + QCommandLineOption exportTxHistoryOption(QStringList() << "export-txhistory", "Output wallet transaction history as CSV to specified path.", "file"); + parser.addOption(exportTxHistoryOption); + + auto parsed = parser.parse(argv_); + if(!parsed) { + qCritical() << parser.errorText(); + exit(1); + } + + const QStringList args = parser.positionalArguments(); + bool debugMode = parser.isSet(debugModeOption); + bool localTor = parser.isSet(useLocalTorOption); + bool stagenet = parser.isSet(stagenetOption); + bool testnet = parser.isSet(testnetOption); + bool quiet = parser.isSet(quietModeOption); + bool exportContacts = parser.isSet(exportContactsOption); + bool exportTxHistory = parser.isSet(exportTxHistoryOption); + bool cliMode = exportContacts || exportTxHistory; + + if(cliMode) { + QCoreApplication cli_app(argc, argv); + QCoreApplication::setApplicationName("feather"); + QCoreApplication::setOrganizationDomain("featherwallet.org"); + QCoreApplication::setOrganizationName("featherwallet.org"); + + auto *ctx = new AppContext(&parser); + ctx->applicationPath = QString(argv[0]); + ctx->isDebug = debugMode; + + auto *cli = new CLI(ctx, &cli_app); + QObject::connect(cli, &CLI::closeApplication, &cli_app, &QCoreApplication::quit); + + if(exportContacts) { + if(!quiet) + qInfo() << "CLI mode: Address book export"; + cli->mode = CLIMode::CLIModeExportContacts; + QTimer::singleShot(0, cli, &CLI::run); + } else if(exportTxHistory) { + if(!quiet) + qInfo() << "CLI mode: Transaction history export"; + cli->mode = CLIMode::CLIModeExportTxHistory; + QTimer::singleShot(0, cli, &CLI::run); + } + + return QCoreApplication::exec(); + } + + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication::setDesktopSettingsAware(true); // use system font + QApplication::setApplicationVersion(FEATHER_VERSION); + + QApplication app(argc, argv); + + QApplication::setApplicationName("feather"); + QApplication::setOrganizationDomain("featherwallet.org"); + QApplication::setOrganizationName("featherwallet.org"); + + parser.process(app); // Parse again for --help and --version + + if(!quiet) { + QMap info; + info["Qt"] = QT_VERSION_STR; + info["Feather"] = FEATHER_VERSION; + if (stagenet) info["Mode"] = "Stagenet"; + else if (testnet) info["Mode"] = "Testnet"; + else info["Mode"] = "Mainnet"; + info["SSL"] = QSslSocket::sslLibraryVersionString(); + info["SSL build"] = QSslSocket::sslLibraryBuildVersionString(); + for (const auto &k: info.keys()) + qWarning().nospace().noquote() << QString("%1: %2").arg(k).arg(info[k]); + } + + auto *ctx = new AppContext(&parser); + ctx->applicationPath = QString(argv[0]); + ctx->isDebug = debugMode; + +#if defined(Q_OS_MAC) + // For some odd reason, if we don't do this, QPushButton's + // need to be clicked *twice* in order to fire ?! + QFont fontDef = QApplication::font(); + fontDef.setPointSize(fontDef.pointSize() + 1); + QApplication::setFont(fontDef); +#endif + + qInstallMessageHandler(Utils::applicationLogHandler); + + auto *mainWindow = new MainWindow(ctx); + return QApplication::exec(); +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 0000000..e8b3efa --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,1058 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include +#include +#include +#include + +#include "mainwindow.h" +#include "widgets/ccswidget.h" +#include "widgets/redditwidget.h" +#include "dialog/txconfdialog.h" +#include "dialog/debuginfodialog.h" +#include "dialog/walletinfodialog.h" +#include "dialog/torinfodialog.h" +#include "utils/utils.h" +#include "utils/config.h" +#include "components.h" +#include "calcwindow.h" +#include "ui_mainwindow.h" + +// libwalletqt +#include "libwalletqt/WalletManager.h" +#include "Wallet.h" +#include "libwalletqt/TransactionHistory.h" +#include "libwalletqt/SubaddressAccount.h" +#include "libwalletqt/AddressBook.h" +#include "model/SubaddressAccountModel.h" +#include "model/SubaddressModel.h" +#include "utils/networktype.h" + +MainWindow * MainWindow::pMainWindow = nullptr; + +MainWindow::MainWindow(AppContext *ctx, QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow), + m_ctx(ctx), + m_aboutDialog(new AboutDialog(this)), + m_windowCalc(new CalcWindow(this)) +{ + pMainWindow = this; + ui->setupUi(this); + + m_windowSettings = new Settings(this); + + // light/dark theme + m_skins.insert("Native", ""); + this->loadSkins(); + QString skin = config()->get(Config::skin).toString(); + qApp->setStyleSheet(m_skins[skin]); + + this->screenDpiRef = 128; + this->screenGeo = QApplication::primaryScreen()->availableGeometry(); + this->screenRect = QGuiApplication::primaryScreen()->geometry(); + this->screenDpi = QGuiApplication::primaryScreen()->logicalDotsPerInch(); + this->screenDpiPhysical = QGuiApplication::primaryScreen()->physicalDotsPerInch(); + this->screenRatio = this->screenDpiPhysical / this->screenDpiRef; + qInfo() << QString("%1x%2 (%3 DPI)").arg(this->screenRect.width()).arg(this->screenRect.height()).arg(this->screenDpi); + + this->restoreGeo(); + + this->create_status_bar(); + + // Bootstrap Tor/websockets + m_ctx->initTor(); + m_ctx->initWS(); + + // update statusbar + connect(m_ctx->tor, &Tor::connectionStateChanged, [this](bool connected){ + connected ? m_statusBtnTor->setIcon(QIcon(":/assets/images/tor_logo.png")) + : m_statusBtnTor->setIcon(QIcon(":/assets/images/tor_logo_disabled.png"));}); + connect(m_ctx->nodes, &Nodes::updateStatus, [=](const QString &msg){ + m_statusLabelStatus->setText(msg); + }); + + // menu connects + connect(ui->actionQuit, &QAction::triggered, this, &MainWindow::menuQuitClicked); + connect(ui->actionSettings, &QAction::triggered, this, &MainWindow::menuSettingsClicked); + connect(ui->actionCalculator, &QAction::triggered, this, &MainWindow::showCalcWindow); + +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + ui->actionCreateDesktopEntry->setDisabled(true); +#endif + connect(ui->actionCreateDesktopEntry, &QAction::triggered, [=]{ + auto msg = Utils::xdgDesktopEntryRegister() ? "Desktop entry created" : "Desktop entry not created due to an error."; + QMessageBox::information(this, "Desktop entry", msg); + }); + connect(ui->actionReport_bug, &QAction::triggered, [this](){ + QMessageBox::information(this, "Reporting Bugs", + "Please report any bugs as issues on our git repo:
\n" + "https://git.wownero.com/feather/feather/issues

" + "\n" + "Before reporting a bug, upgrade to the most recent version of Feather " + "(latest release or git HEAD), and include the version number in your report. " + "Try to explain not only what the bug is, but how it occurs."); + }); + connect(ui->actionShow_debug_info, &QAction::triggered, this, &MainWindow::showDebugInfo); + connect(ui->actionOfficialWebsite, &QAction::triggered, [=] { Utils::externalLinkWarning("https://featherwallet.org"); }); + connect(ui->actionAbout_Qt, &QAction::triggered, [=] { QApplication::aboutQt(); }); + + +#if defined(XMRTO) + // xmr.to connects/widget + connect(ui->xmrToWidget, &XMRToWidget::viewOrder, m_ctx->XMRTo, &XmrTo::onViewOrder); + connect(ui->xmrToWidget, &XMRToWidget::getRates, m_ctx->XMRTo, &XmrTo::onGetRates); + connect(ui->xmrToWidget, &XMRToWidget::createOrder, m_ctx->XMRTo, &XmrTo::createOrder); + connect(m_ctx->XMRTo, &XmrTo::ratesUpdated, ui->xmrToWidget, &XMRToWidget::onRatesUpdated); + connect(m_ctx->XMRTo, &XmrTo::connectionError, ui->xmrToWidget, &XMRToWidget::onConnectionError); + connect(m_ctx->XMRTo, &XmrTo::connectionSuccess, ui->xmrToWidget, &XMRToWidget::onConnectionSuccess); + connect(m_ctx, &AppContext::balanceUpdated, ui->xmrToWidget, &XMRToWidget::onBalanceUpdated); + connect(m_ctx->XMRTo, &XmrTo::openURL, this, [=](const QString &url){ Utils::externalLinkWarning(url); }); + ui->xmrToWidget->setHistoryModel(m_ctx->XMRTo->tableModel); +#else + ui->tabWidget->setTabVisible(5, false); +#endif + + +#if defined(Q_OS_LINUX) + // system tray + m_trayIcon = new QSystemTrayIcon(QIcon(":/assets/images/appicons/64x64.png")); + m_trayIcon->show(); + + m_trayActionCalc = new QAction("Calc", this); + m_trayActionCalc->setStatusTip("Calculator"); + + m_trayActionSend = new QAction("Send", this); + m_trayActionSend->setStatusTip("Send XMR payment"); + + m_trayActionHistory = new QAction("History", this); + m_trayActionHistory->setStatusTip("View incoming transfers"); + + m_trayActionExit = new QAction("Quit", this); + m_trayActionExit->setStatusTip("Exit application"); + + m_trayMenu.addAction(m_trayActionSend); + m_trayMenu.addAction(m_trayActionHistory); + m_trayMenu.addAction(m_trayActionCalc); + m_trayMenu.addAction(m_trayActionExit); + m_trayIcon->setContextMenu(&m_trayMenu); + + // @TODO: only init tray *after* boot + connect(m_trayActionCalc, &QAction::triggered, this, &MainWindow::showCalcWindow); + connect(m_trayActionSend, &QAction::triggered, this, &MainWindow::showSendTab); + connect(m_trayActionHistory, &QAction::triggered, this, &MainWindow::showHistoryTab); + connect(m_trayActionExit, &QAction::triggered, this, &QMainWindow::close); +#endif + + // ticker widgets + m_tickerWidgets.append(new TickerWidget(this, "XMR")); + m_tickerWidgets.append(new TickerWidget(this, "BTC")); + for(auto tickerWidget: m_tickerWidgets) { + ui->tickerLayout->addWidget(tickerWidget); + } + + m_balanceWidget = new TickerWidget(this, "XMR", "Balance", true); + ui->fiatTickerLayout->addWidget(m_balanceWidget); + + // Send widget + connect(ui->sendWidget, &SendWidget::createTransaction, m_ctx, QOverload::of(&AppContext::onCreateTransaction)); + + // Nodes + connect(m_ctx->nodes, &Nodes::nodeExhausted, this, &MainWindow::showNodeExhaustedMessage); + connect(m_ctx->nodes, &Nodes::WSNodeExhausted, this, &MainWindow::showWSNodeExhaustedMessage); + + // CCS/Reddit widget + m_ccsWidget = new CCSWidget(this); + m_redditWidget = new RedditWidget(this); + + m_ccsWidget->hide(); + m_redditWidget->hide(); + + ui->coolLayout->addWidget(m_ccsWidget); + ui->coolLayout->addWidget(m_redditWidget); + + connect(m_ctx, &AppContext::ccsEmpty, [=] { + if(m_ccsWidget->isVisible()) { + // display Reddit widget instead + m_ccsWidget->show(); + m_redditWidget->show(); + } + }); + connect(m_ctx, &AppContext::ccsUpdated, m_ccsWidget->model(), &CCSModel::updateEntries); + connect(m_ctx, &AppContext::redditUpdated, m_redditWidget->model(), &RedditModel::updatePosts); + connect(m_ccsWidget, &CCSWidget::selected, this, &MainWindow::showSendScreen); + + connect(m_ctx, &AppContext::donationNag, [=]{ + auto msg = "Feather is a 100% community-sponsored endeavor. Please consider supporting " + "the project financially. Get rid of this message by donating any amount."; + int ret = QMessageBox::information(this, "Donate to Feather", msg, QMessageBox::Yes, QMessageBox::No); + switch (ret) { + case QMessageBox::Yes: + this->donateButtonClicked(); + case QMessageBox::No: + break; + default: + return; + } + }); + + // libwalletqt + connect(this, &MainWindow::walletClosed, ui->xmrToWidget, &XMRToWidget::onWalletClosed); + connect(this, &MainWindow::walletClosed, ui->sendWidget, &SendWidget::onWalletClosed); + connect(m_ctx, &AppContext::balanceUpdated, this, &MainWindow::onBalanceUpdated); + connect(m_ctx, &AppContext::balanceUpdated, ui->xmrToWidget, &XMRToWidget::onBalanceUpdated); + connect(m_ctx, &AppContext::walletOpened, this, &MainWindow::onWalletOpened); + connect(m_ctx, &AppContext::walletClosed, this, QOverload<>::of(&MainWindow::onWalletClosed)); + connect(m_ctx, &AppContext::walletOpenedError, this, &MainWindow::onWalletOpenedError); + connect(m_ctx, &AppContext::walletCreatedError, this, &MainWindow::onWalletCreatedError); + connect(m_ctx, &AppContext::walletCreated, this, &MainWindow::onWalletCreated); + connect(m_ctx, &AppContext::synchronized, this, &MainWindow::onSynchronized); + connect(m_ctx, &AppContext::blockchainSync, this, &MainWindow::onBlockchainSync); + connect(m_ctx, &AppContext::refreshSync, this, &MainWindow::onRefreshSync); + connect(m_ctx, &AppContext::createTransactionError, this, &MainWindow::onCreateTransactionError); + connect(m_ctx, &AppContext::createTransactionSuccess, this, &MainWindow::onCreateTransactionSuccess); + connect(m_ctx, &AppContext::transactionCommitted, this, &MainWindow::onTransactionCommitted); + connect(m_ctx, &AppContext::walletOpenPasswordNeeded, this, &MainWindow::onWalletOpenPasswordRequired); + + // Send + connect(m_ctx, &AppContext::initiateTransaction, ui->sendWidget, &SendWidget::onInitiateTransaction); + connect(m_ctx, &AppContext::endTransaction, ui->sendWidget, &SendWidget::onEndTransaction); + + // XMR.to + connect(m_ctx, &AppContext::initiateTransaction, ui->xmrToWidget, &XMRToWidget::onInitiateTransaction); + connect(m_ctx, &AppContext::endTransaction, ui->xmrToWidget, &XMRToWidget::onEndTransaction); + + // testnet/stagenet warning + auto worthlessWarning = QString("Feather wallet is currently running in %1 mode. This is meant " + "for developers only. Your coins are WORTHLESS."); + if(m_ctx->networkType == NetworkType::STAGENET) { + if (config()->get(Config::warnOnStagenet).toBool()) { + Utils::showMessageBox("Warning", worthlessWarning.arg("stagenet"), true); + config()->set(Config::warnOnStagenet, false); + } + } + else if(m_ctx->networkType == NetworkType::TESTNET){ + if (config()->get(Config::warnOnTestnet).toBool()) { + Utils::showMessageBox("Warning", worthlessWarning.arg("testnet"), true); + config()->set(Config::warnOnTestnet, false); + } + } + + if(config()->get(Config::warnOnAlpha).toBool()) { + auto alphaWarning = "Feather wallet is currently in alpha. Bugs are to be expected and " + "can be reported on our Git repository or on IRC."; + Utils::showMessageBox("Warning", alphaWarning, true); + config()->set(Config::warnOnAlpha, false); + } + + // settings connects + // Update ticker widget(s) on home tab when settings preferred fiat currency is changed + for(auto tickerWidget: m_tickerWidgets) + connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, tickerWidget, &TickerWidget::init); + connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_balanceWidget, &TickerWidget::init); + connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_ctx, &AppContext::onPreferredFiatCurrencyChanged); + + // CCS/Reddit widget + connect(m_windowSettings, &Settings::homeWidgetChanged, this, &MainWindow::homeWidgetChanged); + + // Skin + connect(m_windowSettings, &Settings::skinChanged, this, &MainWindow::skinChanged); + + // Wizard + connect(this, &MainWindow::closed, [=]{ + if(m_wizard != nullptr) + m_wizard->close(); + }); + + // Receive + connect(ui->receiveWidget, &ReceiveWidget::generateSubaddress, [=]() { + m_ctx->currentWallet->subaddress()->addRow( m_ctx->currentWallet->currentSubaddressAccount(), ""); + m_ctx->storeWallet(); + }); + connect(ui->receiveWidget, &ReceiveWidget::showTransactions, [this](const QString &text) { + ui->historyWidget->setSearchText(text); + ui->tabWidget->setCurrentIndex(1); //history + }); + + // History + connect(ui->historyWidget, &HistoryWidget::spendProof, [&](const QString &txid){ + QString spendProof = m_ctx->currentWallet->getSpendProof(txid, ""); + Utils::copyToClipboard(spendProof); + }); + connect(ui->historyWidget, &HistoryWidget::viewOnBlockExplorer, this, &MainWindow::onViewOnBlockExplorer); + + // Contacts + connect(ui->contactWidget, &ContactsWidget::addContact, this, &MainWindow::onAddContact); + connect(ui->contactWidget, &ContactsWidget::fillAddress, ui->sendWidget, &SendWidget::fillAddress); + + // Open alias + connect(ui->sendWidget, &SendWidget::resolveOpenAlias, m_ctx, &AppContext::onOpenAliasResolve); + connect(m_ctx, &AppContext::openAliasResolveError, ui->sendWidget, &SendWidget::onOpenAliasResolveError); + connect(m_ctx, &AppContext::openAliasResolved, ui->sendWidget, &SendWidget::onOpenAliasResolved); + + // Coins + connect(ui->coinsWidget, &CoinsWidget::freeze, [=](int index) { + m_ctx->currentWallet->coins()->freeze(index); + m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); + m_ctx->updateBalance(); + // subaddress account filtering should be done in Model maybe, so we can update data in coins() directly + }); + connect(ui->coinsWidget, &CoinsWidget::freezeMulti, [&](const QVector& indexes) { + for (int i : indexes) { + m_ctx->currentWallet->coins()->freeze(i); + m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); + m_ctx->updateBalance(); + } + }); + connect(ui->coinsWidget, &CoinsWidget::thaw, [=](int index) { + m_ctx->currentWallet->coins()->thaw(index); + m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); + m_ctx->updateBalance(); + }); + connect(ui->coinsWidget, &CoinsWidget::thawMulti, [&](const QVector& indexes) { + for (int i : indexes) { + m_ctx->currentWallet->coins()->thaw(i); + m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); + m_ctx->updateBalance(); + } + }); + connect(ui->coinsWidget, &CoinsWidget::sweepOutput, m_ctx, &AppContext::onSweepOutput); + + connect(m_ctx, &AppContext::walletClosing, [=]{ + ui->tabWidget->setCurrentIndex(0); + }); + // setup some UI + this->initMain(); + this->initWidgets(); + this->initMenu(); +} + +void MainWindow::initMain() { + // show wizards or open wallet directly based on cmdargs + if(m_ctx->cmdargs->isSet("password")) + m_ctx->walletPassword = m_ctx->cmdargs->value("password"); + + QString openPath = ""; + QString autoPath = config()->get(Config::autoOpenWalletPath).toString(); + if(m_ctx->cmdargs->isSet("wallet-file")) + openPath = m_ctx->cmdargs->value("wallet-file"); + else if(!autoPath.isEmpty()) + if (autoPath.startsWith(QString::number(m_ctx->networkType))) + openPath = autoPath.remove(0, 1); + + if(!openPath.isEmpty() && Utils::fileExists(openPath)) { + this->show(); + this->setEnabled(true); + + m_ctx->onOpenWallet(openPath, m_ctx->walletPassword); + return; + } + + this->setEnabled(false); + this->show(); + m_wizard = this->createWizard(WalletWizard::Page_Menu); + m_wizard->show(); +} + +void MainWindow::initMenu() { + // hide/show tabs + m_tabShowHideSignalMapper = new QSignalMapper(this); + + connect(ui->actionShow_Coins, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map)); + m_tabShowHideMapper["Coins"] = new ToggleTab(ui->tabCoins, "Coins", "Coins", ui->actionShow_Coins, Config::showTabCoins); + m_tabShowHideSignalMapper->setMapping(ui->actionShow_Coins, "Coins"); +#if defined(XMRTO) + connect(ui->actionShow_xmr_to, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map)); + m_tabShowHideMapper["XMRto"] = new ToggleTab(ui->tabXmrTo, "XMRto", "xmr.to", ui->actionShow_xmr_to, Config::showTabXMRto); + m_tabShowHideSignalMapper->setMapping(ui->actionShow_xmr_to, "XMRto"); +#else + ui->actionShow_xmr_to->setVisible(false); +#endif + connect(ui->actionShow_calc, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map)); + m_tabShowHideMapper["Calc"] = new ToggleTab(ui->tabCalc, "Calc", "Calc", ui->actionShow_calc, Config::showTabCalc); + m_tabShowHideSignalMapper->setMapping(ui->actionShow_calc, "Calc"); + + for (const auto &key: m_tabShowHideMapper.keys()) { + const auto toggleTab = m_tabShowHideMapper.value(key); + const bool show = config()->get(toggleTab->configKey).toBool(); + toggleTab->menuAction->setText((show ? QString("Hide ") : QString("Show ")) + toggleTab->name); + ui->tabWidget->setTabVisible(ui->tabWidget->indexOf(toggleTab->tab), show); + } + connect(m_tabShowHideSignalMapper, &QSignalMapper::mappedString, this, &MainWindow::menuToggleTabVisible); + + // Wallet + connect(ui->actionInformation, &QAction::triggered, this, &MainWindow::showWalletInfoDialog); + connect(ui->actionSeed, &QAction::triggered, this, &MainWindow::showSeedDialog); + connect(ui->actionPassword, &QAction::triggered, this, &MainWindow::showPasswordDialog); + connect(ui->actionKeys, &QAction::triggered, this, &MainWindow::showKeysDialog); + connect(ui->actionStore_wallet, &QAction::triggered, [&]{ + m_ctx->currentWallet->store(); + }); + connect(ui->actionRefresh_tabs, &QAction::triggered, [&]{ + m_ctx->refreshModels(); + }); + connect(ui->actionUpdate_balance, &QAction::triggered, [&]{ + m_ctx->updateBalance(); + }); + + // set restore height + connect(ui->actionChange_restore_height, &QAction::triggered, this, &MainWindow::showRestoreHeightDialog); + connect(m_ctx, &AppContext::customRestoreHeightSet, [=](unsigned int height){ + auto msg = QString("The restore height for this wallet has been set to %1. " + "Please re-open the wallet. Feather will now quit.").arg(height); + QMessageBox::information(this, "Cannot set custom restore height", msg); + this->menuQuitClicked(); + }); + + // CSV tx export + connect(ui->actionExport_CSV, &QAction::triggered, [=]{ + if(m_ctx->currentWallet == nullptr) return; + QString fn = QFileDialog::getSaveFileName(this, "Save CSV file", QDir::homePath(), "CSV (*.csv)"); + if(!fn.startsWith(".csv")) fn += ".csv"; + m_ctx->currentWallet->history()->writeCSV(fn); + Utils::showMessageBox("CSV export", QString("Transaction history exported to %1").arg(fn), false); + }); + + // Contact widget + connect(ui->actionExportContactsCSV, &QAction::triggered, [=]{ + if(m_ctx->currentWallet == nullptr) return; + auto *model = m_ctx->currentWallet->addressBookModel(); + if (model->rowCount() <= 0){ + Utils::showMessageBox("Error", "Addressbook empty", true); + return; + } + + const QString targetDir = QFileDialog::getExistingDirectory(this, "Select CSV output directory ", QDir::homePath(), QFileDialog::ShowDirsOnly); + if(targetDir.isEmpty()) return; + + qint64 now = QDateTime::currentDateTime().currentMSecsSinceEpoch(); + QString fn = QString("%1/monero-contacts_%2.csv").arg(targetDir, QString::number(now / 1000)); + if(model->writeCSV(fn)) + Utils::showMessageBox("Address book exported", QString("Address book exported to %1").arg(fn), false); + }); + + // Tools + connect(ui->actionSignVerify, &QAction::triggered, this, &MainWindow::menuSignVerifyClicked); + connect(ui->actionVerifyTxProof, &QAction::triggered, this, &MainWindow::menuVerifyTxProof); + + // About screen + connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::menuAboutClicked); + connect(ui->actionDonate_to_Feather, &QAction::triggered, this, &MainWindow::donateButtonClicked); + + // Close / Open + connect(ui->actionClose, &QAction::triggered, this, &MainWindow::menuWalletCloseClicked); + connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::menuWalletOpenClicked); +} + +void MainWindow::menuToggleTabVisible(const QString &key){ + const auto toggleTab = m_tabShowHideMapper[key]; + bool show = config()->get(toggleTab->configKey).toBool(); + show = !show; + config()->set(toggleTab->configKey, show); + ui->tabWidget->setTabVisible(ui->tabWidget->indexOf(toggleTab->tab), show); + toggleTab->menuAction->setText((show ? QString("Hide ") : QString("Show ")) + toggleTab->name); +} + +void MainWindow::initWidgets() { + auto homeWidget = config()->get(Config::homeWidget).toString(); + if(homeWidget == QString("ccs")) { + m_ccsWidget->show(); + } else if (homeWidget == "reddit") { + m_redditWidget->show(); + } else { + config()->set(Config::homeWidget, "ccs"); + m_ccsWidget->show(); + } +} + +WalletWizard *MainWindow::createWizard(WalletWizard::Page startPage){ + auto *wizard = new WalletWizard(m_ctx, startPage, this); + connect(wizard, &WalletWizard::openWallet, m_ctx, &AppContext::onOpenWallet); + return wizard; +} + +void MainWindow::showWizard(WalletWizard::Page startPage) { + this->setEnabled(false); + m_wizard = this->createWizard(startPage); + m_wizard->show(); +} + +void MainWindow::onWalletClosed() { + this->onWalletClosed(WalletWizard::Page_Menu); +} + +void MainWindow::onWalletClosed(WalletWizard::Page page) { + emit walletClosed(); + m_statusLabelBalance->clear(); + m_statusLabelStatus->clear(); + this->setWindowTitle("Feather"); + this->showWizard(page); +} + +void MainWindow::onWalletCreatedError(const QString &err) { + Utils::showMessageBox("Wallet creation error", err, true); + this->showWizard(WalletWizard::Page_CreateWallet); +} + +void MainWindow::onWalletOpenPasswordRequired(bool invalidPassword) { + QInputDialog passwordDialog(this); + passwordDialog.setInputMode(QInputDialog::TextInput); + passwordDialog.setTextEchoMode(QLineEdit::Password); + passwordDialog.setWindowTitle("Password required"); + passwordDialog.setLabelText("Please enter wallet password."); + passwordDialog.resize(300, 100); + if(!(bool)passwordDialog.exec()) + return this->showWizard(WalletWizard::Page_OpenWallet); + + const auto passwd = passwordDialog.textValue(); + m_ctx->walletPassword = passwd; + m_ctx->onOpenWallet(m_ctx->walletPath, m_ctx->walletPassword); +} + +void MainWindow::onWalletOpenedError(const QString &err) { + qDebug() << Q_FUNC_INFO << QString("Wallet open error: %1").arg(err); + QMessageBox::warning(this, "Wallet open error", err); + this->setWindowTitle("Feather"); + this->showWizard(WalletWizard::Page_OpenWallet); +} + +void MainWindow::onWalletCreated(Wallet *wallet) { + qDebug() << Q_FUNC_INFO; + // emit signal on behalf of walletManager + m_ctx->walletManager->walletOpened(wallet); +} + +void MainWindow::onWalletOpened() { + qDebug() << Q_FUNC_INFO; + if(m_wizard != nullptr) { + m_wizard->hide(); + m_wizard->disconnect(); + m_wizard->deleteLater(); + } + + this->raise(); + this->show(); + this->activateWindow(); + this->setEnabled(true); + if(!m_ctx->tor->torConnected) + m_statusLabelStatus->setText("Wallet opened - Starting Tor (may take a while)"); + else + m_statusLabelStatus->setText("Wallet opened - Searching for node"); + + // window title as wallet name + QFileInfo fileInfo(m_ctx->walletPath); + this->setWindowTitle(QString("Feather - [%1]").arg(fileInfo.fileName())); + + connect(m_ctx->currentWallet, &Wallet::connectionStatusChanged, this, &MainWindow::onConnectionStatusChanged); + + // receive page + m_ctx->currentWallet->subaddress()->refresh( m_ctx->currentWallet->currentSubaddressAccount()); + ui->receiveWidget->setModel( m_ctx->currentWallet->subaddressModel(), m_ctx->currentWallet->subaddress()); + if (m_ctx->currentWallet->subaddress()->count() == 1) { + for (int i = 0; i < 10; i++) { + m_ctx->currentWallet->subaddress()->addRow(m_ctx->currentWallet->currentSubaddressAccount(), ""); + } + } + connect(m_ctx->currentWallet->subaddress(), &Subaddress::labelChanged, [this]{ + m_ctx->storeWallet(); + }); + + // history page + m_ctx->currentWallet->history()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); + ui->historyWidget->setModel(m_ctx->currentWallet->coins(), m_ctx->currentWallet->historyModel(), m_ctx->currentWallet->history()); + connect(m_ctx->currentWallet->history(), &TransactionHistory::txNoteChanged, [this]{ + m_ctx->storeWallet(); + }); + + // contacts widget + ui->contactWidget->setModel(m_ctx->currentWallet->addressBookModel()); + connect(m_ctx->currentWallet->addressBook(), &AddressBook::descriptionChanged, [this]{ + m_ctx->storeWallet(); + }); + + // coins page + m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); + ui->coinsWidget->setModel(m_ctx->currentWallet->coinsModel(), m_ctx->currentWallet->coins()); + connect(m_ctx->currentWallet->coins(), &Coins::coinFrozen, [this]{ + m_ctx->storeWallet(); + }); + connect(m_ctx->currentWallet->coins(), &Coins::coinThawed, [this]{ + m_ctx->storeWallet(); + }); +} + +void MainWindow::onBalanceUpdated(double balance, double unlocked, const QString &balance_str, const QString &unlocked_str) { + qDebug() << Q_FUNC_INFO; + auto label_str = QString("Balance: %1 XMR").arg(unlocked_str); + if(balance > unlocked) + label_str += QString(" (+%1 XMR unconfirmed)").arg(balance - unlocked); + m_statusLabelBalance->setText(label_str); +} + +void MainWindow::onSynchronized() { + m_statusLabelStatus->setText("Synchronized"); + this->onConnectionStatusChanged(Wallet::ConnectionStatus_Connected); +} + +void MainWindow::onBlockchainSync(int height, int target) { + QString heightText = QString("Blockchain sync: %1/%2").arg(height).arg(target); + m_statusLabelStatus->setText(heightText); +} + +void MainWindow::onRefreshSync(int height, int target) { + QString heightText = QString("Wallet refresh: %1/%2").arg(height).arg(target); + m_statusLabelStatus->setText(heightText); +} + +void MainWindow::onConnectionStatusChanged(int status) +{ + qDebug() << "Wallet connection status changed " << status; + + // Update connection info in status bar. + + QString statusIcon; + QString statusMsg; + switch(status){ + case Wallet::ConnectionStatus_Disconnected: + statusIcon = ":/assets/images/status_disconnected.svg"; + m_statusLabelStatus->setText("Disconnected"); + break; + case Wallet::ConnectionStatus_Connected: + if (m_ctx->currentWallet->synchronized()) { + statusIcon = ":/assets/images/status_connected.svg"; + } else { + statusIcon = ":/assets/images/status_waiting.svg"; + } + break; + case Wallet::ConnectionStatus_Connecting: + statusIcon = ":/assets/images/status_lagging.svg"; + m_statusLabelStatus->setText("Connecting to daemon"); + break; + case Wallet::ConnectionStatus_WrongVersion: + statusIcon = ":/assets/images/status_disconnected.svg"; + m_statusLabelStatus->setText("Incompatible daemon"); + break; + default: + statusIcon = ":/assets/images/status_disconnected.svg"; + break; + } + + m_statusBtnConnectionStatusIndicator->setIcon(QIcon(statusIcon)); +} + +void MainWindow::onCreateTransactionSuccess(PendingTransaction *tx, const QString &address, const quint32 &mixin) { + auto tx_status = tx->status(); + auto err = QString("Can't create transaction: "); + + if(tx_status != PendingTransaction::Status_Ok){ + auto tx_err = tx->errorString(); + qCritical() << tx_err; + + if(m_ctx->currentWallet->connected() == Wallet::ConnectionStatus_WrongVersion) + err = QString("%1 Wrong daemon version: %2").arg(err).arg(tx_err); + else + err = QString("%1 %2").arg(err).arg(tx_err); + + qDebug() << Q_FUNC_INFO << err; + Utils::showMessageBox("Transaction error", err, true); + m_ctx->currentWallet->disposeTransaction(tx); + } else if (tx->txCount() == 0) { + err = QString("%1 %2").arg(err).arg("No unmixable outputs to sweep."); + qDebug() << Q_FUNC_INFO << err; + Utils::showMessageBox("Transaction error", err, true); + m_ctx->currentWallet->disposeTransaction(tx); + } else { + const auto &description = m_ctx->tmpTxDescription; + + auto *dialog = new TxConfDialog(tx, address, description, mixin, this); + switch (dialog->exec()) { + case QDialog::Rejected: + m_ctx->onCancelTransaction(tx, address); + break; + case QDialog::Accepted: + m_ctx->currentWallet->commitTransactionAsync(tx); + break; + } + } +} + +void MainWindow::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid) { + if(status) { // success + QString body = QString("Successfully sent %1 transaction(s).").arg(txid.count()); + QMessageBox::information(this, "Transactions sent", body); + ui->sendWidget->clearFields(); + + for(const auto &entry: txid) { + m_ctx->currentWallet->setUserNote(entry, m_ctx->tmpTxDescription); + AppContext::txDescriptionCache[entry] = m_ctx->tmpTxDescription; + } + + m_ctx->tmpTxDescription = ""; + } else { + auto err = tx->errorString(); + QString body = QString("Error committing transaction: %1").arg(err); + QMessageBox::warning(this, "Transaction failed", body); + } +} + +void MainWindow::onCreateTransactionError(const QString &message) { + auto msg = QString("Error while creating transaction: %1").arg(message); + + if (msg.contains("failed to get random outs")) { + msg += "\n\nYour transaction has too many inputs. Try sending a lower amount."; + } + + QMessageBox::warning(this, "Transaction failed", msg); +} + +void MainWindow::create_status_bar() { + this->statusBar()->setFixedHeight(30); + + m_statusLabelStatus = new QLabel("Idle", this); + m_statusLabelStatus->setTextInteractionFlags(Qt::TextSelectableByMouse); + this->statusBar()->addWidget(m_statusLabelStatus); + + m_statusLabelBalance = new QLabel("Balance: 0.00 XMR", this); + m_statusLabelBalance->setTextInteractionFlags(Qt::TextSelectableByMouse); + this->statusBar()->addPermanentWidget(m_statusLabelBalance); + + m_statusBtnConnectionStatusIndicator = new StatusBarButton(QIcon(":/assets/images/status_disconnected.svg"), "Connection status"); + connect(m_statusBtnConnectionStatusIndicator, &StatusBarButton::clicked, this, &MainWindow::showConnectionStatusDialog); + this->statusBar()->addPermanentWidget(m_statusBtnConnectionStatusIndicator); + + m_statusBtnPassword = new StatusBarButton(QIcon(":/assets/images/lock.svg"), "Password"); + connect(m_statusBtnPassword, &StatusBarButton::clicked, this, &MainWindow::showPasswordDialog); + this->statusBar()->addPermanentWidget(m_statusBtnPassword); + + m_statusBtnPreferences = new StatusBarButton(QIcon(":/assets/images/preferences.svg"), "Settings"); + connect(m_statusBtnPreferences, &StatusBarButton::clicked, this, &MainWindow::menuSettingsClicked); + this->statusBar()->addPermanentWidget(m_statusBtnPreferences); + + m_statusBtnSeed = new StatusBarButton(QIcon(":/assets/images/seed.png"), "Seed"); + connect(m_statusBtnSeed, &StatusBarButton::clicked, this, &MainWindow::showSeedDialog); + this->statusBar()->addPermanentWidget(m_statusBtnSeed); + + m_statusBtnTor = new StatusBarButton(QIcon(":/assets/images/tor_logo_disabled.png"), "Tor"); + connect(m_statusBtnTor, &StatusBarButton::clicked, this, &MainWindow::menuTorClicked); + this->statusBar()->addPermanentWidget(m_statusBtnTor); +} + +void MainWindow::showWalletInfoDialog() { + auto *dialog = new WalletInfoDialog(m_ctx, this); + dialog->exec(); + dialog->deleteLater(); +} + +void MainWindow::showSeedDialog() { + QString seed = m_ctx->currentWallet->getCacheAttribute("feather.seed"); + if (seed.isEmpty()) { + seed = m_ctx->currentWallet->getSeed(); + } + + auto *dialog = new SeedDialog(seed, this); + dialog->exec(); + dialog->deleteLater(); +} + +void MainWindow::showConnectionStatusDialog() { + auto status = m_ctx->currentWallet->connected(true); + bool synchronized = m_ctx->currentWallet->synchronized(); + + QString statusMsg; + switch(status){ + case Wallet::ConnectionStatus_Disconnected: + statusMsg = "Wallet is disconnected from daemon."; + break; + case Wallet::ConnectionStatus_Connected: { + auto node = m_ctx->nodes->connection(); + statusMsg = QString("Wallet is connected to %1").arg(node.full); + if (synchronized) + statusMsg += " and synchronized"; + break; + } + case Wallet::ConnectionStatus_Connecting: { + auto node = m_ctx->nodes->connection(); + statusMsg = QString("Wallet is connecting to %1").arg(node.full); + break; + } + case Wallet::ConnectionStatus_WrongVersion: + statusMsg = "Wallet is connected to incompatible daemon."; + break; + default: + statusMsg = "Unknown connection status (this should never happen)."; + } + + QMessageBox::information(this, "Connection Status", statusMsg); +} + +void MainWindow::showPasswordDialog() { + auto *pdialog = new PasswordChangeDialog(this); + int ret = pdialog->exec(); + if (!ret) return; + + QApplication::setActiveWindow(this); + + QString currentPassword = pdialog->getCurrentPassword(); + QString newPassword = pdialog->getNewPassword(); + + if (currentPassword != m_ctx->walletPassword) { + QMessageBox::warning(this, "Error", "Incorrect password"); + return; + } + + if (m_ctx->currentWallet->setPassword(newPassword)) { + QMessageBox::information(this, "Information", "Password changed successfully"); + } + else { + QMessageBox::warning(this, "Error", QString("Error: %1").arg(m_ctx->currentWallet->errorString())); + } + + pdialog->deleteLater(); +} + +void MainWindow::showRestoreHeightDialog() { + // settings custom restore height is only available for 25 word seeds + auto seed = m_ctx->currentWallet->getCacheAttribute("feather.seed"); + if(!seed.isEmpty()) { + const auto msg = "This wallet has a 14 word mnemonic seed which has the restore height embedded."; + QMessageBox::warning(this, "Cannot set custom restore height", msg); + return; + } + + m_restoreDialog = new RestoreDialog(m_ctx, this); + m_restoreDialog->show(); + + connect(m_restoreDialog, &RestoreDialog::accepted, [=]{ + auto height = m_restoreDialog->getHeight(); + m_restoreDialog->disconnect(); + m_restoreDialog->deleteLater(); + m_ctx->onSetRestoreHeight(height); + }); + + connect(m_restoreDialog, &RestoreDialog::rejected, [=]{ + m_restoreDialog->disconnect(); + m_restoreDialog->deleteLater(); + }); +} + +void MainWindow::showKeysDialog() { + auto *dialog = new KeysDialog(m_ctx, this); + dialog->exec(); + dialog->deleteLater(); +} + +void MainWindow::menuTorClicked() { + + auto *dialog = new TorInfoDialog(m_ctx, this); + connect(m_ctx->tor, &Tor::logsUpdated, dialog, &TorInfoDialog::onLogsUpdated); + dialog->exec(); + disconnect(m_ctx->tor, &Tor::logsUpdated, dialog, &TorInfoDialog::onLogsUpdated); + dialog->deleteLater(); +} + +void MainWindow::menuNewRestoreClicked() { + // TODO: implement later +} + +void MainWindow::menuQuitClicked() { + QCoreApplication::quit(); +} + +void MainWindow::menuWalletCloseClicked() { + if(m_ctx->currentWallet == nullptr) return; + m_ctx->walletClose(true); +} + +void MainWindow::menuWalletOpenClicked() { + auto walletPath = config()->get(Config::walletPath).toString(); + if(walletPath.isEmpty()) + walletPath = m_ctx->defaultWalletDir; + QString path = QFileDialog::getOpenFileName(this, "Select your wallet file", walletPath, "Wallet file (*.keys)"); + if(path.isEmpty()) return; + + QFileInfo infoPath(path); + if(!infoPath.isReadable()) { + Utils::showMessageBox("Cannot read wallet file", "Permission error.", true); + return; + } + + if(path == m_ctx->walletPath) { + Utils::showMessageBox("Wallet already opened", "Please open another wallet.", true); + return; + } + + m_ctx->walletClose(false); + emit walletClosed(); + m_ctx->onOpenWallet(path, ""); +} + +void MainWindow::menuAboutClicked() { + m_aboutDialog->show(); +} + +void MainWindow::menuSettingsClicked() { + m_windowSettings->show(); +} + +void MainWindow::menuSignVerifyClicked() { + auto *dialog = new SignVerifyDialog(m_ctx->currentWallet, this); + dialog->exec(); + dialog->deleteLater(); +} + +void MainWindow::menuVerifyTxProof() { + auto *dialog = new VerifyProofDialog(m_ctx->currentWallet, this); + dialog->exec(); + dialog->deleteLater(); +} + +void MainWindow::skinChanged(const QString &skinName) { + if(!m_skins.contains(skinName)) { + qWarning() << QString("No such skin %1").arg(skinName); + return; + } + + config()->set(Config::skin, skinName); + qApp->setStyleSheet(m_skins[skinName]); + qDebug() << QString("Skin changed to %1").arg(skinName); +} + +void MainWindow::homeWidgetChanged(const QString &widgetName) { + if(widgetName == "ccs"){ + m_ccsWidget->show(); + m_redditWidget->hide(); + } else if(widgetName == "reddit") { + m_ccsWidget->hide(); + m_redditWidget->show(); + } +} + +void MainWindow::closeEvent(QCloseEvent *event) { + this->saveGeo(); + if(m_wizard != nullptr) + m_wizard->close(); + + QWidget::closeEvent(event); +} + +void MainWindow::donateButtonClicked() { + double donation = AppContext::prices->convert("EUR", "XMR", m_ctx->featherDonationAmount); + if(donation <= 0) + donation = 1.337; + + ui->sendWidget->fill(m_ctx->featherDonationAddress, "Donation to the Feather development team", donation); + ui->tabWidget->setCurrentIndex(2); +} + +void MainWindow::showHistoryTab() { + this->raise(); + ui->tabWidget->setCurrentIndex(1); +} + +void MainWindow::showSendTab() { + this->raise(); + ui->tabWidget->setCurrentIndex(2); +} + +void MainWindow::showCalcWindow() { + m_windowCalc->show(); +} + +void MainWindow::showSendScreen(const CCSEntry &entry) { + ui->sendWidget->fill(entry); + ui->tabWidget->setCurrentIndex(2); +} + +void MainWindow::onViewOnBlockExplorer(const QString &txid) { + QString blockExplorerLink = Utils::blockExplorerLink(config()->get(Config::blockExplorer).toString(), m_ctx->networkType, txid); + Utils::externalLinkWarning(blockExplorerLink); +} + +void MainWindow::onAddContact(const QString &address, const QString &name) { + bool addressValid = WalletManager::addressValid(address, m_ctx->currentWallet->nettype()); + if (!addressValid) + QMessageBox::warning(this, "Invalid address", "Invalid address"); + else { + m_ctx->currentWallet->addressBook()->addRow(address, "", name); + m_ctx->storeWallet(); + } +} + +MainWindow *MainWindow::getInstance() { + return pMainWindow; +} + +AppContext *MainWindow::getContext(){ + return pMainWindow->m_ctx; +} + +void MainWindow::loadSkins() { + QString qdarkstyle = this->loadStylesheet(":qdarkstyle/style.qss"); + if (!qdarkstyle.isEmpty()) + m_skins.insert("QDarkStyle", qdarkstyle); + + QString breeze_dark = this->loadStylesheet(":/dark.qss"); + if (!breeze_dark.isEmpty()) + m_skins.insert("Breeze/Dark", breeze_dark); + + QString breeze_light = this->loadStylesheet(":/light.qss"); + if (!breeze_light.isEmpty()) + m_skins.insert("Breeze/Light", breeze_light); +} + +QString MainWindow::loadStylesheet(const QString &resource) { + QFile f(resource); + if (!f.exists()) { + printf("Unable to set stylesheet, file not found\n"); + f.close(); + return ""; + } + + f.open(QFile::ReadOnly | QFile::Text); + QTextStream ts(&f); + QString data = ts.readAll(); + f.close(); + + return data; +} + +void MainWindow::saveGeo() { + config()->set(Config::geometry, QString(saveGeometry().toBase64())); + config()->set(Config::windowState, QString(saveState().toBase64())); +} + +void MainWindow::restoreGeo() { + bool geo = this->restoreGeometry(QByteArray::fromBase64(config()->get(Config::geometry).toByteArray())); + bool windowState = this->restoreState(QByteArray::fromBase64(config()->get(Config::windowState).toByteArray())); + qDebug() << "Restored window state: " << geo << " " << windowState; +} + +void MainWindow::showDebugInfo() { + auto *dialog = new DebugInfoDialog(m_ctx, this); + dialog->exec(); + dialog->deleteLater(); +} + +void MainWindow::showNodeExhaustedMessage() { + // Spawning dialogs inside a lambda can cause system freezes on linux so we have to do it this way ¯\_(ツ)_/¯ + + auto msg = "Feather is in 'custom node connection mode' but could not " + "find an eligible node to connect to. Please go to Settings->Node " + "and enter a node manually."; + QMessageBox::warning(this, "Could not connect to a node", msg); +} + +void MainWindow::showWSNodeExhaustedMessage() { + auto msg = "Feather is in 'automatic node connection mode' but the " + "websocket server returned none available nodes. Please go to Settings->Node " + "and enter a node manually."; + QMessageBox::warning(this, "Could not connect to a node", msg); +} + +MainWindow::~MainWindow() { + delete ui; +} diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 0000000..2d7d791 --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "components.h" +#include "calcwindow.h" +#include "widgets/ccswidget.h" +#include "widgets/redditwidget.h" +#include "widgets/tickerwidget.h" +#include "utils/networking.h" +#include "appcontext.h" +#include "utils/config.h" +#include "wizard/walletwizard.h" +#include "settings.h" +#include "dialog/aboutdialog.h" +#include "dialog/signverifydialog.h" +#include "dialog/verifyproofdialog.h" +#include "dialog/seeddialog.h" +#include "dialog/passwordchangedialog.h" +#include "dialog/keysdialog.h" +#include "dialog/aboutdialog.h" +#include "dialog/restoredialog.h" + +namespace Ui { + class MainWindow; +} + +struct ToggleTab { + ToggleTab(QWidget *tab, const QString &name, const QString &description, QAction *menuAction, Config::ConfigKey configKey) : + tab(tab), key(name), name(description), menuAction(menuAction), configKey(configKey){} + QWidget *tab; + QString key; + QString name; + QAction *menuAction; + Config::ConfigKey configKey; +}; + +class MainWindow : public QMainWindow +{ +Q_OBJECT + +public: + explicit MainWindow(AppContext *ctx, QWidget *parent = nullptr); + static MainWindow *getInstance(); + static AppContext *getContext(); + ~MainWindow() override; + + qreal screenDpiRef; + QRect screenGeo; + QRect screenRect; + qreal screenDpi; + qreal screenDpiPhysical; + qreal screenRatio; + +public slots: + void initWidgets(); + void initMenu(); + void showWizard(WalletWizard::Page startPage); + void menuNewRestoreClicked(); + void menuQuitClicked(); + void menuSettingsClicked(); + void menuAboutClicked(); + void menuSignVerifyClicked(); + void menuVerifyTxProof(); + void showWalletInfoDialog(); + void showSeedDialog(); + void showConnectionStatusDialog(); + void showPasswordDialog(); + void showKeysDialog(); + void donateButtonClicked(); + void showCalcWindow(); + void showSendTab(); + void showHistoryTab(); + void showSendScreen(const CCSEntry &entry); + void homeWidgetChanged(const QString &widgetName); + void skinChanged(const QString &skinName); + void menuTorClicked(); + void onBlockchainSync(int height, int target); + void onRefreshSync(int height, int target); + void onWalletOpenedError(const QString &err); + void onWalletCreatedError(const QString &err); + void onWalletCreated(Wallet *wallet); + void menuWalletCloseClicked(); + void menuWalletOpenClicked(); + void onWalletOpenPasswordRequired(bool invalidPassword); + void onViewOnBlockExplorer(const QString &txid); + void onAddContact(const QString &address, const QString &name); + void showRestoreHeightDialog(); + + // libwalletqt + void onBalanceUpdated(double balance, double unlocked, const QString &balance_str, const QString &unlocked_str); + void onSynchronized(); + void onWalletOpened(); + void onWalletClosed(); + void onWalletClosed(WalletWizard::Page page); + void onConnectionStatusChanged(int status); + void onCreateTransactionError(const QString &message); + void onCreateTransactionSuccess(PendingTransaction *tx, const QString &address, const quint32 &mixin); + void onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid); + +signals: + void walletClosed(); + void closed(); + +private: + AppContext *m_ctx; + + static MainWindow * pMainWindow; + void closeEvent(QCloseEvent *event) override; + void create_status_bar(); + void initMain(); + void loadSkins(); + QString loadStylesheet(const QString &resource); + void saveGeo(); + void restoreGeo(); + void showDebugInfo(); + void showNodeExhaustedMessage(); + void showWSNodeExhaustedMessage(); + + WalletWizard *createWizard(WalletWizard::Page startPage); + + Ui::MainWindow *ui; + Settings *m_windowSettings = nullptr; + CalcWindow *m_windowCalc = nullptr; + SignVerifyDialog *m_windowSignVerify = nullptr; + RestoreDialog *m_restoreDialog = nullptr; + AboutDialog *m_aboutDialog = nullptr; + + bool m_windowSpawned = false; + + CCSWidget *m_ccsWidget = nullptr; + RedditWidget *m_redditWidget = nullptr; + + QSystemTrayIcon *m_trayIcon; + QMenu m_trayMenu; + QAction *m_trayActionCalc; + QAction *m_trayActionExit; + QAction *m_trayActionSend; + QAction *m_trayActionHistory; + + QList m_tickerWidgets; + TickerWidget *m_balanceWidget; + + // lower status bar + QLabel *m_statusLabelBalance; + QLabel *m_statusLabelStatus; + StatusBarButton *m_statusBtnConnectionStatusIndicator; + StatusBarButton *m_statusBtnPassword; + StatusBarButton *m_statusBtnPreferences; + StatusBarButton *m_statusBtnSeed; + StatusBarButton *m_statusBtnTor; + + SubaddressProxyModel *subaddressProxyModel; + TransactionHistoryModel *txHistModel; + CoinsModel *coinsModel; + + QSignalMapper *m_tabShowHideSignalMapper; + QMap m_tabShowHideMapper; + WalletWizard *m_wizard = nullptr; + + QMap m_skins; + +private slots: + void menuToggleTabVisible(const QString &key); +}; + +#endif // MAINWINDOW_H diff --git a/src/mainwindow.ui b/src/mainwindow.ui new file mode 100644 index 0000000..3cc0d83 --- /dev/null +++ b/src/mainwindow.ui @@ -0,0 +1,571 @@ + + + MainWindow + + + + 0 + 0 + 894 + 496 + + + + + 0 + 0 + + + + Feather + + + + :/assets/images/appicons/64x64.png:/assets/images/appicons/64x64.png + + + + + 0 + + + 2 + + + 0 + + + 0 + + + 12 + + + + + 0 + + + + 16 + 16 + + + + + + :/assets/images/tab_home.png:/assets/images/tab_home.png + + + Home + + + + 5 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Qt::Horizontal + + + + + + + 9 + + + + + Qt::Vertical + + + + 0 + 40 + + + + + + + + + + + + :/assets/images/history.png:/assets/images/history.png + + + History + + + + 9 + + + + + + + + + + 0 + 0 + + + + + :/assets/images/tab_send.png:/assets/images/tab_send.png + + + Send + + + + 11 + + + 11 + + + + + + 0 + 0 + + + + + 0 + 100 + + + + + 16777215 + 16777215 + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + + + + + :/assets/images/coins.png:/assets/images/coins.png + + + Receive + + + + + + + + + + + :/assets/images/tab_coins.png:/assets/images/tab_coins.png + + + Coins + + + + + + + + + + + :/assets/images/xmrto.png:/assets/images/xmrto.png + + + xmr.to + + + + 0 + + + 0 + + + 0 + + + 1 + + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 0 + + + + + + + + + + :/assets/images/coldcard.png:/assets/images/coldcard.png + + + Calc + + + + + + + + + + + + + + + + 0 + 0 + 894 + 30 + + + + + File + + + + + + + + + + Wallet + + + + History + + + + + + Contacts + + + + + + Advanced + + + + + + + + + + + + + + + + + + + Tools + + + + + + + + + + Help + + + + + + + + + + + + View + + + + + + + + + + + + + + Open wallet + + + + + Quit application + + + + + Network + + + + + Sign/verify message + + + + + About + + + + + Official website + + + + + Settings + + + + + Calculator + + + + + Information + + + + + Password + + + + + Seed + + + + + Report bug + + + + + Donate to Feather + + + + + Export CSV + + + + + Show Coins + + + + + Show Xmr.To + + + + + Show Calc + + + + + Close current wallet + + + + + Verify transaction proof + + + + + Save wallet + + + + + Update balance + + + + + Refresh models + + + + + Export CSV + + + + + Change restore height + + + + + Keys + + + + + About Qt + + + + + Create desktop entry + + + + + Debug info + + + + + + + SendWidget + QWidget +
sendwidget.h
+ 1 +
+ + ContactsWidget + QWidget +
contactswidget.h
+ 1 +
+ + ReceiveWidget + QWidget +
receivewidget.h
+ 1 +
+ + CoinsWidget + QWidget +
coinswidget.h
+ 1 +
+ + HistoryWidget + QWidget +
historywidget.h
+
+ + XMRToWidget + QWidget +
xmrtowidget.h
+ 1 +
+ + CalcWidget + QWidget +
calcwidget.h
+ 1 +
+
+ + + + + + donateButtonClicked() + calcButtonClicked() + +
diff --git a/src/model/AddressBookModel.cpp b/src/model/AddressBookModel.cpp new file mode 100644 index 0000000..a924fec --- /dev/null +++ b/src/model/AddressBookModel.cpp @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "AddressBookModel.h" +#include "AddressBook.h" +#include "ModelUtils.h" +#include "utils/utils.h" +#include + +#include +#include +#include +#include + +AddressBookModel::AddressBookModel(QObject *parent, AddressBook *addressBook) + : QAbstractTableModel(parent), + m_addressBook(addressBook), + m_showFullAddresses(false) +{ + connect(m_addressBook, &AddressBook::refreshStarted, this, &AddressBookModel::startReset); + connect(m_addressBook, &AddressBook::refreshFinished, this, &AddressBookModel::endReset); + m_contactIcon = QIcon(":/assets/images/person.svg"); +} + +void AddressBookModel::startReset(){ + beginResetModel(); +} + +void AddressBookModel::endReset(){ + endResetModel(); +} + +int AddressBookModel::rowCount(const QModelIndex &) const +{ + return m_addressBook->count(); +} + +int AddressBookModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return COUNT; +} + +bool AddressBookModel::isShowFullAddresses() const { + return m_showFullAddresses; +} + +void AddressBookModel::setShowFullAddresses(bool show) +{ + m_showFullAddresses = show; + emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); +} + +bool AddressBookModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::EditRole) { + const int row = index.row(); + + switch (index.column()) { + case Description: + m_addressBook->setDescription(row, value.toString()); + break; + default: + return false; + } + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + + return true; + } + return false; +} + +QVariant AddressBookModel::data(const QModelIndex &index, int role) const +{ + QVariant result; + + bool found = m_addressBook->getRow(index.row(), [this, &result, &role, &index](const AddressBookInfo &row) { + if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) { + switch (index.column()) { + case Address: + { + QString address = row.address(); + if (!m_showFullAddresses && role != Qt::UserRole) { + address = ModelUtils::displayAddress(address); + } + result = address; + break; + } + case Description: + result = row.description(); + break; + default: + qCritical() << "Invalid column" << index.column(); + } + } + else if (role == Qt::FontRole) { + switch (index.column()) { + case Address: + result = ModelUtils::getMonospaceFont(); + } + } + else if (role == Qt::DecorationRole) { + switch (index.column()) { + case Description: { + return QVariant(m_contactIcon); // @TODO: does not actually work + } + default: { + return QVariant(); + } + } + } + return QVariant(); + }); + if (!found) { + qCritical("%s: internal error: invalid index %d", __FUNCTION__, index.row()); + } + + return result; +} + +Qt::ItemFlags AddressBookModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::ItemIsEnabled; + + if (index.column() == Description) + return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; + + return QAbstractTableModel::flags(index); +} + +QVariant AddressBookModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) + { + switch(section) { + case Address: + return QString("Address"); + case Description: + return QString("Name"); + default: + return QVariant(); + } + } + return QVariant(); +} + +bool AddressBookModel::deleteRow(int row) +{ + return m_addressBook->deleteRow(row); +} + +int AddressBookModel::lookupPaymentID(const QString &payment_id) const +{ + return m_addressBook->lookupPaymentID(payment_id); +} + +bool AddressBookModel::writeCSV(const QString &path) { + QString csv = ""; + for(int i = 0; i < this->rowCount(); i++) { + QModelIndex index = this->index(i, 0); + const auto description = this->data(index.siblingAtColumn(AddressBookModel::Description), Qt::UserRole).toString().replace("\"", ""); + const auto address = this->data(index.siblingAtColumn(AddressBookModel::Address), Qt::UserRole).toString(); + if(address.isEmpty()) continue; + csv += QString("%1,\"%2\"\n").arg(address).arg(description); + } + if(csv.isEmpty()) + return false; + csv = QString("address,description\n%1").arg(csv); + return Utils::fileWrite(path, csv); +} diff --git a/src/model/AddressBookModel.h b/src/model/AddressBookModel.h new file mode 100644 index 0000000..109c897 --- /dev/null +++ b/src/model/AddressBookModel.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef ADDRESSBOOKMODEL_H +#define ADDRESSBOOKMODEL_H + +#include +#include + +class AddressBook; + +class AddressBookModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + enum ModelColumn + { + Address = 0, + Description, + COUNT + }; + + AddressBookModel(QObject *parent, AddressBook * addressBook); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + + Q_INVOKABLE bool deleteRow(int row); + Q_INVOKABLE int lookupPaymentID(const QString &payment_id) const; + + bool isShowFullAddresses() const; + void setShowFullAddresses(bool show); + bool writeCSV(const QString &path); + +public slots: + void startReset(); + void endReset(); + +private: + AddressBook * m_addressBook; + QIcon m_contactIcon; + bool m_showFullAddresses; +}; + +#endif // ADDRESSBOOKMODEL_H diff --git a/src/model/AddressBookProxyModel.cpp b/src/model/AddressBookProxyModel.cpp new file mode 100644 index 0000000..a6c81fe --- /dev/null +++ b/src/model/AddressBookProxyModel.cpp @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "AddressBookProxyModel.h" +#include "AddressBookModel.h" + +AddressBookProxyModel::AddressBookProxyModel(QObject *parent) + : QSortFilterProxyModel(parent), + m_searchRegExp("") +{ + m_searchRegExp.setCaseSensitivity(Qt::CaseInsensitive); + m_searchRegExp.setPatternSyntax(QRegExp::RegExp); +} + +bool AddressBookProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QModelIndex addressIndex = sourceModel()->index(sourceRow, AddressBookModel::Address, sourceParent); + QModelIndex descriptionIndex = sourceModel()->index(sourceRow, AddressBookModel::Description, sourceParent); + + QString addressData = sourceModel()->data(addressIndex, Qt::UserRole).toString(); + QString descriptionData = sourceModel()->data(descriptionIndex).toString(); + + return (addressData.contains(m_searchRegExp) || descriptionData.contains(m_searchRegExp)); +} \ No newline at end of file diff --git a/src/model/AddressBookProxyModel.h b/src/model/AddressBookProxyModel.h new file mode 100644 index 0000000..1ce2743 --- /dev/null +++ b/src/model/AddressBookProxyModel.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_ADDRESSBOOKPROXYMODEL_H +#define FEATHER_ADDRESSBOOKPROXYMODEL_H + +#include + +class AddressBookProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + explicit AddressBookProxyModel(QObject* parent = nullptr); + bool filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const override; + +public slots: + void setSearchFilter(const QString& searchString){ + m_searchRegExp.setPattern(searchString); + invalidateFilter(); + } + +private: + QRegExp m_searchRegExp; +}; + +#endif //FEATHER_ADDRESSBOOKPROXYMODEL_H diff --git a/src/model/CCSModel.cpp b/src/model/CCSModel.cpp new file mode 100644 index 0000000..3537294 --- /dev/null +++ b/src/model/CCSModel.cpp @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "CCSModel.h" + +CCSModel::CCSModel(QObject *parent) + : QAbstractTableModel(parent) +{ + +} + +void CCSModel::clear() { + beginResetModel(); + + m_entries.clear(); + + endResetModel(); +} + +void CCSModel::updateEntries(const QList>& entries) { + beginResetModel(); + + m_entries.clear(); + for (const auto& entry : entries) { + if (entry->raised_amount > entry->target_amount) + continue; + m_entries.push_back(entry); + } + + endResetModel(); +} + +int CCSModel::rowCount(const QModelIndex &parent) const{ + if (parent.isValid()) { + return 0; + } + return m_entries.count(); +} + +int CCSModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return ModelColumn::COUNT; +} + +QVariant CCSModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= m_entries.count()) + return QVariant(); + + QSharedPointer entry = m_entries.at(index.row()); + + if(role == Qt::DisplayRole) { + switch(index.column()) { + case Title: + return entry->title; + case Author: + return entry->author; +#ifdef Q_OS_MACOS + case Progress: + return QString("%1/%2 XMR").arg(entry->raised_amount).arg(entry->target_amount); +#endif + default: + return QVariant(); + } + } + return QVariant(); +} + +QVariant CCSModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) + { + switch(section) { + case Title: + return QString("Community Crowdfunding Proposal"); + case Author: + return QString("Author"); + case Progress: + return QString("Progress"); + default: + return QVariant(); + } + } + return QVariant(); +} + +QSharedPointer CCSModel::entry(int row) { + if (row < 0 || row >= m_entries.size()) { + qCritical("%s: no reddit post for index %d", __FUNCTION__, row); + return QSharedPointer(); + } + + return m_entries.at(row); +} \ No newline at end of file diff --git a/src/model/CCSModel.h b/src/model/CCSModel.h new file mode 100644 index 0000000..c5421ac --- /dev/null +++ b/src/model/CCSModel.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_CCSMODEL_H +#define FEATHER_CCSMODEL_H + +#include +#include + +#include "widgets/CCSEntry.h" + +class CCSModel : public QAbstractTableModel +{ +Q_OBJECT + +public: + enum ModelColumn + { + Title = 0, + Author, + Progress, + COUNT + }; + + explicit CCSModel(QObject *parent); + + int rowCount(const QModelIndex &parent) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + + void clear(); + void updateEntries(const QList>& entries); + + QSharedPointer entry(int row); + +private: + QList> m_entries; +}; + + +#endif //FEATHER_CCSMODEL_H diff --git a/src/model/CMakeLists.txt b/src/model/CMakeLists.txt new file mode 100644 index 0000000..9ca31c6 --- /dev/null +++ b/src/model/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB_RECURSE SRC_SOURCES *.cpp) +file(GLOB_RECURSE SRC_HEADERS *.h) + + diff --git a/src/model/CoinsModel.cpp b/src/model/CoinsModel.cpp new file mode 100644 index 0000000..ca788fc --- /dev/null +++ b/src/model/CoinsModel.cpp @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "CoinsModel.h" +#include "CoinsInfo.h" +#include "Coins.h" +#include +#include "ModelUtils.h" + +#include +#include +#include +#include +#include + +CoinsModel::CoinsModel(QObject *parent, Coins *coins) + : QAbstractTableModel(parent), + m_coins(coins) +{ + connect(m_coins, &Coins::refreshStarted, this, &CoinsModel::startReset); + connect(m_coins, &Coins::refreshFinished, this, &CoinsModel::endReset); +} + +void CoinsModel::startReset(){ + beginResetModel(); +} + +void CoinsModel::endReset(){ + endResetModel(); +} + +Coins * CoinsModel::coins() const { + return m_coins; +} + +int CoinsModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } else { + return m_coins->count(); + } +} + +int CoinsModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return ModelColumn::COUNT; +} + +QVariant CoinsModel::data(const QModelIndex &index, int role) const +{ + if (!m_coins) { + return QVariant(); + } + + if (!index.isValid() || index.row() < 0 || static_cast(index.row()) >= m_coins->count()) + return QVariant(); + + QVariant result; + + bool found = m_coins->coin(index.row(), [this, &index, &result, &role](const CoinsInfo &cInfo) { + if(role == Qt::DisplayRole || role == Qt::UserRole) { + result = parseTransactionInfo(cInfo, index.column(), role); + } + else if (role == Qt::BackgroundRole) { + if (cInfo.spent()) { + result = QBrush(QColor(255, 100, 100)); + } + else if (cInfo.frozen()) { + result = QBrush(QColor(173, 216, 230)); + } + else if (!cInfo.unlocked()) { + result = QBrush(QColor("#BFFF00")); + } + } + else if (role == Qt::TextAlignmentRole) { + switch (index.column()) { + case Amount: + result = Qt::AlignRight; + } + } + else if (role == Qt::FontRole) { + switch(index.column()) { + case PubKey: + case OutputPoint: + case Address: + result = ModelUtils::getMonospaceFont(); + } + } + else if (role == Qt::ToolTipRole) { + if (cInfo.frozen()) { + result = "Output is frozen."; + } + else if (!cInfo.unlocked()) { + result = "Output is locked (needs more confirmations)"; + } + } + }); + if (!found) { + qCritical("%s: internal error: no transaction info for index %d", __FUNCTION__, index.row()); + } + return result; +} + +QVariant CoinsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) + { + switch(section) { + case PubKey: + return QString("Pub Key"); + case OutputPoint: + return QString("Output point"); + case BlockHeight: + return QString("Height"); + case Address: + return QString("Address"); + case AddressLabel: + return QString("Label"); + case SpentHeight: + return QString("Spent Height"); + case Amount: + return QString("Amount"); + case Spent: + return QString("Spent"); + case Frozen: + return QString("Frozen"); + default: + return QVariant(); + } + } + return QVariant(); +} + +QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, int role) const +{ + switch (column) + { + case PubKey: + return cInfo.pubKey().mid(0,8); + case OutputPoint: + return cInfo.hash().mid(0, 8) + ":" + QString::number(cInfo.internalOutputIndex()); + case BlockHeight: + return cInfo.blockHeight(); + case Address: + return ModelUtils::displayAddress(cInfo.address(), 1, ""); + case AddressLabel: + { + if (cInfo.subaddrIndex() == 0) { + return cInfo.coinbase() ? "Coinbase" : "Change"; + } + return cInfo.addressLabel(); + } + case Spent: + return cInfo.spent(); + case SpentHeight: + return cInfo.spentHeight(); + case Amount: + return QString::number(cInfo.amount() / 1e12, 'f', 12); + case Frozen: + return cInfo.frozen(); + + default: + { + qCritical() << "Unimplemented role"; + return QVariant(); + } + } +} \ No newline at end of file diff --git a/src/model/CoinsModel.h b/src/model/CoinsModel.h new file mode 100644 index 0000000..db4cb3d --- /dev/null +++ b/src/model/CoinsModel.h @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_COINSMODEL_H +#define FEATHER_COINSMODEL_H + +#include + +#include +#include +#include + +class Coins; +class CoinsInfo; + +class CoinsModel : public QAbstractTableModel +{ +Q_OBJECT + +public: + enum ModelColumn + { + PubKey = 0, + OutputPoint, + Address, + AddressLabel, + BlockHeight, + SpentHeight, + Amount, + Spent, + Frozen, + COUNT + }; + + explicit CoinsModel(QObject *parent, Coins *coins); + + Coins * coins() const; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + +public slots: + void startReset(); + void endReset(); + +private: + QVariant parseTransactionInfo(const CoinsInfo &cInfo, int column, int role) const; + + Coins *m_coins; +}; + +#endif //FEATHER_COINSMODEL_H diff --git a/src/model/CoinsProxyModel.cpp b/src/model/CoinsProxyModel.cpp new file mode 100644 index 0000000..b9ffd8f --- /dev/null +++ b/src/model/CoinsProxyModel.cpp @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "CoinsProxyModel.h" +#include "CoinsModel.h" + +CoinsProxyModel::CoinsProxyModel(QObject *parent) + : QSortFilterProxyModel(parent) +{ +} + +bool CoinsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QModelIndex spentIndex = sourceModel()->index(sourceRow, CoinsModel::Spent, sourceParent); + bool isSpent = sourceModel()->data(spentIndex).toBool(); + + return !(!m_showSpent && isSpent); +} \ No newline at end of file diff --git a/src/model/CoinsProxyModel.h b/src/model/CoinsProxyModel.h new file mode 100644 index 0000000..9a71a51 --- /dev/null +++ b/src/model/CoinsProxyModel.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_COINSPROXYMODEL_H +#define FEATHER_COINSPROXYMODEL_H + +#include + +class CoinsProxyModel : public QSortFilterProxyModel +{ +Q_OBJECT +public: + explicit CoinsProxyModel(QObject* parent = nullptr); + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + +public slots: + void setShowSpent(const bool showSpent){ + m_showSpent = showSpent; + invalidateFilter(); + } + +private: + bool m_showSpent = false; +}; + +#endif //FEATHER_COINSPROXYMODEL_H diff --git a/src/model/ModelUtils.cpp b/src/model/ModelUtils.cpp new file mode 100644 index 0000000..9ac173f --- /dev/null +++ b/src/model/ModelUtils.cpp @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "ModelUtils.h" + +#include +#include +#include +#include +#include +#include +#include + +QString ModelUtils::displayAddress(const QString& address, int sections, const QString& sep) { + QStringList list; + if (sections < 1) sections = 1; + for (int i = 0; i < sections; i += 1) { + list << address.mid(i*5, 5); + } + list << "..."; + for (int i = sections; i > 0; i -= 1) { + list << address.mid(address.length() - i * 5, 5); + } + return list.join(sep); +} + +void ModelUtils::copyColumn(QModelIndex *index, int column) { + QString string(index->model()->data(index->siblingAtColumn(column), Qt::UserRole).toString()); + QClipboard * clipboard = QApplication::clipboard(); + if (!clipboard) { + qWarning() << "Unable to access clipboard"; + return; + } + clipboard->setText(string); +} + +QFont ModelUtils::getMonospaceFont() +{ + if (QFontInfo(QApplication::font()).fixedPitch()) { + return QApplication::font(); + } + return QFontDatabase::systemFont(QFontDatabase::FixedFont); +} \ No newline at end of file diff --git a/src/model/ModelUtils.h b/src/model/ModelUtils.h new file mode 100644 index 0000000..b6b8566 --- /dev/null +++ b/src/model/ModelUtils.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_MODELUTILS_H +#define FEATHER_MODELUTILS_H + +#include +#include + +class ModelUtils { +public: + static QString displayAddress(const QString& address, int sections = 3, const QString & sep = " "); + static void copyColumn(QModelIndex * index, int column); + static QFont getMonospaceFont(); +}; + + +#endif //FEATHER_MODELUTILS_H diff --git a/src/model/NodeModel.cpp b/src/model/NodeModel.cpp new file mode 100644 index 0000000..3b34fc7 --- /dev/null +++ b/src/model/NodeModel.cpp @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "NodeModel.h" +#include +#include "appcontext.h" + +NodeModel::NodeModel(unsigned int nodeSource, QObject *parent) + : QAbstractTableModel(parent) + , m_nodeSource(nodeSource) + , m_offline(QIcon(":/assets/images/expired.png")) + , m_online(QIcon(":/assets/images/confirmed.png")) +{ +} + +void NodeModel::clear() { + beginResetModel(); + m_nodes.clear(); + endResetModel(); +} + +void NodeModel::updateNodes(const QList nodes) { + beginResetModel(); + m_nodes.clear(); + m_nodes = nodes; + endResetModel(); +} + +int NodeModel::rowCount(const QModelIndex &parent) const{ + if (parent.isValid()) + return 0; + return m_nodes.count(); +} + +int NodeModel::columnCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; + return m_nodeSource == NodeSource::websocket ? 2 : 1; +} + +QVariant NodeModel::data(const QModelIndex &index, int role) const { + if (!index.isValid() || index.row() < 0 || index.row() >= m_nodes.count()) + return QVariant(); + + FeatherNode node = m_nodes.at(index.row()); + + if(role == Qt::DisplayRole) { + switch(index.column()) { + case NodeModel::URL: + return node.full; + case NodeModel::Height: + if(node.online) + return node.height == 0 ? QString("-") : QString::number(node.height); + return QString("-"); + default: + return QVariant(); + } + } + else if (role == Qt::DecorationRole) { + switch (index.column()) { + case NodeModel::URL: { + if(m_nodeSource == NodeSource::websocket) + return QVariant(node.online ? m_online : m_offline); + return QVariant(); + } + default: { + return QVariant(); + } + } + } + else if(role == Qt::BackgroundRole) { + if (node.isConnecting) + return QBrush(QColor(186, 247, 255)); + else if (node.isActive) + return QBrush(QColor(158, 250, 158)); + } + return QVariant(); +} + +QVariant NodeModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) { + switch(section) { + case NodeModel::URL: + return QString("Node"); + case NodeModel::Height: + return QString("Height"); + default: + return QVariant(); + } + } + return QVariant(); +} + +FeatherNode NodeModel::node(int row) { + if (row < 0 || row >= m_nodes.size()) { + qCritical("%s: no reddit post for index %d", __FUNCTION__, row); + return FeatherNode("", 0, false); + } + return m_nodes.at(row); +} diff --git a/src/model/NodeModel.h b/src/model/NodeModel.h new file mode 100644 index 0000000..ea4a42e --- /dev/null +++ b/src/model/NodeModel.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_NODEMODEL_H +#define FEATHER_NODEMODEL_H + +#include +#include + +class FeatherNode; + +class NodeModel : public QAbstractTableModel { + Q_OBJECT + +public: + enum ModelColumn { + URL, + Height, + COUNT + }; + + explicit NodeModel(unsigned int nodeSource, QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + FeatherNode node(int row); + + void clear(); + void updateNodes(QList nodes); + +private: + QList m_nodes; + QIcon m_offline; + QIcon m_online; + unsigned int m_nodeSource; +}; + +#endif //FEATHER_NODEMODEL_H diff --git a/src/model/RedditModel.cpp b/src/model/RedditModel.cpp new file mode 100644 index 0000000..2077d64 --- /dev/null +++ b/src/model/RedditModel.cpp @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "RedditModel.h" + +RedditModel::RedditModel(QObject *parent) + : QAbstractTableModel(parent) +{ + +} + +void RedditModel::clear() { + beginResetModel(); + + m_posts.clear(); + + endResetModel(); +} + +void RedditModel::updatePosts(const QList>& posts) { + beginResetModel(); + + m_posts.clear(); + for (const auto& post : posts) { + m_posts.push_back(post); + } + + endResetModel(); +} + +int RedditModel::rowCount(const QModelIndex &parent) const{ + if (parent.isValid()) { + return 0; + } + return m_posts.count(); +} + +int RedditModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return ModelColumn::COUNT; +} + +QVariant RedditModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= m_posts.count()) + return QVariant(); + + QSharedPointer post = m_posts.at(index.row()); + + if(role == Qt::DisplayRole) { + switch(index.column()) { + case Title: + return post->title; + case Author: + return post->author; + case Comments: + return QString::number(post->comments); + default: + return QVariant(); + } + } + else if (role == Qt::TextAlignmentRole) { + switch(index.column()) { + case Comments: + return Qt::AlignRight; + default: + return QVariant(); + } + } + return QVariant(); +} + +QVariant RedditModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) + { + switch(section) { + case Title: + return QString("Reddit Post"); + case Author: + return QString("Author"); + case Comments: + return QString("Comments"); + default: + return QVariant(); + } + } + return QVariant(); +} + +QSharedPointer RedditModel::post(int row) { + if (row < 0 || row >= m_posts.size()) { + qCritical("%s: no reddit post for index %d", __FUNCTION__, row); + return QSharedPointer(); + } + + return m_posts.at(row); +} \ No newline at end of file diff --git a/src/model/RedditModel.h b/src/model/RedditModel.h new file mode 100644 index 0000000..e3eb392 --- /dev/null +++ b/src/model/RedditModel.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_REDDITMODEL_H +#define FEATHER_REDDITMODEL_H + +#include +#include + +#include "widgets/RedditPost.h" + +class RedditModel : public QAbstractTableModel +{ +Q_OBJECT + +public: + enum ModelColumn + { + Title = 0, + Author, + Comments, + COUNT + }; + + explicit RedditModel(QObject *parent); + + int rowCount(const QModelIndex &parent) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + + void clear(); + void updatePosts(const QList>& posts); + + QSharedPointer post(int row); + +private: + QList> m_posts; +}; + +#endif //FEATHER_REDDITMODEL_H diff --git a/src/model/SubaddressAccountModel.cpp b/src/model/SubaddressAccountModel.cpp new file mode 100644 index 0000000..605e119 --- /dev/null +++ b/src/model/SubaddressAccountModel.cpp @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "SubaddressAccountModel.h" +#include "SubaddressAccount.h" +#include + +#include +#include + +SubaddressAccountModel::SubaddressAccountModel(QObject *parent, SubaddressAccount *subaddressAccount) + : QAbstractListModel(parent), m_subaddressAccount(subaddressAccount) +{ + connect(m_subaddressAccount, &SubaddressAccount::refreshStarted, this, &SubaddressAccountModel::startReset); + connect(m_subaddressAccount, &SubaddressAccount::refreshFinished, this, &SubaddressAccountModel::endReset); +} + +void SubaddressAccountModel::startReset(){ + beginResetModel(); +} +void SubaddressAccountModel::endReset(){ + endResetModel(); +} + +int SubaddressAccountModel::rowCount(const QModelIndex &) const +{ + return m_subaddressAccount->count(); +} + +QVariant SubaddressAccountModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || static_cast(index.row()) >= m_subaddressAccount->count()) + return {}; + + QVariant result; + + bool found = m_subaddressAccount->getRow(index.row(), [&result, &role](const Monero::SubaddressAccountRow &row) { + switch (role) { + case SubaddressAccountAddressRole: + result = QString::fromStdString(row.getAddress()); + break; + case SubaddressAccountLabelRole: + result = QString::fromStdString(row.getLabel()); + break; + case SubaddressAccountBalanceRole: + result = QString::fromStdString(row.getBalance()); + break; + case SubaddressAccountUnlockedBalanceRole: + result = QString::fromStdString(row.getUnlockedBalance()); + break; + default: + qCritical() << "Unimplemented role" << role; + } + }); + if (!found) { + qCritical("%s: internal error: invalid index %d", __FUNCTION__, index.row()); + } + + return result; +} + +QHash SubaddressAccountModel::roleNames() const +{ + static QHash roleNames; + if (roleNames.empty()) + { + roleNames.insert(SubaddressAccountAddressRole, "address"); + roleNames.insert(SubaddressAccountLabelRole, "label"); + roleNames.insert(SubaddressAccountBalanceRole, "balance"); + roleNames.insert(SubaddressAccountUnlockedBalanceRole, "unlockedBalance"); + } + return roleNames; +} diff --git a/src/model/SubaddressAccountModel.h b/src/model/SubaddressAccountModel.h new file mode 100644 index 0000000..04d8d58 --- /dev/null +++ b/src/model/SubaddressAccountModel.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef SUBADDRESSACCOUNTMODEL_H +#define SUBADDRESSACCOUNTMODEL_H + +#include + +class SubaddressAccount; + +class SubaddressAccountModel : public QAbstractListModel +{ + Q_OBJECT + +public: + enum SubaddressAccountRowRole { + SubaddressAccountRole = Qt::UserRole + 1, // for the SubaddressAccountRow object; + SubaddressAccountAddressRole, + SubaddressAccountLabelRole, + SubaddressAccountBalanceRole, + SubaddressAccountUnlockedBalanceRole, + }; + Q_ENUM(SubaddressAccountRowRole) + + SubaddressAccountModel(QObject *parent, SubaddressAccount *subaddressAccount); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; + +public slots: + void startReset(); + void endReset(); + +private: + SubaddressAccount *m_subaddressAccount; +}; + +#endif // SUBADDRESSACCOUNTMODEL_H diff --git a/src/model/SubaddressModel.cpp b/src/model/SubaddressModel.cpp new file mode 100644 index 0000000..308f165 --- /dev/null +++ b/src/model/SubaddressModel.cpp @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "SubaddressModel.h" +#include "Subaddress.h" +#include "ModelUtils.h" +#include + +#include +#include +#include +#include +#include + +SubaddressModel::SubaddressModel(QObject *parent, Subaddress *subaddress) + : QAbstractTableModel(parent), + m_subaddress(subaddress), + m_showFullAddresses(false) +{ + connect(m_subaddress, &Subaddress::refreshStarted, this, &SubaddressModel::startReset); + connect(m_subaddress, &Subaddress::refreshFinished, this, &SubaddressModel::endReset); +} + +void SubaddressModel::startReset(){ + beginResetModel(); +} + +void SubaddressModel::endReset(){ + endResetModel(); +} + +int SubaddressModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } else { + return m_subaddress->count(); + } +} + +int SubaddressModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return ModelColumn::COUNT; +} + +QVariant SubaddressModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || static_cast(index.row()) >= m_subaddress->count()) + return QVariant(); + + QVariant result; + + bool found = m_subaddress->getRow(index.row(), [this, &index, &role, &result](const Monero::SubaddressRow &subaddress) { + if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole){ + result = parseSubaddressRow(subaddress, index, role); + } + else if (role == Qt::BackgroundRole) { + if (subaddress.isUsed()) { + result = QBrush(QColor(255,100,100)); + } + } + else if (role == Qt::FontRole) { + switch(index.column()) { + case Address: + { + result = ModelUtils::getMonospaceFont(); + } + } + } + }); + + if (!found) + { + qCritical("%s: internal error: invalid index %d", __FUNCTION__, index.row()); + } + + return result; +} + +QVariant SubaddressModel::parseSubaddressRow(const Monero::SubaddressRow &subaddress, const QModelIndex &index, int role) const +{ + switch (index.column()) { + case Address: + { + QString address = QString::fromStdString(subaddress.getAddress()); + if (!m_showFullAddresses && role != Qt::UserRole) { + address = ModelUtils::displayAddress(address); + } + return address; + } + case Label: + return index.row() == 0 ? tr("Primary address") : QString::fromStdString(subaddress.getLabel()); + case isUsed: + return subaddress.isUsed(); + default: + qCritical() << "Invalid column" << index.column(); + return QVariant(); + } +} + + +QVariant SubaddressModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) + { + switch(section) { + case Address: + return QString("Address"); + case Label: + return QString("Label"); + case isUsed: + return QString("Used"); + default: + return QVariant(); + } + } + return QVariant(); +} + +bool SubaddressModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::EditRole) { + const int row = index.row(); + + switch (index.column()) { + case Label: + m_subaddress->setLabel(0, row, value.toString()); // Todo: get actual account index + break; + default: + return false; + } + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + + return true; + } + return false; +} + +void SubaddressModel::setShowFullAddresses(bool show) +{ + m_showFullAddresses = show; + emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); +} + +Qt::ItemFlags SubaddressModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::ItemIsEnabled; + + if (index.column() == Label && index.row() != 0) + return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; + + return QAbstractTableModel::flags(index); +} + +bool SubaddressModel::isShowFullAddresses() const { + return m_showFullAddresses; +} + +int SubaddressModel::unusedLookahead() const { + return m_subaddress->unusedLookahead(); +} diff --git a/src/model/SubaddressModel.h b/src/model/SubaddressModel.h new file mode 100644 index 0000000..afe378f --- /dev/null +++ b/src/model/SubaddressModel.h @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef SUBADDRESSMODEL_H +#define SUBADDRESSMODEL_H + +#include + +#include +#include +#include + +class Subaddress; + +class SubaddressModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + enum ModelColumn + { + Address = 0, + Label, + isUsed, + COUNT + }; + + explicit SubaddressModel(QObject *parent, Subaddress *subaddress); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + + bool isShowFullAddresses() const; + void setShowFullAddresses(bool show); + + int unusedLookahead() const; + +public slots: + void startReset(); + void endReset(); + +private: + Subaddress *m_subaddress; + QVariant parseSubaddressRow(const Monero::SubaddressRow &subaddress, const QModelIndex &index, int role) const; + + bool m_showFullAddresses; +}; + +#endif // SUBADDRESSMODEL_H diff --git a/src/model/SubaddressProxyModel.cpp b/src/model/SubaddressProxyModel.cpp new file mode 100644 index 0000000..dc486e9 --- /dev/null +++ b/src/model/SubaddressProxyModel.cpp @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "SubaddressProxyModel.h" + +SubaddressProxyModel::SubaddressProxyModel(QObject *parent, Subaddress *subaddress, bool hidePrimary) + : QSortFilterProxyModel(parent), + m_searchRegExp(""), + m_searchCaseSensitiveRegExp(""), + m_subaddress(subaddress), + m_hidePrimary(hidePrimary) +{ + m_searchRegExp.setCaseSensitivity(Qt::CaseInsensitive); + m_searchRegExp.setPatternSyntax(QRegExp::FixedString); + m_searchCaseSensitiveRegExp.setPatternSyntax(QRegExp::FixedString); +} + +bool SubaddressProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QString address, label; + bool isUsed; + m_subaddress->getRow(sourceRow, [&isUsed, &address, &label](const Monero::SubaddressRow &subaddress){ + isUsed = subaddress.isUsed(); + address = QString::fromStdString(subaddress.getAddress()); + label = QString::fromStdString(subaddress.getLabel()); + }); + + // Hide primary address + if (sourceRow == 0 && m_hidePrimary) + return false; + + if (!m_searchRegExp.isEmpty()) { + return address.contains(m_searchCaseSensitiveRegExp) || label.contains(m_searchRegExp); + } + return (m_showUsed || !isUsed); +} diff --git a/src/model/SubaddressProxyModel.h b/src/model/SubaddressProxyModel.h new file mode 100644 index 0000000..68f6165 --- /dev/null +++ b/src/model/SubaddressProxyModel.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_SUBADDRESSPROXYMODEL_H +#define FEATHER_SUBADDRESSPROXYMODEL_H + +#include "libwalletqt/Subaddress.h" + +#include + +class SubaddressProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + explicit SubaddressProxyModel(QObject* parent, Subaddress *subaddress, bool hidePrimary = true); + bool filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const; + +public slots: + void setSearchFilter(const QString& searchString){ + m_searchRegExp.setPattern(searchString); + m_searchCaseSensitiveRegExp.setPattern(searchString); + invalidateFilter(); + } + void setShowUsed(const bool showUsed){ + m_showUsed = showUsed; + invalidateFilter(); + } +private: + Subaddress *m_subaddress; + + QRegExp m_searchRegExp; + QRegExp m_searchCaseSensitiveRegExp; + bool m_showUsed = false; + bool m_hidePrimary; +}; + +#endif //FEATHER_SUBADDRESSPROXYMODEL_H diff --git a/src/model/TransactionHistoryModel.cpp b/src/model/TransactionHistoryModel.cpp new file mode 100644 index 0000000..590386e --- /dev/null +++ b/src/model/TransactionHistoryModel.cpp @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "TransactionHistoryModel.h" +#include "TransactionHistory.h" +#include "TransactionInfo.h" + +#include +#include +#include + +TransactionHistoryModel::TransactionHistoryModel(QObject *parent) + : QAbstractTableModel(parent), + m_transactionHistory(nullptr) +{ + m_unconfirmedTx = QIcon(":/assets/images/unconfirmed.png"); + m_warning = QIcon(":/assets/images/warning.png"); + m_clock1 = QIcon(":/assets/images/clock1.png"); + m_clock2 = QIcon(":/assets/images/clock2.png"); + m_clock3 = QIcon(":/assets/images/clock3.png"); + m_clock4 = QIcon(":/assets/images/clock4.png"); + m_clock5 = QIcon(":/assets/images/clock5.png"); + m_confirmedTx = QIcon(":/assets/images/confirmed.png"); +} + +void TransactionHistoryModel::setTransactionHistory(TransactionHistory *th) { + beginResetModel(); + m_transactionHistory = th; + endResetModel(); + + connect(m_transactionHistory, &TransactionHistory::refreshStarted, + this, &TransactionHistoryModel::beginResetModel); + connect(m_transactionHistory, &TransactionHistory::refreshFinished, + this, &TransactionHistoryModel::endResetModel); + + emit transactionHistoryChanged(); +} + +TransactionHistory *TransactionHistoryModel::transactionHistory() const { + return m_transactionHistory; +} + +int TransactionHistoryModel::rowCount(const QModelIndex &parent) const { + if (parent.isValid()) { + return 0; + } else { + return m_transactionHistory ? m_transactionHistory->count() : 0; + } +} + +int TransactionHistoryModel::columnCount(const QModelIndex &parent) const { + if (parent.isValid()) { + return 0; + } + + return Column::COUNT; +} + +QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const { + if (!m_transactionHistory) { + return QVariant(); + } + + if (!index.isValid() || index.row() < 0 || static_cast(index.row()) >= m_transactionHistory->count()) + return QVariant(); + + QVariant result; + + bool found = m_transactionHistory->transaction(index.row(), [this, &index, &result, &role](const TransactionInfo &tInfo) { + if(role == Qt::DisplayRole || role == Qt::EditRole) { + result = parseTransactionInfo(tInfo, index.column()); + } + else if (role == Qt::TextAlignmentRole) { + switch (index.column()) { + case Column::Amount: + case Column::FiatAmount: + result = Qt::AlignRight; + } + } + else if (role == Qt::DecorationRole) { + switch (index.column()) { + case Column::Date: + { + if (tInfo.isFailed()) + result = QVariant(m_warning); + else if (tInfo.isPending()) + result = QVariant(m_unconfirmedTx); + else if (tInfo.confirmations() <= (1.0/5.0 * tInfo.confirmationsRequired())) + result = QVariant(m_clock1); + else if (tInfo.confirmations() <= (2.0/5.0 * tInfo.confirmationsRequired())) + result = QVariant(m_clock2); + else if (tInfo.confirmations() <= (3.0/5.0 * tInfo.confirmationsRequired())) + result = QVariant(m_clock3); + else if (tInfo.confirmations() <= (4.0/5.0 * tInfo.confirmationsRequired())) + result = QVariant(m_clock4); + else if (tInfo.confirmations() < tInfo.confirmationsRequired()) + result = QVariant(m_clock5); + else if (tInfo.confirmations()) + result = QVariant(m_confirmedTx); + } + } + } + else if (role == Qt::ToolTipRole) { + switch(index.column()) { + case Column::Date: + { + if (tInfo.confirmations() < tInfo.confirmationsRequired()) + result = QString("%1/%2 confirmations").arg(QString::number(tInfo.confirmations()), QString::number(tInfo.confirmationsRequired())); + else + result = QString("%1 confirmations").arg(QString::number(tInfo.confirmations())); + } + } + } + else if (role == Qt::ForegroundRole) { + switch(index.column()) { + case Column::FiatAmount: + case Column::Amount: + { + if (tInfo.direction() == TransactionInfo::Direction_Out && tInfo.amount() > 0) { + result = QVariant(QColor("#BC1E1E")); + } + } + } + } + }); + + if (!found) { + qCritical("%s: internal error: no transaction info for index %d", __FUNCTION__, index.row()); + } + return result; +} + +QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tInfo, int column) const +{ + switch (column) + { + case Column::Date: + return tInfo.timestamp().toString("yyyy-MM-dd HH:mm"); + case Column::Description: { + // if this tx is still in the pool, then we wont get the + // description. We've cached it inside `AppContext::txDescriptionCache` + // for the time being. + if(tInfo.isPending()) { + auto hash = tInfo.hash(); + if (AppContext::txDescriptionCache.contains(hash)) + return AppContext::txDescriptionCache[hash]; + } + return tInfo.description(); + } + case Column::Amount: + { + QString amount = QString::number(tInfo.atomicAmount() / 1e12, 'f', 4); + amount = (tInfo.direction() == TransactionInfo::Direction_Out && tInfo.amount() > 0) ? "-" + amount : "+" + amount; + return amount; + } + case Column::TxID: + return tInfo.hash(); + case Column::FiatAmount: + { + double usd_price = AppContext::txFiatHistory->get(tInfo.timestamp().toString("yyyyMMdd")); + if (usd_price == 0.0) + return QVariant("?"); + + double usd_amount = usd_price * tInfo.amount(); + if(this->preferredFiatSign != "$") + usd_amount = AppContext::prices->convert("USD", this->preferredFiatSymbol, usd_amount); + double fiat_rounded = ceil(Utils::roundSignificant(usd_amount, 3) * 100.0) / 100.0; + + return QString("%1%2").arg(this->preferredFiatSign).arg(QString::number(fiat_rounded)); + } + default: + { + qCritical() << "Unimplemented role"; + return QVariant(); + } + } +} + +QVariant TransactionHistoryModel::headerData(int section, Qt::Orientation orientation, int role) const { + Q_UNUSED(orientation) + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) { + switch(section) { + case Column::Date: + return QString("Date"); + case Column::Description: + return QString("Description"); + case Column::Amount: + return QString("Amount"); + case Column::TxID: + return QString("Txid"); + case Column::FiatAmount: + return QString("Fiat"); + default: + return QVariant(); + } + } + return QVariant(); +} + +bool TransactionHistoryModel::setData(const QModelIndex &index, const QVariant &value, int role) { + if (index.isValid() && role == Qt::EditRole) { + QString hash; + + switch (index.column()) { + case Column::Description: + { + m_transactionHistory->transaction(index.row(), [this, &hash, &value](const TransactionInfo &tInfo){ + hash = tInfo.hash(); + }); + m_transactionHistory->setTxNote(hash, value.toString()); + break; + } + default: + return false; + } + + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + } + return false; +} + +Qt::ItemFlags TransactionHistoryModel::flags(const QModelIndex &index) const { + bool isPending; + m_transactionHistory->transaction(index.row(), [this, &isPending](const TransactionInfo &tInfo){ + isPending = tInfo.isPending(); + }); + + if (!index.isValid()) + return Qt::ItemIsEnabled; + + if (index.column() == Description && !isPending) + return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; + + return QAbstractTableModel::flags(index); +} \ No newline at end of file diff --git a/src/model/TransactionHistoryModel.h b/src/model/TransactionHistoryModel.h new file mode 100644 index 0000000..82b140d --- /dev/null +++ b/src/model/TransactionHistoryModel.h @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef TRANSACTIONHISTORYMODEL_H +#define TRANSACTIONHISTORYMODEL_H + +#include +#include +#include "appcontext.h" + +class TransactionHistory; +class TransactionInfo; + +/** + * @brief The TransactionHistoryModel class - read-only table model for Transaction History + */ + +class TransactionHistoryModel : public QAbstractTableModel +{ + Q_OBJECT + Q_PROPERTY(TransactionHistory * transactionHistory READ transactionHistory WRITE setTransactionHistory NOTIFY transactionHistoryChanged) + +public: + enum Column + { + Date = 0, + Description, + Amount, + TxID, + FiatAmount, + COUNT + }; + + explicit TransactionHistoryModel(QObject * parent = nullptr); + void setTransactionHistory(TransactionHistory * th); + TransactionHistory * transactionHistory() const; + + QString preferredFiatSign = "$"; + QString preferredFiatSymbol = "USD"; + int rowCount(const QModelIndex & parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + +signals: + void transactionHistoryChanged(); + +private: + QVariant parseTransactionInfo(const TransactionInfo &tInfo, int column) const; + + TransactionHistory * m_transactionHistory; + QIcon m_unconfirmedTx; + QIcon m_warning; + QIcon m_clock1; + QIcon m_clock2; + QIcon m_clock3; + QIcon m_clock4; + QIcon m_clock5; + QIcon m_confirmedTx; +}; + +#endif // TRANSACTIONHISTORYMODEL_H diff --git a/src/model/TransactionHistoryProxyModel.cpp b/src/model/TransactionHistoryProxyModel.cpp new file mode 100644 index 0000000..479780e --- /dev/null +++ b/src/model/TransactionHistoryProxyModel.cpp @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "TransactionHistoryProxyModel.h" +#include "TransactionHistoryModel.h" + +#include "libwalletqt/TransactionInfo.h" +#include + +TransactionHistoryProxyModel::TransactionHistoryProxyModel(Wallet *wallet, QObject *parent) + : QSortFilterProxyModel(parent), + m_wallet(wallet), + m_searchRegExp("") +{ + m_searchRegExp.setCaseSensitivity(Qt::CaseInsensitive); + m_searchRegExp.setPatternSyntax(QRegExp::RegExp); +} + +bool TransactionHistoryProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QModelIndex descriptionIndex = sourceModel()->index(sourceRow, TransactionHistoryModel::Description, sourceParent); + QModelIndex txidIndex = sourceModel()->index(sourceRow, TransactionHistoryModel::TxID, sourceParent); + + QString descriptionData = sourceModel()->data(descriptionIndex).toString(); + QString txidData = sourceModel()->data(txidIndex).toString(); + + quint32 subaddrAcount; + QSet subaddrIndex; + + m_wallet->history()->transaction(sourceRow, [&subaddrAcount, &subaddrIndex](TransactionInfo &tInfo){ + subaddrAcount = tInfo.subaddrAccount(); + subaddrIndex = tInfo.subaddrIndex(); + }); + + bool addressFound; + for (quint32 i : subaddrIndex) { + QString address = m_wallet->address(subaddrAcount, i); + addressFound = address.contains(m_searchRegExp); + if (addressFound) break; + } + + return (descriptionData.contains(m_searchRegExp) || txidData.contains(m_searchRegExp)) || addressFound; +} \ No newline at end of file diff --git a/src/model/TransactionHistoryProxyModel.h b/src/model/TransactionHistoryProxyModel.h new file mode 100644 index 0000000..559f1ff --- /dev/null +++ b/src/model/TransactionHistoryProxyModel.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_TRANSACTIONHISTORYPROXYMODEL_H +#define FEATHER_TRANSACTIONHISTORYPROXYMODEL_H + +#include "libwalletqt/TransactionHistory.h" +#include "libwalletqt/Wallet.h" + +#include + +class TransactionHistoryProxyModel : public QSortFilterProxyModel +{ +Q_OBJECT +public: + explicit TransactionHistoryProxyModel(Wallet *wallet, QObject* parent = nullptr); + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + +public slots: + void setSearchFilter(const QString& searchString){ + m_searchRegExp.setPattern(searchString); + invalidateFilter(); + } + +private: + Wallet * m_wallet; + + QRegExp m_searchRegExp; +}; + +#endif //FEATHER_TRANSACTIONHISTORYPROXYMODEL_H diff --git a/src/model/XmrToModel.cpp b/src/model/XmrToModel.cpp new file mode 100644 index 0000000..b14ac45 --- /dev/null +++ b/src/model/XmrToModel.cpp @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "XmrToModel.h" +#include "model/ModelUtils.h" +#include "utils/xmrto.h" + +XmrToModel::XmrToModel(QList *orders, QObject *parent) + : QAbstractTableModel(parent), + orders(orders) +{ +} + +void XmrToModel::update() { + beginResetModel(); + endResetModel(); +} + +int XmrToModel::rowCount(const QModelIndex &) const { + return this->orders->count(); +} + +int XmrToModel::columnCount(const QModelIndex &) const { + return COUNT; +} + +QVariant XmrToModel::data(const QModelIndex &index, int role) const { + const int _row = index.row(); + const int _col = index.column(); + const auto order = this->orders->at(_row); + + if (role == Qt::DisplayRole){ + switch(index.column()){ + case Status: + { + QString status = XmrTo::stateMap[(OrderState) order->state]; + + if (order->state == OrderState::Status_OrderUnpaid) + return QString("%1 (%2)").arg(status, QString::number(order->countdown)); + + return status; + } + case ID: + return !order->uuid.isEmpty() ? order->uuid.split("-")[1] : "-"; + case Destination: + return ModelUtils::displayAddress(order->btc_dest_address, 1); + case Conversion: + if(order->state <= OrderState::Status_OrderToBeCreated) + return ""; + + return QString("%1 XMR ⟶ %2 BTC").arg(QString::number(order->incoming_amount_total), QString::number(order->btc_amount)); + case Rate: + return order->incoming_price_btc ? QString::number(order->incoming_price_btc, 'f', 6) : ""; + case ErrorMsg: + if(order->errorMsg.isEmpty()) return ""; + return order->errorMsg; + default: return {}; + } + } + + else if(role == Qt::BackgroundRole) { + if (_col == 0) { + if (order->state == OrderState::Status_OrderPaid || order->state == OrderState::Status_OrderPaidUnconfirmed) + return QBrush(Qt::darkGreen); + else if (order->state == OrderState::Status_OrderCreating || order->state == OrderState::Status_OrderToBeCreated) + return QBrush(Qt::yellow); + else if (order->state == OrderState::Status_OrderUnpaid) + return QBrush(Qt::cyan); + else if (order->state == OrderState::Status_OrderBTCSent) + return QBrush(Qt::green); + else if (order->state == OrderState::Status_OrderFailed || order->state == OrderState::Status_OrderTimedOut) + return QBrush(QColor(191, 255, 0)); // lime + } + } + else if (role == Qt::FontRole) { + switch(index.column()) { + case ID: + case Destination: + return ModelUtils::getMonospaceFont(); + } + } + + return QVariant(); +} + +QVariant XmrToModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { + switch (section) { + case Status: + return QString("Status"); + case ID: + return QString("ID"); + case Destination: + return QString("Address"); + case Conversion: + return QString("Conversion"); + case Rate: + return QString("Rate"); + case ErrorMsg: + return QString("Message"); + default: + return QVariant(); + } + } + return QVariant(); +} \ No newline at end of file diff --git a/src/model/XmrToModel.h b/src/model/XmrToModel.h new file mode 100644 index 0000000..f428f0e --- /dev/null +++ b/src/model/XmrToModel.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_XMRTOMODEL_H +#define FEATHER_XMRTOMODEL_H + +#include + +class XmrToOrder; +class XmrToModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + enum ModelColumn + { + Status = 0, + ID, + Conversion, + Rate, + Destination, + ErrorMsg, + COUNT + }; + + XmrToModel(QList *orders, QObject *parent = nullptr); + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QList *orders; + +public slots: + void update(); +}; + + +#endif //FEATHER_XMRTOMODEL_H diff --git a/src/openpgp/CMakeLists.txt b/src/openpgp/CMakeLists.txt new file mode 100644 index 0000000..1c3f4ba --- /dev/null +++ b/src/openpgp/CMakeLists.txt @@ -0,0 +1,20 @@ +file(GLOB_RECURSE SOURCES *.cpp) +file(GLOB_RECURSE HEADERS *.h) + +find_library(GCRYPT_LIBRARY gcrypt) +find_library(GPG_ERROR_LIBRARY gpg-error) + +add_library(openpgp + ${SOURCES} + ${HEADERS}) + +find_package(GCrypt) +target_include_directories(openpgp PUBLIC + ${CMAKE_SOURCE_DIR}/monero/contrib/epee/include + ${GCRYPT_INCLUDE_DIRS} + ) + +target_link_libraries(openpgp + PUBLIC + ${GCRYPT_LIBRARY} + ${GPG_ERROR_LIBRARY}) diff --git a/src/openpgp/hash.h b/src/openpgp/hash.h new file mode 100644 index 0000000..4f69851 --- /dev/null +++ b/src/openpgp/hash.h @@ -0,0 +1,107 @@ +// Copyright (c) 2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include + +#include +#include + +namespace openpgp +{ + +class hash +{ +public: + enum algorithm : uint8_t + { + sha256 = 8, + }; + + hash(const hash &) = delete; + hash &operator=(const hash &) = delete; + + hash(uint8_t algorithm) + : algo(algorithm) + , consumed(0) + { + if (gcry_md_open(&md, algo, 0) != GPG_ERR_NO_ERROR) + { + throw std::runtime_error("failed to create message digest object"); + } + } + + ~hash() + { + gcry_md_close(md); + } + + hash &operator<<(uint8_t byte) + { + gcry_md_putc(md, byte); + ++consumed; + return *this; + } + + hash &operator<<(const epee::span &bytes) + { + gcry_md_write(md, &bytes[0], bytes.size()); + consumed += bytes.size(); + return *this; + } + + hash &operator<<(const std::vector &bytes) + { + return *this << epee::to_span(bytes); + } + + std::vector finish() const + { + std::vector result(gcry_md_get_algo_dlen(algo)); + const void *digest = gcry_md_read(md, algo); + if (digest == nullptr) + { + throw std::runtime_error("failed to read the digest"); + } + memcpy(&result[0], digest, result.size()); + return result; + } + + size_t consumed_bytes() const + { + return consumed; + } + +private: + const uint8_t algo; + gcry_md_hd_t md; + size_t consumed; +}; + +} diff --git a/src/openpgp/mpi.h b/src/openpgp/mpi.h new file mode 100644 index 0000000..800bcac --- /dev/null +++ b/src/openpgp/mpi.h @@ -0,0 +1,78 @@ +// Copyright (c) 2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include + +namespace openpgp +{ + +class mpi +{ +public: + mpi(const mpi &) = delete; + mpi &operator=(const mpi &) = delete; + + mpi(mpi &&other) + : data(other.data) + { + other.data = nullptr; + } + + template < + typename byte_container, + typename = typename std::enable_if<(sizeof(typename byte_container::value_type) == 1)>::type> + mpi(const byte_container &buffer, gcry_mpi_format format = GCRYMPI_FMT_USG) + : mpi(&buffer[0], buffer.size(), format) + { + } + + mpi(const void *buffer, size_t size, gcry_mpi_format format = GCRYMPI_FMT_USG) + { + if (gcry_mpi_scan(&data, format, buffer, size, nullptr) != GPG_ERR_NO_ERROR) + { + throw std::runtime_error("failed to read mpi from buffer"); + } + } + + ~mpi() + { + gcry_mpi_release(data); + } + + const gcry_mpi_t &get() const + { + return data; + } + +private: + gcry_mpi_t data; +}; + +} // namespace openpgp diff --git a/src/openpgp/openpgp.cpp b/src/openpgp/openpgp.cpp new file mode 100644 index 0000000..fa50301 --- /dev/null +++ b/src/openpgp/openpgp.cpp @@ -0,0 +1,382 @@ +// Copyright (c) 2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "openpgp.h" + +#include +#include +#include + +#include + +#include "hash.h" +#include "mpi.h" +#include "packet_stream.h" +#include "s_expression.h" +#include "serialization.h" + +namespace openpgp +{ +namespace +{ + +std::string::const_iterator find_next_line(std::string::const_iterator begin, const std::string::const_iterator &end) +{ + begin = std::find(begin, end, '\n'); + return begin != end ? ++begin : end; +} + +std::string::const_iterator find_line_starting_with( + std::string::const_iterator it, + const std::string::const_iterator &end, + const std::string &starts_with) +{ + for (std::string::const_iterator next_line; it != end; it = next_line) + { + next_line = find_next_line(it, end); + const size_t line_length = static_cast(std::distance(it, next_line)); + if (line_length >= starts_with.size() && std::equal(starts_with.begin(), starts_with.end(), it)) + { + return it; + } + } + return end; +} + +std::string::const_iterator find_empty_line(std::string::const_iterator it, const std::string::const_iterator &end) +{ + for (; it != end && *it != '\r' && *it != '\n'; it = find_next_line(it, end)) + { + } + return it; +} + +std::string get_armored_block_contents(const std::string &text, const std::string &block_name) +{ + static constexpr const char dashes[] = "-----"; + const std::string armor_header = dashes + block_name + dashes; + auto block_start = find_line_starting_with(text.begin(), text.end(), armor_header); + auto block_headers = find_next_line(block_start, text.end()); + auto block_end = find_line_starting_with(block_headers, text.end(), dashes); + auto contents_begin = find_next_line(find_empty_line(block_headers, block_end), block_end); + if (contents_begin == block_end) + { + throw std::runtime_error("armored block not found"); + } + return std::string(contents_begin, block_end); +} + +} // namespace + +public_key_rsa::public_key_rsa(s_expression expression, size_t bits) + : m_expression(std::move(expression)) + , m_bits(bits) +{ +} + +const gcry_sexp_t &public_key_rsa::get() const +{ + return m_expression.get(); +} + +size_t public_key_rsa::bits() const +{ + return m_bits; +} + +public_key_block::public_key_block(const std::string &armored) + : public_key_block(epee::to_byte_span(epee::to_span(epee::string_encoding::base64_decode( + strip_line_breaks(get_armored_block_contents(armored, "BEGIN PGP PUBLIC KEY BLOCK")))))) +{ +} + +// TODO: Public-Key expiration, User ID and Public-Key certification, Subkey binding checks +public_key_block::public_key_block(const epee::span buffer) +{ + packet_stream packets(buffer); + + const std::vector *data = packets.find_first(packet_tag::type::user_id); + if (data == nullptr) + { + throw std::runtime_error("user id is missing"); + } + m_user_id.assign(data->begin(), data->end()); + + const auto append_public_key = [this](const std::vector &data) { + deserializer> serialized(data); + + const auto version = serialized.read_big_endian(); + if (version != 4) + { + throw std::runtime_error("unsupported public key version"); + } + + /* const auto timestamp = */ serialized.read_big_endian(); + + const auto algorithm = serialized.read_big_endian(); + if (algorithm != openpgp::algorithm::rsa) + { + throw std::runtime_error("unsupported public key algorithm"); + } + + { + const mpi public_key_n = serialized.read_mpi(); + const mpi public_key_e = serialized.read_mpi(); + + emplace_back( + s_expression("(public-key (rsa (n %m) (e %m)))", public_key_n.get(), public_key_e.get()), + gcry_mpi_get_nbits(public_key_n.get())); + } + }; + + data = packets.find_first(packet_tag::type::public_key); + if (data == nullptr) + { + throw std::runtime_error("public key is missing"); + } + append_public_key(*data); + + packets.for_each(packet_tag::type::public_subkey, append_public_key); +} + +std::string public_key_block::user_id() const +{ + return m_user_id; +} + +// TODO: Signature expiration check +signature_rsa::signature_rsa( + uint8_t algorithm, + std::pair hash_leftmost_bytes, + uint8_t hash_algorithm, + const std::vector &hashed_data, + type type, + s_expression signature, + uint8_t version) + : m_hash_algorithm(hash_algorithm) + , m_hash_leftmost_bytes(hash_leftmost_bytes) + , m_hashed_appendix(format_hashed_appendix(algorithm, hash_algorithm, hashed_data, type, version)) + , m_signature(std::move(signature)) + , m_type(type) +{ +} + +signature_rsa signature_rsa::from_armored(const std::string &armored_signed_message) +{ + return from_base64(get_armored_block_contents(armored_signed_message, "BEGIN PGP SIGNATURE")); +} + +signature_rsa signature_rsa::from_base64(const std::string &base64) +{ + std::string decoded = epee::string_encoding::base64_decode(strip_line_breaks(base64)); + epee::span buffer(reinterpret_cast(&decoded[0]), decoded.size()); + return from_buffer(buffer); +} + +signature_rsa signature_rsa::from_buffer(const epee::span input) +{ + packet_stream packets(input); + + const std::vector *data = packets.find_first(packet_tag::type::signature); + if (data == nullptr) + { + throw std::runtime_error("signature is missing"); + } + + deserializer> buffer(*data); + + const auto version = buffer.read_big_endian(); + if (version != 4) + { + throw std::runtime_error("unsupported signature version"); + } + + const auto signature_type = static_cast(buffer.read_big_endian()); + + const auto algorithm = buffer.read_big_endian(); + if (algorithm != openpgp::algorithm::rsa) + { + throw std::runtime_error("unsupported signature algorithm"); + } + + const auto hash_algorithm = buffer.read_big_endian(); + + const auto hashed_data_length = buffer.read_big_endian(); + std::vector hashed_data = buffer.read(hashed_data_length); + + const auto unhashed_data_length = buffer.read_big_endian(); + buffer.read_span(unhashed_data_length); + + std::pair hash_leftmost_bytes{buffer.read_big_endian(), buffer.read_big_endian()}; + + const mpi signature = buffer.read_mpi(); + + return signature_rsa( + algorithm, + std::move(hash_leftmost_bytes), + hash_algorithm, + hashed_data, + signature_type, + s_expression("(sig-val (rsa (s %m)))", signature.get()), + version); +} + +bool signature_rsa::verify(const epee::span message, const public_key_rsa &public_key) const +{ + const s_expression signed_data = hash_message(message, public_key.bits()); + return gcry_pk_verify(m_signature.get(), signed_data.get(), public_key.get()) == 0; +} + +s_expression signature_rsa::hash_message(const epee::span message, size_t public_key_bits) const +{ + switch (m_type) + { + case type::binary_document: + return hash_bytes(message, public_key_bits); + case type::canonical_text_document: + { + std::vector crlf_formatted; + crlf_formatted.reserve(message.size()); + const size_t message_size = message.size(); + for (size_t offset = 0; offset < message_size; ++offset) + { + const auto &character = message[offset]; + if (character == '\r') + { + continue; + } + if (character == '\n') + { + const bool skip_last_crlf = offset + 1 == message_size; + if (skip_last_crlf) + { + break; + } + crlf_formatted.push_back('\r'); + } + crlf_formatted.push_back(character); + } + return hash_bytes(epee::to_span(crlf_formatted), public_key_bits); + } + default: + throw std::runtime_error("unsupported signature type"); + } +} + +std::vector signature_rsa::hash_asn_object_id() const +{ + size_t size; + if (gcry_md_algo_info(m_hash_algorithm, GCRYCTL_GET_ASNOID, nullptr, &size) != GPG_ERR_NO_ERROR) + { + throw std::runtime_error("failed to get ASN.1 Object Identifier (OID) size"); + } + + std::vector asn_object_id(size); + if (gcry_md_algo_info(m_hash_algorithm, GCRYCTL_GET_ASNOID, &asn_object_id[0], &size) != GPG_ERR_NO_ERROR) + { + throw std::runtime_error("failed to get ASN.1 Object Identifier (OID)"); + } + + return asn_object_id; +} + +s_expression signature_rsa::hash_bytes(const epee::span message, size_t public_key_bits) const +{ + const std::vector plain_hash = (hash(m_hash_algorithm) << message << m_hashed_appendix).finish(); + if (plain_hash.size() < 2) + { + throw std::runtime_error("insufficient message hash size"); + } + if (plain_hash[0] != m_hash_leftmost_bytes.first || plain_hash[1] != m_hash_leftmost_bytes.second) + { + throw std::runtime_error("signature checksum doesn't match the expected value"); + } + + std::vector asn_object_id = hash_asn_object_id(); + + const size_t public_key_bytes = bits_to_bytes(public_key_bits); + if (public_key_bytes < plain_hash.size() + asn_object_id.size() + 11) + { + throw std::runtime_error("insufficient public key bit length"); + } + + std::vector emsa_pkcs1_v1_5_encoded; + emsa_pkcs1_v1_5_encoded.reserve(public_key_bytes); + emsa_pkcs1_v1_5_encoded.push_back(0); + emsa_pkcs1_v1_5_encoded.push_back(1); + const size_t ps_size = public_key_bytes - plain_hash.size() - asn_object_id.size() - 3; + emsa_pkcs1_v1_5_encoded.insert(emsa_pkcs1_v1_5_encoded.end(), ps_size, 0xff); + emsa_pkcs1_v1_5_encoded.push_back(0); + emsa_pkcs1_v1_5_encoded.insert(emsa_pkcs1_v1_5_encoded.end(), asn_object_id.begin(), asn_object_id.end()); + emsa_pkcs1_v1_5_encoded.insert(emsa_pkcs1_v1_5_encoded.end(), plain_hash.begin(), plain_hash.end()); + + mpi value(emsa_pkcs1_v1_5_encoded); + return s_expression("(data (flags raw) (value %m))", value.get()); +} + +std::vector signature_rsa::format_hashed_appendix( + uint8_t algorithm, + uint8_t hash_algorithm, + const std::vector &hashed_data, + uint8_t type, + uint8_t version) +{ + const uint16_t hashed_data_size = static_cast(hashed_data.size()); + const uint32_t hashed_pefix_size = sizeof(version) + sizeof(type) + sizeof(algorithm) + sizeof(hash_algorithm) + + sizeof(hashed_data_size) + hashed_data.size(); + + std::vector appendix; + appendix.reserve(hashed_pefix_size + sizeof(version) + sizeof(uint8_t) + sizeof(hashed_pefix_size)); + appendix.push_back(version); + appendix.push_back(type); + appendix.push_back(algorithm); + appendix.push_back(hash_algorithm); + appendix.push_back(static_cast(hashed_data_size >> 8)); + appendix.push_back(static_cast(hashed_data_size)); + appendix.insert(appendix.end(), hashed_data.begin(), hashed_data.end()); + appendix.push_back(version); + appendix.push_back(0xff); + appendix.push_back(static_cast(hashed_pefix_size >> 24)); + appendix.push_back(static_cast(hashed_pefix_size >> 16)); + appendix.push_back(static_cast(hashed_pefix_size >> 8)); + appendix.push_back(static_cast(hashed_pefix_size)); + + return appendix; +} + +message_armored::message_armored(const std::string &message_armored) + : m_message(get_armored_block_contents(message_armored, "BEGIN PGP SIGNED MESSAGE")) +{ +} + +message_armored::operator epee::span() const +{ + return epee::to_byte_span(epee::to_span(m_message)); +} + +} // namespace openpgp diff --git a/src/openpgp/openpgp.h b/src/openpgp/openpgp.h new file mode 100644 index 0000000..e876ecc --- /dev/null +++ b/src/openpgp/openpgp.h @@ -0,0 +1,127 @@ +// Copyright (c) 2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include + +#include + +#include + +#include "s_expression.h" + +namespace openpgp +{ + +enum algorithm : uint8_t +{ + rsa = 1, +}; + +class public_key_rsa +{ +public: + public_key_rsa(s_expression expression, size_t bits); + + size_t bits() const; + const gcry_sexp_t &get() const; + +private: + s_expression m_expression; + size_t m_bits; +}; + +class public_key_block : public std::vector +{ +public: + public_key_block(const std::string &armored); + public_key_block(const epee::span buffer); + + std::string user_id() const; + +private: + std::string m_user_id; +}; + +class signature_rsa +{ +public: + enum type : uint8_t + { + binary_document = 0, + canonical_text_document = 1, + }; + + signature_rsa( + uint8_t algorithm, + std::pair hash_leftmost_bytes, + uint8_t hash_algorithm, + const std::vector &hashed_data, + type type, + s_expression signature, + uint8_t version); + + static signature_rsa from_armored(const std::string &armored_signed_message); + static signature_rsa from_base64(const std::string &base64); + static signature_rsa from_buffer(const epee::span input); + + bool verify(const epee::span message, const public_key_rsa &public_key) const; + +private: + s_expression hash_message(const epee::span message, size_t public_key_bits) const; + std::vector hash_asn_object_id() const; + s_expression hash_bytes(const epee::span message, size_t public_key_bits) const; + + static std::vector format_hashed_appendix( + uint8_t algorithm, + uint8_t hash_algorithm, + const std::vector &hashed_data, + uint8_t type, + uint8_t version); + +private: + uint8_t m_hash_algorithm; + std::pair m_hash_leftmost_bytes; + std::vector m_hashed_appendix; + s_expression m_signature; + type m_type; +}; + +class message_armored +{ +public: + message_armored(const std::string &message_armored); + + operator epee::span() const; + +private: + std::string m_message; +}; + +} // namespace openpgp diff --git a/src/openpgp/packet_stream.h b/src/openpgp/packet_stream.h new file mode 100644 index 0000000..6a993e9 --- /dev/null +++ b/src/openpgp/packet_stream.h @@ -0,0 +1,88 @@ +// Copyright (c) 2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include + +#include + +#include "serialization.h" + +namespace openpgp +{ + +class packet_stream +{ +public: + packet_stream(const epee::span buffer) + : packet_stream(deserializer>(buffer)) + { + } + + template < + typename byte_container, + typename = typename std::enable_if<(sizeof(typename byte_container::value_type) == 1)>::type> + packet_stream(deserializer buffer) + { + while (!buffer.empty()) + { + packet_tag tag = buffer.read_packet_tag(); + packets.push_back({std::move(tag), buffer.read(tag.length)}); + } + } + + const std::vector *find_first(packet_tag::type type) const + { + for (const auto &packet : packets) + { + if (packet.first.packet_type == type) + { + return &packet.second; + } + } + return nullptr; + } + + template + void for_each(packet_tag::type type, Callback &callback) const + { + for (const auto &packet : packets) + { + if (packet.first.packet_type == type) + { + callback(packet.second); + } + } + } + +private: + std::vector>> packets; +}; + +} // namespace openpgp diff --git a/src/openpgp/s_expression.h b/src/openpgp/s_expression.h new file mode 100644 index 0000000..b46bf21 --- /dev/null +++ b/src/openpgp/s_expression.h @@ -0,0 +1,78 @@ +// Copyright (c) 2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include +#include + +#include + +namespace openpgp +{ + +class s_expression +{ +public: + s_expression(const s_expression &) = delete; + s_expression &operator=(const s_expression &) = delete; + + template + s_expression(Args... args) + { + if (gcry_sexp_build(&data, nullptr, args...) != GPG_ERR_NO_ERROR) + { + throw std::runtime_error("failed to build S-expression"); + } + } + + s_expression(s_expression &&other) + { + std::swap(data, other.data); + } + + s_expression(gcry_sexp_t data) + : data(data) + { + } + + ~s_expression() + { + gcry_sexp_release(data); + } + + const gcry_sexp_t &get() const + { + return data; + } + +private: + gcry_sexp_t data = nullptr; +}; + +} // namespace openpgp diff --git a/src/openpgp/serialization.h b/src/openpgp/serialization.h new file mode 100644 index 0000000..fb42c1b --- /dev/null +++ b/src/openpgp/serialization.h @@ -0,0 +1,172 @@ +// Copyright (c) 2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include "mpi.h" + +namespace openpgp +{ + +size_t bits_to_bytes(size_t bits) +{ + constexpr const uint16_t bits_in_byte = 8; + return (bits + bits_in_byte - 1) / bits_in_byte; +} + +std::string strip_line_breaks(const std::string &string) +{ + std::string result; + result.reserve(string.size()); + for (const auto &character : string) + { + if (character != '\r' && character != '\n') + { + result.push_back(character); + } + } + return result; +} + +struct packet_tag +{ + enum type : uint8_t + { + signature = 2, + public_key = 6, + user_id = 13, + public_subkey = 14, + }; + + const type packet_type; + const size_t length; +}; + +template < + typename byte_container, + typename = typename std::enable_if<(sizeof(typename byte_container::value_type) == 1)>::type> +class deserializer +{ +public: + deserializer(byte_container buffer) + : buffer(std::move(buffer)) + , cursor(0) + { + } + + bool empty() const + { + return buffer.size() - cursor == 0; + } + + packet_tag read_packet_tag() + { + const auto tag = read_big_endian(); + + constexpr const uint8_t format_mask = 0b11000000; + constexpr const uint8_t format_old_tag = 0b10000000; + if ((tag & format_mask) != format_old_tag) + { + throw std::runtime_error("invalid packet tag"); + } + + const packet_tag::type packet_type = static_cast((tag & 0b00111100) >> 2); + const uint8_t length_type = tag & 0b00000011; + + size_t length; + switch (length_type) + { + case 0: + length = read_big_endian(); + break; + case 1: + length = read_big_endian(); + break; + case 2: + length = read_big_endian(); + break; + default: + throw std::runtime_error("unsupported packet length type"); + } + + return {packet_type, length}; + } + + mpi read_mpi() + { + const size_t bit_length = read_big_endian(); + return mpi(read_span(bits_to_bytes(bit_length))); + } + + std::vector read(size_t size) + { + if (buffer.size() - cursor < size) + { + throw std::runtime_error("insufficient buffer size"); + } + + const size_t offset = cursor; + cursor += size; + + return {&buffer[offset], &buffer[cursor]}; + } + + template ::value>::type> + T read_big_endian() + { + if (buffer.size() - cursor < sizeof(T)) + { + throw std::runtime_error("insufficient buffer size"); + } + T result = 0; + for (size_t read = 0; read < sizeof(T); ++read) + { + result = (result << 8) | static_cast(buffer[cursor++]); + } + return result; + } + + epee::span read_span(size_t size) + { + if (buffer.size() - cursor < size) + { + throw std::runtime_error("insufficient buffer size"); + } + + const size_t offset = cursor; + cursor += size; + + return {reinterpret_cast(&buffer[offset]), size}; + } + +private: + byte_container buffer; + size_t cursor; +}; + +} // namespace openpgp diff --git a/src/qrcode/CMakeLists.txt b/src/qrcode/CMakeLists.txt new file mode 100644 index 0000000..9ffcf58 --- /dev/null +++ b/src/qrcode/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (C) 2017 KeePassXC Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 or (at your option) +# version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(qrcode_SOURCES + QrCode.cpp +) + +add_library(qrcode STATIC ${qrcode_SOURCES}) +target_link_libraries(qrcode Qt5::Core Qt5::Widgets Qt5::Svg ${QRENCODE_LIBRARY}) diff --git a/src/qrcode/QrCode.cpp b/src/qrcode/QrCode.cpp new file mode 100644 index 0000000..7a51155 --- /dev/null +++ b/src/qrcode/QrCode.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Portions copyright (c) 2020, The Monero Project + */ + +#include "QrCode.h" +#include "QrCode_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QrCodePrivate::QrCodePrivate() + : m_qrcode(nullptr) +{ +} + +QrCodePrivate::~QrCodePrivate() +{ + if (m_qrcode) { + QRcode_free(m_qrcode); + } +} + +QrCode::QrCode() + : d_ptr(new QrCodePrivate()) +{ +} + +QrCode::QrCode(const QString& data, const Version version, const ErrorCorrectionLevel ecl, const bool caseSensitive) + : d_ptr(new QrCodePrivate()) +{ + init(data, version, ecl, caseSensitive); +} + +QrCode::QrCode(const QByteArray& data, const Version version, const ErrorCorrectionLevel ecl) + : d_ptr(new QrCodePrivate()) +{ + init(data, version, ecl); +} + +QrCode::~QrCode() = default; + +void QrCode::init(const QString& data, const Version version, const ErrorCorrectionLevel ecl, bool caseSensitive) +{ + if (data.isEmpty()) { + return; + } + + d_ptr->m_qrcode = QRcode_encodeString(data.toLocal8Bit().data(), + static_cast(version), + static_cast(ecl), + QR_MODE_8, + caseSensitive ? 1 : 0); +} + +void QrCode::init(const QByteArray& data, const Version version, const ErrorCorrectionLevel ecl) +{ + if (data.isEmpty()) { + return; + } + + d_ptr->m_qrcode = QRcode_encodeData(data.size(), + reinterpret_cast(data.data()), + static_cast(version), + static_cast(ecl)); +} + +bool QrCode::isValid() const +{ + return d_ptr->m_qrcode != nullptr; +} + +void QrCode::writeSvg(QIODevice* outputDevice, const int dpi, const int margin) const +{ + if (margin < 0 || d_ptr->m_qrcode == nullptr || outputDevice == nullptr) { + return; + } + + const int width = d_ptr->m_qrcode->width + margin * 2; + + QSvgGenerator generator; + generator.setSize(QSize(width, width)); + generator.setViewBox(QRect(0, 0, width, width)); + generator.setResolution(dpi); + generator.setOutputDevice(outputDevice); + + QPainter painter; + painter.begin(&generator); + + // Background + painter.setClipRect(QRect(0, 0, width, width)); + painter.fillRect(QRect(0, 0, width, width), Qt::white); + + // Foreground + // "Dots" are stored in a quint8 x quint8 array using row-major order. + // A dot is black if the LSB of its corresponding quint8 is 1. + const QPen pen(Qt::black, 0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); + const QBrush brush(Qt::black); + painter.setPen(pen); + painter.setBrush(brush); + + const int rowSize = d_ptr->m_qrcode->width; + unsigned char* dot = d_ptr->m_qrcode->data; + for (int y = 0; y < rowSize; ++y) { + for (int x = 0; x < rowSize; ++x) { + if (quint8(0x01) == (static_cast(*dot++) & quint8(0x01))) { + painter.drawRect(margin + x, margin + y, 1, 1); + } + } + } + + painter.end(); +} + +QPixmap QrCode::toPixmap(const int margin) const +{ + if (margin < 0 || d_ptr->m_qrcode == nullptr) { + return QPixmap(); + } + + const int width = d_ptr->m_qrcode->width + margin * 2; + + QPixmap pixmap(width, width); + pixmap.fill(Qt::white); + + QPainter painter; + painter.begin(&pixmap); + + // Foreground + // "Dots" are stored in a quint8 x quint8 array using row-major order. + // A dot is black if the LSB of its corresponding quint8 is 1. + const QPen pen(Qt::black, 1); + const QBrush brush(Qt::black); + painter.setPen(pen); + painter.setBrush(brush); + + const int rowSize = d_ptr->m_qrcode->width; + unsigned char* dot = d_ptr->m_qrcode->data; + for (int y = 0; y < rowSize; ++y) { + for (int x = 0; x < rowSize; ++x) { + if (quint8(0x01) == (static_cast(*dot++) & quint8(0x01))) { + painter.drawPoint(margin +x, margin + y); + } + } + } + painter.end(); + + return pixmap; +} \ No newline at end of file diff --git a/src/qrcode/QrCode.h b/src/qrcode/QrCode.h new file mode 100644 index 0000000..50173b4 --- /dev/null +++ b/src/qrcode/QrCode.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Portions copyright (c) 2020, The Monero Project + */ + +#ifndef KEEPASSX_QRCODE_H +#define KEEPASSX_QRCODE_H + +#include +#include +#include + +class QImage; +class QIODevice; +class QString; +class QByteArray; + +struct QrCodePrivate; + +class QrCode +{ + +public: + enum class ErrorCorrectionLevel : int + { + LOW = 0, + MEDIUM, + QUARTILE, + HIGH + }; + + // See: http://www.qrcode.com/en/about/version.html + // clang-format off + enum class Version : int + { + AUTO = 0, + V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, + V21, V22, V23, V24, V25, V26, V27, V28, V29, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V40 + }; + // clang-format on + + // Uses QRcode_encodeString (can't contain NUL characters) + explicit QrCode(const QString& data, + const Version version = Version::AUTO, + const ErrorCorrectionLevel ecl = ErrorCorrectionLevel::HIGH, + const bool caseSensitive = true); + + // Uses QRcode_encodeData (can contain NUL characters) + explicit QrCode(const QByteArray& data, + const Version version = Version::AUTO, + const ErrorCorrectionLevel ecl = ErrorCorrectionLevel::HIGH); + + QrCode(); + ~QrCode(); + + bool isValid() const; + void writeSvg(QIODevice* outputDevice, const int dpi, const int margin = 4) const; + QPixmap toPixmap(const int margin = 4) const; + +private: + void init(const QString& data, const Version version, const ErrorCorrectionLevel ecl, const bool caseSensitive); + + void init(const QByteArray& data, const Version version, const ErrorCorrectionLevel ecl); + + QScopedPointer d_ptr; +}; + +#endif // KEEPASSX_QRCODE_H diff --git a/src/qrcode/QrCode_p.h b/src/qrcode/QrCode_p.h new file mode 100644 index 0000000..0161b79 --- /dev/null +++ b/src/qrcode/QrCode_p.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* This class exists to isolate from the rest of the code base. */ + +#ifndef KEEPASSX_QRCODEPRIVATE_H +#define KEEPASSX_QRCODEPRIVATE_H + +#include + +struct QrCodePrivate +{ + QRcode* m_qrcode; + + QrCodePrivate(); + ~QrCodePrivate(); +}; + +#endif // KEEPASSX_QRCODEPRIVATE_H diff --git a/src/receivewidget.cpp b/src/receivewidget.cpp new file mode 100644 index 0000000..813eb17 --- /dev/null +++ b/src/receivewidget.cpp @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "ui_receivewidget.h" +#include "receivewidget.h" +#include "qrcode/QrCode.h" +#include "model/ModelUtils.h" +#include "dialog/qrcodedialog.h" + +#include +#include + +ReceiveWidget::ReceiveWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::ReceiveWidget) +{ + ui->setupUi(this); + + // header context menu + ui->addresses->header()->setContextMenuPolicy(Qt::CustomContextMenu); + m_headerMenu = new QMenu(this); + m_showFullAddressesAction = m_headerMenu->addAction("Show full addresses", this, &ReceiveWidget::setShowFullAddresses); + m_showFullAddressesAction->setCheckable(true); + m_showUsedAddressesAction = m_headerMenu->addAction("Show used addresses", this, &ReceiveWidget::setShowUsedAddresses); + m_showUsedAddressesAction->setCheckable(true); + connect(ui->addresses->header(), &QHeaderView::customContextMenuRequested, this, &ReceiveWidget::showHeaderMenu); + + // context menu + ui->addresses->setContextMenuPolicy(Qt::CustomContextMenu); + m_showTransactionsAction = new QAction("Show transactions"); + connect(m_showTransactionsAction, &QAction::triggered, this, &ReceiveWidget::onShowTransactions); + connect(ui->addresses, &QTreeView::customContextMenuRequested, this, &ReceiveWidget::showContextMenu); + + connect(ui->btn_generateSubaddress, &QPushButton::clicked, [=]() { + emit generateSubaddress(); + }); + + connect(ui->qrCode, &ClickableLabel::clicked, this, &ReceiveWidget::showQrCodeDialog); + connect(ui->label_addressSearch, &QLineEdit::textChanged, this, &ReceiveWidget::setSearchFilter); +} + +void ReceiveWidget::setModel(SubaddressModel * model, Subaddress * subaddress) { + m_subaddress = subaddress; + m_model = model; + m_proxyModel = new SubaddressProxyModel(this, subaddress); + m_proxyModel->setSourceModel(m_model); + ui->addresses->setModel(m_proxyModel); + + ui->addresses->setColumnHidden(SubaddressModel::isUsed, true); + ui->addresses->header()->setSectionResizeMode(SubaddressModel::Address, QHeaderView::Stretch); + ui->addresses->header()->setSectionResizeMode(SubaddressModel::Label, QHeaderView::ResizeToContents); + ui->addresses->header()->setMinimumSectionSize(200); + + connect(ui->addresses->selectionModel(), &QItemSelectionModel::currentRowChanged, [=](QModelIndex current, QModelIndex prev){ + if (current.isValid()) + this->setQrCode(current.model()->data(current.siblingAtColumn(SubaddressModel::Address), Qt::UserRole).toString()); + else + ui->qrCode->clear(); + }); +// connect(m_model, &SubaddressModel::modelReset, [this](){ +// ui->btn_generateSubaddress->setEnabled(m_model->unusedLookahead() < SUBADDRESS_LOOKAHEAD_MINOR); +// }); +} + +void ReceiveWidget::copyAddress() { + QModelIndex index = ui->addresses->currentIndex(); + ModelUtils::copyColumn(&index, SubaddressModel::Address); +} + +void ReceiveWidget::copyLabel() { + QModelIndex index = ui->addresses->currentIndex(); + ModelUtils::copyColumn(&index, SubaddressModel::Label); +} + +void ReceiveWidget::editLabel() { + QModelIndex index = ui->addresses->currentIndex().siblingAtColumn(m_model->ModelColumn::Label); + ui->addresses->setCurrentIndex(index); + ui->addresses->edit(index); +} + +void ReceiveWidget::showContextMenu(const QPoint &point) { + QModelIndex index = ui->addresses->indexAt(point); + if (!index.isValid()) { + return; + } + + auto *menu = new QMenu(ui->addresses); + bool isUsed = index.model()->data(index.siblingAtColumn(SubaddressModel::isUsed), Qt::UserRole).toBool(); + + menu->addAction(QIcon(":/assets/images/copy.png"), "Copy address", this, &ReceiveWidget::copyAddress); + menu->addAction(QIcon(":/assets/images/copy.png"), "Copy label", this, &ReceiveWidget::copyLabel); + menu->addAction(QIcon(":/assets/images/edit.png"), "Edit label", this, &ReceiveWidget::editLabel); + + if (isUsed) { + menu->addAction(m_showTransactionsAction); + } + + menu->popup(ui->addresses->viewport()->mapToGlobal(point)); +} + +void ReceiveWidget::onShowTransactions() { + QModelIndex index = ui->addresses->currentIndex(); + if (!index.isValid()) { + return; + } + + QString address = index.model()->data(index.siblingAtColumn(SubaddressModel::Address), Qt::UserRole).toString(); + emit showTransactions(address); +} + +void ReceiveWidget::setShowFullAddresses(bool show) { + if (!m_model) return; + m_model->setShowFullAddresses(show); +} + +void ReceiveWidget::setShowUsedAddresses(bool show) { + if (!m_proxyModel) return; + m_proxyModel->setShowUsed(show); +} + +void ReceiveWidget::setSearchFilter(const QString &filter) { + if (!m_proxyModel) return; + m_proxyModel->setSearchFilter(filter); +} + +void ReceiveWidget::showHeaderMenu(const QPoint& position) +{ + m_showFullAddressesAction->setChecked(m_model->isShowFullAddresses()); + m_headerMenu->exec(QCursor::pos()); +} + +void ReceiveWidget::setQrCode(const QString &address){ + const QrCode qrc(address, QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::MEDIUM); + + int width = ui->qrCode->width() - 4; + if (qrc.isValid()) { + ui->qrCode->setPixmap(qrc.toPixmap(1).scaled(width, width, Qt::KeepAspectRatio)); + } +} + +void ReceiveWidget::showQrCodeDialog() { + QModelIndex index = ui->addresses->currentIndex(); + QString address = index.model()->data(index.siblingAtColumn(SubaddressModel::Address), Qt::UserRole).toString(); + auto *dialog = new QrCodeDialog(this, address, "Address"); + dialog->exec(); + dialog->deleteLater(); +} + +ReceiveWidget::~ReceiveWidget() { + delete ui; +} diff --git a/src/receivewidget.h b/src/receivewidget.h new file mode 100644 index 0000000..73c9f85 --- /dev/null +++ b/src/receivewidget.h @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_RECEIVEWIDGET_H +#define FEATHER_RECEIVEWIDGET_H + +#include "appcontext.h" +#include "qrcode/QrCode.h" +#include "libwalletqt/Subaddress.h" +#include "model/SubaddressProxyModel.h" +#include "model/SubaddressModel.h" + +#include +#include + +namespace Ui { + class ReceiveWidget; +} + +class ReceiveWidget : public QWidget +{ +Q_OBJECT + +public: + explicit ReceiveWidget(QWidget *parent = nullptr); + void setModel(SubaddressModel * model, Subaddress * subaddress); + ~ReceiveWidget() override; + + +public slots: + void copyAddress(); + void copyLabel(); + void editLabel(); + void showContextMenu(const QPoint& point); + void setShowFullAddresses(bool show); + void setShowUsedAddresses(bool show); + void setSearchFilter(const QString &filter); + void onShowTransactions(); + +signals: + void generateSubaddress(); + void showTransactions(const QString& address); + +private slots: + void showHeaderMenu(const QPoint& position); + +private: + Ui::ReceiveWidget *ui; + QMenu *m_headerMenu; + QAction *m_showFullAddressesAction; + QAction *m_showUsedAddressesAction; + QAction *m_showTransactionsAction; + Subaddress * m_subaddress; + SubaddressModel * m_model; + SubaddressProxyModel * m_proxyModel; + + void setQrCode(const QString &address); + void showQrCodeDialog(); +}; + +#endif //FEATHER_RECEIVEWIDGET_H diff --git a/src/receivewidget.ui b/src/receivewidget.ui new file mode 100644 index 0000000..4061f43 --- /dev/null +++ b/src/receivewidget.ui @@ -0,0 +1,107 @@ + + + ReceiveWidget + + + + 0 + 0 + 878 + 512 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + + + Search... + + + + + + + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + false + + + false + + + + + + + QLayout::SetMinimumSize + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Generate Subaddress + + + + + + + + + + + + ClickableLabel + QLabel +
components.h
+
+
+ + +
diff --git a/src/sendwidget.cpp b/src/sendwidget.cpp new file mode 100644 index 0000000..32f93f6 --- /dev/null +++ b/src/sendwidget.cpp @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + + +#include +#include "sendwidget.h" +#include "widgets/ccswidget.h" +#include "mainwindow.h" +#include "ui_sendwidget.h" + +SendWidget::SendWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::SendWidget) +{ + ui->setupUi(this); + + QString amount_rx = R"(^\d{0,8}[\.,]\d{0,12}|(all)$)"; + QRegExp rx; + rx.setPattern(amount_rx); + QValidator *validator = new QRegExpValidator(rx, this); + ui->lineAmount->setValidator(validator); + + connect(ui->btnSend, &QPushButton::clicked, this, &SendWidget::sendClicked); + connect(ui->btnClear, &QPushButton::clicked, this, &SendWidget::clearClicked); + connect(ui->btnMax, &QPushButton::clicked, this, &SendWidget::btnMaxClicked); + connect(ui->comboCurrencySelection, QOverload::of(&QComboBox::currentIndexChanged), this, &SendWidget::currencyComboChanged); + connect(ui->lineAmount, &QLineEdit::textEdited, this, &SendWidget::amountEdited); + connect(ui->lineAddress, &QLineEdit::textEdited, this, &SendWidget::addressEdited); + connect(ui->btn_openAlias, &QPushButton::clicked, this, &SendWidget::aliasClicked); + ui->label_xmrAmount->setText(""); + ui->label_xmrAmount->hide(); + ui->btn_openAlias->hide(); +} + +void SendWidget::currencyComboChanged(int index) { + QString amount = ui->lineAmount->text(); + if(amount.isEmpty()) return; + this->amountEdited(amount); +} + +void SendWidget::addressEdited(const QString &text) { + text.contains(".") ? ui->btn_openAlias->show() : ui->btn_openAlias->hide(); +} + +void SendWidget::amountEdited(const QString &text) { + this->updateConversionLabel(); +} + +void SendWidget::fill(const CCSEntry &entry) { + this->fill(entry.address, QString("CCS: %1").arg(entry.title), 0.0); +} + +void SendWidget::fill(double amount) { + ui->lineAmount->setText(QString::number(amount)); +} + +void SendWidget::fill(const QString &address, const QString& description){ + ui->lineDescription->setText(description); + ui->lineAddress->setText(address); + ui->lineAddress->setCursorPosition(0); +} + +void SendWidget::fill(const QString &address, const QString &description, double amount) { + ui->lineDescription->setText(description); + ui->lineAmount->setText(QString::number(amount)); + ui->lineAddress->setText(address); + ui->lineAddress->setCursorPosition(0); +} + +void SendWidget::fillAddress(const QString &address) { + ui->lineAddress->setText(address); + ui->lineAddress->setCursorPosition(0); +} + +void SendWidget::sendClicked() { + double amount = 0.0; + QString currency = ui->comboCurrencySelection->currentText(); + QString recipient = ui->lineAddress->text(); // @TODO: regex + QString description = ui->lineDescription->text(); + if(recipient.isEmpty()) { + QMessageBox::warning(this, "Malformed recipient", "The recipient address was not correct"); + return; + } + + if (currency != "XMR") { + amount = this->conversionAmount(); + if(amount <= 0.0) { + QMessageBox::warning(this, "Fiat conversion error", "Could not create transaction."); + return; + } + emit createTransaction(recipient, amount, description, false); + return; + } + + amount = this->amount(); + bool sendAll = amount == -1.0; + if(amount == 0.0){ + QMessageBox::warning(this, "Amount error", "Invalid amount specified."); + return; + } + + emit createTransaction(recipient, amount, description, sendAll); +} + +void SendWidget::aliasClicked() { + auto address = ui->lineAddress->text(); + emit resolveOpenAlias(address); +} + +void SendWidget::clearClicked() { + ui->lineAddress->clear(); + ui->lineAmount->clear(); + ui->lineDescription->clear(); +} + +void SendWidget::btnMaxClicked() { + ui->lineAmount->setText("all"); +} + +void SendWidget::updateConversionLabel() { + auto amount = this->amount(); + if(amount == -1) return; + ui->label_xmrAmount->setText(""); + if(amount <= 0) { + ui->label_xmrAmount->hide(); + return; + } + + QString currency = ui->comboCurrencySelection->currentText(); + if (currency != "XMR") { + QString xmr_str = QString("%1 XMR").arg(QString::number(this->conversionAmount())); + ui->label_xmrAmount->setText(xmr_str); + ui->label_xmrAmount->show(); + } +} + +double SendWidget::conversionAmount() { + QString currency = ui->comboCurrencySelection->currentText(); + return AppContext::prices->convert(currency, "XMR", this->amount()); +} + +double SendWidget::amount() { + // grab amount from "amount" text box + QString amount = ui->lineAmount->text(); + if(amount == "all") return -1.0; + amount.replace(',', '.'); + if(amount.isEmpty()) return 0.0; + auto amount_num = amount.toDouble(); + if(amount_num <= 0) return 0.0; + return amount_num; +} + +void SendWidget::onOpenAliasResolved(const QString &address, const QString &openAlias) { + this->fill(address, openAlias); + ui->btn_openAlias->hide(); +} + +void SendWidget::onOpenAliasResolveError(const QString &msg) { + QMessageBox::warning(this, "OpenAlias error", msg); +} + +void SendWidget::clearFields() { + ui->lineAddress->clear(); + ui->lineAmount->clear(); + ui->lineDescription->clear(); + ui->label_xmrAmount->clear(); +} + +void SendWidget::onWalletClosed() { + this->clearFields(); +} + +void SendWidget::onInitiateTransaction() { + ui->btnSend->setEnabled(false); +} + +void SendWidget::onEndTransaction() { + ui->btnSend->setEnabled(true); +} + +SendWidget::~SendWidget() { + delete ui; +} diff --git a/src/sendwidget.h b/src/sendwidget.h new file mode 100644 index 0000000..fd6338c --- /dev/null +++ b/src/sendwidget.h @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef SENDWIDGET_H +#define SENDWIDGET_H + +#include +#include "appcontext.h" +#include "widgets/ccswidget.h" + +namespace Ui { + class SendWidget; +} + +class SendWidget : public QWidget +{ +Q_OBJECT + +public: + explicit SendWidget(QWidget *parent = nullptr); + void fill(const CCSEntry &entry); + void fill(const QString &address, const QString& description); + void fill(const QString &address, const QString& description, double amount); + void fill(double amount); + void clearFields(); + ~SendWidget() override; + +public slots: + void sendClicked(); + void clearClicked(); + void aliasClicked(); + void btnMaxClicked(); + void amountEdited(const QString &text); + void addressEdited(const QString &text); + void currencyComboChanged(int index); + void fillAddress(const QString &address); + void updateConversionLabel(); + void onOpenAliasResolveError(const QString &err); + void onOpenAliasResolved(const QString &address, const QString &openAlias); + void onWalletClosed(); + + void onInitiateTransaction(); + void onEndTransaction(); + +signals: + void resolveOpenAlias(const QString &address); + void createTransaction(const QString &address, double amount, const QString &description, bool all); + +private: + Ui::SendWidget *ui; + AppContext *m_ctx; + double amount(); + double conversionAmount(); +}; + +#endif // SENDWIDGET_H diff --git a/src/sendwidget.ui b/src/sendwidget.ui new file mode 100644 index 0000000..fb0b265 --- /dev/null +++ b/src/sendwidget.ui @@ -0,0 +1,225 @@ + + + SendWidget + + + + 0 + 0 + 500 + 148 + + + + Form + + + + QLayout::SetMinimumSize + + + QFormLayout::ExpandingFieldsGrow + + + QFormLayout::DontWrapRows + + + 9 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Pay to + + + + + + + + + + + + + + Description + + + + + + + + + + Amount + + + + + + + 12 + + + QLayout::SetDefaultConstraint + + + + + 0 + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + 200 + 16777215 + + + + + + + + + XMR + + + + + EUR + + + + + USD + + + + + GBP + + + + + JPY + + + + + RMB + + + + + + + + + + Max + + + + + + + true + + + xmrAmount + + + + + + + Qt::Horizontal + + + + 100 + 20 + + + + + + + + + + 6 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Resolve OpenAlias + + + + + + + Clear + + + + + + + Send + + + + + + + + + + + sendClicked() + maxClicked() + clearClicked() + + diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 0000000..5175eb9 --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "settings.h" +#include "ui_settings.h" +#include "appcontext.h" +#include "utils/config.h" +#include "mainwindow.h" + +Settings::Settings(QWidget *parent) : + QDialog(parent), + ui(new Ui::Settings) +{ + ui->setupUi(this); + this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png")); + + if(m_ctx == nullptr) + m_ctx = MainWindow::getContext(); + + ui->tabWidget->setTabVisible(2, false); + ui->tabWidget->setTabVisible(4, false); + + connect(ui->btnCopyToClipboard, &QPushButton::clicked, this, &Settings::copyToClipboard); + connect(ui->checkBox_checkForAppUpdates, &QCheckBox::clicked, this, &Settings::checkboxExternalLinkWarn); + connect(ui->checkBox_externalLink, &QCheckBox::clicked, this, &Settings::checkboxExternalLinkWarn); + connect(ui->closeButton, &QDialogButtonBox::accepted, this, &Settings::close); + + // nodes + ui->nodeWidget->setupUI(m_ctx); + connect(ui->nodeWidget, &NodeWidget::nodeSourceChanged, m_ctx->nodes, &Nodes::onNodeSourceChanged); + connect(ui->nodeWidget, &NodeWidget::connectToNode, m_ctx->nodes, QOverload::of(&Nodes::connectToNode)); + + // setup checkboxes + ui->checkBox_externalLink->setChecked(config()->get(Config::warnOnExternalLink).toBool()); + ui->checkBox_checkForAppUpdates->setChecked(config()->get(Config::checkForAppUpdates).toBool()); + + // setup comboboxes + auto settingsHomeWidget = config()->get(Config::homeWidget).toString(); + if (m_homeWidgets.contains(settingsHomeWidget)) + ui->comboBox_homeWidget->setCurrentIndex(m_homeWidgets.indexOf(settingsHomeWidget)); + + this->setupSkinCombobox(); + auto settingsSkin = config()->get(Config::skin).toString(); + if (m_skins.contains(settingsSkin)) + ui->comboBox_skin->setCurrentIndex(m_skins.indexOf(settingsSkin)); + + connect(ui->comboBox_homeWidget, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_homeWidgetChanged); + connect(ui->comboBox_skin, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_skinChanged); + connect(ui->comboBox_blockExplorer, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_blockExplorerChanged); + + // setup preferred fiat currency combobox + QStringList fiatCurrencies; + for (int index = 0; index < ui->comboBox_fiatCurrency->count(); index++) + fiatCurrencies << ui->comboBox_fiatCurrency->itemText(index); + + auto preferredFiatCurrency = config()->get(Config::preferredFiatCurrency).toString(); + if(!preferredFiatCurrency.isEmpty()) + if(fiatCurrencies.contains(preferredFiatCurrency)) + ui->comboBox_fiatCurrency->setCurrentText(preferredFiatCurrency); + + connect(ui->comboBox_fiatCurrency, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::fiatCurrencySelected); + + // setup path tab +#if defined(Q_OS_LINUX) + ui->textEditPaths->appendPlainText(m_ctx->applicationPath); +#endif + ui->textEditPaths->appendPlainText(m_ctx->configDirectory); + ui->textEditPaths->appendPlainText(m_ctx->defaultWalletDir); + + this->adjustSize(); +} + +void Settings::fiatCurrencySelected(int index) { + QString selection = ui->comboBox_fiatCurrency->itemText(index); + config()->set(Config::preferredFiatCurrency, selection); + emit preferredFiatCurrencyChanged(selection); +} + +void Settings::checkboxCheckForAppUpdates() { + bool state = ui->checkBox_checkForAppUpdates->isChecked(); + config()->set(Config::checkForAppUpdates, state); +} + +void Settings::comboBox_skinChanged(int pos) { + emit skinChanged(m_skins.at(pos)); +} + +void Settings::comboBox_homeWidgetChanged(int pos) { + config()->set(Config::homeWidget, m_homeWidgets.at(pos)); + + emit homeWidgetChanged(m_homeWidgets.at(pos)); +} + +void Settings::comboBox_blockExplorerChanged(int pos) { + QString blockExplorer = ui->comboBox_blockExplorer->currentText(); + config()->set(Config::blockExplorer, blockExplorer); + emit blockExplorerChanged(blockExplorer); +} + +void Settings::copyToClipboard() { + ui->textLogs->copy(); +} + +void Settings::checkboxExternalLinkWarn() { + bool state = ui->checkBox_externalLink->isChecked(); + config()->set(Config::warnOnExternalLink, state); +} + +void Settings::setupSkinCombobox() { +#if defined(Q_OS_WIN) + m_skins.removeOne("Breeze/Dark"); + m_skins.removeOne("Breeze/Light"); +#elif defined(Q_OS_MAC) + m_skins.removeOne("QDarkStyle"); +#endif + + ui->comboBox_skin->insertItems(0, m_skins); +} + +Settings::~Settings() { + delete ui; +} diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..845c79b --- /dev/null +++ b/src/settings.h @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef SETTINGS_H +#define SETTINGS_H + +#include +#include +#include + +#include "appcontext.h" +#include "widgets/nodewidget.h" + +namespace Ui { + class Settings; +} + +class Settings : public QDialog +{ +Q_OBJECT + +public: + explicit Settings(QWidget *parent = nullptr); + ~Settings() override; + +signals: + void closed(); + void preferredFiatCurrencyChanged(QString currency); + void homeWidgetChanged(QString widgetName); + void skinChanged(QString skinName); + void showHomeCCS(bool); + void blockExplorerChanged(QString blockExplorer); + +public slots: + void copyToClipboard(); + void checkboxExternalLinkWarn(); + void checkboxCheckForAppUpdates(); + void fiatCurrencySelected(int index); + void comboBox_homeWidgetChanged(int pos); + void comboBox_skinChanged(int pos); + void comboBox_blockExplorerChanged(int post); + +private: + const QStringList m_homeWidgets{"ccs", "reddit"}; + QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"}; + +private: + void setupSkinCombobox(); + + AppContext *m_ctx = nullptr; + Ui::Settings *ui; +}; + +#endif // SETTINGS_H diff --git a/src/settings.ui b/src/settings.ui new file mode 100644 index 0000000..91d7870 --- /dev/null +++ b/src/settings.ui @@ -0,0 +1,520 @@ + + + Settings + + + + 0 + 0 + 754 + 278 + + + + Settings + + + + + + 0 + + + + General + + + + + + Preferred fiat currency: + + + + + + + + USD + + + + + EUR + + + + + RUB + + + + + GBP + + + + + CAD + + + + + CHF + + + + + CNY + + + + + CZK + + + + + JPY + + + + + KRW + + + + + MXN + + + + + SEK + + + + + THB + + + + + TRY + + + + + ZAR + + + + + + + + Home screen widget: + + + + + + + + CCS proposals + + + + + /r/monero + + + + + + + + Appearance: + + + + + + + + + + Block explorer: + + + + + + + + exploremonero.com + + + + + xmrchain.net + + + + + moneroblocks.info + + + + + + + + Warn on wallet update available + + + + + + + Warn before opening external link + + + + + + + + Node + + + + + + + + + + Network + + + + + + + + + 0 + 0 + + + + Websockets + + + + + + Disable websocket + + + + + + + Websocket server + + + + + + + + 300 + 16777215 + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Paths + + + + 6 + + + + + This application uses the following paths: + + + + + + + true + + + + + + + + + .. + + + Console + + + + + + + 0 + 0 + + + + + 16777215 + 70 + + + + Log source + + + + + + Qt Application + + + + + + + RPC daemon + + + + + + + Tor daemon + + + + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + 1 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Copy to clipboard + + + + + + + Open log directory + + + + + + + Clear + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 70 + + + + Log level + + + + + + Critical + + + true + + + + + + + Warning + + + true + + + + + + + Info + + + false + + + + + + + Debug + + + + + + + + + + true + + + true + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QDialogButtonBox::Ok + + + + + + + + + + NodeWidget + QWidget +
widgets/nodewidget.h
+ 1 +
+
+ + + + copyToClipboard() + checkboxExternalLinkWarn() + closeClicked(QAbstractButton*) + checkboxCheckForAppUpdates() + fiatCurrencySelected(QString) + homeWidgetChanged(int) + +
diff --git a/src/tor/.gitkeep b/src/tor/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/ui/BreezeStyleSheets/breeze.qrc b/src/ui/BreezeStyleSheets/breeze.qrc new file mode 100644 index 0000000..88fb185 --- /dev/null +++ b/src/ui/BreezeStyleSheets/breeze.qrc @@ -0,0 +1,89 @@ + + + light/hmovetoolbar.svg + light/vmovetoolbar.svg + light/hsepartoolbar.svg + light/vsepartoolbars.svg + light/stylesheet-branch-end.svg + light/stylesheet-branch-end-closed.svg + light/stylesheet-branch-end-open.svg + light/stylesheet-vline.svg + light/stylesheet-branch-more.svg + light/branch_closed.svg + light/branch_closed-on.svg + light/branch_open.svg + light/branch_open-on.svg + light/down_arrow.svg + light/down_arrow_disabled.svg + light/down_arrow-hover.svg + light/left_arrow.svg + light/left_arrow_disabled.svg + light/right_arrow.svg + light/right_arrow_disabled.svg + light/up_arrow.svg + light/up_arrow_disabled.svg + light/up_arrow-hover.svg + light/sizegrip.svg + light/transparent.svg + light/close.svg + light/close-hover.svg + light/close-pressed.svg + light/undock.svg + light/undock-hover.svg + light/checkbox_checked-hover.svg + light/checkbox_checked.svg + light/checkbox_checked_disabled.svg + light/checkbox_indeterminate.svg + light/checkbox_indeterminate-hover.svg + light/checkbox_indeterminate_disabled.svg + light/checkbox_unchecked-hover.svg + light/checkbox_unchecked_disabled.svg + light/radio_checked-hover.svg + light/radio_checked.svg + light/radio_checked_disabled.svg + light/radio_unchecked-hover.svg + light/radio_unchecked_disabled.svg + dark/hmovetoolbar.svg + dark/vmovetoolbar.svg + dark/hsepartoolbar.svg + dark/vsepartoolbars.svg + dark/stylesheet-branch-end.svg + dark/stylesheet-branch-end-closed.svg + dark/stylesheet-branch-end-open.svg + dark/stylesheet-vline.svg + dark/stylesheet-branch-more.svg + dark/branch_closed.svg + dark/branch_closed-on.svg + dark/branch_open.svg + dark/branch_open-on.svg + dark/down_arrow.svg + dark/down_arrow_disabled.svg + dark/down_arrow-hover.svg + dark/left_arrow.svg + dark/left_arrow_disabled.svg + dark/right_arrow.svg + dark/right_arrow_disabled.svg + dark/up_arrow.svg + dark/up_arrow_disabled.svg + dark/up_arrow-hover.svg + dark/sizegrip.svg + dark/transparent.svg + dark/close.svg + dark/close-hover.svg + dark/close-pressed.svg + dark/undock.svg + dark/undock-hover.svg + dark/checkbox_checked.svg + dark/checkbox_checked_disabled.svg + dark/checkbox_indeterminate.svg + dark/checkbox_indeterminate_disabled.svg + dark/checkbox_unchecked.svg + dark/checkbox_unchecked_disabled.svg + dark/radio_checked.svg + dark/radio_checked_disabled.svg + dark/radio_unchecked.svg + dark/radio_unchecked_disabled.svg + light.qss + dark.qss + + diff --git a/src/ui/BreezeStyleSheets/dark.qss b/src/ui/BreezeStyleSheets/dark.qss new file mode 100644 index 0000000..83f6395 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark.qss @@ -0,0 +1,1664 @@ +/* + * BreezeDark stylesheet. + * + * :author: Colin Duquesnoy + * :editor: Alex Huszagh + * :license: MIT, see LICENSE.md + * + * This is originally a fork of QDarkStyleSheet, and is based on Breeze/ + * BreezeDark color scheme, but is in no way affiliated with KDE. + * + * --------------------------------------------------------------------- + * The MIT License (MIT) + * + * Copyright (c) <2013-2014> + * Copyright (c) <2015-2016> + * + * 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. + * --------------------------------------------------------------------- + */ + +QToolTip +{ + border: 0.1ex solid #eff0f1; + background-color: #31363b; + alternate-background-color: #3b4045; + color: #eff0f1; + padding: 0.5ex; + opacity: 200; +} + +QWidget +{ + color: #eff0f1; + background-color: #31363b; + selection-background-color:#3daee9; + selection-color: #eff0f1; + background-clip: border; + border-image: none; + border: 0px transparent black; + outline: 0; +} + +QWidget:item:hover +{ + background-color: #3daee9; + color: #eff0f1; +} + +QWidget:item:selected +{ + background-color: #3daee9; +} + + +QCheckBox +{ + spacing: 0.5ex; + outline: none; + color: #eff0f1; + margin-bottom: 0.2ex; + opacity: 200; +} + +QCheckBox:disabled +{ + color: #76797c; +} + +QGroupBox::indicator +{ + margin-left: 0.2ex; +} + +QCheckBox::indicator:unchecked, +QCheckBox::indicator:unchecked:focus +{ + border-image: url(:/dark/checkbox_unchecked_disabled.svg); +} + +QCheckBox::indicator:unchecked:hover, +QCheckBox::indicator:unchecked:pressed, +QGroupBox::indicator:unchecked:hover, +QGroupBox::indicator:unchecked:focus, +QGroupBox::indicator:unchecked:pressed +{ + border: none; + border-image: url(:/dark/checkbox_unchecked.svg); +} + +QCheckBox::indicator:checked +{ + border-image: url(:/dark/checkbox_checked.svg); +} + +QCheckBox::indicator:checked:hover, +QCheckBox::indicator:checked:focus, +QCheckBox::indicator:checked:pressed, +QGroupBox::indicator:checked:hover, +QGroupBox::indicator:checked:focus, +QGroupBox::indicator:checked:pressed +{ + border: none; + border-image: url(:/dark/checkbox_checked.svg); +} + +QCheckBox::indicator:indeterminate +{ + border-image: url(:/dark/checkbox_indeterminate.svg); +} + +QCheckBox::indicator:indeterminate:focus, +QCheckBox::indicator:indeterminate:hover, +QCheckBox::indicator:indeterminate:pressed +{ + border-image: url(:/dark/checkbox_indeterminate.svg); +} + +QCheckBox::indicator:indeterminate:disabled +{ + border-image: url(:/dark/checkbox_indeterminate_disabled.svg); +} + +QCheckBox::indicator:checked:disabled, +QGroupBox::indicator:checked:disabled +{ + border-image: url(:/dark/checkbox_checked_disabled.svg); +} + +QCheckBox::indicator:unchecked:disabled, +QGroupBox::indicator:unchecked:disabled +{ + border-image: url(:/dark/checkbox_unchecked_disabled.svg); +} + +QRadioButton +{ + spacing: 0.5ex; + outline: none; + color: #eff0f1; + margin-bottom: 0.2ex; +} + +QRadioButton:disabled +{ + color: #76797c; +} + +QRadioButton::indicator:unchecked, +QRadioButton::indicator:unchecked:focus +{ + border-image: url(:/dark/radio_unchecked_disabled.svg); +} + + +QRadioButton::indicator:unchecked:hover, +QRadioButton::indicator:unchecked:pressed +{ + border: none; + outline: none; + border-image: url(:/dark/radio_unchecked.svg); +} + + +QRadioButton::indicator:checked +{ + border: none; + outline: none; + border-image: url(:/dark/radio_checked.svg); +} + +QRadioButton::indicator:checked:hover, +QRadioButton::indicator:checked:focus, +QRadioButton::indicator:checked:pressed +{ + border: none; + outline: none; + border-image: url(:/dark/radio_checked.svg); +} + +QRadioButton::indicator:checked:disabled +{ + outline: none; + border-image: url(:/dark/radio_checked_disabled.svg); +} + +QRadioButton::indicator:unchecked:disabled +{ + border-image: url(:/dark/radio_unchecked_disabled.svg); +} + +QMenuBar +{ + background-color: #31363b; + color: #eff0f1; +} + +QMenuBar::item +{ + background: transparent; +} + +QMenuBar::item:selected +{ + background: transparent; + border: 0.1ex solid #76797c; +} + +QMenuBar::item:pressed +{ + border: 0.1ex solid #76797c; + background-color: #3daee9; + color: #eff0f1; + margin-bottom: -0.1ex; + padding-bottom: 0.1ex; +} + +QMenu +{ + border: 0.1ex solid #76797c; + color: #eff0f1; + margin: 0.2ex; +} + +QMenu::icon +{ + margin: 0.5ex; +} + +QMenu::item +{ + padding: 0.5ex 3ex 0.5ex 3ex; + margin-left: 0.5ex; + border: 0.1ex solid transparent; /* reserve space for selection border */ +} + +QMenu::item:selected +{ + color: #eff0f1; +} + +QMenu::separator +{ + height: 0.2ex; + background: lightblue; + margin-left: 1ex; + margin-right: 0.5ex; +} + +/* non-exclusive indicator = check box style indicator + (see QActionGroup::setExclusive) */ +QMenu::indicator:non-exclusive:unchecked +{ + border-image: url(:/dark/checkbox_unchecked_disabled.svg); +} + +QMenu::indicator:non-exclusive:unchecked:selected +{ + border-image: url(:/dark/checkbox_unchecked_disabled.svg); +} + +QMenu::indicator:non-exclusive:checked +{ + border-image: url(:/dark/checkbox_checked.svg); +} + +QMenu::indicator:non-exclusive:checked:selected +{ + border-image: url(:/dark/checkbox_checked.svg); +} + +/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ +QMenu::indicator:exclusive:unchecked +{ + border-image: url(:/dark/radio_unchecked_disabled.svg); +} + +QMenu::indicator:exclusive:unchecked:selected +{ + border-image: url(:/dark/radio_unchecked_disabled.svg); +} + +QMenu::indicator:exclusive:checked +{ + border-image: url(:/dark/radio_checked.svg); +} + +QMenu::indicator:exclusive:checked:selected +{ + border-image: url(:/dark/radio_checked.svg); +} + +QMenu::right-arrow +{ + margin: 0.5ex; + border-image: url(:/light/right_arrow.svg); + width: 0.6ex; + height: 0.9ex; +} + + +QWidget:disabled +{ + color: #454545; + background-color: #31363b; +} + +QAbstractItemView +{ + alternate-background-color: #31363b; + color: #eff0f1; + border: 0.1ex solid 3A3939; + border-radius: 0.2ex; +} + +QWidget:focus, +QMenuBar:focus +{ + border: 0.1ex solid #3daee9; +} + +QTabWidget:focus, +QCheckBox:focus, +QRadioButton:focus, +QSlider:focus +{ + border: none; +} + +QLineEdit +{ + background-color: #232629; + padding: 0.5ex; + border-style: solid; + border: 0.1ex solid #76797c; + border-radius: 0.2ex; + color: #eff0f1; +} + +QGroupBox +{ + border: 0.1ex solid #76797c; + border-radius: 0.2ex; + padding-top: 1ex; + margin-top: 1ex; +} + +QGroupBox::title +{ + subcontrol-origin: margin; + subcontrol-position: top center; + padding-left: 0.1ex; + padding-right: 0.1ex; + margin-top: -0.7ex; +} + +QAbstractScrollArea +{ + border-radius: 0.2ex; + border: 0.1ex solid #76797c; + background-color: transparent; +} + +QScrollBar:horizontal +{ + height: 1.5ex; + margin: 0.3ex 1.5ex 0.3ex 1.5ex; + border: 0.1ex transparent #2A2929; + border-radius: 0.4ex; + background-color: #2A2929; +} + +QScrollBar::handle:horizontal +{ + background-color: #3daee9; + min-width: 0.5ex; + border-radius: 0.4ex; +} + +QScrollBar::add-line:horizontal +{ + margin: 0px 0.3ex 0px 0.3ex; + border-image: url(:/dark/right_arrow_disabled.svg); + width: 1ex; + height: 1ex; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal +{ + margin: 0ex 0.3ex 0ex 0.3ex; + border-image: url(:/dark/left_arrow_disabled.svg); + width: 1ex; + height: 1ex; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover, +QScrollBar::add-line:horizontal:on +{ + border-image: url(:/dark/right_arrow.svg); + width: 1ex; + height: 1ex; + subcontrol-position: right; + subcontrol-origin: margin; +} + + +QScrollBar::sub-line:horizontal:hover, +QScrollBar::sub-line:horizontal:on +{ + border-image: url(:/dark/left_arrow.svg); + width: 1ex; + height: 1ex; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:horizontal, +QScrollBar::down-arrow:horizontal +{ + background: none; +} + + +QScrollBar::add-page:horizontal, +QScrollBar::sub-page:horizontal +{ + background: none; +} + +QScrollBar:vertical +{ + background-color: #2A2929; + width: 1.5ex; + margin: 1.5ex 0.3ex 1.5ex 0.3ex; + border: 0.1ex transparent #2A2929; + border-radius: 0.4ex; +} + +QScrollBar::handle:vertical +{ + background-color: #3daee9; + min-height: 0.5ex; + border-radius: 0.4ex; +} + +QScrollBar::sub-line:vertical +{ + margin: 0.3ex 0ex 0.3ex 0ex; + border-image: url(:/dark/up_arrow_disabled.svg); + height: 1ex; + width: 1ex; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical +{ + margin: 0.3ex 0ex 0.3ex 0ex; + border-image: url(:/dark/down_arrow_disabled.svg); + height: 1ex; + width: 1ex; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover, +QScrollBar::sub-line:vertical:on +{ + + border-image: url(:/dark/up_arrow.svg); + height: 1ex; + width: 1ex; + subcontrol-position: top; + subcontrol-origin: margin; +} + + +QScrollBar::add-line:vertical:hover, +QScrollBar::add-line:vertical:on +{ + border-image: url(:/dark/down_arrow.svg); + height: 1ex; + width: 1ex; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical +{ + background: none; +} + + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical +{ + background: none; +} + +QTextEdit +{ + background-color: #232629; + color: #eff0f1; + border: 0.1ex solid #76797c; +} + +QPlainTextEdit +{ + background-color: #232629;; + color: #eff0f1; + border-radius: 0.2ex; + border: 0.1ex solid #76797c; +} + +QHeaderView::section +{ + background-color: #76797c; + color: #eff0f1; + padding: 0.5ex; + border: 0.1ex solid #76797c; +} + +QSizeGrip +{ + border-image: url(:/dark/sizegrip.svg); + width: 1.2ex; + height: 1.2ex; +} + +QMainWindow::separator +{ + background-color: #31363b; + color: white; + padding-left: 0.4ex; + spacing: 0.2ex; + border: 0.1ex dashed #76797c; +} + +QMainWindow::separator:hover +{ + + background-color: #787876; + color: white; + padding-left: 0.4ex; + border: 0.1ex solid #76797c; + spacing: 0.2ex; +} + +QMenu::separator +{ + height: 0.1ex; + background-color: #76797c; + color: white; + padding-left: 0.4ex; + margin-left: 1ex; + margin-right: 0.5ex; +} + +QFrame[frameShape="2"], /* QFrame::Panel == 0x0003 */ +QFrame[frameShape="3"], /* QFrame::WinPanel == 0x0003 */ +QFrame[frameShape="4"], /* QFrame::HLine == 0x0004 */ +QFrame[frameShape="5"], /* QFrame::VLine == 0x0005 */ +QFrame[frameShape="6"] /* QFrame::StyledPanel == 0x0006 */ +{ + border-width: 0.1ex; + padding: 0.1ex; + border-style: solid; + border-color: #31363b; + background-color: #76797c; + border-radius: 0.5ex; +} + +QStackedWidget +{ + border: 0.1ex transparent black; +} + +QToolBar +{ + border: 0.1ex transparent #393838; + background: 0.1ex solid #31363b; + font-weight: bold; +} + +QToolBar::handle:horizontal +{ + border-image: url(:/dark/hmovetoolbar.svg); + width = 1.6ex; + height = 6.4ex; +} + +QToolBar::handle:vertical +{ + border-image: url(:/dark/vmovetoolbar.svg); + width = 5.4ex; + height = 1ex; +} + +QToolBar::separator:horizontal +{ + border-image: url(:/dark/hsepartoolbar.svg); + width = 0.7ex; + height = 6.3ex; +} + +QToolBar::separator:vertical +{ + border-image: url(:/dark/vsepartoolbars.svg); + width = 6.3ex; + height = 0.7ex; +} + +QPushButton +{ + color: #eff0f1; + background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #3b4045, stop: 0.5 #31363b); + border-width: 0.1ex; + border-color: #76797c; + border-style: solid; + padding: 0.5ex; + border-radius: 0.2ex; + outline: none; +} + +QPushButton:disabled +{ + background-color: #31363b; + border-width: 0.1ex; + border-color: #454545; + border-style: solid; + padding-top: 0.5ex; + padding-bottom: 0.5ex; + padding-left: 1ex; + padding-right: 1ex; + border-radius: 0.2ex; + color: #454545; +} + +QPushButton:focus +{ + color: white; +} + +QPushButton:pressed +{ + background-color: #31363b; + padding-top: -1.5ex; + padding-bottom: -1.7ex; +} + +QComboBox +{ + selection-background-color: #3daee9; + border-style: solid; + border: 0.1ex solid #76797c; + border-radius: 0.2ex; + padding: 0.5ex; + min-width: 7.5ex; +} + +QPushButton:checked +{ + background-color: #76797c; + border-color: #6A6969; +} + +QPushButton:hover +{ + background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #454a4f, stop: 0.5 #3b4045); + border: 0.1ex solid #3daee9; + color: #eff0f1; +} + +QPushButton:checked:hover +{ + background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #808386, stop: 0.5 #76797c); + border: 0.1ex solid #3daee9; + color: #eff0f1; +} + +QComboBox:hover, +QAbstractSpinBox:hover, +QLineEdit:hover, +QTextEdit:hover, +QPlainTextEdit:hover, +QAbstractView:hover, +QTreeView:hover +{ + border: 0.1ex solid #3daee9; + color: #eff0f1; +} + +QComboBox:hover:pressed, +QPushButton:hover:pressed, +QAbstractSpinBox:hover:pressed, +QLineEdit:hover:pressed, +QTextEdit:hover:pressed, +QPlainTextEdit:hover:pressed, +QAbstractView:hover:pressed, +QTreeView:hover:pressed +{ + background-color: #31363b; +} + +QComboBox:on +{ + padding-top: 0.3ex; + padding-left: 0.4ex; + selection-background-color: #4a4a4a; +} + +QComboBox QAbstractItemView +{ + background-color: #232629; + border-radius: 0.2ex; + border: 0.1ex solid #76797c; + selection-background-color: #3daee9; +} + +QComboBox::drop-down +{ + subcontrol-origin: padding; + subcontrol-position: top right; + width: 1.5ex; + + border-left-width: 0ex; + border-left-color: darkgray; + border-left-style: solid; + border-top-right-radius: 0.3ex; + border-bottom-right-radius: 0.3ex; +} + +QComboBox::down-arrow +{ + border-image: url(:/dark/down_arrow_disabled.svg); + width: 0.9ex; + height: 0.6ex; +} + +QComboBox::down-arrow:on, +QComboBox::down-arrow:hover, +QComboBox::down-arrow:focus +{ + border-image: url(:/dark/down_arrow.svg); + width: 0.9ex; + height: 0.6ex; +} + +QAbstractSpinBox +{ + padding: 0.5ex; + border: 0.1ex solid #76797c; + background-color: #232629; + color: #eff0f1; + border-radius: 0.2ex; + min-width: 7.5ex; +} + +QAbstractSpinBox:up-button +{ + background-color: transparent; + subcontrol-origin: border; + subcontrol-position: center right; +} + +QAbstractSpinBox:down-button +{ + background-color: transparent; + subcontrol-origin: border; + subcontrol-position: center left; +} + +QAbstractSpinBox::up-arrow, +QAbstractSpinBox::up-arrow:disabled, +QAbstractSpinBox::up-arrow:off +{ + border-image: url(:/dark/up_arrow_disabled.svg); + width: 0.9ex; + height: 0.6ex; +} + +QAbstractSpinBox::up-arrow:hover +{ + border-image: url(:/dark/up_arrow.svg); + width: 0.9ex; + height: 0.6ex; +} + +QAbstractSpinBox::down-arrow, +QAbstractSpinBox::down-arrow:disabled, +QAbstractSpinBox::down-arrow:off +{ + border-image: url(:/dark/down_arrow_disabled.svg); + width: 0.9ex; + height: 0.6ex; +} + +QAbstractSpinBox::down-arrow:hover +{ + border-image: url(:/dark/down_arrow.svg); + width: 0.9ex; + height: 0.6ex; +} + +QLabel +{ + border: 0ex solid black; +} + +/* BORDERS */ +QTabWidget::pane +{ + padding: 0.5ex; + margin: 0.1ex; +} + +QTabWidget::pane:top +{ + border: 0.1ex solid #76797c; + top: -0.1ex; +} + +QTabWidget::pane:bottom +{ + border: 0.1ex solid #76797c; + bottom: -0.1ex; +} + +QTabWidget::pane:left +{ + border: 0.1ex solid #76797c; + right: -0.1ex; +} + +QTabWidget::pane:right +{ + border: 0.1ex solid #76797c; + left: -0.1ex; +} + + +QTabBar +{ + qproperty-drawBase: 0; + left: 0.5ex; /* move to the right by 0.5ex */ + border-radius: 0.3ex; +} + +QTabBar:focus +{ + border: 0ex transparent black; +} + +QTabBar::close-button +{ + border-image: url(:/dark/close.svg); + background: transparent; +} + +QTabBar::close-button:hover +{ + border-image: url(:/dark/close-hover.svg); + width: 1.2ex; + height: 1.2ex; + background: transparent; +} + +QTabBar::close-button:pressed +{ + border-image: url(:/dark/close-pressed.svg); + width: 1.2ex; + height: 1.2ex; + background: transparent; +} + +/* TOP TABS */ +QTabBar::tab:top +{ + color: #eff0f1; + border: 0.1ex transparent black; + border-left: 0.1ex solid #76797c; + border-top: 0.1ex solid #76797c; + background-color: #31363b; + padding: 0.5ex; + min-width: 50px; + border-top-left-radius: 0.2ex; + border-top-right-radius: 0.2ex; +} + +QTabBar::tab:top:last, +QTabBar::tab:top:only-one +{ + color: #eff0f1; + border: 0.1ex transparent black; + border-left: 0.1ex solid #76797c; + border-right: 0.1ex solid #76797c; + border-top: 0.1ex solid #76797c; + background-color: #31363b; + padding: 0.5ex; + min-width: 50px; + border-top-left-radius: 0.2ex; + border-top-right-radius: 0.2ex; +} + +QTabBar::tab:top:!selected +{ + color: #eff0f1; + background-color: #54575B; + border: 0.1ex transparent black; + border-left: 0.1ex solid #76797c; + border-top-left-radius: 0.2ex; + border-top-right-radius: 0.2ex; +} + +QTabBar::tab:top:first:!selected +{ + color: #eff0f1; + background-color: #54575B; + border: 0.1ex transparent black; + border-top-left-radius: 0.2ex; + border-top-right-radius: 0.2ex; +} + +QTabBar::tab:top:!selected:hover +{ + background-color: rgba(61, 173, 232, 0.2); + border: 0.1ex rgba(61, 173, 232, 0.2); + border-left: 0.1ex solid #76797c; +} + +QTabBar::tab:top:!selected:first:hover +{ + background-color: rgba(61, 173, 232, 0.2); + border: 0.1ex rgba(61, 173, 232, 0.2); +} + +/* BOTTOM TABS */ + +QTabBar::tab:bottom +{ + color: #eff0f1; + border: 0.1ex transparent black; + border-left: 0.1ex solid #76797c; + border-bottom: 0.1ex solid #76797c; + background-color: #31363b; + padding: 0.5ex; + border-bottom-left-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; + min-width: 50px; +} + +QTabBar::tab:bottom:last, +QTabBar::tab:bottom:only-one +{ + color: #eff0f1; + border: 0.1ex transparent black; + border-left: 0.1ex solid #76797c; + border-right: 0.1ex solid #76797c; + border-bottom: 0.1ex solid #76797c; + background-color: #31363b; + padding: 0.5ex; + border-bottom-left-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; + min-width: 50px; +} + +QTabBar::tab:bottom:!selected +{ + color: #eff0f1; + background-color: #54575B; + border: 0.1ex transparent black; + border-left: 0.1ex solid #76797c; + border-bottom-left-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; +} + +QTabBar::tab:bottom:first:!selected +{ + color: #eff0f1; + background-color: #54575B; + border: 0.1ex transparent black; + border-top-left-radius: 0.2ex; + border-top-right-radius: 0.2ex; +} + +QTabBar::tab:bottom:!selected:hover +{ + background-color: rgba(61, 173, 232, 0.2); + border: 0.1ex rgba(61, 173, 232, 0.2); + border-left: 0.1ex solid #76797c; +} + +QTabBar::tab:bottom:!selected:first:hover +{ + background-color: rgba(61, 173, 232, 0.2); + border: 0.1ex rgba(61, 173, 232, 0.2); +} + +/* LEFT TABS */ +QTabBar::tab:left +{ + color: #eff0f1; + border: 0.1ex transparent black; + border-top: 0.1ex solid #76797c; + border-right: 0.1ex solid #76797c; + background-color: #31363b; + padding: 0.5ex; + border-top-right-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; + min-height: 50px; +} + +QTabBar::tab:left:last, +QTabBar::tab:left:only-one +{ + color: #eff0f1; + border: 0.1ex transparent black; + border-top: 0.1ex solid #76797c; + border-bottom: 0.1ex solid #76797c; + border-right: 0.1ex solid #76797c; + background-color: #31363b; + padding: 0.5ex; + border-top-right-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; + min-height: 50px; +} + +QTabBar::tab:left:!selected +{ + color: #eff0f1; + background-color: #54575B; + border: 0.1ex transparent black; + border-top: 0.1ex solid #76797c; + border-top-right-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; +} + +QTabBar::tab:left:!selected:hover +{ + background-color: rgba(61, 173, 232, 0.2); + border: 0.1ex rgba(61, 173, 232, 0.2); + border-top: 0.1ex solid #76797c; +} + +QTabBar::tab:left:!selected:first:hover +{ + background-color: rgba(61, 173, 232, 0.2); + border: 0.1ex rgba(61, 173, 232, 0.2); +} + +/* RIGHT TABS */ +QTabBar::tab:right +{ + color: #eff0f1; + border: 0.1ex transparent black; + border-top: 0.1ex solid #76797c; + border-left: 0.1ex solid #76797c; + background-color: #31363b; + padding: 0.5ex; + border-top-left-radius: 0.2ex; + border-bottom-left-radius: 0.2ex; + min-height: 50px; +} + +QTabBar::tab:right:last, +QTabBar::tab:right:only-one +{ + color: #eff0f1; + border: 0.1ex transparent black; + border-top: 0.1ex solid #76797c; + border-bottom: 0.1ex solid #76797c; + border-left: 0.1ex solid #76797c; + background-color: #31363b; + padding: 0.5ex; + border-top-left-radius: 0.2ex; + border-bottom-left-radius: 0.2ex; + min-height: 50px; +} + +QTabBar::tab:right:!selected +{ + color: #eff0f1; + background-color: #54575B; + border: 0.1ex transparent black; + border-top: 0.1ex solid #76797c; + border-top-left-radius: 0.2ex; + border-bottom-left-radius: 0.2ex; +} + +QTabBar::tab:right:!selected:hover +{ + background-color: rgba(61, 173, 232, 0.2); + border: 0.1ex rgba(61, 173, 232, 0.2); + border-top: 0.1ex solid #76797c; +} + +QTabBar::tab:right:!selected:first:hover +{ + background-color: rgba(61, 173, 232, 0.2); + border: 0.1ex rgba(61, 173, 232, 0.2); +} + +QTabBar QToolButton::right-arrow:enabled +{ + border-image: url(:/dark/right_arrow.svg); +} + +QTabBar QToolButton::left-arrow:enabled +{ + border-image: url(:/dark/left_arrow.svg); +} + +QTabBar QToolButton::right-arrow:disabled +{ + border-image: url(:/dark/right_arrow_disabled.svg); +} + +QTabBar QToolButton::left-arrow:disabled +{ + border-image: url(:/dark/left_arrow_disabled.svg); +} + +QDockWidget +{ + background: #31363b; + border: 0.1ex solid #403F3F; + titlebar-close-icon: url(:/dark/transparent.svg); + titlebar-normal-icon: url(:/dark/transparent.svg); +} + +QDockWidget::close-button, +QDockWidget::float-button +{ + border: 0.1ex solid transparent; + border-radius: 0.2ex; + background: transparent; +} + +QDockWidget::float-button +{ + border-image: url(:/dark/undock.svg); +} + +QDockWidget::float-button:hover +{ + border-image: url(:/dark/undock-hover.svg) ; +} + +QDockWidget::close-button +{ + border-image: url(:/dark/close.svg) ; +} + +QDockWidget::close-button:hover +{ + border-image: url(:/dark/close-hover.svg) ; +} + +QDockWidget::close-button:pressed +{ + border-image: url(:/dark/close-pressed.svg) ; +} + +QTreeView, +QListView +{ + border: 0.1ex solid #76797c; + background-color: #232629; +} + +QTreeView::branch:has-siblings:!adjoins-item +{ + border-image: url(:/dark/stylesheet-vline.svg) 0; +} + +QTreeView::branch:has-siblings:adjoins-item +{ + border-image: url(:/dark/stylesheet-branch-more.svg) 0; +} + +QTreeView::branch:!has-children:!has-siblings:adjoins-item +{ + border-image: url(:/dark/stylesheet-branch-end.svg) 0; +} + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings +{ + border-image: url(:/dark/stylesheet-branch-end-closed.svg) 0; + image: url(:/dark/branch_closed.svg); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings +{ + border-image: url(:/dark/stylesheet-branch-end-open.svg) 0; + image: url(:/dark/branch_open.svg); +} + +/* +QTreeView::branch:has-siblings:!adjoins-item { + background: cyan; +} + +QTreeView::branch:has-siblings:adjoins-item { + background: red; +} + +QTreeView::branch:!has-children:!has-siblings:adjoins-item { + background: blue; +} + +QTreeView::branch:closed:has-children:has-siblings { + background: pink; +} + +QTreeView::branch:has-children:!has-siblings:closed { + background: gray; +} + +QTreeView::branch:open:has-children:has-siblings { + background: magenta; +} + +QTreeView::branch:open:has-children:!has-siblings { + background: green; +} +*/ + +QTableView::item, +QListView::item, +QTreeView::item +{ + padding: 0.3ex; +} + +QTableView::item:!selected:hover, +QListView::item:!selected:hover, +QTreeView::item:!selected:hover +{ + background-color: rgba(61, 173, 232, 0.2); + outline: 0; + color: #eff0f1; + padding: 0.3ex; +} + + +QSlider::groove:horizontal +{ + border: 0.1ex solid #31363b; + height: 0.4ex; + background: #565a5e; + margin: 0ex; + border-radius: 0.2ex; +} + +QSlider::handle:horizontal +{ + background: #232629; + border: 0.1ex solid #626568; + width: 1.6ex; + height: 1.6ex; + margin: -0.8ex 0; + border-radius: 0.9ex; +} + +QSlider::groove:vertical +{ + border: 0.1ex solid #31363b; + width: 0.4ex; + background: #565a5e; + margin: 0ex; + border-radius: 0.3ex; +} + +QSlider::handle:vertical +{ + background: #232629; + border: 0.1ex solid #626568; + width: 1.6ex; + height: 1.6ex; + margin: 0 -0.8ex; + border-radius: 0.9ex; +} + +QSlider::handle:horizontal:hover, +QSlider::handle:horizontal:focus, +QSlider::handle:vertical:hover, +QSlider::handle:vertical:focus +{ + border: 0.1ex solid #3daee9; +} + +QSlider::sub-page:horizontal, +QSlider::add-page:vertical +{ + background: #3daee9; + border-radius: 0.3ex; +} + +QSlider::add-page:horizontal, +QSlider::sub-page:vertical +{ + background: #626568; + border-radius: 0.3ex; +} + +QToolButton +{ + background-color: transparent; + border: 0.1ex solid #76797c; + border-radius: 0.2ex; + margin: 0.3ex; + padding: 0.5ex; +} + +QToolButton[popupMode="1"] /* only for MenuButtonPopup */ +{ + padding-right: 2ex; /* make way for the popup button */ +} + +QToolButton[popupMode="2"] /* only for InstantPopup */ +{ + padding-right: 1ex; /* make way for the popup button */ +} + +QToolButton::menu-indicator +{ + border-image: none; + image: url(:/dark/down_arrow.svg); + top: -0.7ex; + left: -0.2ex; +} + +QToolButton::menu-arrow +{ + border-image: none; + image: url(:/dark/down_arrow.svg); +} + +QToolButton:hover, +QToolButton::menu-button:hover +{ + background-color: transparent; + border: 0.1ex solid #3daee9; +} + +QToolButton:checked, +QToolButton:pressed, +QToolButton::menu-button:pressed +{ + background-color: #3daee9; + border: 0.1ex solid #3daee9; + padding: 0.5ex; +} + +QToolButton::menu-button +{ + border: 0.1ex solid #76797c; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + /* 1ex width + 0.4ex for border + no text = 2ex allocated above */ + width: 1ex; + padding: 0.5ex; + outline: none; +} + +QToolButton::menu-arrow:open +{ + border: 0.1ex solid #76797c; +} + +QPushButton::menu-indicator +{ + subcontrol-origin: padding; + subcontrol-position: bottom right; + left: 0.8ex; +} + +QTableView +{ + border: 0.1ex solid #76797c; + gridline-color: #31363b; + background-color: #232629; +} + + +QTableView, +QHeaderView +{ + border-radius: 0px; +} + +QTableView::item:pressed, +QListView::item:pressed, +QTreeView::item:pressed +{ + background: #3daee9; + color: #eff0f1; +} + +QTableView::item:selected:active, +QTreeView::item:selected:active, +QListView::item:selected:active +{ + background: #3daee9; + color: #eff0f1; +} + +QListView::item:selected:hover, +QTreeView::item:selected:hover +{ + background-color: #47b8f3; + color: #eff0f1; +} + +QHeaderView +{ + background-color: #31363b; + border: 0.1ex transparent; + border-radius: 0px; + margin: 0px; + padding: 0px; + +} + +QHeaderView::section +{ + background-color: #31363b; + color: #eff0f1; + padding: 0.5ex; + border: 0.1ex solid #76797c; + border-radius: 0px; + text-align: center; +} + +QHeaderView::section::vertical::first, +QHeaderView::section::vertical::only-one +{ + border-top: 0.1ex solid #76797c; +} + +QHeaderView::section::vertical +{ + border-top: transparent; +} + +QHeaderView::section::horizontal::first, +QHeaderView::section::horizontal::only-one +{ + border-left: 0.1ex solid #76797c; +} + +QHeaderView::section::horizontal +{ + border-left: transparent; +} + + +QHeaderView::section:checked +{ + color: white; + background-color: #334e5e; +} + + /* style the sort indicator */ +QHeaderView::down-arrow +{ + image: url(:/dark/down_arrow.svg); +} + +QHeaderView::up-arrow +{ + image: url(:/dark/up_arrow.svg); +} + +QTableCornerButton::section +{ + background-color: #31363b; + border: 0.1ex transparent #76797c; + border-radius: 0px; +} + +QToolBox +{ + padding: 0.5ex; + border: 0.1ex transparent black; +} + +QToolBox:selected +{ + background-color: #31363b; + border-color: #3daee9; +} + +QToolBox:hover +{ + border-color: #3daee9; +} + +QStatusBar::item +{ + border: 0px transparent dark; +} + +QFrame[height="3"], +QFrame[width="3"] +{ + background-color: #76797c; +} + +QSplitter::handle +{ + border: 0.1ex dashed #76797c; +} + +QSplitter::handle:hover +{ + background-color: #787876; + border: 0.1ex solid #76797c; +} + +QSplitter::handle:horizontal +{ + width: 0.1ex; +} + +QSplitter::handle:vertical +{ + height: 0.1ex; +} + +QProgressBar:horizontal +{ + background-color: #626568; + border: 0.1ex solid #31363b; + border-radius: 0.3ex; + height: 0.5ex; + text-align: right; + margin-top: 0.5ex; + margin-bottom: 0.5ex; + margin-right: 5ex; + padding: 0px; +} + +QProgressBar::chunk:horizontal +{ + background-color: #3daee9; + border: 0.1ex transparent; + border-radius: 0.3ex; +} + +QSpinBox, +QDoubleSpinBox +{ + padding-right: 1.5ex; +} + +QSpinBox::up-button, +QDoubleSpinBox::up-button +{ + subcontrol-origin: content; + subcontrol-position: right top; + + width: 1.6ex; + border-width: 0.1ex; +} + +QSpinBox::up-arrow, +QDoubleSpinBox::up-arrow +{ + border-image: url(:/dark/up_arrow.svg); + width: 0.9ex; + height: 0.6ex; +} + +QSpinBox::up-arrow:hover, +QSpinBox::up-arrow:pressed, +QDoubleSpinBox::up-arrow:hover, +QDoubleSpinBox::up-arrow:pressed +{ + border-image: url(:/dark/up_arrow-hover.svg); + width: 0.9ex; + height: 0.6ex; +} + +QSpinBox::up-arrow:disabled, +QSpinBox::up-arrow:off, +QDoubleSpinBox::up-arrow:disabled, +QDoubleSpinBox::up-arrow:off +{ + border-image: url(:/dark/up_arrow_disabled.svg); +} + +QSpinBox::down-button, +QDoubleSpinBox::down-button +{ + subcontrol-origin: content; + subcontrol-position: right bottom; + + width: 1.6ex; + border-width: 0.1ex; +} + +QSpinBox::down-arrow, +QDoubleSpinBox::down-arrow +{ + border-image: url(:/dark/down_arrow.svg); + width: 0.9ex; + height: 0.6ex; +} + +QSpinBox::down-arrow:hover, +QSpinBox::down-arrow:pressed, +QDoubleSpinBox::down-arrow:hover, +QDoubleSpinBox::down-arrow:pressed +{ + border-image: url(:/dark/down_arrow-hover.svg); + width: 0.9ex; + height: 0.6ex; +} + +QSpinBox::down-arrow:disabled, +QSpinBox::down-arrow:off, +QDoubleSpinBox::down-arrow:disabled, +QDoubleSpinBox::down-arrow:off +{ + border-image: url(:/dark/down_arrow_disabled.svg); +} + +/* fixes */ + +QPushButton:flat { + background-color: transparent; + border: none; +} + +QLabel:disabled { + color: #787878; +} + +QTableView::item:!selected:hover +{ + background-color: transparent; +} \ No newline at end of file diff --git a/src/ui/BreezeStyleSheets/dark/branch_closed-on.svg b/src/ui/BreezeStyleSheets/dark/branch_closed-on.svg new file mode 100755 index 0000000..8bd398f --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/branch_closed-on.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/branch_closed.svg b/src/ui/BreezeStyleSheets/dark/branch_closed.svg new file mode 100755 index 0000000..f5a072f --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/branch_closed.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/branch_open-on.svg b/src/ui/BreezeStyleSheets/dark/branch_open-on.svg new file mode 100755 index 0000000..4dd0c06 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/branch_open-on.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/branch_open.svg b/src/ui/BreezeStyleSheets/dark/branch_open.svg new file mode 100755 index 0000000..0745890 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/branch_open.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/checkbox_checked.svg b/src/ui/BreezeStyleSheets/dark/checkbox_checked.svg new file mode 100755 index 0000000..6753d8b --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/checkbox_checked.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/dark/checkbox_checked_disabled.svg b/src/ui/BreezeStyleSheets/dark/checkbox_checked_disabled.svg new file mode 100755 index 0000000..ff7e63a --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/checkbox_checked_disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/dark/checkbox_indeterminate.svg b/src/ui/BreezeStyleSheets/dark/checkbox_indeterminate.svg new file mode 100755 index 0000000..0f17124 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/checkbox_indeterminate.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/ui/BreezeStyleSheets/dark/checkbox_indeterminate_disabled.svg b/src/ui/BreezeStyleSheets/dark/checkbox_indeterminate_disabled.svg new file mode 100755 index 0000000..bc0f285 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/checkbox_indeterminate_disabled.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/ui/BreezeStyleSheets/dark/checkbox_unchecked.svg b/src/ui/BreezeStyleSheets/dark/checkbox_unchecked.svg new file mode 100755 index 0000000..6f3e569 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/checkbox_unchecked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/dark/checkbox_unchecked_disabled.svg b/src/ui/BreezeStyleSheets/dark/checkbox_unchecked_disabled.svg new file mode 100755 index 0000000..dd73f75 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/checkbox_unchecked_disabled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/dark/close-hover.svg b/src/ui/BreezeStyleSheets/dark/close-hover.svg new file mode 100755 index 0000000..e2b0dd8 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/close-hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/close-pressed.svg b/src/ui/BreezeStyleSheets/dark/close-pressed.svg new file mode 100755 index 0000000..a0dc249 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/close-pressed.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/close.svg b/src/ui/BreezeStyleSheets/dark/close.svg new file mode 100755 index 0000000..07b50c9 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/close.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/down_arrow-hover.svg b/src/ui/BreezeStyleSheets/dark/down_arrow-hover.svg new file mode 100755 index 0000000..408397f --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/down_arrow-hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/down_arrow.svg b/src/ui/BreezeStyleSheets/dark/down_arrow.svg new file mode 100755 index 0000000..a50df00 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/down_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/down_arrow_disabled.svg b/src/ui/BreezeStyleSheets/dark/down_arrow_disabled.svg new file mode 100755 index 0000000..af74a30 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/down_arrow_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/hmovetoolbar.svg b/src/ui/BreezeStyleSheets/dark/hmovetoolbar.svg new file mode 100755 index 0000000..e4904db --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/hmovetoolbar.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/dark/hsepartoolbar.svg b/src/ui/BreezeStyleSheets/dark/hsepartoolbar.svg new file mode 100755 index 0000000..89beb22 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/hsepartoolbar.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/left_arrow.svg b/src/ui/BreezeStyleSheets/dark/left_arrow.svg new file mode 100755 index 0000000..9c787ce --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/left_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/left_arrow_disabled.svg b/src/ui/BreezeStyleSheets/dark/left_arrow_disabled.svg new file mode 100755 index 0000000..2d749e7 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/left_arrow_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/radio_checked.svg b/src/ui/BreezeStyleSheets/dark/radio_checked.svg new file mode 100755 index 0000000..b8f7064 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/radio_checked.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/dark/radio_checked_disabled.svg b/src/ui/BreezeStyleSheets/dark/radio_checked_disabled.svg new file mode 100755 index 0000000..523ee00 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/radio_checked_disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/dark/radio_unchecked.svg b/src/ui/BreezeStyleSheets/dark/radio_unchecked.svg new file mode 100755 index 0000000..1a556e3 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/radio_unchecked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/dark/radio_unchecked_disabled.svg b/src/ui/BreezeStyleSheets/dark/radio_unchecked_disabled.svg new file mode 100755 index 0000000..b3da8a2 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/radio_unchecked_disabled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/dark/right_arrow.svg b/src/ui/BreezeStyleSheets/dark/right_arrow.svg new file mode 100755 index 0000000..b793513 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/right_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/right_arrow_disabled.svg b/src/ui/BreezeStyleSheets/dark/right_arrow_disabled.svg new file mode 100755 index 0000000..4940025 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/right_arrow_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/sizegrip.svg b/src/ui/BreezeStyleSheets/dark/sizegrip.svg new file mode 100755 index 0000000..3388f07 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/sizegrip.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/spinup_disabled.svg b/src/ui/BreezeStyleSheets/dark/spinup_disabled.svg new file mode 100755 index 0000000..838436d --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/spinup_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/stylesheet-branch-end-closed.svg b/src/ui/BreezeStyleSheets/dark/stylesheet-branch-end-closed.svg new file mode 100755 index 0000000..eb73b13 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/stylesheet-branch-end-closed.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/dark/stylesheet-branch-end-open.svg b/src/ui/BreezeStyleSheets/dark/stylesheet-branch-end-open.svg new file mode 100755 index 0000000..eb73b13 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/stylesheet-branch-end-open.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/dark/stylesheet-branch-end.svg b/src/ui/BreezeStyleSheets/dark/stylesheet-branch-end.svg new file mode 100755 index 0000000..334ca0c --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/stylesheet-branch-end.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/dark/stylesheet-branch-more.svg b/src/ui/BreezeStyleSheets/dark/stylesheet-branch-more.svg new file mode 100755 index 0000000..f5250ba --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/stylesheet-branch-more.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/dark/stylesheet-vline.svg b/src/ui/BreezeStyleSheets/dark/stylesheet-vline.svg new file mode 100755 index 0000000..4e7ff6a --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/stylesheet-vline.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/transparent.svg b/src/ui/BreezeStyleSheets/dark/transparent.svg new file mode 100755 index 0000000..3a8ca5c --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/transparent.svg @@ -0,0 +1 @@ + diff --git a/src/ui/BreezeStyleSheets/dark/undock-hover.svg b/src/ui/BreezeStyleSheets/dark/undock-hover.svg new file mode 100755 index 0000000..6bddbd7 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/undock-hover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/dark/undock.svg b/src/ui/BreezeStyleSheets/dark/undock.svg new file mode 100755 index 0000000..9ab2197 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/undock.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/up_arrow-hover.svg b/src/ui/BreezeStyleSheets/dark/up_arrow-hover.svg new file mode 100755 index 0000000..dd1271a --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/up_arrow-hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/up_arrow.svg b/src/ui/BreezeStyleSheets/dark/up_arrow.svg new file mode 100755 index 0000000..9f42239 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/up_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/up_arrow_disabled.svg b/src/ui/BreezeStyleSheets/dark/up_arrow_disabled.svg new file mode 100755 index 0000000..742e1c5 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/up_arrow_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/dark/vmovetoolbar.svg b/src/ui/BreezeStyleSheets/dark/vmovetoolbar.svg new file mode 100755 index 0000000..0a30d45 --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/vmovetoolbar.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/ui/BreezeStyleSheets/dark/vsepartoolbars.svg b/src/ui/BreezeStyleSheets/dark/vsepartoolbars.svg new file mode 100755 index 0000000..00e91ab --- /dev/null +++ b/src/ui/BreezeStyleSheets/dark/vsepartoolbars.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/ui/BreezeStyleSheets/light.qss b/src/ui/BreezeStyleSheets/light.qss new file mode 100644 index 0000000..27feca9 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light.qss @@ -0,0 +1,1685 @@ +/* + * Breeze stylesheet. + * + * :author: Colin Duquesnoy + * :editor: Alex Huszagh + * :license: MIT, see LICENSE.md + * + * This is originally a fork of QDarkStyleSheet, and is based on Breeze/ + * BreezeDark color scheme, but is in no way affiliated with KDE. + * + * --------------------------------------------------------------------- + * The MIT License (MIT) + * + * Copyright (c) <2013-2014> + * Copyright (c) <2015-2016> + * + * 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. + * --------------------------------------------------------------------- + */ + +QToolTip +{ + background-color: black; + color: white; + padding: 0.5ex; +} + +QWidget +{ + color: #31363B; + background-color: #EFF0F1; + selection-background-color:#33A4DF; + selection-color: #31363B; + background-clip: border; + border-image: none; + border: 0px transparent black; + outline: 0; +} + +QWidget:item:hover +{ + background-color: #33A4DF; + color: #31363B; +} + +QWidget:item:selected +{ + background-color: #33A4DF; +} + + +QCheckBox +{ + spacing: 0.5ex; + outline: none; + color: #31363B; + margin-bottom: 0.2ex; + opacity: 200; +} + +QCheckBox:disabled +{ + color: #BAB9B8; +} + +QGroupBox::indicator +{ + margin-left: 0.2ex; + margin-left: 0.2ex; +} + +QCheckBox::indicator:unchecked, +QCheckBox::indicator:unchecked:focus +{ + border-image: url(:/light/checkbox_unchecked_disabled.svg); +} + +QCheckBox::indicator:unchecked:hover, +QCheckBox::indicator:unchecked:pressed, +QGroupBox::indicator:unchecked:hover, +QGroupBox::indicator:unchecked:focus, +QGroupBox::indicator:unchecked:pressed +{ + border: none; + border-image: url(:/light/checkbox_unchecked-hover.svg); +} + +QCheckBox::indicator:checked +{ + border-image: url(:/light/checkbox_checked.svg); +} + +QCheckBox::indicator:checked:focus, +QCheckBox::indicator:checked:pressed, +QGroupBox::indicator:checked:focus, +QGroupBox::indicator:checked:pressed +{ + border: none; + border-image: url(:/light/checkbox_checked.svg); +} + +QCheckBox::indicator:checked:hover, +QGroupBox::indicator:checked:hover +{ + border-image: url(:/light/checkbox_checked-hover.svg); +} + +QCheckBox::indicator:indeterminate +{ + border-image: url(:/light/checkbox_indeterminate.svg); +} + +QCheckBox::indicator:indeterminate:hover +{ + border-image: url(:/light/checkbox_indeterminate-hover.svg); +} + +QCheckBox::indicator:indeterminate:focus, +QCheckBox::indicator:indeterminate:pressed +{ +} + +QCheckBox::indicator:indeterminate:disabled +{ + border-image: url(:/light/checkbox_indeterminate_disabled.svg); +} + +QCheckBox::indicator:checked:disabled, +QGroupBox::indicator:checked:disabled +{ + border-image: url(:/light/checkbox_checked_disabled.svg); +} + +QCheckBox::indicator:unchecked:disabled, +QGroupBox::indicator:unchecked:disabled +{ + border-image: url(:/light/checkbox_unchecked_disabled.svg); +} + +QRadioButton +{ + spacing: 0.5ex; + outline: none; + color: #31363B; + margin-bottom: 0.2ex; +} + +QRadioButton:disabled +{ + color: #BAB9B8; +} + +QRadioButton::indicator:unchecked, +QRadioButton::indicator:unchecked:focus +{ + border-image: url(:/light/radio_unchecked_disabled.svg); +} + +QRadioButton::indicator:unchecked:hover, +QRadioButton::indicator:unchecked:pressed +{ + border: none; + outline: none; + border-image: url(:/light/radio_unchecked-hover.svg); +} + +QRadioButton::indicator:checked +{ + border: none; + outline: none; + border-image: url(:/light/radio_checked.svg); +} + +QRadioButton::indicator:checked:focus, +QRadioButton::indicator:checked:pressed +{ + border: none; + outline: none; + border-image: url(:/light/radio_checked.svg); +} + +QRadioButton::indicator:checked:hover +{ + border-image: url(:/light/radio_checked-hover.svg); +} + +QRadioButton::indicator:checked:disabled +{ + outline: none; + border-image: url(:/light/radio_checked_disabled.svg); +} + +QRadioButton::indicator:unchecked:disabled +{ + border-image: url(:/light/radio_unchecked_disabled.svg); +} + +QMenuBar +{ + background-color: #EFF0F1; + color: #31363B; +} + +QMenuBar::item +{ + background: transparent; +} + +QMenuBar::item:selected +{ + background: transparent; + border: 0.1ex solid #BAB9B8; +} + +QMenuBar::item:pressed +{ + border: 0.1ex solid #BAB9B8; + background-color: #33A4DF; + color: #31363B; + margin-bottom: -0.1ex; + padding-bottom: 0.1ex; +} + +QMenu +{ + border: 0.1ex solid #BAB9B8; + color: #31363B; + margin: 0.2ex; +} + +QMenu::icon +{ + margin: 0.5ex; +} + +QMenu::item +{ + padding: 0.5ex 3ex 0.5ex 3ex; + margin-left: 0.5ex; + border: 0.1ex solid transparent; /* reserve space for selection border */ +} + +QMenu::item:selected +{ + color: #31363B; +} + +QMenu::separator +{ + height: 0.2ex; + background: lightblue; + margin-left: 1ex; + margin-right: 0.5ex; +} + +/* non-exclusive indicator = check box style indicator + (see QActionGroup::setExclusive) */ +QMenu::indicator:non-exclusive:unchecked +{ + border-image: url(:/light/checkbox_unchecked_disabled.svg); +} + +QMenu::indicator:non-exclusive:unchecked:selected +{ + border-image: url(:/light/checkbox_unchecked_disabled.svg); +} + +QMenu::indicator:non-exclusive:checked +{ + border-image: url(:/light/checkbox_checked.svg); +} + +QMenu::indicator:non-exclusive:checked:selected +{ + border-image: url(:/light/checkbox_checked.svg); +} + +/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ +QMenu::indicator:exclusive:unchecked +{ + border-image: url(:/light/radio_unchecked_disabled.svg); +} + +QMenu::indicator:exclusive:unchecked:selected +{ + border-image: url(:/light/radio_unchecked_disabled.svg); +} + +QMenu::indicator:exclusive:checked +{ + border-image: url(:/light/radio_checked.svg); +} + +QMenu::indicator:exclusive:checked:selected +{ + border-image: url(:/light/radio_checked.svg); +} + +QMenu::right-arrow +{ + margin: 0.5ex; + border-image: url(:/light/right_arrow.svg); + width: 0.6ex; + height: 0.9ex; +} + + +QWidget:disabled +{ + color: #454545; + background-color: #EFF0F1; +} + +QAbstractItemView +{ + alternate-background-color: #EFF0F1; + color: #31363B; + border: 0.1ex solid 3A3939; + border-radius: 0.2ex; +} + +QWidget:focus, +QMenuBar:focus +{ + border: 0.1ex solid #33A4DF; +} + +QTabWidget:focus, +QCheckBox:focus, +QRadioButton:focus, +QSlider:focus +{ + border: none; +} + +QLineEdit +{ + background-color: #FCFCFC; + padding: 0.5ex; + border-style: solid; + border: 0.1ex solid #BAB9B8; + border-radius: 0.2ex; + color: #31363B; +} + +QGroupBox +{ + border: 0.1ex solid #BAB9B8; + border-radius: 0.2ex; + padding-top: 1ex; + margin-top: 1ex; +} + +QGroupBox::title +{ + subcontrol-origin: margin; + subcontrol-position: top center; + padding-left: 0.1ex; + padding-right: 0.1ex; + margin-top: -0.7ex; +} + +QAbstractScrollArea +{ + border-radius: 0.2ex; + border: 0.1ex solid #BAB9B8; + background-color: transparent; +} + +QScrollBar:horizontal +{ + height: 1.5ex; + margin: 0.3ex 1.5ex 0.3ex 1.5ex; + border: 0.1ex transparent #2A2929; + border-radius: 0.4ex; + background-color: #2A2929; +} + +QScrollBar::handle:horizontal +{ + background-color: #605F5F; + min-width: 0.5ex; + border-radius: 0.4ex; +} + +QScrollBar::add-line:horizontal +{ + margin: 0ex 0.3ex 0ex 0.3ex; + border-image: url(:/light/right_arrow_disabled.svg); + width: 1ex; + height: 1ex; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal +{ + margin: 0px 0.3ex 0px 0.3ex; + border-image: url(:/light/left_arrow_disabled.svg); + height: 1ex; + width: 1ex; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on +{ + border-image: url(:/light/right_arrow.svg); + width: 1ex; + height: 1ex; + subcontrol-position: right; + subcontrol-origin: margin; +} + + +QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on +{ + border-image: url(:/light/left_arrow.svg); + width: 1ex; + height: 1ex; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal +{ + background: none; +} + + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal +{ + background: none; +} + +QScrollBar:vertical +{ + background-color: #2A2929; + width: 1.5ex; + margin: 1.5ex 0.3ex 1.5ex 0.3ex; + border: 0.1ex transparent #2A2929; + border-radius: 0.4ex; +} + +QScrollBar::handle:vertical +{ + background-color: #605F5F; + min-height: 0.5ex; + border-radius: 0.4ex; +} + +QScrollBar::sub-line:vertical +{ + margin: 0.3ex 0ex 0.3ex 0ex; + border-image: url(:/light/up_arrow_disabled.svg); + height: 1ex; + width: 1ex; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical +{ + margin: 0.3ex 0ex 0.3ex 0ex; + border-image: url(:/light/down_arrow_disabled.svg); + height: 1ex; + width: 1ex; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover, +QScrollBar::sub-line:vertical:on +{ + + border-image: url(:/light/up_arrow.svg); + height: 1ex; + width: 1ex; + subcontrol-position: top; + subcontrol-origin: margin; +} + + +QScrollBar::add-line:vertical:hover, +QScrollBar::add-line:vertical:on +{ + border-image: url(:/light/down_arrow.svg); + height: 1ex; + width: 1ex; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:vertical, +QScrollBar::down-arrow:vertical +{ + background: none; +} + + +QScrollBar::add-page:vertical, +QScrollBar::sub-page:vertical +{ + background: none; +} + +QTextEdit +{ + background-color: #EFF0F1; + color: #31363B; + border: 0.1ex solid #BAB9B8; +} + +QPlainTextEdit +{ + background-color: #EFF0F1; + color: #31363B; + border-radius: 0.2ex; + border: 0.1ex solid #BAB9B8; +} + +QHeaderView::section +{ + background-color: #BAB9B8; + color: #31363B; + padding: 0.5ex; + border: 0.1ex solid #BAB9B8; +} + +QSizeGrip +{ + border-image: url(:/light/sizegrip.svg); + width: 1.2ex; + height: 1.2ex; +} + +QMainWindow::separator +{ + background-color: #EFF0F1; + color: white; + padding-left: 0.4ex; + spacing: 0.2ex; + border: 0.1ex dashed #BAB9B8; +} + +QMainWindow::separator:hover +{ + + background-color: #787876; + color: white; + padding-left: 0.4ex; + border: 0.1ex solid #BAB9B8; + spacing: 0.2x; +} + +QMenu::separator +{ + height: 0.1ex; + background-color: #BAB9B8; + color: white; + padding-left: 0.4ex; + margin-left: 1ex; + margin-right: 0.5ex; +} + +QFrame[frameShape="2"], /* QFrame::Panel == 0x0003 */ +QFrame[frameShape="3"], /* QFrame::WinPanel == 0x0003 */ +QFrame[frameShape="4"], /* QFrame::HLine == 0x0004 */ +QFrame[frameShape="5"], /* QFrame::VLine == 0x0005 */ +QFrame[frameShape="6"] /* QFrame::StyledPanel == 0x0006 */ +{ + border-width: 0.1ex; + padding: 0.1ex; + border-style: solid; + border-color: #EFF0F1; + background-color: #bcbfc2; + border-radius: 0.5ex; +} + +QStackedWidget +{ + border: 0.1ex transparent black; +} + +QToolBar +{ + border: 0.1ex transparent #393838; + background: 0.1ex solid #EFF0F1; + font-weight: bold; +} + +QToolBar::handle:horizontal +{ + border-image: url(:/light/hmovetoolbar.svg); + width = 1.6ex; + height = 6.4ex; +} + +QToolBar::handle:vertical +{ + border-image: url(:/light/vmovetoolbar.svg); + width = 5.4ex; + height = 1ex; +} + +QToolBar::separator:horizontal +{ + border-image: url(:/light/hsepartoolbar.svg); + width = 0.7ex; + height = 6.3ex; +} + +QToolBar::separator:vertical +{ + border-image: url(:/light/vsepartoolbars.svg); + width = 6.3ex; + height = 0.7ex; +} + +QPushButton +{ + color: #31363B; + background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #EFF0F1, stop: 0.5 #eaebec); + border-width: 0.1ex; + border-color: #BAB9B8; + border-style: solid; + padding: 0.5ex; + border-radius: 0.2ex; + outline: none; +} + +QPushButton:disabled +{ + background-color: #e0e1e2; + border-width: 0.1ex; + border-color: #b4b4b4; + border-style: solid; + padding-top: 0.5ex; + padding-bottom: 0.5ex; + padding-left: 1ex; + padding-right: 1ex; + border-radius: 0.2ex; + color: #b4b4b4; +} + +QPushButton:focus +{ + color: black; +} + +QComboBox +{ + selection-background-color: #33A4DF; + border-style: solid; + border: 0.1ex solid #BAB9B8; + border-radius: 0.2ex; + padding: 0.5ex; + min-width: 7.5ex; +} + +QPushButton:checked +{ + background-color: #BAB9B8; + border-color: #6A6969; +} + +QComboBox:hover, +QAbstractSpinBox:hover, +QLineEdit:hover, +QTextEdit:hover, +QPlainTextEdit:hover, +QAbstractView:hover, +QTreeView:hover +{ + border: 0.1ex solid #33A4DF; + color: #31363B; +} + +QComboBox:hover:pressed, +QPushButton:hover:pressed, +QAbstractSpinBox:hover:pressed, +QLineEdit:hover:pressed, +QTextEdit:hover:pressed, +QPlainTextEdit:hover:pressed, +QAbstractView:hover:pressed, +QTreeView:hover:pressed +{ + background-color: #EFF0F1; +} + +QComboBox:on +{ + padding-top: 0.3ex; + padding-left: 0.4ex; + selection-background-color: #4a4a4a; +} + +QComboBox QAbstractItemView +{ + background-color: #FCFCFC; + border-radius: 0.2ex; + border: 0.1ex solid #BAB9B8; + selection-background-color: #33A4DF; +} + +QComboBox::drop-down +{ + subcontrol-origin: padding; + subcontrol-position: top right; + width: 1.5ex; + + border-left-width: 0ex; + border-left-color: darkgray; + border-left-style: solid; + border-top-right-radius: 0.3ex; + border-bottom-right-radius: 0.3ex; +} + +QComboBox::down-arrow +{ + border-image: url(:/light/down_arrow_disabled.svg); + width: 0.9ex; + height: 0.6ex; +} + +QComboBox::down-arrow:on, +QComboBox::down-arrow:hover, +QComboBox::down-arrow:focus +{ + border-image: url(:/light/down_arrow.svg); + width: 0.9ex; + height: 0.6ex; +} + +QAbstractSpinBox +{ + padding: 0.5ex; + border: 0.1ex solid #BAB9B8; + background-color: #D9D8D7; + color: #31363B; + border-radius: 0.2ex; + min-width: 7.5ex; +} + +QAbstractSpinBox:up-button +{ + background-color: transparent; + subcontrol-origin: border; + subcontrol-position: center right; +} + +QAbstractSpinBox:down-button +{ + background-color: transparent; + subcontrol-origin: border; + subcontrol-position: center left; +} + +QAbstractSpinBox::up-arrow, +QAbstractSpinBox::up-arrow:disabled, +QAbstractSpinBox::up-arrow:off +{ + border-image: url(:/light/up_arrow_disabled.svg); + width: 0.9ex; + height: 0.6ex; +} + +QAbstractSpinBox::up-arrow:hover +{ + border-image: url(:/light/up_arrow.svg); + width: 0.9ex; + height: 0.6ex; +} + +QAbstractSpinBox::down-arrow, +QAbstractSpinBox::down-arrow:disabled, +QAbstractSpinBox::down-arrow:off +{ + border-image: url(:/light/down_arrow_disabled.svg); + width: 0.9ex; + height: 0.6ex; +} + +QAbstractSpinBox::down-arrow:hover +{ + border-image: url(:/light/down_arrow.svg); + width: 0.9ex; + height: 0.6ex; +} + +QLabel +{ + border: 0ex solid black; +} + +QTabWidget{ + border: 0.1ex solid #BAB9B8; +} + +/* BORDERS */ +QTabWidget::pane +{ + padding: 0.5ex; + margin: 0.1ex; +} + +QTabWidget::pane:top +{ + border: 0.1ex solid #BAB9B8; + top: -0.1ex; +} + +QTabWidget::pane:bottom +{ + border: 0.1ex solid #BAB9B8; + bottom: -0.1ex; +} + +QTabWidget::pane:left +{ + border: 0.1ex solid #BAB9B8; + right: -0.1ex; +} + +QTabWidget::pane:right +{ + border: 0.1ex solid #BAB9B8; + left: -0.1ex; +} + +QTabBar +{ + qproperty-drawBase: 0; + left: 0.5ex; /* move to the right by 0.5ex */ + border-radius: 0.3ex; +} + +QTabBar:focus +{ + border: 0ex transparent black; +} + +QTabBar::close-button +{ + border-image: url(:/light/close.svg); + width: 1.2ex; + height: 1.2ex; + background: transparent; +} + +QTabBar::close-button:hover +{ + border-image: url(:/light/close-hover.svg); + width: 1.2ex; + height: 1.2ex; + background: transparent; +} + +QTabBar::close-button:pressed +{ + border-image: url(:/light/close-pressed.svg); + width: 1.2ex; + height: 1.2ex; + background: transparent; +} + +/* TOP TABS */ +QTabBar::tab:top +{ + color: #31363B; + border: 0.1ex transparent black; + border-left: 0.1ex solid #BAB9B8; + border-top: 0.1ex solid #BAB9B8; + background-color: #EFF0F1; + padding: 0.5ex; + min-width: 5ex; + border-top-left-radius: 0.2ex; + border-top-right-radius: 0.2ex; +} + +QTabBar::tab:top:last, +QTabBar::tab:top:only-one +{ + color: #31363B; + border: 0.1ex transparent black; + border-left: 0.1ex solid #BAB9B8; + border-right: 0.1ex solid #BAB9B8; + border-top: 0.1ex solid #BAB9B8; + background-color: #EFF0F1; + padding: 0.5ex; + min-width: 5ex; + border-top-left-radius: 0.2ex; + border-top-right-radius: 0.2ex; +} + +QTabBar::tab:top:!selected +{ + color: #31363B; + background-color: #D9D8D7; + border: 0.1ex transparent black; + border-left: 0.1ex solid #BAB9B8; + border-top-left-radius: 0.2ex; + border-top-right-radius: 0.2ex; +} + +QTabBar::tab:top:first:!selected +{ + color: #31363B; + background-color: #D9D8D7; + border: 0.1ex transparent black; + border-top-left-radius: 0.2ex; + border-top-right-radius: 0.2ex; +} + +QTabBar::tab:top:!selected:hover +{ + background-color: rgba(61, 173, 232, 0.1); + border: 0.1ex rgba(61, 173, 232, 0.1); + border-left: 0.1ex solid #BAB9B8; +} + +QTabBar::tab:top:!selected:first:hover +{ + background-color: rgba(61, 173, 232, 0.1); + border: 0.1ex rgba(61, 173, 232, 0.1); +} + +/* BOTTOM TABS */ +QTabBar::tab:bottom +{ + color: #31363B; + border: 0.1ex transparent black; + border-left: 0.1ex solid #BAB9B8; + border-bottom: 0.1ex solid #BAB9B8; + background-color: #EFF0F1; + padding: 0.5ex; + border-bottom-left-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; + min-width: 5ex; +} + +QTabBar::tab:bottom:last, +QTabBar::tab:bottom:only-one +{ + color: #31363B; + border: 0.1ex transparent black; + border-left: 0.1ex solid #BAB9B8; + border-right: 0.1ex solid #BAB9B8; + border-bottom: 0.1ex solid #BAB9B8; + background-color: #EFF0F1; + padding: 0.5ex; + border-bottom-left-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; + min-width: 5ex; +} + +QTabBar::tab:bottom:!selected +{ + color: #31363B; + background-color: #D9D8D7; + border: 0.1ex transparent black; + border-left: 0.1ex solid #BAB9B8; + border-bottom-left-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; +} + +QTabBar::tab:bottom:first:!selected +{ + color: #31363B; + background-color: #D9D8D7; + border: 0.1ex transparent black; + border-bottom-left-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; +} + +QTabBar::tab:bottom:!selected:hover +{ + background-color: rgba(61, 173, 232, 0.1); + border: 0.1ex rgba(61, 173, 232, 0.1); + border-left: 0.1ex solid #BAB9B8; +} + +QTabBar::tab:bottom:!selected:first:hover +{ + background-color: rgba(61, 173, 232, 0.1); + border: 0.1ex rgba(61, 173, 232, 0.1); +} + +/* LEFT TABS */ +QTabBar::tab:left +{ + color: #31363B; + border: 0.1ex transparent black; + border-top: 0.1ex solid #BAB9B8; + border-right: 0.1ex solid #BAB9B8; + background-color: #EFF0F1; + padding: 0.5ex; + border-top-right-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; + min-height: 5ex; +} + +QTabBar::tab:left:last, +QTabBar::tab:left:only-one +{ + color: #31363B; + border: 0.1ex transparent black; + border-top: 0.1ex solid #BAB9B8; + border-bottom: 0.1ex solid #BAB9B8; + border-right: 0.1ex solid #BAB9B8; + background-color: #EFF0F1; + padding: 0.5ex; + border-top-right-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; + min-height: 5ex; +} + +QTabBar::tab:left:!selected +{ + color: #31363B; + background-color: #D9D8D7; + border: 0.1ex transparent black; + border-top: 0.1ex solid #BAB9B8; + border-top-right-radius: 0.2ex; + border-bottom-right-radius: 0.2ex; +} + +QTabBar::tab:left:!selected:hover +{ + background-color: rgba(61, 173, 232, 0.1); + border: 0.1ex rgba(61, 173, 232, 0.1); + border-top: 0.1ex solid #BAB9B8; +} + +QTabBar::tab:left:!selected:first:hover +{ + background-color: rgba(61, 173, 232, 0.1); + border: 0.1ex rgba(61, 173, 232, 0.1); +} + +/* RIGHT TABS */ +QTabBar::tab:right +{ + color: #31363B; + border: 0.1ex transparent black; + border-top: 0.1ex solid #BAB9B8; + border-left: 0.1ex solid #BAB9B8; + background-color: #D9D8D7; + padding: 0.5ex; + border-top-left-radius: 0.2ex; + border-bottom-left-radius: 0.2ex; + min-height: 5ex; +} + +QTabBar::tab:right:last, +QTabBar::tab:right:only-one +{ + color: #31363B; + border: 0.1ex transparent black; + border-top: 0.1ex solid #BAB9B8; + border-bottom: 0.1ex solid #BAB9B8; + border-left: 0.1ex solid #BAB9B8; + background-color: #D9D8D7; + padding: 0.5ex; + border-top-left-radius: 0.2ex; + border-bottom-left-radius: 0.2ex; + min-height: 5ex; +} + +QTabBar::tab:right:!selected +{ + color: #31363B; + background-color: #54575B; + border: 0.1ex transparent black; + border-top: 0.1ex solid #BAB9B8; + border-top-left-radius: 0.2ex; + border-bottom-left-radius: 0.2ex; +} + +QTabBar::tab:right:!selected:hover +{ + background-color: rgba(61, 173, 232, 0.1); + border: 0.1ex rgba(61, 173, 232, 0.1); + border-top: 0.1ex solid #BAB9B8; +} + +QTabBar::tab:right:!selected:first:hover +{ + background-color: rgba(61, 173, 232, 0.1); + border: 0.1ex rgba(61, 173, 232, 0.1); +} + +QTabBar QToolButton::right-arrow:enabled +{ + border-image: url(:/light/right_arrow.svg); +} + +QTabBar QToolButton::left-arrow:enabled +{ + border-image: url(:/light/left_arrow.svg); +} + +QTabBar QToolButton::right-arrow:disabled +{ + border-image: url(:/light/right_arrow_disabled.svg); +} + +QTabBar QToolButton::left-arrow:disabled +{ + border-image: url(:/light/left_arrow_disabled.svg); +} + +QDockWidget +{ + background: #EFF0F1; + border: 0.1ex solid #403F3F; + titlebar-close-icon: url(:/light/transparent.svg); + titlebar-normal-icon: url(:/light/transparent.svg); +} + +QDockWidget::close-button, +QDockWidget::float-button +{ + border: 0.1ex solid transparent; + border-radius: 0.2ex; + background: transparent; +} + + +QDockWidget::float-button +{ + border-image: url(:/dark/undock.svg); +} + +QDockWidget::float-button:hover +{ + border-image: url(:/dark/undock-hover.svg) ; +} + +QDockWidget::close-button +{ + border-image: url(:/dark/close.svg) ; +} + +QDockWidget::close-button:hover +{ + border-image: url(:/dark/close-hover.svg) ; +} + +QDockWidget::close-button:pressed +{ + border-image: url(:/dark/close-pressed.svg) ; +} + +QTreeView, +QListView +{ + border: 0.1ex solid #BAB9B8; + background-color: #FCFCFC; +} + + +QTreeView::branch:has-siblings:!adjoins-item +{ + border-image: url(:/light/stylesheet-vline.svg) 0; +} + +QTreeView::branch:has-siblings:adjoins-item +{ + border-image: url(:/light/stylesheet-branch-more.svg) 0; +} + +QTreeView::branch:!has-children:!has-siblings:adjoins-item +{ + border-image: url(:/light/stylesheet-branch-end.svg) 0; +} + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings +{ + border-image: url(:/light/stylesheet-branch-end-closed.svg) 0; + image: url(:/light/branch_closed.svg); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings +{ + border-image: url(:/light/stylesheet-branch-end-open.svg) 0; + image: url(:/light/branch_open.svg); +} + +QTableView::item, +QListView::item, +QTreeView::item +{ + padding: 0.3ex; +} + +QTableView::item:!selected:hover, +QListView::item:!selected:hover, +QTreeView::item:!selected:hover +{ + background-color: rgba(61, 173, 232, 0.1); + outline: 0; + color: #31363B; + padding: 0.3ex; +} + +QSlider::groove:horizontal +{ + border: 0.1ex solid #EFF0F1; + height: 0.4ex; + background: #9CA0A4; + margin: 0px; + border-radius: 0.2ex; +} + +QSlider::handle:horizontal +{ + background: #D9D8D7; + border: 0.1ex solid #BABEC2; + width: 1.6ex; + height: 1.6ex; + margin: -0.8ex 0; + border-radius: 0.9ex; +} + +QSlider::groove:vertical +{ + border: 0.1ex solid #EFF0F1; + width: 0.4ex; + background: #9CA0A4; + margin: 0ex; + border-radius: 0.3ex; +} + +QSlider::handle:vertical +{ + background: #D9D8D7; + border: 0.1ex solid #BABEC2; + width: 1.6ex; + height: 1.6ex; + margin: 0 -0.8ex; + border-radius: 0.9ex; +} + +QSlider::handle:horizontal:focus, +QSlider::handle:vertical:focus +{ + border: 0.1ex solid #33A4DF; +} + +QSlider::handle:horizontal:hover, +QSlider::handle:vertical:hover +{ + border: 0.1ex solid #51c2fc; +} + +QSlider::sub-page:horizontal, +QSlider::add-page:vertical +{ + background: #33A4DF; + border-radius: 0.3ex; +} + +QSlider::add-page:horizontal, +QSlider::sub-page:vertical +{ + background: #BABEC2; + border-radius: 0.3ex; +} + +QToolButton +{ + background-color: transparent; + border: 0.1ex solid #BAB9B8; + border-radius: 0.2ex; + margin: 0.3ex; + padding: 0.5ex; +} + +QToolButton[popupMode="1"] /* only for MenuButtonPopup */ +{ + padding-right: 2ex; /* make way for the popup button */ +} + +QToolButton[popupMode="2"] /* only for InstantPopup */ +{ + padding-right: 1ex; /* make way for the popup button */ +} + +QToolButton::menu-indicator +{ + border-image: url(:/light/down_arrow.svg); + top: -0.7ex; left: -0.2ex; /* shift it a bit */ + width = 0.9ex; + height = 0.6ex; +} + +QToolButton::menu-arrow +{ + border-image: url(:/light/down_arrow.svg); + width = 0.9ex; + height = 0.6ex; +} + +QToolButton:hover, +QToolButton::menu-button:hover +{ + background-color: transparent; + border: 0.1ex solid #33A4DF; +} + +QToolButton:checked, +QToolButton:pressed, +QToolButton::menu-button:pressed +{ + background-color: #47b8fc; + border: 0.1ex solid #47b8fc; + padding: 0.5ex; +} + +QToolButton::menu-button +{ + border: 0.1ex solid #BAB9B8; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + /* 1ex width + 0.4ex for border + no text = 2ex allocated above */ + width: 1ex; + padding: 0.5ex; + outline: none; +} + +QToolButton::menu-arrow:open +{ + border: 0.1ex solid #BAB9B8; +} + +QPushButton::menu-indicator +{ + subcontrol-origin: padding; + subcontrol-position: bottom right; + left: 0.8ex; +} + +QTableView +{ + border: 0.1ex solid #BAB9B8; + gridline-color: #BAB9B8; + background-color: #FCFCFC; +} + + +QTableView, +QHeaderView +{ + border-radius: 0px; +} + +QTableView::item:pressed +{ + background: #33A4DF; + color: #31363B; +} + +QTableView::item:selected:active +{ + background: #33A4DF; + color: #31363B; +} + +QTableView::item:selected:hover +{ + background-color: #47b8f3; + color: #31363B; +} + +QListView::item:pressed, +QTreeView::item:pressed +{ + background: #3daee9; + color: #31363B; +} + +QTreeView::item:selected:active, +QListView::item:selected:active +{ + background: #3daee9; + color: #31363B; +} + +QListView::item:selected:hover, +QTreeView::item:selected:hover +{ + background-color: #51c2fc; + color: #31363B; +} + + +QHeaderView +{ + background-color: #EFF0F1; + border: 0.1ex transparent; + border-radius: 0px; + margin: 0px; + padding: 0px; + +} + +QHeaderView::section +{ + background-color: #EFF0F1; + color: #31363B; + padding: 0.5ex; + border: 0.1ex solid #BAB9B8; + border-radius: 0px; + text-align: center; +} + +QHeaderView::section::vertical::first, +QHeaderView::section::vertical::only-one +{ + border-top: 0.1ex solid #BAB9B8; +} + +QHeaderView::section::vertical +{ + border-top: transparent; +} + +QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one +{ + border-left: 0.1ex solid #BAB9B8; +} + +QHeaderView::section::horizontal +{ + border-left: transparent; +} + + +QHeaderView::section:checked + + { + color: black; + background-color: #b9dae7; + } + + /* style the sort indicator */ +QHeaderView::down-arrow +{ + image: url(:/light/down_arrow.svg); +} + +QHeaderView::up-arrow +{ + image: url(:/light/up_arrow.svg); +} + +QTableCornerButton::section +{ + background-color: #EFF0F1; + border: 0.1ex transparent #BAB9B8; + border-radius: 0px; +} + +QToolBox +{ + padding: 0.5ex; + border: 0.1ex transparent black; +} + +QToolBox:selected +{ + background-color: #EFF0F1; + border-color: #33A4DF; +} + +QToolBox:hover +{ + border-color: #33A4DF; +} + +QStatusBar::item +{ + border: 0px transparent dark; +} + +QSplitter::handle +{ + border: 0.1ex dashed #BAB9B8; +} + +QSplitter::handle:hover +{ + background-color: #787876; + border: 0.1ex solid #BAB9B8; +} + +QSplitter::handle:horizontal +{ + width: 0.1ex; +} + +QSplitter::handle:vertical +{ + height: 0.1ex; +} + +QProgressBar:horizontal +{ + background-color: #BABEC2; + border: 0.1ex solid #EFF0F1; + border-radius: 0.3ex; + height: 0.5ex; + text-align: right; + margin-top: 0.5ex; + margin-bottom: 0.5ex; + margin-right: 5ex; + padding: 0px; +} + +QProgressBar::chunk:horizontal +{ + background-color: #33A4DF; + border: 0.1ex transparent; + border-radius: 0.3ex; +} + +QAbstractSpinBox +{ + background-color: #EFF0F1; +} + +QSpinBox, +QDoubleSpinBox +{ + padding-right: 1.5ex; +} + +QSpinBox::up-button, +QDoubleSpinBox::up-button +{ + subcontrol-origin: content; + subcontrol-position: right top; + + width: 1.6ex; + border-width: 0.1ex; +} + +QSpinBox::up-arrow, +QDoubleSpinBox::up-arrow +{ + border-image: url(:/light/up_arrow.svg); + width: 0.9ex; + height: 0.6ex; +} + +QSpinBox::up-arrow:hover, +QSpinBox::up-arrow:pressed, +QDoubleSpinBox::up-arrow:hover, +QDoubleSpinBox::up-arrow:pressed +{ + border-image: url(:/light/up_arrow-hover.svg); + width: 0.9ex; + height: 0.6ex; +} + +QSpinBox::up-arrow:disabled, +QSpinBox::up-arrow:off, +QDoubleSpinBox::up-arrow:disabled, +QDoubleSpinBox::up-arrow:off +{ + border-image: url(:/light/up_arrow_disabled.svg); +} + +QSpinBox::down-button, +QDoubleSpinBox::down-button +{ + subcontrol-origin: content; + subcontrol-position: right bottom; + + width: 1.6ex; + border-width: 0.1ex; +} + +QSpinBox::down-arrow, +QDoubleSpinBox::down-arrow +{ + border-image: url(:/light/down_arrow.svg); + width: 0.9ex; + height: 0.6ex; +} + +QSpinBox::down-arrow:hover, +QSpinBox::down-arrow:pressed, +QDoubleSpinBox::down-arrow:hover, +QDoubleSpinBox::down-arrow:pressed +{ + border-image: url(:/light/down_arrow-hover.svg); + width: 0.9ex; + height: 0.6ex; +} + +QSpinBox::down-arrow:disabled, +QSpinBox::down-arrow:off, +QDoubleSpinBox::down-arrow:disabled, +QDoubleSpinBox::down-arrow:off +{ + border-image: url(:/light/down_arrow_disabled.svg); +} + +QPushButton:hover +{ + border: 0.1ex solid #3daef3; + color: #31363B; +} + +QPushButton:focus +{ + background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #4cbdff, stop: 0.5 #33a4e8); + color: white; +} + +QPushButton:focus:hover +{ + background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #bedfec, stop: 0.5 #b9dae7); + color: #31363B; +} + +QPushButton:focus:pressed, +QPushButton:pressed +{ + background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #bedfec, stop: 0.5 #b9dae7); + color: #31363B; +} + +/* fixes */ + +QPushButton:flat { + background-color: transparent; + border: none; +} + +QScrollBar::handle:vertical +{ + background-color: #BAB9B8; +} + +QScrollBar:vertical +{ + background-color: #eff0f1; + border: 0.1ex transparent #eff0f1; +} + +QPlainTextEdit +{ + background-color: #fcfcfc; +} + +QTableView::item:!selected:hover +{ + background-color: transparent; +} + +QLabel:disabled { + color: #787878; +} \ No newline at end of file diff --git a/src/ui/BreezeStyleSheets/light/branch_closed-on.svg b/src/ui/BreezeStyleSheets/light/branch_closed-on.svg new file mode 100755 index 0000000..23c5421 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/branch_closed-on.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/branch_closed.svg b/src/ui/BreezeStyleSheets/light/branch_closed.svg new file mode 100755 index 0000000..286c1a9 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/branch_closed.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/branch_open-on.svg b/src/ui/BreezeStyleSheets/light/branch_open-on.svg new file mode 100755 index 0000000..9e75927 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/branch_open-on.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/branch_open.svg b/src/ui/BreezeStyleSheets/light/branch_open.svg new file mode 100755 index 0000000..514a312 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/branch_open.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/checkbox_checked-hover.svg b/src/ui/BreezeStyleSheets/light/checkbox_checked-hover.svg new file mode 100755 index 0000000..64d6667 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/checkbox_checked-hover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/light/checkbox_checked.svg b/src/ui/BreezeStyleSheets/light/checkbox_checked.svg new file mode 100755 index 0000000..f3acb63 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/checkbox_checked.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/light/checkbox_checked_disabled.svg b/src/ui/BreezeStyleSheets/light/checkbox_checked_disabled.svg new file mode 100755 index 0000000..b7be04b --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/checkbox_checked_disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/light/checkbox_indeterminate-hover.svg b/src/ui/BreezeStyleSheets/light/checkbox_indeterminate-hover.svg new file mode 100755 index 0000000..def9596 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/checkbox_indeterminate-hover.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/ui/BreezeStyleSheets/light/checkbox_indeterminate.svg b/src/ui/BreezeStyleSheets/light/checkbox_indeterminate.svg new file mode 100755 index 0000000..a619ab0 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/checkbox_indeterminate.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/ui/BreezeStyleSheets/light/checkbox_indeterminate_disabled.svg b/src/ui/BreezeStyleSheets/light/checkbox_indeterminate_disabled.svg new file mode 100755 index 0000000..74d7168 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/checkbox_indeterminate_disabled.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/ui/BreezeStyleSheets/light/checkbox_unchecked-hover.svg b/src/ui/BreezeStyleSheets/light/checkbox_unchecked-hover.svg new file mode 100755 index 0000000..8f0bb01 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/checkbox_unchecked-hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/light/checkbox_unchecked_disabled.svg b/src/ui/BreezeStyleSheets/light/checkbox_unchecked_disabled.svg new file mode 100755 index 0000000..0ef4300 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/checkbox_unchecked_disabled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/light/close-hover.svg b/src/ui/BreezeStyleSheets/light/close-hover.svg new file mode 100755 index 0000000..cb44c78 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/close-hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/close-pressed.svg b/src/ui/BreezeStyleSheets/light/close-pressed.svg new file mode 100755 index 0000000..a0dc249 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/close-pressed.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/close.svg b/src/ui/BreezeStyleSheets/light/close.svg new file mode 100755 index 0000000..07b50c9 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/close.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/down_arrow-hover.svg b/src/ui/BreezeStyleSheets/light/down_arrow-hover.svg new file mode 100755 index 0000000..408397f --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/down_arrow-hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/down_arrow.svg b/src/ui/BreezeStyleSheets/light/down_arrow.svg new file mode 100755 index 0000000..34c5d6a --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/down_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/down_arrow_disabled.svg b/src/ui/BreezeStyleSheets/light/down_arrow_disabled.svg new file mode 100755 index 0000000..af74a30 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/down_arrow_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/hmovetoolbar.svg b/src/ui/BreezeStyleSheets/light/hmovetoolbar.svg new file mode 100755 index 0000000..57e54c9 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/hmovetoolbar.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/light/hsepartoolbar.svg b/src/ui/BreezeStyleSheets/light/hsepartoolbar.svg new file mode 100755 index 0000000..a446425 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/hsepartoolbar.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/left_arrow.svg b/src/ui/BreezeStyleSheets/light/left_arrow.svg new file mode 100755 index 0000000..f77acf4 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/left_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/left_arrow_disabled.svg b/src/ui/BreezeStyleSheets/light/left_arrow_disabled.svg new file mode 100755 index 0000000..2d749e7 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/left_arrow_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/radio_checked-hover.svg b/src/ui/BreezeStyleSheets/light/radio_checked-hover.svg new file mode 100755 index 0000000..f3d5c98 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/radio_checked-hover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/light/radio_checked.svg b/src/ui/BreezeStyleSheets/light/radio_checked.svg new file mode 100755 index 0000000..86ff6bf --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/radio_checked.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/light/radio_checked_disabled.svg b/src/ui/BreezeStyleSheets/light/radio_checked_disabled.svg new file mode 100755 index 0000000..269ae12 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/radio_checked_disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/light/radio_unchecked-hover.svg b/src/ui/BreezeStyleSheets/light/radio_unchecked-hover.svg new file mode 100755 index 0000000..f5fc943 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/radio_unchecked-hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/light/radio_unchecked_disabled.svg b/src/ui/BreezeStyleSheets/light/radio_unchecked_disabled.svg new file mode 100755 index 0000000..41f503d --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/radio_unchecked_disabled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/light/right_arrow.svg b/src/ui/BreezeStyleSheets/light/right_arrow.svg new file mode 100755 index 0000000..a43ea2b --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/right_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/right_arrow_disabled.svg b/src/ui/BreezeStyleSheets/light/right_arrow_disabled.svg new file mode 100755 index 0000000..4940025 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/right_arrow_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/sizegrip.svg b/src/ui/BreezeStyleSheets/light/sizegrip.svg new file mode 100755 index 0000000..3388f07 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/sizegrip.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/spinup_disabled.svg b/src/ui/BreezeStyleSheets/light/spinup_disabled.svg new file mode 100755 index 0000000..838436d --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/spinup_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/stylesheet-branch-end-closed.svg b/src/ui/BreezeStyleSheets/light/stylesheet-branch-end-closed.svg new file mode 100755 index 0000000..a31f5c0 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/stylesheet-branch-end-closed.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/light/stylesheet-branch-end-open.svg b/src/ui/BreezeStyleSheets/light/stylesheet-branch-end-open.svg new file mode 100755 index 0000000..a31f5c0 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/stylesheet-branch-end-open.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/light/stylesheet-branch-end.svg b/src/ui/BreezeStyleSheets/light/stylesheet-branch-end.svg new file mode 100755 index 0000000..a1c0a42 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/stylesheet-branch-end.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/light/stylesheet-branch-more.svg b/src/ui/BreezeStyleSheets/light/stylesheet-branch-more.svg new file mode 100755 index 0000000..ebef839 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/stylesheet-branch-more.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/BreezeStyleSheets/light/stylesheet-vline.svg b/src/ui/BreezeStyleSheets/light/stylesheet-vline.svg new file mode 100755 index 0000000..688177e --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/stylesheet-vline.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/transparent.svg b/src/ui/BreezeStyleSheets/light/transparent.svg new file mode 100755 index 0000000..3a8ca5c --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/transparent.svg @@ -0,0 +1 @@ + diff --git a/src/ui/BreezeStyleSheets/light/undock-hover.svg b/src/ui/BreezeStyleSheets/light/undock-hover.svg new file mode 100755 index 0000000..6bddbd7 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/undock-hover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/BreezeStyleSheets/light/undock.svg b/src/ui/BreezeStyleSheets/light/undock.svg new file mode 100755 index 0000000..9ab2197 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/undock.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/up_arrow-hover.svg b/src/ui/BreezeStyleSheets/light/up_arrow-hover.svg new file mode 100755 index 0000000..dd1271a --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/up_arrow-hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/up_arrow.svg b/src/ui/BreezeStyleSheets/light/up_arrow.svg new file mode 100755 index 0000000..b02bb26 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/up_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/up_arrow_disabled.svg b/src/ui/BreezeStyleSheets/light/up_arrow_disabled.svg new file mode 100755 index 0000000..742e1c5 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/up_arrow_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/BreezeStyleSheets/light/vmovetoolbar.svg b/src/ui/BreezeStyleSheets/light/vmovetoolbar.svg new file mode 100755 index 0000000..0a30d45 --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/vmovetoolbar.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/ui/BreezeStyleSheets/light/vsepartoolbars.svg b/src/ui/BreezeStyleSheets/light/vsepartoolbars.svg new file mode 100755 index 0000000..00e91ab --- /dev/null +++ b/src/ui/BreezeStyleSheets/light/vsepartoolbars.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/ui/qdarkstyle/rc/arrow_down.png b/src/ui/qdarkstyle/rc/arrow_down.png new file mode 100644 index 0000000..4fc454e Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_down.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_down@2x.png b/src/ui/qdarkstyle/rc/arrow_down@2x.png new file mode 100644 index 0000000..fab22c4 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_down@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_down_disabled.png b/src/ui/qdarkstyle/rc/arrow_down_disabled.png new file mode 100644 index 0000000..39bd0c1 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_down_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_down_disabled@2x.png b/src/ui/qdarkstyle/rc/arrow_down_disabled@2x.png new file mode 100644 index 0000000..5f3ab00 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_down_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_down_focus.png b/src/ui/qdarkstyle/rc/arrow_down_focus.png new file mode 100644 index 0000000..5986712 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_down_focus.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_down_focus@2x.png b/src/ui/qdarkstyle/rc/arrow_down_focus@2x.png new file mode 100644 index 0000000..cef37e8 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_down_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_down_pressed.png b/src/ui/qdarkstyle/rc/arrow_down_pressed.png new file mode 100644 index 0000000..e1d5d3a Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_down_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_down_pressed@2x.png b/src/ui/qdarkstyle/rc/arrow_down_pressed@2x.png new file mode 100644 index 0000000..f54850f Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_down_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_left.png b/src/ui/qdarkstyle/rc/arrow_left.png new file mode 100644 index 0000000..bd7d54f Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_left.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_left@2x.png b/src/ui/qdarkstyle/rc/arrow_left@2x.png new file mode 100644 index 0000000..aa3fcfe Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_left@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_left_disabled.png b/src/ui/qdarkstyle/rc/arrow_left_disabled.png new file mode 100644 index 0000000..673ad11 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_left_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_left_disabled@2x.png b/src/ui/qdarkstyle/rc/arrow_left_disabled@2x.png new file mode 100644 index 0000000..56a1c0f Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_left_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_left_focus.png b/src/ui/qdarkstyle/rc/arrow_left_focus.png new file mode 100644 index 0000000..e7fad8f Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_left_focus.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_left_focus@2x.png b/src/ui/qdarkstyle/rc/arrow_left_focus@2x.png new file mode 100644 index 0000000..473b6f7 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_left_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_left_pressed.png b/src/ui/qdarkstyle/rc/arrow_left_pressed.png new file mode 100644 index 0000000..2f69cbf Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_left_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_left_pressed@2x.png b/src/ui/qdarkstyle/rc/arrow_left_pressed@2x.png new file mode 100644 index 0000000..2955581 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_left_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_right.png b/src/ui/qdarkstyle/rc/arrow_right.png new file mode 100644 index 0000000..26050b8 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_right.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_right@2x.png b/src/ui/qdarkstyle/rc/arrow_right@2x.png new file mode 100644 index 0000000..efbc8de Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_right@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_right_disabled.png b/src/ui/qdarkstyle/rc/arrow_right_disabled.png new file mode 100644 index 0000000..1e59a58 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_right_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_right_disabled@2x.png b/src/ui/qdarkstyle/rc/arrow_right_disabled@2x.png new file mode 100644 index 0000000..a6222d7 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_right_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_right_focus.png b/src/ui/qdarkstyle/rc/arrow_right_focus.png new file mode 100644 index 0000000..9bdcd85 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_right_focus.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_right_focus@2x.png b/src/ui/qdarkstyle/rc/arrow_right_focus@2x.png new file mode 100644 index 0000000..e24c3ba Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_right_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_right_pressed.png b/src/ui/qdarkstyle/rc/arrow_right_pressed.png new file mode 100644 index 0000000..4f4fc8e Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_right_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_right_pressed@2x.png b/src/ui/qdarkstyle/rc/arrow_right_pressed@2x.png new file mode 100644 index 0000000..1a85167 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_right_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_up.png b/src/ui/qdarkstyle/rc/arrow_up.png new file mode 100644 index 0000000..9f45d8e Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_up.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_up@2x.png b/src/ui/qdarkstyle/rc/arrow_up@2x.png new file mode 100644 index 0000000..2fe1c6b Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_up@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_up_disabled.png b/src/ui/qdarkstyle/rc/arrow_up_disabled.png new file mode 100644 index 0000000..a77807c Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_up_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_up_disabled@2x.png b/src/ui/qdarkstyle/rc/arrow_up_disabled@2x.png new file mode 100644 index 0000000..e12c4ee Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_up_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_up_focus.png b/src/ui/qdarkstyle/rc/arrow_up_focus.png new file mode 100644 index 0000000..b3970bd Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_up_focus.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_up_focus@2x.png b/src/ui/qdarkstyle/rc/arrow_up_focus@2x.png new file mode 100644 index 0000000..00c6c44 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_up_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_up_pressed.png b/src/ui/qdarkstyle/rc/arrow_up_pressed.png new file mode 100644 index 0000000..8f9dcf4 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_up_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/arrow_up_pressed@2x.png b/src/ui/qdarkstyle/rc/arrow_up_pressed@2x.png new file mode 100644 index 0000000..40c7f20 Binary files /dev/null and b/src/ui/qdarkstyle/rc/arrow_up_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/base_icon.png b/src/ui/qdarkstyle/rc/base_icon.png new file mode 100644 index 0000000..bb00857 Binary files /dev/null and b/src/ui/qdarkstyle/rc/base_icon.png differ diff --git a/src/ui/qdarkstyle/rc/base_icon@2x.png b/src/ui/qdarkstyle/rc/base_icon@2x.png new file mode 100644 index 0000000..bc4ab78 Binary files /dev/null and b/src/ui/qdarkstyle/rc/base_icon@2x.png differ diff --git a/src/ui/qdarkstyle/rc/base_icon_disabled.png b/src/ui/qdarkstyle/rc/base_icon_disabled.png new file mode 100644 index 0000000..bb00857 Binary files /dev/null and b/src/ui/qdarkstyle/rc/base_icon_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/base_icon_disabled@2x.png b/src/ui/qdarkstyle/rc/base_icon_disabled@2x.png new file mode 100644 index 0000000..bc4ab78 Binary files /dev/null and b/src/ui/qdarkstyle/rc/base_icon_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/base_icon_focus.png b/src/ui/qdarkstyle/rc/base_icon_focus.png new file mode 100644 index 0000000..bb00857 Binary files /dev/null and b/src/ui/qdarkstyle/rc/base_icon_focus.png differ diff --git a/src/ui/qdarkstyle/rc/base_icon_focus@2x.png b/src/ui/qdarkstyle/rc/base_icon_focus@2x.png new file mode 100644 index 0000000..bc4ab78 Binary files /dev/null and b/src/ui/qdarkstyle/rc/base_icon_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/base_icon_pressed.png b/src/ui/qdarkstyle/rc/base_icon_pressed.png new file mode 100644 index 0000000..bb00857 Binary files /dev/null and b/src/ui/qdarkstyle/rc/base_icon_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/base_icon_pressed@2x.png b/src/ui/qdarkstyle/rc/base_icon_pressed@2x.png new file mode 100644 index 0000000..bc4ab78 Binary files /dev/null and b/src/ui/qdarkstyle/rc/base_icon_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_closed.png b/src/ui/qdarkstyle/rc/branch_closed.png new file mode 100644 index 0000000..caa34ce Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_closed.png differ diff --git a/src/ui/qdarkstyle/rc/branch_closed@2x.png b/src/ui/qdarkstyle/rc/branch_closed@2x.png new file mode 100644 index 0000000..bc87d01 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_closed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_closed_disabled.png b/src/ui/qdarkstyle/rc/branch_closed_disabled.png new file mode 100644 index 0000000..a83f842 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_closed_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/branch_closed_disabled@2x.png b/src/ui/qdarkstyle/rc/branch_closed_disabled@2x.png new file mode 100644 index 0000000..4bb3f6e Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_closed_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_closed_focus.png b/src/ui/qdarkstyle/rc/branch_closed_focus.png new file mode 100644 index 0000000..6d19399 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_closed_focus.png differ diff --git a/src/ui/qdarkstyle/rc/branch_closed_focus@2x.png b/src/ui/qdarkstyle/rc/branch_closed_focus@2x.png new file mode 100644 index 0000000..c02f8a8 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_closed_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_closed_pressed.png b/src/ui/qdarkstyle/rc/branch_closed_pressed.png new file mode 100644 index 0000000..17b7784 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_closed_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/branch_closed_pressed@2x.png b/src/ui/qdarkstyle/rc/branch_closed_pressed@2x.png new file mode 100644 index 0000000..51db176 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_closed_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_end.png b/src/ui/qdarkstyle/rc/branch_end.png new file mode 100644 index 0000000..05cf7b6 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_end.png differ diff --git a/src/ui/qdarkstyle/rc/branch_end@2x.png b/src/ui/qdarkstyle/rc/branch_end@2x.png new file mode 100644 index 0000000..6df213e Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_end@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_end_disabled.png b/src/ui/qdarkstyle/rc/branch_end_disabled.png new file mode 100644 index 0000000..8d1c2ce Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_end_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/branch_end_disabled@2x.png b/src/ui/qdarkstyle/rc/branch_end_disabled@2x.png new file mode 100644 index 0000000..0a9305f Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_end_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_end_focus.png b/src/ui/qdarkstyle/rc/branch_end_focus.png new file mode 100644 index 0000000..3227c78 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_end_focus.png differ diff --git a/src/ui/qdarkstyle/rc/branch_end_focus@2x.png b/src/ui/qdarkstyle/rc/branch_end_focus@2x.png new file mode 100644 index 0000000..331af9c Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_end_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_end_pressed.png b/src/ui/qdarkstyle/rc/branch_end_pressed.png new file mode 100644 index 0000000..3537347 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_end_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/branch_end_pressed@2x.png b/src/ui/qdarkstyle/rc/branch_end_pressed@2x.png new file mode 100644 index 0000000..e5e4bce Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_end_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_line.png b/src/ui/qdarkstyle/rc/branch_line.png new file mode 100644 index 0000000..36c7ddf Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_line.png differ diff --git a/src/ui/qdarkstyle/rc/branch_line@2x.png b/src/ui/qdarkstyle/rc/branch_line@2x.png new file mode 100644 index 0000000..573c551 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_line@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_line_disabled.png b/src/ui/qdarkstyle/rc/branch_line_disabled.png new file mode 100644 index 0000000..36f9b4e Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_line_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/branch_line_disabled@2x.png b/src/ui/qdarkstyle/rc/branch_line_disabled@2x.png new file mode 100644 index 0000000..cf615a5 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_line_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_line_focus.png b/src/ui/qdarkstyle/rc/branch_line_focus.png new file mode 100644 index 0000000..b81bc5b Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_line_focus.png differ diff --git a/src/ui/qdarkstyle/rc/branch_line_focus@2x.png b/src/ui/qdarkstyle/rc/branch_line_focus@2x.png new file mode 100644 index 0000000..c474ed9 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_line_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_line_pressed.png b/src/ui/qdarkstyle/rc/branch_line_pressed.png new file mode 100644 index 0000000..445aa18 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_line_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/branch_line_pressed@2x.png b/src/ui/qdarkstyle/rc/branch_line_pressed@2x.png new file mode 100644 index 0000000..4117b54 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_line_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_more.png b/src/ui/qdarkstyle/rc/branch_more.png new file mode 100644 index 0000000..1b91df3 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_more.png differ diff --git a/src/ui/qdarkstyle/rc/branch_more@2x.png b/src/ui/qdarkstyle/rc/branch_more@2x.png new file mode 100644 index 0000000..2e1bebe Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_more@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_more_disabled.png b/src/ui/qdarkstyle/rc/branch_more_disabled.png new file mode 100644 index 0000000..72ec42b Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_more_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/branch_more_disabled@2x.png b/src/ui/qdarkstyle/rc/branch_more_disabled@2x.png new file mode 100644 index 0000000..65d1d9a Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_more_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_more_focus.png b/src/ui/qdarkstyle/rc/branch_more_focus.png new file mode 100644 index 0000000..9ff3921 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_more_focus.png differ diff --git a/src/ui/qdarkstyle/rc/branch_more_focus@2x.png b/src/ui/qdarkstyle/rc/branch_more_focus@2x.png new file mode 100644 index 0000000..95ac204 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_more_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_more_pressed.png b/src/ui/qdarkstyle/rc/branch_more_pressed.png new file mode 100644 index 0000000..a4f20e0 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_more_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/branch_more_pressed@2x.png b/src/ui/qdarkstyle/rc/branch_more_pressed@2x.png new file mode 100644 index 0000000..b113484 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_more_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_open.png b/src/ui/qdarkstyle/rc/branch_open.png new file mode 100644 index 0000000..eee8188 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_open.png differ diff --git a/src/ui/qdarkstyle/rc/branch_open@2x.png b/src/ui/qdarkstyle/rc/branch_open@2x.png new file mode 100644 index 0000000..bcfdc84 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_open@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_open_disabled.png b/src/ui/qdarkstyle/rc/branch_open_disabled.png new file mode 100644 index 0000000..b6d2d47 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_open_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/branch_open_disabled@2x.png b/src/ui/qdarkstyle/rc/branch_open_disabled@2x.png new file mode 100644 index 0000000..dffe12f Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_open_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_open_focus.png b/src/ui/qdarkstyle/rc/branch_open_focus.png new file mode 100644 index 0000000..1f7bfdc Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_open_focus.png differ diff --git a/src/ui/qdarkstyle/rc/branch_open_focus@2x.png b/src/ui/qdarkstyle/rc/branch_open_focus@2x.png new file mode 100644 index 0000000..3cc22d7 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_open_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/branch_open_pressed.png b/src/ui/qdarkstyle/rc/branch_open_pressed.png new file mode 100644 index 0000000..db44859 Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_open_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/branch_open_pressed@2x.png b/src/ui/qdarkstyle/rc/branch_open_pressed@2x.png new file mode 100644 index 0000000..bdf8b2d Binary files /dev/null and b/src/ui/qdarkstyle/rc/branch_open_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_checked.png b/src/ui/qdarkstyle/rc/checkbox_checked.png new file mode 100644 index 0000000..5acad08 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_checked.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_checked@2x.png b/src/ui/qdarkstyle/rc/checkbox_checked@2x.png new file mode 100644 index 0000000..99e66ca Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_checked@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_checked_disabled.png b/src/ui/qdarkstyle/rc/checkbox_checked_disabled.png new file mode 100644 index 0000000..bad9677 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_checked_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_checked_disabled@2x.png b/src/ui/qdarkstyle/rc/checkbox_checked_disabled@2x.png new file mode 100644 index 0000000..3c3ea0b Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_checked_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_checked_focus.png b/src/ui/qdarkstyle/rc/checkbox_checked_focus.png new file mode 100644 index 0000000..464b573 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_checked_focus.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_checked_focus@2x.png b/src/ui/qdarkstyle/rc/checkbox_checked_focus@2x.png new file mode 100644 index 0000000..1c30bd1 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_checked_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_checked_pressed.png b/src/ui/qdarkstyle/rc/checkbox_checked_pressed.png new file mode 100644 index 0000000..4ca5764 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_checked_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_checked_pressed@2x.png b/src/ui/qdarkstyle/rc/checkbox_checked_pressed@2x.png new file mode 100644 index 0000000..a617952 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_checked_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_indeterminate.png b/src/ui/qdarkstyle/rc/checkbox_indeterminate.png new file mode 100644 index 0000000..b1c6e71 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_indeterminate.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_indeterminate@2x.png b/src/ui/qdarkstyle/rc/checkbox_indeterminate@2x.png new file mode 100644 index 0000000..0d8feb9 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_indeterminate@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_indeterminate_disabled.png b/src/ui/qdarkstyle/rc/checkbox_indeterminate_disabled.png new file mode 100644 index 0000000..04d7da1 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_indeterminate_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_indeterminate_disabled@2x.png b/src/ui/qdarkstyle/rc/checkbox_indeterminate_disabled@2x.png new file mode 100644 index 0000000..de228aa Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_indeterminate_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_indeterminate_focus.png b/src/ui/qdarkstyle/rc/checkbox_indeterminate_focus.png new file mode 100644 index 0000000..f7f6d71 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_indeterminate_focus.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_indeterminate_focus@2x.png b/src/ui/qdarkstyle/rc/checkbox_indeterminate_focus@2x.png new file mode 100644 index 0000000..3638a7f Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_indeterminate_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_indeterminate_pressed.png b/src/ui/qdarkstyle/rc/checkbox_indeterminate_pressed.png new file mode 100644 index 0000000..31220be Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_indeterminate_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_indeterminate_pressed@2x.png b/src/ui/qdarkstyle/rc/checkbox_indeterminate_pressed@2x.png new file mode 100644 index 0000000..8d112b1 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_indeterminate_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_unchecked.png b/src/ui/qdarkstyle/rc/checkbox_unchecked.png new file mode 100644 index 0000000..4e68c78 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_unchecked.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_unchecked@2x.png b/src/ui/qdarkstyle/rc/checkbox_unchecked@2x.png new file mode 100644 index 0000000..c0c4ec9 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_unchecked@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_unchecked_disabled.png b/src/ui/qdarkstyle/rc/checkbox_unchecked_disabled.png new file mode 100644 index 0000000..9fb0036 Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_unchecked_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_unchecked_disabled@2x.png b/src/ui/qdarkstyle/rc/checkbox_unchecked_disabled@2x.png new file mode 100644 index 0000000..8d6c0ed Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_unchecked_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_unchecked_focus.png b/src/ui/qdarkstyle/rc/checkbox_unchecked_focus.png new file mode 100644 index 0000000..2d6b2fc Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_unchecked_focus.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_unchecked_focus@2x.png b/src/ui/qdarkstyle/rc/checkbox_unchecked_focus@2x.png new file mode 100644 index 0000000..ed63aaa Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_unchecked_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_unchecked_pressed.png b/src/ui/qdarkstyle/rc/checkbox_unchecked_pressed.png new file mode 100644 index 0000000..85c6c9b Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_unchecked_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/checkbox_unchecked_pressed@2x.png b/src/ui/qdarkstyle/rc/checkbox_unchecked_pressed@2x.png new file mode 100644 index 0000000..2a4b99a Binary files /dev/null and b/src/ui/qdarkstyle/rc/checkbox_unchecked_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/line_horizontal.png b/src/ui/qdarkstyle/rc/line_horizontal.png new file mode 100644 index 0000000..a89a1ed Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_horizontal.png differ diff --git a/src/ui/qdarkstyle/rc/line_horizontal@2x.png b/src/ui/qdarkstyle/rc/line_horizontal@2x.png new file mode 100644 index 0000000..3c6899f Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_horizontal@2x.png differ diff --git a/src/ui/qdarkstyle/rc/line_horizontal_disabled.png b/src/ui/qdarkstyle/rc/line_horizontal_disabled.png new file mode 100644 index 0000000..b89b2c9 Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_horizontal_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/line_horizontal_disabled@2x.png b/src/ui/qdarkstyle/rc/line_horizontal_disabled@2x.png new file mode 100644 index 0000000..027a030 Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_horizontal_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/line_horizontal_focus.png b/src/ui/qdarkstyle/rc/line_horizontal_focus.png new file mode 100644 index 0000000..148a2df Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_horizontal_focus.png differ diff --git a/src/ui/qdarkstyle/rc/line_horizontal_focus@2x.png b/src/ui/qdarkstyle/rc/line_horizontal_focus@2x.png new file mode 100644 index 0000000..bdce2bb Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_horizontal_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/line_horizontal_pressed.png b/src/ui/qdarkstyle/rc/line_horizontal_pressed.png new file mode 100644 index 0000000..c4587b8 Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_horizontal_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/line_horizontal_pressed@2x.png b/src/ui/qdarkstyle/rc/line_horizontal_pressed@2x.png new file mode 100644 index 0000000..9210add Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_horizontal_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/line_vertical.png b/src/ui/qdarkstyle/rc/line_vertical.png new file mode 100644 index 0000000..36c7ddf Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_vertical.png differ diff --git a/src/ui/qdarkstyle/rc/line_vertical@2x.png b/src/ui/qdarkstyle/rc/line_vertical@2x.png new file mode 100644 index 0000000..573c551 Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_vertical@2x.png differ diff --git a/src/ui/qdarkstyle/rc/line_vertical_disabled.png b/src/ui/qdarkstyle/rc/line_vertical_disabled.png new file mode 100644 index 0000000..36f9b4e Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_vertical_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/line_vertical_disabled@2x.png b/src/ui/qdarkstyle/rc/line_vertical_disabled@2x.png new file mode 100644 index 0000000..cf615a5 Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_vertical_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/line_vertical_focus.png b/src/ui/qdarkstyle/rc/line_vertical_focus.png new file mode 100644 index 0000000..b81bc5b Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_vertical_focus.png differ diff --git a/src/ui/qdarkstyle/rc/line_vertical_focus@2x.png b/src/ui/qdarkstyle/rc/line_vertical_focus@2x.png new file mode 100644 index 0000000..c474ed9 Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_vertical_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/line_vertical_pressed.png b/src/ui/qdarkstyle/rc/line_vertical_pressed.png new file mode 100644 index 0000000..445aa18 Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_vertical_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/line_vertical_pressed@2x.png b/src/ui/qdarkstyle/rc/line_vertical_pressed@2x.png new file mode 100644 index 0000000..4117b54 Binary files /dev/null and b/src/ui/qdarkstyle/rc/line_vertical_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/radio_checked.png b/src/ui/qdarkstyle/rc/radio_checked.png new file mode 100644 index 0000000..3521990 Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_checked.png differ diff --git a/src/ui/qdarkstyle/rc/radio_checked@2x.png b/src/ui/qdarkstyle/rc/radio_checked@2x.png new file mode 100644 index 0000000..b4db822 Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_checked@2x.png differ diff --git a/src/ui/qdarkstyle/rc/radio_checked_disabled.png b/src/ui/qdarkstyle/rc/radio_checked_disabled.png new file mode 100644 index 0000000..6bf1e26 Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_checked_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/radio_checked_disabled@2x.png b/src/ui/qdarkstyle/rc/radio_checked_disabled@2x.png new file mode 100644 index 0000000..c2c08f9 Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_checked_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/radio_checked_focus.png b/src/ui/qdarkstyle/rc/radio_checked_focus.png new file mode 100644 index 0000000..a74da48 Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_checked_focus.png differ diff --git a/src/ui/qdarkstyle/rc/radio_checked_focus@2x.png b/src/ui/qdarkstyle/rc/radio_checked_focus@2x.png new file mode 100644 index 0000000..3282d3e Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_checked_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/radio_checked_pressed.png b/src/ui/qdarkstyle/rc/radio_checked_pressed.png new file mode 100644 index 0000000..06131ab Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_checked_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/radio_checked_pressed@2x.png b/src/ui/qdarkstyle/rc/radio_checked_pressed@2x.png new file mode 100644 index 0000000..f7b1f57 Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_checked_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/radio_unchecked.png b/src/ui/qdarkstyle/rc/radio_unchecked.png new file mode 100644 index 0000000..3428257 Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_unchecked.png differ diff --git a/src/ui/qdarkstyle/rc/radio_unchecked@2x.png b/src/ui/qdarkstyle/rc/radio_unchecked@2x.png new file mode 100644 index 0000000..b34782b Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_unchecked@2x.png differ diff --git a/src/ui/qdarkstyle/rc/radio_unchecked_disabled.png b/src/ui/qdarkstyle/rc/radio_unchecked_disabled.png new file mode 100644 index 0000000..1205d7f Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_unchecked_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/radio_unchecked_disabled@2x.png b/src/ui/qdarkstyle/rc/radio_unchecked_disabled@2x.png new file mode 100644 index 0000000..e050fee Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_unchecked_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/radio_unchecked_focus.png b/src/ui/qdarkstyle/rc/radio_unchecked_focus.png new file mode 100644 index 0000000..caa245f Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_unchecked_focus.png differ diff --git a/src/ui/qdarkstyle/rc/radio_unchecked_focus@2x.png b/src/ui/qdarkstyle/rc/radio_unchecked_focus@2x.png new file mode 100644 index 0000000..dd81932 Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_unchecked_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/radio_unchecked_pressed.png b/src/ui/qdarkstyle/rc/radio_unchecked_pressed.png new file mode 100644 index 0000000..21711dc Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_unchecked_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/radio_unchecked_pressed@2x.png b/src/ui/qdarkstyle/rc/radio_unchecked_pressed@2x.png new file mode 100644 index 0000000..1a1b9c2 Binary files /dev/null and b/src/ui/qdarkstyle/rc/radio_unchecked_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_horizontal.png b/src/ui/qdarkstyle/rc/toolbar_move_horizontal.png new file mode 100644 index 0000000..5dbf8c2 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_horizontal.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_horizontal@2x.png b/src/ui/qdarkstyle/rc/toolbar_move_horizontal@2x.png new file mode 100644 index 0000000..e775854 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_horizontal@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_horizontal_disabled.png b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_disabled.png new file mode 100644 index 0000000..0563329 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_horizontal_disabled@2x.png b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_disabled@2x.png new file mode 100644 index 0000000..42eed67 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_horizontal_focus.png b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_focus.png new file mode 100644 index 0000000..d870747 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_focus.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_horizontal_focus@2x.png b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_focus@2x.png new file mode 100644 index 0000000..f292153 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_horizontal_pressed.png b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_pressed.png new file mode 100644 index 0000000..69cc1c5 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_horizontal_pressed@2x.png b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_pressed@2x.png new file mode 100644 index 0000000..9819881 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_horizontal_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_vertical.png b/src/ui/qdarkstyle/rc/toolbar_move_vertical.png new file mode 100644 index 0000000..4450862 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_vertical.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_vertical@2x.png b/src/ui/qdarkstyle/rc/toolbar_move_vertical@2x.png new file mode 100644 index 0000000..3f0618f Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_vertical@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_vertical_disabled.png b/src/ui/qdarkstyle/rc/toolbar_move_vertical_disabled.png new file mode 100644 index 0000000..1369e44 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_vertical_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_vertical_disabled@2x.png b/src/ui/qdarkstyle/rc/toolbar_move_vertical_disabled@2x.png new file mode 100644 index 0000000..5820962 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_vertical_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_vertical_focus.png b/src/ui/qdarkstyle/rc/toolbar_move_vertical_focus.png new file mode 100644 index 0000000..28cedf1 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_vertical_focus.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_vertical_focus@2x.png b/src/ui/qdarkstyle/rc/toolbar_move_vertical_focus@2x.png new file mode 100644 index 0000000..828ed59 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_vertical_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_vertical_pressed.png b/src/ui/qdarkstyle/rc/toolbar_move_vertical_pressed.png new file mode 100644 index 0000000..2b413d3 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_vertical_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_move_vertical_pressed@2x.png b/src/ui/qdarkstyle/rc/toolbar_move_vertical_pressed@2x.png new file mode 100644 index 0000000..4e80a0b Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_move_vertical_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_horizontal.png b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal.png new file mode 100644 index 0000000..a1e84c1 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_horizontal@2x.png b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal@2x.png new file mode 100644 index 0000000..664323f Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_disabled.png b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_disabled.png new file mode 100644 index 0000000..bedbab4 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_disabled@2x.png b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_disabled@2x.png new file mode 100644 index 0000000..d421e81 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_focus.png b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_focus.png new file mode 100644 index 0000000..1632c59 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_focus.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_focus@2x.png b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_focus@2x.png new file mode 100644 index 0000000..da41f2c Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_pressed.png b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_pressed.png new file mode 100644 index 0000000..e03fb80 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_pressed@2x.png b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_pressed@2x.png new file mode 100644 index 0000000..64a94a4 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_horizontal_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_vertical.png b/src/ui/qdarkstyle/rc/toolbar_separator_vertical.png new file mode 100644 index 0000000..86688ee Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_vertical.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_vertical@2x.png b/src/ui/qdarkstyle/rc/toolbar_separator_vertical@2x.png new file mode 100644 index 0000000..e4efe8c Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_vertical@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_vertical_disabled.png b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_disabled.png new file mode 100644 index 0000000..2445368 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_vertical_disabled@2x.png b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_disabled@2x.png new file mode 100644 index 0000000..393920e Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_vertical_focus.png b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_focus.png new file mode 100644 index 0000000..d286348 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_focus.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_vertical_focus@2x.png b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_focus@2x.png new file mode 100644 index 0000000..ad701df Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_vertical_pressed.png b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_pressed.png new file mode 100644 index 0000000..7f09d5a Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/toolbar_separator_vertical_pressed@2x.png b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_pressed@2x.png new file mode 100644 index 0000000..08d83e1 Binary files /dev/null and b/src/ui/qdarkstyle/rc/toolbar_separator_vertical_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/transparent.png b/src/ui/qdarkstyle/rc/transparent.png new file mode 100644 index 0000000..6775361 Binary files /dev/null and b/src/ui/qdarkstyle/rc/transparent.png differ diff --git a/src/ui/qdarkstyle/rc/transparent@2x.png b/src/ui/qdarkstyle/rc/transparent@2x.png new file mode 100644 index 0000000..4012944 Binary files /dev/null and b/src/ui/qdarkstyle/rc/transparent@2x.png differ diff --git a/src/ui/qdarkstyle/rc/transparent_disabled.png b/src/ui/qdarkstyle/rc/transparent_disabled.png new file mode 100644 index 0000000..6775361 Binary files /dev/null and b/src/ui/qdarkstyle/rc/transparent_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/transparent_disabled@2x.png b/src/ui/qdarkstyle/rc/transparent_disabled@2x.png new file mode 100644 index 0000000..4012944 Binary files /dev/null and b/src/ui/qdarkstyle/rc/transparent_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/transparent_focus.png b/src/ui/qdarkstyle/rc/transparent_focus.png new file mode 100644 index 0000000..6775361 Binary files /dev/null and b/src/ui/qdarkstyle/rc/transparent_focus.png differ diff --git a/src/ui/qdarkstyle/rc/transparent_focus@2x.png b/src/ui/qdarkstyle/rc/transparent_focus@2x.png new file mode 100644 index 0000000..4012944 Binary files /dev/null and b/src/ui/qdarkstyle/rc/transparent_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/transparent_pressed.png b/src/ui/qdarkstyle/rc/transparent_pressed.png new file mode 100644 index 0000000..6775361 Binary files /dev/null and b/src/ui/qdarkstyle/rc/transparent_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/transparent_pressed@2x.png b/src/ui/qdarkstyle/rc/transparent_pressed@2x.png new file mode 100644 index 0000000..4012944 Binary files /dev/null and b/src/ui/qdarkstyle/rc/transparent_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_close.png b/src/ui/qdarkstyle/rc/window_close.png new file mode 100644 index 0000000..c7ac3e7 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_close.png differ diff --git a/src/ui/qdarkstyle/rc/window_close@2x.png b/src/ui/qdarkstyle/rc/window_close@2x.png new file mode 100644 index 0000000..b11aa08 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_close@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_close_disabled.png b/src/ui/qdarkstyle/rc/window_close_disabled.png new file mode 100644 index 0000000..d60edac Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_close_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/window_close_disabled@2x.png b/src/ui/qdarkstyle/rc/window_close_disabled@2x.png new file mode 100644 index 0000000..b571b12 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_close_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_close_focus.png b/src/ui/qdarkstyle/rc/window_close_focus.png new file mode 100644 index 0000000..c970d3f Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_close_focus.png differ diff --git a/src/ui/qdarkstyle/rc/window_close_focus@2x.png b/src/ui/qdarkstyle/rc/window_close_focus@2x.png new file mode 100644 index 0000000..f87ac73 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_close_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_close_pressed.png b/src/ui/qdarkstyle/rc/window_close_pressed.png new file mode 100644 index 0000000..c6da5c8 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_close_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/window_close_pressed@2x.png b/src/ui/qdarkstyle/rc/window_close_pressed@2x.png new file mode 100644 index 0000000..749009c Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_close_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_grip.png b/src/ui/qdarkstyle/rc/window_grip.png new file mode 100644 index 0000000..e3df93b Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_grip.png differ diff --git a/src/ui/qdarkstyle/rc/window_grip@2x.png b/src/ui/qdarkstyle/rc/window_grip@2x.png new file mode 100644 index 0000000..c5a0dcc Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_grip@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_grip_disabled.png b/src/ui/qdarkstyle/rc/window_grip_disabled.png new file mode 100644 index 0000000..3c0d86e Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_grip_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/window_grip_disabled@2x.png b/src/ui/qdarkstyle/rc/window_grip_disabled@2x.png new file mode 100644 index 0000000..f57b353 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_grip_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_grip_focus.png b/src/ui/qdarkstyle/rc/window_grip_focus.png new file mode 100644 index 0000000..2d35380 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_grip_focus.png differ diff --git a/src/ui/qdarkstyle/rc/window_grip_focus@2x.png b/src/ui/qdarkstyle/rc/window_grip_focus@2x.png new file mode 100644 index 0000000..d92f09b Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_grip_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_grip_pressed.png b/src/ui/qdarkstyle/rc/window_grip_pressed.png new file mode 100644 index 0000000..89d5908 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_grip_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/window_grip_pressed@2x.png b/src/ui/qdarkstyle/rc/window_grip_pressed@2x.png new file mode 100644 index 0000000..ef2dc70 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_grip_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_minimize.png b/src/ui/qdarkstyle/rc/window_minimize.png new file mode 100644 index 0000000..a850c48 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_minimize.png differ diff --git a/src/ui/qdarkstyle/rc/window_minimize@2x.png b/src/ui/qdarkstyle/rc/window_minimize@2x.png new file mode 100644 index 0000000..83b82b6 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_minimize@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_minimize_disabled.png b/src/ui/qdarkstyle/rc/window_minimize_disabled.png new file mode 100644 index 0000000..d66d070 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_minimize_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/window_minimize_disabled@2x.png b/src/ui/qdarkstyle/rc/window_minimize_disabled@2x.png new file mode 100644 index 0000000..3a7f2af Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_minimize_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_minimize_focus.png b/src/ui/qdarkstyle/rc/window_minimize_focus.png new file mode 100644 index 0000000..f533977 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_minimize_focus.png differ diff --git a/src/ui/qdarkstyle/rc/window_minimize_focus@2x.png b/src/ui/qdarkstyle/rc/window_minimize_focus@2x.png new file mode 100644 index 0000000..a2b376a Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_minimize_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_minimize_pressed.png b/src/ui/qdarkstyle/rc/window_minimize_pressed.png new file mode 100644 index 0000000..ac050a0 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_minimize_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/window_minimize_pressed@2x.png b/src/ui/qdarkstyle/rc/window_minimize_pressed@2x.png new file mode 100644 index 0000000..b701572 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_minimize_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_undock.png b/src/ui/qdarkstyle/rc/window_undock.png new file mode 100644 index 0000000..fab0e72 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_undock.png differ diff --git a/src/ui/qdarkstyle/rc/window_undock@2x.png b/src/ui/qdarkstyle/rc/window_undock@2x.png new file mode 100644 index 0000000..9574d4a Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_undock@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_undock_disabled.png b/src/ui/qdarkstyle/rc/window_undock_disabled.png new file mode 100644 index 0000000..a2e1649 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_undock_disabled.png differ diff --git a/src/ui/qdarkstyle/rc/window_undock_disabled@2x.png b/src/ui/qdarkstyle/rc/window_undock_disabled@2x.png new file mode 100644 index 0000000..b6d5c6c Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_undock_disabled@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_undock_focus.png b/src/ui/qdarkstyle/rc/window_undock_focus.png new file mode 100644 index 0000000..2932dea Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_undock_focus.png differ diff --git a/src/ui/qdarkstyle/rc/window_undock_focus@2x.png b/src/ui/qdarkstyle/rc/window_undock_focus@2x.png new file mode 100644 index 0000000..62de7ba Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_undock_focus@2x.png differ diff --git a/src/ui/qdarkstyle/rc/window_undock_pressed.png b/src/ui/qdarkstyle/rc/window_undock_pressed.png new file mode 100644 index 0000000..4ccf8a5 Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_undock_pressed.png differ diff --git a/src/ui/qdarkstyle/rc/window_undock_pressed@2x.png b/src/ui/qdarkstyle/rc/window_undock_pressed@2x.png new file mode 100644 index 0000000..fba29fc Binary files /dev/null and b/src/ui/qdarkstyle/rc/window_undock_pressed@2x.png differ diff --git a/src/ui/qdarkstyle/style.qrc b/src/ui/qdarkstyle/style.qrc new file mode 100644 index 0000000..e301854 --- /dev/null +++ b/src/ui/qdarkstyle/style.qrc @@ -0,0 +1,216 @@ + + + + rc/arrow_down.png + rc/arrow_down@2x.png + rc/arrow_down_disabled.png + rc/arrow_down_disabled@2x.png + rc/arrow_down_focus.png + rc/arrow_down_focus@2x.png + rc/arrow_down_pressed.png + rc/arrow_down_pressed@2x.png + rc/arrow_left.png + rc/arrow_left@2x.png + rc/arrow_left_disabled.png + rc/arrow_left_disabled@2x.png + rc/arrow_left_focus.png + rc/arrow_left_focus@2x.png + rc/arrow_left_pressed.png + rc/arrow_left_pressed@2x.png + rc/arrow_right.png + rc/arrow_right@2x.png + rc/arrow_right_disabled.png + rc/arrow_right_disabled@2x.png + rc/arrow_right_focus.png + rc/arrow_right_focus@2x.png + rc/arrow_right_pressed.png + rc/arrow_right_pressed@2x.png + rc/arrow_up.png + rc/arrow_up@2x.png + rc/arrow_up_disabled.png + rc/arrow_up_disabled@2x.png + rc/arrow_up_focus.png + rc/arrow_up_focus@2x.png + rc/arrow_up_pressed.png + rc/arrow_up_pressed@2x.png + rc/base_icon.png + rc/base_icon@2x.png + rc/base_icon_disabled.png + rc/base_icon_disabled@2x.png + rc/base_icon_focus.png + rc/base_icon_focus@2x.png + rc/base_icon_pressed.png + rc/base_icon_pressed@2x.png + rc/branch_closed.png + rc/branch_closed@2x.png + rc/branch_closed_disabled.png + rc/branch_closed_disabled@2x.png + rc/branch_closed_focus.png + rc/branch_closed_focus@2x.png + rc/branch_closed_pressed.png + rc/branch_closed_pressed@2x.png + rc/branch_end.png + rc/branch_end@2x.png + rc/branch_end_disabled.png + rc/branch_end_disabled@2x.png + rc/branch_end_focus.png + rc/branch_end_focus@2x.png + rc/branch_end_pressed.png + rc/branch_end_pressed@2x.png + rc/branch_line.png + rc/branch_line@2x.png + rc/branch_line_disabled.png + rc/branch_line_disabled@2x.png + rc/branch_line_focus.png + rc/branch_line_focus@2x.png + rc/branch_line_pressed.png + rc/branch_line_pressed@2x.png + rc/branch_more.png + rc/branch_more@2x.png + rc/branch_more_disabled.png + rc/branch_more_disabled@2x.png + rc/branch_more_focus.png + rc/branch_more_focus@2x.png + rc/branch_more_pressed.png + rc/branch_more_pressed@2x.png + rc/branch_open.png + rc/branch_open@2x.png + rc/branch_open_disabled.png + rc/branch_open_disabled@2x.png + rc/branch_open_focus.png + rc/branch_open_focus@2x.png + rc/branch_open_pressed.png + rc/branch_open_pressed@2x.png + rc/checkbox_checked.png + rc/checkbox_checked@2x.png + rc/checkbox_checked_disabled.png + rc/checkbox_checked_disabled@2x.png + rc/checkbox_checked_focus.png + rc/checkbox_checked_focus@2x.png + rc/checkbox_checked_pressed.png + rc/checkbox_checked_pressed@2x.png + rc/checkbox_indeterminate.png + rc/checkbox_indeterminate@2x.png + rc/checkbox_indeterminate_disabled.png + rc/checkbox_indeterminate_disabled@2x.png + rc/checkbox_indeterminate_focus.png + rc/checkbox_indeterminate_focus@2x.png + rc/checkbox_indeterminate_pressed.png + rc/checkbox_indeterminate_pressed@2x.png + rc/checkbox_unchecked.png + rc/checkbox_unchecked@2x.png + rc/checkbox_unchecked_disabled.png + rc/checkbox_unchecked_disabled@2x.png + rc/checkbox_unchecked_focus.png + rc/checkbox_unchecked_focus@2x.png + rc/checkbox_unchecked_pressed.png + rc/checkbox_unchecked_pressed@2x.png + rc/line_horizontal.png + rc/line_horizontal@2x.png + rc/line_horizontal_disabled.png + rc/line_horizontal_disabled@2x.png + rc/line_horizontal_focus.png + rc/line_horizontal_focus@2x.png + rc/line_horizontal_pressed.png + rc/line_horizontal_pressed@2x.png + rc/line_vertical.png + rc/line_vertical@2x.png + rc/line_vertical_disabled.png + rc/line_vertical_disabled@2x.png + rc/line_vertical_focus.png + rc/line_vertical_focus@2x.png + rc/line_vertical_pressed.png + rc/line_vertical_pressed@2x.png + rc/radio_checked.png + rc/radio_checked@2x.png + rc/radio_checked_disabled.png + rc/radio_checked_disabled@2x.png + rc/radio_checked_focus.png + rc/radio_checked_focus@2x.png + rc/radio_checked_pressed.png + rc/radio_checked_pressed@2x.png + rc/radio_unchecked.png + rc/radio_unchecked@2x.png + rc/radio_unchecked_disabled.png + rc/radio_unchecked_disabled@2x.png + rc/radio_unchecked_focus.png + rc/radio_unchecked_focus@2x.png + rc/radio_unchecked_pressed.png + rc/radio_unchecked_pressed@2x.png + rc/toolbar_move_horizontal.png + rc/toolbar_move_horizontal@2x.png + rc/toolbar_move_horizontal_disabled.png + rc/toolbar_move_horizontal_disabled@2x.png + rc/toolbar_move_horizontal_focus.png + rc/toolbar_move_horizontal_focus@2x.png + rc/toolbar_move_horizontal_pressed.png + rc/toolbar_move_horizontal_pressed@2x.png + rc/toolbar_move_vertical.png + rc/toolbar_move_vertical@2x.png + rc/toolbar_move_vertical_disabled.png + rc/toolbar_move_vertical_disabled@2x.png + rc/toolbar_move_vertical_focus.png + rc/toolbar_move_vertical_focus@2x.png + rc/toolbar_move_vertical_pressed.png + rc/toolbar_move_vertical_pressed@2x.png + rc/toolbar_separator_horizontal.png + rc/toolbar_separator_horizontal@2x.png + rc/toolbar_separator_horizontal_disabled.png + rc/toolbar_separator_horizontal_disabled@2x.png + rc/toolbar_separator_horizontal_focus.png + rc/toolbar_separator_horizontal_focus@2x.png + rc/toolbar_separator_horizontal_pressed.png + rc/toolbar_separator_horizontal_pressed@2x.png + rc/toolbar_separator_vertical.png + rc/toolbar_separator_vertical@2x.png + rc/toolbar_separator_vertical_disabled.png + rc/toolbar_separator_vertical_disabled@2x.png + rc/toolbar_separator_vertical_focus.png + rc/toolbar_separator_vertical_focus@2x.png + rc/toolbar_separator_vertical_pressed.png + rc/toolbar_separator_vertical_pressed@2x.png + rc/transparent.png + rc/transparent@2x.png + rc/transparent_disabled.png + rc/transparent_disabled@2x.png + rc/transparent_focus.png + rc/transparent_focus@2x.png + rc/transparent_pressed.png + rc/transparent_pressed@2x.png + rc/window_close.png + rc/window_close@2x.png + rc/window_close_disabled.png + rc/window_close_disabled@2x.png + rc/window_close_focus.png + rc/window_close_focus@2x.png + rc/window_close_pressed.png + rc/window_close_pressed@2x.png + rc/window_grip.png + rc/window_grip@2x.png + rc/window_grip_disabled.png + rc/window_grip_disabled@2x.png + rc/window_grip_focus.png + rc/window_grip_focus@2x.png + rc/window_grip_pressed.png + rc/window_grip_pressed@2x.png + rc/window_minimize.png + rc/window_minimize@2x.png + rc/window_minimize_disabled.png + rc/window_minimize_disabled@2x.png + rc/window_minimize_focus.png + rc/window_minimize_focus@2x.png + rc/window_minimize_pressed.png + rc/window_minimize_pressed@2x.png + rc/window_undock.png + rc/window_undock@2x.png + rc/window_undock_disabled.png + rc/window_undock_disabled@2x.png + rc/window_undock_focus.png + rc/window_undock_focus@2x.png + rc/window_undock_pressed.png + rc/window_undock_pressed@2x.png + + + style.qss + + diff --git a/src/ui/qdarkstyle/style.qss b/src/ui/qdarkstyle/style.qss new file mode 100644 index 0000000..4605041 --- /dev/null +++ b/src/ui/qdarkstyle/style.qss @@ -0,0 +1,2195 @@ +/* QDarkStyleSheet ----------------------------------------------------------- + +This is the main style sheet, the palette has nine colors. + +It is based on three selecting colors, three greyish (background) colors +plus three whitish (foreground) colors. Each set of widgets of the same +type have a header like this: + + ------------------ + GroupName -------- + ------------------ + +And each widget is separated with a header like this: + + QWidgetName ------ + +This makes more easy to find and change some css field. The basic +configuration is described bellow. + + BACKGROUND ----------- + + Light (unpressed) + Normal (border, disabled, pressed, checked, toolbars, menus) + Dark (background) + + FOREGROUND ----------- + + Light (texts/labels) + Normal (not used yet) + Dark (disabled texts) + + SELECTION ------------ + + Light (selection/hover/active) + Normal (selected) + Dark (selected disabled) + +If a stranger configuration is required because of a bugfix or anything +else, keep the comment on the line above so nobody changes it, including the +issue number. + +*/ +/* + +See Qt documentation: + + - https://doc.qt.io/qt-5/stylesheet.html + - https://doc.qt.io/qt-5/stylesheet-reference.html + - https://doc.qt.io/qt-5/stylesheet-examples.html + +--------------------------------------------------------------------------- */ +/* QWidget ---------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QWidget { + background-color: #19232D; + border: 0px solid #32414B; + padding: 0px; + color: #F0F0F0; + selection-background-color: #1464A0; + selection-color: #F0F0F0; +} + +QWidget:disabled { + background-color: #19232D; + color: #787878; + selection-background-color: #14506E; + selection-color: #787878; +} + +QWidget::item:selected { + background-color: #1464A0; +} + +QWidget::item:hover { + background-color: #148CD2; + color: #32414B; +} + +/* QMainWindow ------------------------------------------------------------ + +This adjusts the splitter in the dock widget, not qsplitter +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow + +--------------------------------------------------------------------------- */ +QMainWindow::separator { + background-color: #32414B; + border: 0px solid #19232D; + spacing: 0px; + padding: 2px; +} + +QMainWindow::separator:hover { + background-color: #505F69; + border: 0px solid #148CD2; +} + +QMainWindow::separator:horizontal { + width: 5px; + margin-top: 2px; + margin-bottom: 2px; + image: url(":/qss_icons/rc/toolbar_separator_vertical.png"); +} + +QMainWindow::separator:vertical { + height: 5px; + margin-left: 2px; + margin-right: 2px; + image: url(":/qss_icons/rc/toolbar_separator_horizontal.png"); +} + +/* QToolTip --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip + +--------------------------------------------------------------------------- */ +QToolTip { + background-color: #148CD2; + border: 1px solid #19232D; + color: #19232D; + /* Remove padding, for fix combo box tooltip */ + padding: 0px; + /* Remove opacity, fix #174 - may need to use RGBA */ +} + +/* QStatusBar ------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar + +--------------------------------------------------------------------------- */ +QStatusBar { + border: 1px solid #32414B; + /* Fixes Spyder #9120, #9121 */ + background: #32414B; + /* Fixes #205, white vertical borders separating items */ +} + +QStatusBar::item { + border: none; +} + +QStatusBar QToolTip { + background-color: #148CD2; + border: 1px solid #19232D; + color: #19232D; + /* Remove padding, for fix combo box tooltip */ + padding: 0px; + /* Reducing transparency to read better */ + opacity: 230; +} + +QStatusBar QLabel { + /* Fixes Spyder #9120, #9121 */ + background: transparent; +} + +/* QCheckBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox + +--------------------------------------------------------------------------- */ +QCheckBox { + background-color: #19232D; + color: #F0F0F0; + spacing: 4px; + outline: none; + padding-top: 4px; + padding-bottom: 4px; +} + +QCheckBox:focus { + border: none; +} + +QCheckBox QWidget:disabled { + background-color: #19232D; + color: #787878; +} + +QCheckBox::indicator { + margin-left: 4px; + height: 16px; + width: 16px; +} + +QCheckBox::indicator:unchecked { + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QCheckBox::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QCheckBox::indicator:checked { + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QCheckBox::indicator:checked:disabled { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + +QCheckBox::indicator:indeterminate { + image: url(":/qss_icons/rc/checkbox_indeterminate.png"); +} + +QCheckBox::indicator:indeterminate:disabled { + image: url(":/qss_icons/rc/checkbox_indeterminate_disabled.png"); +} + +QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed { + image: url(":/qss_icons/rc/checkbox_indeterminate_focus.png"); +} + +/* QGroupBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox + +--------------------------------------------------------------------------- */ +QGroupBox { + font-weight: bold; + border: 1px solid #32414B; + border-radius: 4px; + padding: 4px; + margin-top: 16px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + left: 3px; + padding-left: 3px; + padding-right: 5px; + padding-top: 8px; + padding-bottom: 16px; +} + +QGroupBox::indicator { + margin-left: 2px; + height: 12px; + width: 12px; +} + +QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QGroupBox::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QGroupBox::indicator:checked:disabled { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + +/* QRadioButton ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton + +--------------------------------------------------------------------------- */ +QRadioButton { + background-color: #19232D; + color: #F0F0F0; + spacing: 4px; + padding: 0px; + border: none; + outline: none; +} + +QRadioButton:focus { + border: none; +} + +QRadioButton:disabled { + background-color: #19232D; + color: #787878; + border: none; + outline: none; +} + +QRadioButton QWidget { + background-color: #19232D; + color: #F0F0F0; + spacing: 0px; + padding: 0px; + outline: none; + border: none; +} + +QRadioButton::indicator { + border: none; + outline: none; + margin-left: 4px; + height: 16px; + width: 16px; +} + +QRadioButton::indicator:unchecked { + image: url(":/qss_icons/rc/radio_unchecked.png"); +} + +QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed { + border: none; + outline: none; + image: url(":/qss_icons/rc/radio_unchecked_focus.png"); +} + +QRadioButton::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/radio_unchecked_disabled.png"); +} + +QRadioButton::indicator:checked { + border: none; + outline: none; + image: url(":/qss_icons/rc/radio_checked.png"); +} + +QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed { + border: none; + outline: none; + image: url(":/qss_icons/rc/radio_checked_focus.png"); +} + +QRadioButton::indicator:checked:disabled { + outline: none; + image: url(":/qss_icons/rc/radio_checked_disabled.png"); +} + +/* QMenuBar --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar + +--------------------------------------------------------------------------- */ +QMenuBar { + background-color: #32414B; + padding: 2px; + border: 1px solid #19232D; + color: #F0F0F0; +} + +QMenuBar:focus { + border: 1px solid #148CD2; +} + +QMenuBar::item { + background: transparent; + padding: 4px; +} + +QMenuBar::item:selected { + padding: 4px; + background: transparent; + border: 0px solid #32414B; +} + +QMenuBar::item:pressed { + padding: 4px; + border: 0px solid #32414B; + background-color: #148CD2; + color: #F0F0F0; + margin-bottom: 0px; + padding-bottom: 0px; +} + +/* QMenu ------------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu + +--------------------------------------------------------------------------- */ +QMenu { + border: 0px solid #32414B; + color: #F0F0F0; + margin: 0px; +} + +QMenu::separator { + height: 1px; + background-color: #505F69; + color: #F0F0F0; +} + +QMenu::icon { + margin: 0px; + padding-left: 8px; +} + +QMenu::item { + background-color: #32414B; + padding: 4px 24px 4px 24px; + /* Reserve space for selection border */ + border: 1px transparent #32414B; +} + +QMenu::item:selected { + color: #F0F0F0; +} + +QMenu::indicator { + width: 12px; + height: 12px; + padding-left: 6px; + /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ + /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ +} + +QMenu::indicator:non-exclusive:unchecked { + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QMenu::indicator:non-exclusive:unchecked:selected { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QMenu::indicator:non-exclusive:checked { + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QMenu::indicator:non-exclusive:checked:selected { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + +QMenu::indicator:exclusive:unchecked { + image: url(":/qss_icons/rc/radio_unchecked.png"); +} + +QMenu::indicator:exclusive:unchecked:selected { + image: url(":/qss_icons/rc/radio_unchecked_disabled.png"); +} + +QMenu::indicator:exclusive:checked { + image: url(":/qss_icons/rc/radio_checked.png"); +} + +QMenu::indicator:exclusive:checked:selected { + image: url(":/qss_icons/rc/radio_checked_disabled.png"); +} + +QMenu::right-arrow { + margin: 5px; + image: url(":/qss_icons/rc/arrow_right.png"); + height: 12px; + width: 12px; +} + +/* QAbstractItemView ------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox + +--------------------------------------------------------------------------- */ +QAbstractItemView { + alternate-background-color: #19232D; + color: #F0F0F0; + border: 1px solid #32414B; + border-radius: 4px; +} + +QAbstractItemView QLineEdit { + padding: 2px; +} + +/* QAbstractScrollArea ---------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea + +--------------------------------------------------------------------------- */ +QAbstractScrollArea { + background-color: #19232D; + border: 1px solid #32414B; + border-radius: 4px; + padding: 2px; + /* fix #159 */ + min-height: 1.25em; + /* fix #159 */ + color: #F0F0F0; +} + +QAbstractScrollArea:disabled { + color: #787878; +} + +/* QScrollArea ------------------------------------------------------------ + +--------------------------------------------------------------------------- */ +QScrollArea QWidget QWidget:disabled { + background-color: #19232D; +} + +/* QScrollBar ------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar + +--------------------------------------------------------------------------- */ +QScrollBar:horizontal { + height: 16px; + margin: 2px 16px 2px 16px; + border: 1px solid #32414B; + border-radius: 4px; + background-color: #19232D; +} + +QScrollBar:vertical { + background-color: #19232D; + width: 16px; + margin: 16px 2px 16px 2px; + border: 1px solid #32414B; + border-radius: 4px; +} + +QScrollBar::handle:horizontal { + background-color: #787878; + border: 1px solid #32414B; + border-radius: 4px; + min-width: 8px; +} + +QScrollBar::handle:horizontal:hover { + background-color: #148CD2; + border: 1px solid #148CD2; + border-radius: 4px; + min-width: 8px; +} + +QScrollBar::handle:horizontal:focus { + border: 1px solid #1464A0; +} + +QScrollBar::handle:vertical { + background-color: #787878; + border: 1px solid #32414B; + min-height: 8px; + border-radius: 4px; +} + +QScrollBar::handle:vertical:hover { + background-color: #148CD2; + border: 1px solid #148CD2; + border-radius: 4px; + min-height: 8px; +} + +QScrollBar::handle:vertical:focus { + border: 1px solid #1464A0; +} + +QScrollBar::add-line:horizontal { + margin: 0px 0px 0px 0px; + border-image: url(":/qss_icons/rc/arrow_right_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { + border-image: url(":/qss_icons/rc/arrow_right.png"); + height: 12px; + width: 12px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { + border-image: url(":/qss_icons/rc/arrow_down.png"); + height: 12px; + width: 12px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal { + margin: 0px 3px 0px 3px; + border-image: url(":/qss_icons/rc/arrow_left_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { + border-image: url(":/qss_icons/rc/arrow_left.png"); + height: 12px; + width: 12px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(":/qss_icons/rc/arrow_up_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { + border-image: url(":/qss_icons/rc/arrow_up.png"); + height: 12px; + width: 12px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { + background: none; +} + +QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { + background: none; +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background: none; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; +} + +/* QTextEdit -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets + +--------------------------------------------------------------------------- */ +QTextEdit { + background-color: #19232D; + color: #F0F0F0; + border-radius: 4px; + border: 1px solid #32414B; +} + +QTextEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QTextEdit:focus { + border: 1px solid #1464A0; +} + +QTextEdit:selected { + background: #1464A0; + color: #32414B; +} + +/* QPlainTextEdit --------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QPlainTextEdit { + background-color: #19232D; + color: #F0F0F0; + border-radius: 4px; + border: 1px solid #32414B; +} + +QPlainTextEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPlainTextEdit:focus { + border: 1px solid #1464A0; +} + +QPlainTextEdit:selected { + background: #1464A0; + color: #32414B; +} + +/* QSizeGrip -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip + +--------------------------------------------------------------------------- */ +QSizeGrip { + background: transparent; + width: 12px; + height: 12px; + image: url(":/qss_icons/rc/window_grip.png"); +} + +/* QStackedWidget --------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QStackedWidget { + padding: 2px; + border: 1px solid #32414B; + border: 1px solid #19232D; +} + +/* QToolBar --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar + +--------------------------------------------------------------------------- */ +QToolBar { + background-color: #32414B; + border-bottom: 1px solid #19232D; + padding: 2px; + font-weight: bold; + spacing: 2px; +} + +QToolBar QToolButton { + background-color: #32414B; + border: 1px solid #32414B; +} + +QToolBar QToolButton:hover { + border: 1px solid #148CD2; +} + +QToolBar QToolButton:checked { + border: 1px solid #19232D; + background-color: #19232D; +} + +QToolBar QToolButton:checked:hover { + border: 1px solid #148CD2; +} + +QToolBar::handle:horizontal { + width: 16px; + image: url(":/qss_icons/rc/toolbar_move_horizontal.png"); +} + +QToolBar::handle:vertical { + height: 16px; + image: url(":/qss_icons/rc/toolbar_move_vertical.png"); +} + +QToolBar::separator:horizontal { + width: 16px; + image: url(":/qss_icons/rc/toolbar_separator_horizontal.png"); +} + +QToolBar::separator:vertical { + height: 16px; + image: url(":/qss_icons/rc/toolbar_separator_vertical.png"); +} + +QToolButton#qt_toolbar_ext_button { + background: #32414B; + border: 0px; + color: #F0F0F0; + image: url(":/qss_icons/rc/arrow_right.png"); +} + +/* QAbstractSpinBox ------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QAbstractSpinBox { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + /* This fixes 103, 111 */ + padding-top: 2px; + /* This fixes 103, 111 */ + padding-bottom: 2px; + padding-left: 4px; + padding-right: 4px; + border-radius: 4px; + /* min-width: 5px; removed to fix 109 */ +} + +QAbstractSpinBox:up-button { + background-color: transparent #19232D; + subcontrol-origin: border; + subcontrol-position: top right; + border-left: 1px solid #32414B; + border-bottom: 1px solid #32414B; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin: 1px; + width: 12px; + margin-bottom: -1px; +} + +QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off { + image: url(":/qss_icons/rc/arrow_up_disabled.png"); + height: 8px; + width: 8px; +} + +QAbstractSpinBox::up-arrow:hover { + image: url(":/qss_icons/rc/arrow_up.png"); +} + +QAbstractSpinBox:down-button { + background-color: transparent #19232D; + subcontrol-origin: border; + subcontrol-position: bottom right; + border-left: 1px solid #32414B; + border-top: 1px solid #32414B; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin: 1px; + width: 12px; + margin-top: -1px; +} + +QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off { + image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QAbstractSpinBox::down-arrow:hover { + image: url(":/qss_icons/rc/arrow_down.png"); +} + +QAbstractSpinBox:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QAbstractSpinBox:focus { + border: 1px solid #1464A0; +} + +QAbstractSpinBox:selected { + background: #1464A0; + color: #32414B; +} + +/* ------------------------------------------------------------------------ */ +/* DISPLAYS --------------------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QLabel ----------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe + +--------------------------------------------------------------------------- */ +QLabel { + background-color: #19232D; + border: 0px solid #32414B; + padding: 2px; + margin: 0px; + color: #F0F0F0; +} + +QLabel:disabled { + background-color: #19232D; + border: 0px solid #32414B; + color: #787878; +} + +/* QTextBrowser ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea + +--------------------------------------------------------------------------- */ +QTextBrowser { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; +} + +QTextBrowser:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; +} + +QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { + border: 1px solid #32414B; +} + +/* QGraphicsView ---------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QGraphicsView { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; +} + +QGraphicsView:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; +} + +QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { + border: 1px solid #32414B; +} + +/* QCalendarWidget -------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QCalendarWidget { + border: 1px solid #32414B; + border-radius: 4px; +} + +QCalendarWidget:disabled { + background-color: #19232D; + color: #787878; +} + +/* QLCDNumber ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QLCDNumber { + background-color: #19232D; + color: #F0F0F0; +} + +QLCDNumber:disabled { + background-color: #19232D; + color: #787878; +} + +/* QProgressBar ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar + +--------------------------------------------------------------------------- */ +QProgressBar { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + text-align: center; +} + +QProgressBar:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + text-align: center; +} + +QProgressBar::chunk { + background-color: #1464A0; + color: #19232D; + border-radius: 4px; +} + +QProgressBar::chunk:disabled { + background-color: #14506E; + color: #787878; + border-radius: 4px; +} + +/* ------------------------------------------------------------------------ */ +/* BUTTONS ---------------------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QPushButton ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton + +--------------------------------------------------------------------------- */ +QPushButton { + background-color: #505F69; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + padding: 3px; + outline: none; + /* Issue #194 - Special case of QPushButton inside dialogs, for better UI */ + min-width: 80px; +} + +QPushButton:disabled { + background-color: #32414B; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + padding: 3px; +} + +QPushButton:checked { + background-color: #32414B; + border: 1px solid #32414B; + border-radius: 4px; + padding: 3px; + outline: none; +} + +QPushButton:checked:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + padding: 3px; + outline: none; +} + +QPushButton:checked:selected { + background: #1464A0; + color: #32414B; +} + +QPushButton::menu-indicator { + subcontrol-origin: padding; + subcontrol-position: bottom right; + bottom: 4px; +} + +QPushButton:pressed { + background-color: #19232D; + border: 1px solid #19232D; +} + +QPushButton:pressed:hover { + border: 1px solid #148CD2; +} + +QPushButton:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPushButton:selected { + background: #1464A0; + color: #32414B; +} + +QPushButton:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPushButton:focus { + border: 1px solid #1464A0; +} + +/* QToolButton ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton + +--------------------------------------------------------------------------- */ +QToolButton { + background-color: transparent; + border: 1px solid transparent; + border-radius: 4px; + margin: 0px; + padding: 2px; + /* The subcontrols below are used only in the DelayedPopup mode */ + /* The subcontrols below are used only in the MenuButtonPopup mode */ + /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ +} + +QToolButton:checked { + background-color: transparent; + border: 1px solid #1464A0; +} + +QToolButton:checked:disabled { + border: 1px solid #14506E; +} + +QToolButton:pressed { + margin: 1px; + background-color: transparent; + border: 1px solid #1464A0; +} + +QToolButton:disabled { + border: none; +} + +QToolButton:hover { + border: 1px solid #148CD2; +} + +QToolButton[popupMode="0"] { + /* Only for DelayedPopup */ + padding-right: 2px; +} + +QToolButton[popupMode="1"] { + /* Only for MenuButtonPopup */ + padding-right: 20px; +} + +QToolButton[popupMode="1"]::menu-button { + border: none; +} + +QToolButton[popupMode="1"]::menu-button:hover { + border: none; + border-left: 1px solid #148CD2; + border-radius: 0; +} + +QToolButton[popupMode="2"] { + /* Only for InstantPopup */ + padding-right: 2px; +} + +QToolButton::menu-button { + padding: 2px; + border-radius: 4px; + border: 1px solid #32414B; + width: 12px; + outline: none; +} + +QToolButton::menu-button:hover { + border: 1px solid #148CD2; +} + +QToolButton::menu-button:checked:hover { + border: 1px solid #148CD2; +} + +QToolButton::menu-indicator { + image: url(":/qss_icons/rc/arrow_down.png"); + height: 8px; + width: 8px; + top: 0; + /* Exclude a shift for better image */ + left: -2px; + /* Shift it a bit */ +} + +QToolButton::menu-arrow { + image: url(":/qss_icons/rc/arrow_down.png"); + height: 8px; + width: 8px; +} + +QToolButton::menu-arrow:hover { + image: url(":/qss_icons/rc/arrow_down_focus.png"); +} + +/* QCommandLinkButton ----------------------------------------------------- + +--------------------------------------------------------------------------- */ +QCommandLinkButton { + background-color: transparent; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + padding: 0px; + margin: 0px; +} + +QCommandLinkButton:disabled { + background-color: transparent; + color: #787878; +} + +/* ------------------------------------------------------------------------ */ +/* INPUTS - NO FIELDS ----------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QComboBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox + +--------------------------------------------------------------------------- */ +QComboBox { + border: 1px solid #32414B; + border-radius: 4px; + selection-background-color: #1464A0; + padding-left: 4px; + padding-right: 36px; + /* 4 + 16*2 See scrollbar size */ + /* Fixes #103, #111 */ + min-height: 1.5em; + /* padding-top: 2px; removed to fix #132 */ + /* padding-bottom: 2px; removed to fix #132 */ + /* min-width: 75px; removed to fix #109 */ + /* Needed to remove indicator - fix #132 */ +} + +QComboBox QAbstractItemView { + border: 1px solid #32414B; + border-radius: 0; + background-color: #19232D; + selection-background-color: #1464A0; +} + +QComboBox QAbstractItemView:hover { + background-color: #19232D; + color: #F0F0F0; +} + +QComboBox QAbstractItemView:selected { + background: #1464A0; + color: #32414B; +} + +QComboBox QAbstractItemView:alternate { + background: #19232D; +} + +QComboBox:disabled { + background-color: #19232D; + color: #787878; +} + +QComboBox:hover { + border: 1px solid #148CD2; +} + +QComboBox:focus { + border: 1px solid #1464A0; +} + +QComboBox:on { + selection-background-color: #1464A0; +} + +QComboBox::indicator { + border: none; + border-radius: 0; + background-color: transparent; + selection-background-color: transparent; + color: transparent; + selection-color: transparent; + /* Needed to remove indicator - fix #132 */ +} + +QComboBox::indicator:alternate { + background: #19232D; +} + +QComboBox::item:alternate { + background: #19232D; +} + +QComboBox::item:checked { + font-weight: bold; +} + +QComboBox::item:selected { + border: 0px solid transparent; +} + +QComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 12px; + border-left: 1px solid #32414B; +} + +QComboBox::down-arrow { + image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { + image: url(":/qss_icons/rc/arrow_down.png"); +} + +/* QSlider ---------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider + +--------------------------------------------------------------------------- */ +QSlider:disabled { + background: #19232D; +} + +QSlider:focus { + border: none; +} + +QSlider::groove:horizontal { + background: #32414B; + border: 1px solid #32414B; + height: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::groove:vertical { + background: #32414B; + border: 1px solid #32414B; + width: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::add-page:vertical { + background: #1464A0; + border: 1px solid #32414B; + width: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::add-page:vertical :disabled { + background: #14506E; +} + +QSlider::sub-page:horizontal { + background: #1464A0; + border: 1px solid #32414B; + height: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::sub-page:horizontal:disabled { + background: #14506E; +} + +QSlider::handle:horizontal { + background: #787878; + border: 1px solid #32414B; + width: 8px; + height: 8px; + margin: -8px 0px; + border-radius: 4px; +} + +QSlider::handle:horizontal:hover { + background: #148CD2; + border: 1px solid #148CD2; +} + +QSlider::handle:horizontal:focus { + border: 1px solid #1464A0; +} + +QSlider::handle:vertical { + background: #787878; + border: 1px solid #32414B; + width: 8px; + height: 8px; + margin: 0 -8px; + border-radius: 4px; +} + +QSlider::handle:vertical:hover { + background: #148CD2; + border: 1px solid #148CD2; +} + +QSlider::handle:vertical:focus { + border: 1px solid #1464A0; +} + +/* QLineEdit -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit + +--------------------------------------------------------------------------- */ +QLineEdit { + background-color: #19232D; + padding-top: 2px; + /* This QLineEdit fix 103, 111 */ + padding-bottom: 2px; + /* This QLineEdit fix 103, 111 */ + padding-left: 4px; + padding-right: 4px; + border-style: solid; + border: 1px solid #32414B; + border-radius: 4px; + color: #F0F0F0; +} + +QLineEdit:disabled { + background-color: #19232D; + color: #787878; +} + +QLineEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QLineEdit:focus { + border: 1px solid #1464A0; +} + +QLineEdit:selected { + background-color: #1464A0; + color: #32414B; +} + +/* QTabWiget -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabWidget { + padding: 2px; + selection-background-color: #32414B; +} + +QTabWidget QWidget { + /* Fixes #189 */ + border-radius: 4px; +} + +QTabWidget::pane { + border: 1px solid #32414B; + border-radius: 4px; + margin: 0px; + /* Fixes double border inside pane with pyqt5 */ + padding: 0px; +} + +QTabWidget::pane:selected { + background-color: #32414B; + border: 1px solid #1464A0; +} + +/* QTabBar ---------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabBar { + qproperty-drawBase: 0; + border-radius: 4px; + margin: 0px; + padding: 2px; + border: 0; + /* left: 5px; move to the right by 5px - removed for fix */ +} + +QTabBar::close-button { + border: 0; + margin: 2px; + padding: 2px; + image: url(":/qss_icons/rc/window_close.png"); +} + +QTabBar::close-button:hover { + image: url(":/qss_icons/rc/window_close_focus.png"); +} + +QTabBar::close-button:pressed { + image: url(":/qss_icons/rc/window_close_pressed.png"); +} + +/* QTabBar::tab - selected ------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabBar::tab { + /* !selected and disabled ----------------------------------------- */ + /* selected ------------------------------------------------------- */ +} + +QTabBar::tab:top:selected:disabled { + border-bottom: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:bottom:selected:disabled { + border-top: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:left:selected:disabled { + border-right: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:right:selected:disabled { + border-left: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:top:!selected:disabled { + border-bottom: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:bottom:!selected:disabled { + border-top: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:left:!selected:disabled { + border-right: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:right:!selected:disabled { + border-left: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:top:!selected { + border-bottom: 2px solid #19232D; + margin-top: 2px; +} + +QTabBar::tab:bottom:!selected { + border-top: 2px solid #19232D; + margin-bottom: 3px; +} + +QTabBar::tab:left:!selected { + border-left: 2px solid #19232D; + margin-right: 2px; +} + +QTabBar::tab:right:!selected { + border-right: 2px solid #19232D; + margin-left: 2px; +} + +QTabBar::tab:top { + background-color: #32414B; + color: #F0F0F0; + margin-left: 2px; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + min-width: 5px; + border-bottom: 3px solid #32414B; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} + +QTabBar::tab:top:selected { + background-color: #505F69; + color: #F0F0F0; + border-bottom: 3px solid #1464A0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} + +QTabBar::tab:top:!selected:hover { + border: 1px solid #148CD2; + border-bottom: 3px solid #148CD2; + /* Fixes spyder-ide/spyder#9766 */ + padding-left: 4px; + padding-right: 4px; +} + +QTabBar::tab:bottom { + color: #F0F0F0; + border-top: 3px solid #32414B; + background-color: #32414B; + margin-left: 2px; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + min-width: 5px; +} + +QTabBar::tab:bottom:selected { + color: #F0F0F0; + background-color: #505F69; + border-top: 3px solid #1464A0; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} + +QTabBar::tab:bottom:!selected:hover { + border: 1px solid #148CD2; + border-top: 3px solid #148CD2; + /* Fixes spyder-ide/spyder#9766 */ + padding-left: 4px; + padding-right: 4px; +} + +QTabBar::tab:left { + color: #F0F0F0; + background-color: #32414B; + margin-top: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 4px; + padding-bottom: 4px; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + min-height: 5px; +} + +QTabBar::tab:left:selected { + color: #F0F0F0; + background-color: #505F69; + border-right: 3px solid #1464A0; +} + +QTabBar::tab:left:!selected:hover { + border: 1px solid #148CD2; + border-right: 3px solid #148CD2; + padding: 0px; +} + +QTabBar::tab:right { + color: #F0F0F0; + background-color: #32414B; + margin-top: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 4px; + padding-bottom: 4px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + min-height: 5px; +} + +QTabBar::tab:right:selected { + color: #F0F0F0; + background-color: #505F69; + border-left: 3px solid #1464A0; +} + +QTabBar::tab:right:!selected:hover { + border: 1px solid #148CD2; + border-left: 3px solid #148CD2; + padding: 0px; +} + +QTabBar QToolButton { + /* Fixes #136 */ + background-color: #32414B; + height: 12px; + width: 12px; +} + +QTabBar QToolButton:pressed { + background-color: #32414B; +} + +QTabBar QToolButton:pressed:hover { + border: 1px solid #148CD2; +} + +QTabBar QToolButton::left-arrow:enabled { + image: url(":/qss_icons/rc/arrow_left.png"); +} + +QTabBar QToolButton::left-arrow:disabled { + image: url(":/qss_icons/rc/arrow_left_disabled.png"); +} + +QTabBar QToolButton::right-arrow:enabled { + image: url(":/qss_icons/rc/arrow_right.png"); +} + +QTabBar QToolButton::right-arrow:disabled { + image: url(":/qss_icons/rc/arrow_right_disabled.png"); +} + +/* QDockWiget ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QDockWidget { + outline: 1px solid #32414B; + background-color: #19232D; + border: 1px solid #32414B; + border-radius: 4px; + titlebar-close-icon: url(":/qss_icons/rc/window_close.png"); + titlebar-normal-icon: url(":/qss_icons/rc/window_undock.png"); +} + +QDockWidget::title { + /* Better size for title bar */ + padding: 6px; + spacing: 4px; + border: none; + background-color: #32414B; +} + +QDockWidget::close-button { + background-color: #32414B; + border-radius: 4px; + border: none; +} + +QDockWidget::close-button:hover { + image: url(":/qss_icons/rc/window_close_focus.png"); +} + +QDockWidget::close-button:pressed { + image: url(":/qss_icons/rc/window_close_pressed.png"); +} + +QDockWidget::float-button { + background-color: #32414B; + border-radius: 4px; + border: none; +} + +QDockWidget::float-button:hover { + image: url(":/qss_icons/rc/window_undock_focus.png"); +} + +QDockWidget::float-button:pressed { + image: url(":/qss_icons/rc/window_undock_pressed.png"); +} + +/* QTreeView QListView QTableView ----------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview + +--------------------------------------------------------------------------- */ +QTreeView:branch:selected, QTreeView:branch:hover { + background: url(":/qss_icons/rc/transparent.png"); +} + +QTreeView:branch:has-siblings:!adjoins-item { + border-image: url(":/qss_icons/rc/branch_line.png") 0; +} + +QTreeView:branch:has-siblings:adjoins-item { + border-image: url(":/qss_icons/rc/branch_more.png") 0; +} + +QTreeView:branch:!has-children:!has-siblings:adjoins-item { + border-image: url(":/qss_icons/rc/branch_end.png") 0; +} + +QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings { + border-image: none; + image: url(":/qss_icons/rc/branch_closed.png"); +} + +QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings { + border-image: none; + image: url(":/qss_icons/rc/branch_open.png"); +} + +QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover { + image: url(":/qss_icons/rc/branch_closed_focus.png"); +} + +QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover { + image: url(":/qss_icons/rc/branch_open_focus.png"); +} + +QTreeView::indicator:checked, +QListView::indicator:checked { + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed, +QListView::indicator:checked:hover, +QListView::indicator:checked:focus, +QListView::indicator:checked:pressed { + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QTreeView::indicator:unchecked, +QListView::indicator:unchecked { + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed, +QListView::indicator:unchecked:hover, +QListView::indicator:unchecked:focus, +QListView::indicator:unchecked:pressed { + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QTreeView::indicator:indeterminate, +QListView::indicator:indeterminate { + image: url(":/qss_icons/rc/checkbox_indeterminate.png"); +} + +QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed, +QListView::indicator:indeterminate:hover, +QListView::indicator:indeterminate:focus, +QListView::indicator:indeterminate:pressed { + image: url(":/qss_icons/rc/checkbox_indeterminate_focus.png"); +} + +QTreeView, +QListView, +QTableView, +QColumnView { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + gridline-color: #32414B; + border-radius: 4px; +} + +QTreeView:disabled, +QListView:disabled, +QTableView:disabled, +QColumnView:disabled { + background-color: #19232D; + color: #787878; +} + +QTreeView:selected, +QListView:selected, +QTableView:selected, +QColumnView:selected { + background-color: #1464A0; + color: #32414B; +} + +QTreeView:hover, +QListView:hover, +QTableView:hover, +QColumnView:hover { + background-color: #19232D; +} + +QTreeView::item:pressed, +QListView::item:pressed, +QTableView::item:pressed, +QColumnView::item:pressed { + color: #FFFFFF; + background-color: #1464A0; +} + +QTreeView::item:selected:hover, +QListView::item:selected:hover, +QTableView::item:selected:hover, +QColumnView::item:selected:hover { + background: #1464A0; + color: #FFFFFF; +} + +QTreeView::item:selected:active, +QListView::item:selected:active, +QTableView::item:selected:active, +QColumnView::item:selected:active { + color: #FFFFFF; + background-color: #1464A0; +} + +QTreeView::item:!selected:hover, +QListView::item:!selected:hover, +QTableView::item:!selected:hover, +QColumnView::item:!selected:hover { + outline: 0; + color: #FFFFFF; + background-color: #19232D; +} + +QTableCornerButton::section { + background-color: #19232D; + border: 1px transparent #32414B; + border-radius: 0px; +} + +/* QHeaderView ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview + +--------------------------------------------------------------------------- */ +QHeaderView { + background-color: #32414B; + border: 0px transparent #32414B; + padding: 0px; + margin: 0px; + border-radius: 0px; +} + +QHeaderView:disabled { + background-color: #32414B; + border: 1px transparent #32414B; + padding: 2px; +} + +QHeaderView::section { + background-color: #32414B; + color: #F0F0F0; + padding: 2px; + border-radius: 0px; + text-align: left; +} + +QHeaderView::section:checked { + color: #F0F0F0; + background-color: #32414B; +} + +QHeaderView::section:checked:disabled { + color: #787878; + background-color: #14506E; +} + +QHeaderView::section::horizontal { + padding-left: 4px; + padding-right: 4px; + border-left: 1px solid #19232D; +} + +QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { + border-left: 1px solid #32414B; +} + +QHeaderView::section::horizontal:disabled { + color: #787878; +} + +QHeaderView::section::vertical { + padding-left: 4px; + padding-right: 4px; + border-top: 1px solid #19232D; +} + +QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { + border-top: 1px solid #32414B; +} + +QHeaderView::section::vertical:disabled { + color: #787878; +} + +QHeaderView::down-arrow { + /* Those settings (border/width/height/background-color) solve bug */ + /* transparent arrow background and size */ + background-color: #32414B; + border: none; + height: 12px; + width: 12px; + padding-left: 2px; + padding-right: 2px; + image: url(":/qss_icons/rc/arrow_down.png"); +} + +QHeaderView::up-arrow { + background-color: #32414B; + border: none; + height: 12px; + width: 12px; + padding-left: 2px; + padding-right: 2px; + image: url(":/qss_icons/rc/arrow_up.png"); +} + +/* QToolBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox + +--------------------------------------------------------------------------- */ +QToolBox { + padding: 0px; + border: 0px; + border: 1px solid #32414B; +} + +QToolBox:selected { + padding: 0px; + border: 2px solid #1464A0; +} + +QToolBox::tab { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} + +QToolBox::tab:disabled { + color: #787878; +} + +QToolBox::tab:selected { + background-color: #505F69; + border-bottom: 2px solid #1464A0; +} + +QToolBox::tab:selected:disabled { + background-color: #32414B; + border-bottom: 2px solid #14506E; +} + +QToolBox::tab:!selected { + background-color: #32414B; + border-bottom: 2px solid #32414B; +} + +QToolBox::tab:!selected:disabled { + background-color: #19232D; +} + +QToolBox::tab:hover { + border-color: #148CD2; + border-bottom: 2px solid #148CD2; +} + +QToolBox QScrollArea QWidget QWidget { + padding: 0px; + border: 0px; + background-color: #19232D; +} + +/* QFrame ----------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe +https://doc.qt.io/qt-5/qframe.html#-prop +https://doc.qt.io/qt-5/qframe.html#details +https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color + +--------------------------------------------------------------------------- */ +/* (dot) .QFrame fix #141, #126, #123 */ +.QFrame { + border-radius: 4px; + border: 1px solid #32414B; + /* No frame */ + /* HLine */ + /* HLine */ +} + +.QFrame[frameShape="0"] { + border-radius: 4px; + border: 1px transparent #32414B; +} + +.QFrame[frameShape="4"] { + max-height: 2px; + border: none; + background-color: #32414B; +} + +.QFrame[frameShape="5"] { + max-width: 2px; + border: none; + background-color: #32414B; +} + +/* QSplitter -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter + +--------------------------------------------------------------------------- */ +QSplitter { + background-color: #32414B; + spacing: 0px; + padding: 0px; + margin: 0px; +} + +QSplitter::handle { + background-color: #32414B; + border: 0px solid #19232D; + spacing: 0px; + padding: 1px; + margin: 0px; +} + +QSplitter::handle:hover { + background-color: #787878; +} + +QSplitter::handle:horizontal { + width: 5px; + image: url(":/qss_icons/rc/line_vertical.png"); +} + +QSplitter::handle:vertical { + height: 5px; + image: url(":/qss_icons/rc/line_horizontal.png"); +} + +/* QDateEdit -------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QDateEdit { + selection-background-color: #1464A0; + border-style: solid; + border: 1px solid #32414B; + border-radius: 4px; + /* This fixes 103, 111 */ + padding-top: 2px; + /* This fixes 103, 111 */ + padding-bottom: 2px; + padding-left: 4px; + padding-right: 4px; + min-width: 10px; +} + +QDateEdit:on { + selection-background-color: #1464A0; +} + +QDateEdit::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 12px; + border-left: 1px solid #32414B; +} + +QDateEdit::down-arrow { + image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus { + image: url(":/qss_icons/rc/arrow_down.png"); +} + +QDateEdit QAbstractItemView { + background-color: #19232D; + border-radius: 4px; + border: 1px solid #32414B; + selection-background-color: #1464A0; +} + +/* QAbstractView ---------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QAbstractView:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QAbstractView:selected { + background: #1464A0; + color: #32414B; +} + +/* PlotWidget ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +PlotWidget { + /* Fix cut labels in plots #134 */ + padding: 0px; +} + +/* fixes */ + +QComboBox::item:checked { + font-weight: bold; + max-height: 30px; +} + +QPushButton { + min-width: default; +} + +QPushButton:flat { + background-color: transparent; + border: none; +} + +/* GroupBox checkbox contrast */ + +QGroupBox::indicator:unchecked { + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QGroupBox::indicator:checked { + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QGroupBox::indicator:indeterminate { + image: url(":/qss_icons/rc/checkbox_indeterminate.png"); +} + +QGroupBox::indicator:indeterminate:disabled { + image: url(":/qss_icons/rc/checkbox_indeterminate_disabled.png"); +} + +QGroupBox::indicator:indeterminate:focus, QGroupBox::indicator:indeterminate:hover, QGroupBox::indicator:indeterminate:pressed { + image: url(":/qss_icons/rc/checkbox_indeterminate_focus.png"); +} diff --git a/src/ui/qdarkstyle/svg/arrow_down.svg b/src/ui/qdarkstyle/svg/arrow_down.svg new file mode 100644 index 0000000..301d663 --- /dev/null +++ b/src/ui/qdarkstyle/svg/arrow_down.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/arrow_left.svg b/src/ui/qdarkstyle/svg/arrow_left.svg new file mode 100644 index 0000000..1f7c290 --- /dev/null +++ b/src/ui/qdarkstyle/svg/arrow_left.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/arrow_right.svg b/src/ui/qdarkstyle/svg/arrow_right.svg new file mode 100644 index 0000000..03c6620 --- /dev/null +++ b/src/ui/qdarkstyle/svg/arrow_right.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/arrow_up.svg b/src/ui/qdarkstyle/svg/arrow_up.svg new file mode 100644 index 0000000..ccfa66b --- /dev/null +++ b/src/ui/qdarkstyle/svg/arrow_up.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/base_icon.svg b/src/ui/qdarkstyle/svg/base_icon.svg new file mode 100644 index 0000000..abf5d6b --- /dev/null +++ b/src/ui/qdarkstyle/svg/base_icon.svg @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/base_palette.svg b/src/ui/qdarkstyle/svg/base_palette.svg new file mode 100644 index 0000000..317b2eb --- /dev/null +++ b/src/ui/qdarkstyle/svg/base_palette.svg @@ -0,0 +1,443 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/branch_closed.svg b/src/ui/qdarkstyle/svg/branch_closed.svg new file mode 100644 index 0000000..e7664f4 --- /dev/null +++ b/src/ui/qdarkstyle/svg/branch_closed.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/branch_end.svg b/src/ui/qdarkstyle/svg/branch_end.svg new file mode 100644 index 0000000..d35acd0 --- /dev/null +++ b/src/ui/qdarkstyle/svg/branch_end.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/branch_line.svg b/src/ui/qdarkstyle/svg/branch_line.svg new file mode 100644 index 0000000..f327723 --- /dev/null +++ b/src/ui/qdarkstyle/svg/branch_line.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/branch_more.svg b/src/ui/qdarkstyle/svg/branch_more.svg new file mode 100644 index 0000000..f2bf317 --- /dev/null +++ b/src/ui/qdarkstyle/svg/branch_more.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/branch_open.svg b/src/ui/qdarkstyle/svg/branch_open.svg new file mode 100644 index 0000000..701cb60 --- /dev/null +++ b/src/ui/qdarkstyle/svg/branch_open.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/checkbox_checked.svg b/src/ui/qdarkstyle/svg/checkbox_checked.svg new file mode 100644 index 0000000..f8fb5dd --- /dev/null +++ b/src/ui/qdarkstyle/svg/checkbox_checked.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/checkbox_indeterminate.svg b/src/ui/qdarkstyle/svg/checkbox_indeterminate.svg new file mode 100644 index 0000000..7c6bdf9 --- /dev/null +++ b/src/ui/qdarkstyle/svg/checkbox_indeterminate.svg @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/checkbox_unchecked.svg b/src/ui/qdarkstyle/svg/checkbox_unchecked.svg new file mode 100644 index 0000000..cb17a25 --- /dev/null +++ b/src/ui/qdarkstyle/svg/checkbox_unchecked.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/line_horizontal.svg b/src/ui/qdarkstyle/svg/line_horizontal.svg new file mode 100644 index 0000000..f088e55 --- /dev/null +++ b/src/ui/qdarkstyle/svg/line_horizontal.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/line_vertical.svg b/src/ui/qdarkstyle/svg/line_vertical.svg new file mode 100644 index 0000000..7bed6cd --- /dev/null +++ b/src/ui/qdarkstyle/svg/line_vertical.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/radio_checked.svg b/src/ui/qdarkstyle/svg/radio_checked.svg new file mode 100644 index 0000000..0a0fd71 --- /dev/null +++ b/src/ui/qdarkstyle/svg/radio_checked.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/radio_unchecked.svg b/src/ui/qdarkstyle/svg/radio_unchecked.svg new file mode 100644 index 0000000..f1ce8a6 --- /dev/null +++ b/src/ui/qdarkstyle/svg/radio_unchecked.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/toolbar_move_horizontal.svg b/src/ui/qdarkstyle/svg/toolbar_move_horizontal.svg new file mode 100644 index 0000000..5ca9132 --- /dev/null +++ b/src/ui/qdarkstyle/svg/toolbar_move_horizontal.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/toolbar_move_vertical.svg b/src/ui/qdarkstyle/svg/toolbar_move_vertical.svg new file mode 100644 index 0000000..9db354d --- /dev/null +++ b/src/ui/qdarkstyle/svg/toolbar_move_vertical.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/toolbar_separator_horizontal.svg b/src/ui/qdarkstyle/svg/toolbar_separator_horizontal.svg new file mode 100644 index 0000000..49782cc --- /dev/null +++ b/src/ui/qdarkstyle/svg/toolbar_separator_horizontal.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/toolbar_separator_vertical.svg b/src/ui/qdarkstyle/svg/toolbar_separator_vertical.svg new file mode 100644 index 0000000..fa6c871 --- /dev/null +++ b/src/ui/qdarkstyle/svg/toolbar_separator_vertical.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/transparent.svg b/src/ui/qdarkstyle/svg/transparent.svg new file mode 100644 index 0000000..94adcfd --- /dev/null +++ b/src/ui/qdarkstyle/svg/transparent.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/window_close.svg b/src/ui/qdarkstyle/svg/window_close.svg new file mode 100644 index 0000000..bb73e25 --- /dev/null +++ b/src/ui/qdarkstyle/svg/window_close.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/window_grip.svg b/src/ui/qdarkstyle/svg/window_grip.svg new file mode 100644 index 0000000..2a03260 --- /dev/null +++ b/src/ui/qdarkstyle/svg/window_grip.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/window_minimize.svg b/src/ui/qdarkstyle/svg/window_minimize.svg new file mode 100644 index 0000000..c5a73b8 --- /dev/null +++ b/src/ui/qdarkstyle/svg/window_minimize.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/ui/qdarkstyle/svg/window_undock.svg b/src/ui/qdarkstyle/svg/window_undock.svg new file mode 100644 index 0000000..b6dda46 --- /dev/null +++ b/src/ui/qdarkstyle/svg/window_undock.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt new file mode 100644 index 0000000..7d16b0f --- /dev/null +++ b/src/utils/CMakeLists.txt @@ -0,0 +1,2 @@ +file(GLOB_RECURSE SRC_SOURCES *.cpp) +file(GLOB_RECURSE SRC_HEADERS *.h) diff --git a/src/utils/ScopeGuard.h b/src/utils/ScopeGuard.h new file mode 100644 index 0000000..6d5df04 --- /dev/null +++ b/src/utils/ScopeGuard.h @@ -0,0 +1,205 @@ +// Author: ricab +// Source: https://github.com/ricab/scope_guard +// +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// 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 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. +// +// For more information, please refer to + +#ifndef SCOPE_GUARD_HPP_ +#define SCOPE_GUARD_HPP_ + +#include +#include + +#if __cplusplus >= 201703L && defined(SG_REQUIRE_NOEXCEPT_IN_CPP17) +#define SG_REQUIRE_NOEXCEPT +#endif + +namespace sg +{ + namespace detail + { + /* --- Some custom type traits --- */ + + // Type trait determining whether a type is callable with no arguments + template + struct is_noarg_callable_t + : public std::false_type + {}; // in general, false + + template + struct is_noarg_callable_t()())> + : public std::true_type + {}; // only true when call expression valid + + // Type trait determining whether a no-argument callable returns void + template + struct returns_void_t + : public std::is_same()())> + {}; + + /* Type trait determining whether a no-arg callable is nothrow invocable if + required. This is where SG_REQUIRE_NOEXCEPT logic is encapsulated. */ + template + struct is_nothrow_invocable_if_required_t + : public +#ifdef SG_REQUIRE_NOEXCEPT + std::is_nothrow_invocable /* Note: _r variants not enough to + confirm void return: any return can be + discarded so all returns are + compatible with void */ +#else + std::true_type +#endif + {}; + + // logic AND of two or more type traits + template + struct and_t : public and_t> + {}; // for more than two arguments + + template + struct and_t : public std::conditional::type + {}; // for two arguments + + // Type trait determining whether a type is a proper scope_guard callback. + template + struct is_proper_sg_callback_t + : public and_t, + returns_void_t, + is_nothrow_invocable_if_required_t, + std::is_nothrow_destructible> + {}; + + + /* --- The actual scope_guard template --- */ + + template::value>::type> + class scope_guard; + + + /* --- Now the friend maker --- */ + + template + detail::scope_guard make_scope_guard(Callback&& callback) + noexcept(std::is_nothrow_constructible::value); /* + we need this in the inner namespace due to MSVC bugs preventing + sg::detail::scope_guard from befriending a sg::make_scope_guard + template instance in the parent namespace (see https://is.gd/xFfFhE). */ + + + /* --- The template specialization that actually defines the class --- */ + + template + class scope_guard final + { + public: + typedef Callback callback_type; + + scope_guard(scope_guard&& other) + noexcept(std::is_nothrow_constructible::value); + + ~scope_guard() noexcept; // highlight noexcept dtor + + void dismiss() noexcept; + + public: + scope_guard() = delete; + scope_guard(const scope_guard&) = delete; + scope_guard& operator=(const scope_guard&) = delete; + scope_guard& operator=(scope_guard&&) = delete; + + private: + explicit scope_guard(Callback&& callback) + noexcept(std::is_nothrow_constructible::value); /* + meant for friends only */ + + friend scope_guard make_scope_guard(Callback&&) + noexcept(std::is_nothrow_constructible::value); /* + only make_scope_guard can create scope_guards from scratch (i.e. non-move) + */ + + private: + Callback m_callback; + bool m_active; + + }; + +} // namespace detail + + +/* --- Now the single public maker function --- */ + +using detail::make_scope_guard; // see comment on declaration above + +} // namespace sg + +//////////////////////////////////////////////////////////////////////////////// +template +sg::detail::scope_guard::scope_guard(Callback&& callback) +noexcept(std::is_nothrow_constructible::value) + : m_callback(std::forward(callback)) /* use () instead of {} because + of DR 1467 (https://is.gd/WHmWuo), which still impacts older compilers + (e.g. GCC 4.x and clang <=3.6, see https://godbolt.org/g/TE9tPJ and + https://is.gd/Tsmh8G) */ + , m_active{true} +{} + +//////////////////////////////////////////////////////////////////////////////// +template +sg::detail::scope_guard::~scope_guard() noexcept +{ + if(m_active) + m_callback(); +} + +//////////////////////////////////////////////////////////////////////////////// +template +sg::detail::scope_guard::scope_guard(scope_guard&& other) +noexcept(std::is_nothrow_constructible::value) + : m_callback(std::forward(other.m_callback)) // idem + , m_active{std::move(other.m_active)} +{ + other.m_active = false; +} + +//////////////////////////////////////////////////////////////////////////////// +template +inline void sg::detail::scope_guard::dismiss() noexcept +{ + m_active = false; +} + +//////////////////////////////////////////////////////////////////////////////// +template +inline auto sg::detail::make_scope_guard(Callback&& callback) +noexcept(std::is_nothrow_constructible::value) +-> detail::scope_guard +{ + return detail::scope_guard{std::forward(callback)}; +} + +#endif /* SCOPE_GUARD_HPP_ */ diff --git a/src/utils/childproc.cpp b/src/utils/childproc.cpp new file mode 100644 index 0000000..383fe53 --- /dev/null +++ b/src/utils/childproc.cpp @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include "utils/childproc.h" + +ChildProcess::ChildProcess(QObject* parent) {} +ChildProcess::~ChildProcess() {} + +void ChildProcess::setupChildProcess() { +#if defined(HAVE_SYS_PRCTL_H) && defined(Q_OS_UNIX) + // https://smackerelofopinion.blogspot.com/2015/11/using-prsetpdeathsig-to-reap-child.html + ::prctl(PR_SET_PDEATHSIG, SIGKILL); +#endif +} \ No newline at end of file diff --git a/src/utils/childproc.h b/src/utils/childproc.h new file mode 100644 index 0000000..5f2bb43 --- /dev/null +++ b/src/utils/childproc.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_FPROCESS_H +#define FEATHER_FPROCESS_H + +#include +#include + +#if defined(HAVE_SYS_PRCTL_H) && defined(Q_OS_UNIX) +#include +#include +#endif + +class ChildProcess : public QProcess { + Q_OBJECT +public: + explicit ChildProcess(QObject* parent = nullptr); + ~ChildProcess(); +protected: + void setupChildProcess() override; +}; + + +#endif //FEATHER_FPROCESS_H diff --git a/src/utils/config.cpp b/src/utils/config.cpp new file mode 100644 index 0000000..362df96 --- /dev/null +++ b/src/utils/config.cpp @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (C) 2020 KeePassXC Team +// Copyright (C) 2011 Felix Geyer +// Copyright (C) 2020, The Monero Project. + +#include "config.h" +#include "utils/utils.h" +#include "utils/tails.h" + +#include +#include +#include + +#define QS QStringLiteral + +struct ConfigDirective +{ + QString name; + QVariant defaultValue; +}; + +static const QHash configStrings = { + // General + {Config::warnOnExternalLink,{QS("warnOnExternalLink"), true}}, + {Config::checkForAppUpdates,{QS("checkForAppUpdates"), true}}, + {Config::warnOnStagenet,{QS("warnOnStagenet"), true}}, + {Config::warnOnTestnet,{QS("warnOnTestnet"), true}}, + {Config::warnOnAlpha,{QS("warnOnAlpha"), true}}, + {Config::homeWidget,{QS("homeWidget"), "ccs"}}, + {Config::donateBeg,{QS("donateBeg"), 1}}, + {Config::skin,{QS("skin"), "light"}}, + {Config::preferredFiatCurrency,{QS("preferredFiatCurrency"), "USD"}}, + {Config::blockExplorer,{QS("blockExplorer"), "exploremonero.com"}}, + {Config::walletDirectory,{QS("walletDirectory"), ""}}, + {Config::autoOpenWalletPath,{QS("autoOpenWalletPath"), ""}}, + {Config::walletPath,{QS("walletPath"), ""}}, + {Config::nodes,{QS("nodes"), "{}"}}, + {Config::websocketEnabled,{QS("websocketEnabled"), true}}, + {Config::nodeSource,{QS("nodeSource"), 0}}, + {Config::useOnionNodes,{QS("useOnionNodes"), false}}, + {Config::showTabCoins,{QS("showTabCoins"), false}}, + {Config::showTabXMRto,{QS("showTabXMRto"), true}}, + {Config::showTabCalc,{QS("showTabCalc"), true}}, + {Config::geometry, {QS("geometry"), {}}}, + {Config::windowState, {QS("windowState"), {}}}, + {Config::firstRun,{QS("firstRun"), false}}, +}; + + +QPointer Config::m_instance(nullptr); + +QVariant Config::get(ConfigKey key) +{ + auto cfg = configStrings[key]; + auto defaultValue = configStrings[key].defaultValue; + + return m_settings->value(cfg.name, defaultValue); +} + +QString Config::getFileName() +{ + return m_settings->fileName(); +} + +void Config::set(ConfigKey key, const QVariant& value) +{ + if (get(key) == value) { + return; + } + + auto cfg = configStrings[key]; + m_settings->setValue(cfg.name, value); + + this->sync(); + emit changed(key); +} + +/** + * Sync configuration with persistent storage. + * + * Usually, you don't need to call this method manually, but if you are writing + * configurations after an emitted \link QCoreApplication::aboutToQuit() signal, + * use it to guarantee your config values are persisted. + */ +void Config::sync() +{ + m_settings->sync(); +} + +void Config::resetToDefaults() +{ + m_settings->clear(); +} + +Config::Config(const QString& fileName, QObject* parent) + : QObject(parent) +{ + init(fileName); +} + +Config::Config(QObject* parent) + : QObject(parent) +{ + QString configPath; + + bool isTails = TailsOS::detect(); + + configPath = QDir::homePath(); + if (isTails) { // #if defined(PORTABLE) + QString appImagePath = qgetenv("APPIMAGE"); + QFileInfo appImageDir(appImagePath); + + QDir portablePath(appImageDir.absoluteDir().path() + "/.feather"); + if (portablePath.mkpath(".")) { + configPath = portablePath.path(); + } + else { + qCritical() << "Unable to create portable directory: " << portablePath.path(); + } + } + + configPath += "/.config/feather/settings.json"; + + init(QDir::toNativeSeparators(configPath)); +} + + +Config::~Config() +{ +} + +void Config::init(const QString& configFileName) +{ + const QSettings::Format jsonFormat = QSettings::registerFormat("json", Utils::readJsonFile, Utils::writeJsonFile); + QSettings::setDefaultFormat(jsonFormat); + m_settings.reset(new QSettings(configFileName, jsonFormat)); + + connect(qApp, &QCoreApplication::aboutToQuit, this, &Config::sync); +} + +Config* Config::instance() +{ + if (!m_instance) { + m_instance = new Config(qApp); + } + + return m_instance; +} \ No newline at end of file diff --git a/src/utils/config.h b/src/utils/config.h new file mode 100644 index 0000000..2995062 --- /dev/null +++ b/src/utils/config.h @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (C) 2020 KeePassXC Team +// Copyright (C) 2011 Felix Geyer +// Copyright (C) 2020, The Monero Project. + +#ifndef FEATHER_SETTINGS_H +#define FEATHER_SETTINGS_H + +#include +#include +#include + +class Config : public QObject +{ + Q_OBJECT + +public: + Q_DISABLE_COPY(Config) + + enum ConfigKey + { + warnOnExternalLink, + checkForAppUpdates, + warnOnStagenet, + warnOnTestnet, + warnOnAlpha, + homeWidget, + donateBeg, + autoOpenWalletPath, + skin, + preferredFiatCurrency, + blockExplorer, + walletDirectory, + walletPath, + nodes, + websocketEnabled, + nodeSource, + useOnionNodes, + showTabCoins, + showTabXMRto, + showTabCalc, + geometry, + windowState, + firstRun + }; + + ~Config() override; + QVariant get(ConfigKey key); + QString getFileName(); + void set(ConfigKey key, const QVariant& value); + void sync(); + void resetToDefaults(); + + static Config* instance(); + +signals: + void changed(ConfigKey key); + +private: + Config(const QString& fileName, QObject* parent = nullptr); + explicit Config(QObject* parent); + void init(const QString& configFileName); + + static QPointer m_instance; + + QScopedPointer m_settings; + QHash m_defaults; +}; + +inline Config* config() +{ + return Config::instance(); +} + +#endif //FEATHER_SETTINGS_H diff --git a/src/utils/keysfiles.cpp b/src/utils/keysfiles.cpp new file mode 100644 index 0000000..39081bc --- /dev/null +++ b/src/utils/keysfiles.cpp @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "appcontext.h" +#include "utils/config.h" +#include "utils/networktype.h" +#include "utils/utils.h" +#include "keysfiles.h" + +using namespace std::chrono; + + +WalletKeysFiles::WalletKeysFiles(const QFileInfo &info, quint8 networkType, QString address) : + m_fileName(info.fileName()), + m_modified(info.lastModified().toSecsSinceEpoch()), + m_path(QDir::toNativeSeparators(info.absoluteFilePath())), + m_networkType(networkType), + m_address(std::move(address)) {} + +QString WalletKeysFiles::fileName() const { + return m_fileName; +} + +qint64 WalletKeysFiles::modified() const { + return m_modified; +} + +QString WalletKeysFiles::address() const { + return m_address; +} + +QString WalletKeysFiles::path() const { + return m_path; +} + +quint8 WalletKeysFiles::networkType() const { + return m_networkType; +} + +WalletKeysFilesModel::WalletKeysFilesModel(AppContext *ctx, QObject *parent) : + QAbstractTableModel(parent), + m_ctx(ctx) { + this->walletDirectories << m_ctx->defaultWalletDirRoot; + auto walletPath = config()->get(Config::walletPath).toString(); + if(!walletPath.isEmpty() && Utils::fileExists(walletPath)) { + QDir d = QFileInfo(walletPath).absoluteDir(); + this->walletDirectories << d.absolutePath(); + } + + this->walletDirectories << m_ctx->homeDir; + this->walletDirectories.removeDuplicates(); + + this->m_walletKeysFilesItemModel = qobject_cast(this); +} + +void WalletKeysFilesModel::clear() { + beginResetModel(); + m_walletKeyFiles.clear(); + endResetModel(); +} + +void WalletKeysFilesModel::refresh() { + this->clear(); + this->findWallets(); +} + +void WalletKeysFilesModel::findWallets() { + qDebug() << "wallet .keys search initiated"; + auto now = high_resolution_clock::now(); + + QRegExp rx("*.keys"); + rx.setPatternSyntax(QRegExp::Wildcard); + QStringList walletPaths; + + for(auto i = 0; i != this->walletDirectories.length(); i++) { + // Scan default wallet dir (~/Monero/) + walletPaths << Utils::fileFind(rx, this->walletDirectories[i], 0, i == 0 ? 2 : 0, 200); + } + + walletPaths.removeDuplicates(); + for(const auto &walletPath: walletPaths) { + QFile walletPathFile(walletPath); + if(walletPathFile.size() <= 0) + continue; + + QFileInfo fileInfo(walletPath); + const QString absPath = fileInfo.absoluteFilePath(); + const QString path = fileInfo.path(); + const QString baseName = fileInfo.baseName(); + const QString basePath = QString("%1/%2").arg(path).arg(baseName); + QString addr = QString(""); + quint8 networkType = NetworkType::MAINNET; + + if (Utils::fileExists(basePath + ".address.txt")) { + QFile file(basePath + ".address.txt"); + file.open(QFile::ReadOnly | QFile::Text); + const QString _address = QTextCodec::codecForMib(106)->toUnicode(file.readAll()); + + if (!_address.isEmpty()) { + addr = _address; + if (addr.startsWith("5") || addr.startsWith("7")) + networkType = NetworkType::STAGENET; + else if (addr.startsWith("9") || addr.startsWith("B")) + networkType = NetworkType::TESTNET; + } + file.close(); + } + + this->addWalletKeysFile(WalletKeysFiles(fileInfo, networkType, std::move(addr))); + } + + auto duration = duration_cast(high_resolution_clock::now() - now).count(); + qDebug() << QString("wallet .keys search completed in %1 ms").arg(duration); +} + +void WalletKeysFilesModel::addWalletKeysFile(const WalletKeysFiles &walletKeysFile) { + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + m_walletKeyFiles << walletKeysFile; + endInsertRows(); +} + +int WalletKeysFilesModel::rowCount(const QModelIndex & parent) const { + return parent.isValid() ? 0 : m_walletKeyFiles.count(); +} + +int WalletKeysFilesModel::columnCount(const QModelIndex &) const { + return 3; +} + +QVariant WalletKeysFilesModel::data(const QModelIndex &index, int role) const { + if (index.row() < 0 || index.row() >= m_walletKeyFiles.count()) + return QVariant(); + + const auto &walletKeyFile = m_walletKeyFiles[index.row()]; + + if (role == Qt::DisplayRole) { + switch(index.column()) { + case ModelColumns::NetworkType: { + auto c = static_cast(walletKeyFile.networkType()); + if (c == NetworkType::Type::STAGENET) + return QString("stage"); + else if (c == NetworkType::Type::TESTNET) + return QString("test"); + return QString("main"); + } + case ModelColumns::FileName: + return walletKeyFile.fileName(); + case ModelColumns::Path: { + auto fp = walletKeyFile.path(); +#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) + if (fp.startsWith(m_ctx->homeDir)) + fp = QString("~/%1").arg(fp.remove(0, m_ctx->homeDir.length() + 1)); +#endif + return fp; + } + default: + break; + } + } else if(role == Qt::UserRole) { + switch(index.column()) { + case ModelColumns::NetworkType: + return static_cast(walletKeyFile.networkType()); + case ModelColumns::FileName: + return walletKeyFile.fileName(); + case ModelColumns::Modified: + return (int)walletKeyFile.modified(); + case ModelColumns::Path: + return walletKeyFile.path(); + default: + break; + } + } + + return QVariant(); +} + +QVariant WalletKeysFilesModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (role != Qt::DisplayRole) + return QVariant(); + if (orientation == Qt::Horizontal) { + switch(section) { + case NetworkType: + return QString("Type"); + case FileName: + return QString("Name"); + case Path: + return QString("Path"); + default: + return QVariant(); + } + } + return QVariant(); +} + +WalletKeysFilesProxyModel::WalletKeysFilesProxyModel(QObject *parent) : + QSortFilterProxyModel(parent) {} + +bool WalletKeysFilesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { + return true; +} \ No newline at end of file diff --git a/src/utils/keysfiles.h b/src/utils/keysfiles.h new file mode 100644 index 0000000..4ce9a30 --- /dev/null +++ b/src/utils/keysfiles.h @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef KEYSFILES_H +#define KEYSFILES_H + +#include "libwalletqt/WalletManager.h" +#include "utils/networktype.h" +#include "utils/utils.h" +#include + +class WalletKeysFiles +{ +public: + WalletKeysFiles(const QFileInfo &info, quint8 networkType, QString address); + + QString fileName() const; + qint64 modified() const; + QString path() const; + quint8 networkType() const; + QString address() const; + +private: + QString m_fileName; + qint64 m_modified; + QString m_path; + quint8 m_networkType; + QString m_address; +}; + +class WalletKeysFilesModel : public QAbstractTableModel +{ + Q_OBJECT +public: + enum ModelColumns { + NetworkType = 0, + FileName, + Path, + Modified + }; + + explicit WalletKeysFilesModel(AppContext *ctx, QObject *parent = nullptr); + + Q_INVOKABLE void refresh(); + Q_INVOKABLE void clear(); + + void findWallets(); + void addWalletKeysFile(const WalletKeysFiles &walletKeysFile); + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QStringList walletDirectories; + +private: + AppContext *m_ctx; + QList m_walletKeyFiles; + QAbstractItemModel *m_walletKeysFilesItemModel; + QSortFilterProxyModel m_walletKeysFilesModelProxy; +}; + +class WalletKeysFilesProxyModel : public QSortFilterProxyModel +{ +Q_OBJECT +public: + explicit WalletKeysFilesProxyModel(QObject *parent = nullptr); + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; +}; + +#endif // KEYSFILES_H diff --git a/src/utils/networking.cpp b/src/utils/networking.cpp new file mode 100644 index 0000000..1a50331 --- /dev/null +++ b/src/utils/networking.cpp @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include + +#include "utils/utils.h" +#include "utils/networking.h" + +UtilsNetworking::UtilsNetworking(QNetworkAccessManager *networkAccessManager, QObject *parent) : + QObject(parent), + m_networkAccessManager(networkAccessManager) {} + +void UtilsNetworking::setUserAgent(const QString &userAgent) { + this->m_userAgent = userAgent; +} + +void UtilsNetworking::get(const QString &url) { + QNetworkRequest request; + request.setUrl(QUrl(url)); + request.setRawHeader("User-Agent", m_userAgent.toUtf8()); + + QNetworkReply *reply; + reply = this->m_networkAccessManager->get(request); + connect(reply, &QNetworkReply::finished, std::bind(&UtilsNetworking::webResponse, this, reply)); +} + +QNetworkReply* UtilsNetworking::getJson(const QString &url) { + QNetworkRequest request; + request.setUrl(QUrl(url)); + request.setRawHeader("User-Agent", m_userAgent.toUtf8()); + request.setRawHeader("Content-Type", "application/json"); + + return this->m_networkAccessManager->get(request); +} + +QNetworkReply* UtilsNetworking::postJson(const QString &url, const QJsonObject &data) { + QNetworkRequest request; + request.setUrl(QUrl(url)); + request.setRawHeader("User-Agent", m_userAgent.toUtf8()); + request.setRawHeader("Content-Type", "application/json"); + + QJsonDocument doc(data); + QByteArray bytes = doc.toJson(); + return this->m_networkAccessManager->post(request, bytes); +} + +void UtilsNetworking::webResponse(QNetworkReply *reply) { + QByteArray data = reply->readAll(); + QString err; + if (reply->error()) { + err = reply->errorString(); + qCritical() << err; + qCritical() << data; + if (!data.isEmpty()) + err += QString("%1 %2").arg(err).arg(Utils::barrayToString(data)); + } + reply->deleteLater(); + + if(!err.isEmpty()) + emit webErrorReceived(err); + else + emit webReceived(data); +} + +QString UtilsNetworking::validateJSON(QNetworkReply *reply){ + QList headerList = reply->rawHeaderList(); + QByteArray headerJson = reply->rawHeader("Content-Type"); + if(headerJson.length() <= 15) + return "Bad Content-Type"; + QString headerJsonStr = QTextCodec::codecForMib(106)->toUnicode(headerJson); + int _contentType = headerList.indexOf("Content-Type"); + if (_contentType < 0 || !headerJsonStr.startsWith("application/json")) + return "Bad Content-Type"; + QByteArray data = reply->readAll(); + if(!Utils::validateJSON(data)) + return "Bad or empty JSON"; + return "OK"; +} diff --git a/src/utils/networking.h b/src/utils/networking.h new file mode 100644 index 0000000..d0be889 --- /dev/null +++ b/src/utils/networking.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_NETWORKING_H +#define FEATHER_NETWORKING_H + +#include +#include +#include +#include +#include +#include + +#include "utils/utils.h" + +static QStringList randomHTTPAgents; +class CCSEntry; + +class UtilsNetworking : public QObject +{ +Q_OBJECT + +public: + explicit UtilsNetworking(QNetworkAccessManager *networkAccessManager, QObject *parent = nullptr); + + void get(const QString &url); + QNetworkReply* getJson(const QString &url); + QNetworkReply* postJson(const QString &url, const QJsonObject &data); + void setUserAgent(const QString &userAgent); + static QString validateJSON(QNetworkReply *reply); + +private slots: + void webResponse(QNetworkReply *reply); + +signals: + void webErrorReceived(QString msg); + void webReceived(QByteArray data); + +private: + QString m_userAgent = "Mozilla/5.0 (Windows NT 10.0; rv:68.0) Gecko/20100101 Firefox/68.0"; + QNetworkAccessManager *m_networkAccessManager; +}; + +#endif //FEATHER_NETWORKING_H diff --git a/src/utils/networktype.h b/src/utils/networktype.h new file mode 100644 index 0000000..227b003 --- /dev/null +++ b/src/utils/networktype.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#pragma once + +#include +#include + +class NetworkType : public QObject +{ + Q_OBJECT + +public: + enum Type : uint8_t { + MAINNET = Monero::MAINNET, + TESTNET = Monero::TESTNET, + STAGENET = Monero::STAGENET + }; + Q_ENUM(Type) +}; diff --git a/src/utils/nodes.cpp b/src/utils/nodes.cpp new file mode 100644 index 0000000..edcdcea --- /dev/null +++ b/src/utils/nodes.cpp @@ -0,0 +1,379 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include + +#include "nodes.h" +#include "utils/utils.h" +#include "utils/networking.h" +#include "appcontext.h" + +Nodes::Nodes(AppContext *ctx, QNetworkAccessManager *networkAccessManager, QObject *parent) : + QObject(parent), + m_ctx(ctx), + m_networkAccessManager(networkAccessManager), + m_connection(FeatherNode("", 0, false)), + modelWebsocket(new NodeModel(NodeSource::websocket, this)), + modelCustom(new NodeModel(NodeSource::custom, this)) { + this->loadConfig(); + + connect(m_connectionTimer, &QTimer::timeout, this, &Nodes::onConnectionTimer); +} + +void Nodes::loadConfig() { + QString msg; + auto configNodes = config()->get(Config::nodes).toByteArray(); + auto key = QString::number(m_ctx->networkType); + if (!Utils::validateJSON(configNodes)) { + m_configJson[key] = QJsonObject(); + qCritical() << "fixed malformed config key \"nodes\""; + } + + QJsonDocument doc = QJsonDocument::fromJson(configNodes); + m_configJson = doc.object(); + + if(!m_configJson.contains(key)) + m_configJson[key] = QJsonObject(); + + auto obj = m_configJson.value(key).toObject(); + if (!obj.contains("custom")) + obj["custom"] = QJsonArray(); + if (!obj.contains("ws")) + obj["ws"] = QJsonArray(); + + // load custom nodes + auto nodes = obj.value("custom").toArray(); + foreach (const QJsonValue &value, nodes) { + auto customNode = FeatherNode(value.toString(), 0, false); + customNode.custom = true; + + if(m_connection == customNode) { + if(m_connection.isActive) + customNode.isActive = true; + else if(m_connection.isConnecting) + customNode.isConnecting = true; + } + + m_customNodes.append(customNode); + } + + // load cached websocket nodes + auto ws = obj.value("ws").toArray(); + foreach (const QJsonValue &value, ws) { + auto wsNode = FeatherNode(value.toString(), 0, false); + wsNode.custom = false; + wsNode.online = true; // assume online + + if(m_connection == wsNode) { + if(m_connection.isActive) + wsNode.isActive = true; + else if(m_connection.isConnecting) + wsNode.isConnecting = true; + } + + m_websocketNodes.append(wsNode); + } + + if (!obj.contains("source")) + obj["source"] = NodeSource::websocket; + m_source = static_cast(obj.value("source").toInt()); + + if(m_websocketNodes.count() > 0){ + msg = QString("Loaded %1 cached websocket nodes from config").arg(m_websocketNodes.count()); + activityLog.append(msg); + } + + if(m_customNodes.count() > 0){ + msg = QString("Loaded %1 custom nodes from config").arg(m_customNodes.count()); + activityLog.append(msg); + } + + m_configJson[key] = obj; + this->writeConfig(); + this->updateModels(); +} + +void Nodes::writeConfig() { + QJsonDocument doc(m_configJson); + QString output(doc.toJson(QJsonDocument::Compact)); + config()->set(Config::nodes, output); + + auto msg = QString("Saved node config."); + activityLog.append(msg); +} + +void Nodes::connectToNode() { + // auto connect + m_connectionAttempts.clear(); + m_wsExhaustedWarningEmitted = false; + m_customExhaustedWarningEmitted = false; + m_connectionTimer->start(2000); + this->onConnectionTimer(); +} + +void Nodes::connectToNode(FeatherNode node) { + if(node.address.isEmpty()) + return; + + emit updateStatus(QString("Connecting to %1").arg(node.address)); + auto msg = QString("Attempting to connect to %1 (%2)") + .arg(node.address).arg(node.custom ? "custom" : "ws"); + qInfo() << msg; + activityLog.append(msg); + + if(!node.username.isEmpty() && !node.password.isEmpty()) + m_ctx->currentWallet->setDaemonLogin(node.username, node.password); + m_ctx->currentWallet->initAsync(node.address, true, 0, false, false, 0); + m_connectionAttemptTime = std::time(nullptr); + + m_connection = node; + m_connection.isActive = false; + m_connection.isConnecting = true; + + this->resetLocalState(); + this->updateModels(); + + m_connectionTimer->start(1000); +} + +void Nodes::onConnectionTimer() { + // this function is responsible for automatically connecting to a daemon. + if (m_ctx->currentWallet == nullptr) { + m_connectionTimer->stop(); + return; + } + + QString msg; + Wallet::ConnectionStatus status = m_ctx->currentWallet->connected(true); + NodeSource nodeSource = this->source(); + auto wsMode = nodeSource == NodeSource::websocket; + auto nodes = wsMode ? m_customNodes : m_websocketNodes; + + if(wsMode && !m_wsNodesReceived && m_websocketNodes.count() == 0) { + // this situation should rarely occur due to the usage of the websocket node cache on startup. + msg = QString("Feather is in websocket connection mode but was not able to receive any nodes (yet)."); + qInfo() << msg; + activityLog.append(msg); + return; + } + + if(status == Wallet::ConnectionStatus::ConnectionStatus_Disconnected) { + // try a connect + auto node = this->pickEligibleNode(); + this->connectToNode(node); + return; + } else if(status == Wallet::ConnectionStatus::ConnectionStatus_Connecting){ + if(!m_connection.isConnecting) { + // Weirdly enough, status == connecting directly after a wallet is opened. + auto node = this->pickEligibleNode(); + this->connectToNode(node); + return; + } + + // determine timeout + unsigned int nodeConnectionTimeout = 6; + if(m_connection.tor) + nodeConnectionTimeout = 25; + + auto connectionTimeout = static_cast(std::time(nullptr) - m_connectionAttemptTime); + if(connectionTimeout < nodeConnectionTimeout) + return; // timeout not reached yet + + msg = QString("Node connection attempt stale after %1 seconds, picking new node").arg(nodeConnectionTimeout); + activityLog.append(msg); + qInfo() << msg; + + auto newNode = this->pickEligibleNode(); + this->connectToNode(newNode); + return; + } else if(status == Wallet::ConnectionStatus::ConnectionStatus_Connected) { + // wallet is connected to daemon successfully, poll status every 3 seconds + if(!m_connection.isConnecting) + return; + + msg = QString("Node connected to %1").arg(m_connection.address); + qInfo() << msg; + activityLog.append(msg); + + // set current connection object + m_connection.isConnecting = false; + m_connection.isActive = true; + this->resetLocalState(); + this->updateModels(); + + // reset node exhaustion state + m_connectionAttempts.clear(); + m_wsExhaustedWarningEmitted = false; + m_customExhaustedWarningEmitted = false; + m_connectionTimer->setInterval(3000); + } +} + +FeatherNode Nodes::pickEligibleNode() { + // Pick a node at random to connect to + FeatherNode rtn("", 0, false); + NodeSource nodeSource = this->source(); + auto wsMode = nodeSource == NodeSource::websocket; + auto nodes = wsMode ? m_websocketNodes : m_customNodes; + + if(nodes.count() == 0) { + this->exhausted(); + return rtn; + } + + while(true) { + // keep track of nodes we have previously tried to connect to + if(m_connectionAttempts.count() == nodes.count()) { + this->exhausted(); + m_connectionTimer->stop(); + return rtn; + } + + int random = QRandomGenerator::global()->bounded(nodes.count()); + FeatherNode node = nodes.at(random); + if(m_connectionAttempts.contains(node.full)) + continue; + m_connectionAttempts.append(node.full); + + if(wsMode && !node.online) + continue; + return node; + } +} + +void Nodes::onWSNodesReceived(const QList> &nodes) { + m_websocketNodes.clear(); + m_wsNodesReceived = true; + + for(auto &node: nodes) { + if(m_connection == *node) { + if(m_connection.isActive) + node->isActive = true; + else if(m_connection.isConnecting) + node->isConnecting = true; + } + m_websocketNodes.push_back(*node); + } + + // cache into config + auto key = QString::number(m_ctx->networkType); + auto obj = m_configJson.value(key).toObject(); + auto ws = QJsonArray(); + for(auto const &node: m_websocketNodes) + ws.push_back(node.address); + + obj["ws"] = ws; + m_configJson[key] = obj; + this->writeConfig(); + this->resetLocalState(); + this->updateModels(); +} + +void Nodes::onNodeSourceChanged(NodeSource nodeSource) { + if(nodeSource == this->source()) return; + auto key = QString::number(m_ctx->networkType); + auto obj = m_configJson.value(key).toObject(); + obj["source"] = nodeSource; + + m_configJson[key] = obj; + this->writeConfig(); + this->resetLocalState(); + this->updateModels(); +} + +void Nodes::setCustomNodes(QList nodes) { + m_customNodes.clear(); + auto key = QString::number(m_ctx->networkType); + auto obj = m_configJson.value(key).toObject(); + + QStringList nodesList; + for(auto const &node: nodes) { + if(nodesList.contains(node.full)) continue; + nodesList.append(node.full); + m_customNodes.append(node); + } + + auto arr = QJsonArray::fromStringList(nodesList); + obj["custom"] = arr; + m_configJson[key] = obj; + this->writeConfig(); + this->resetLocalState(); + this->updateModels(); +} + +void Nodes::updateModels() { + this->modelCustom->updateNodes(m_customNodes); + this->modelWebsocket->updateNodes(m_websocketNodes); +} + +void Nodes::resetLocalState() { + QList*> models = {&m_customNodes, &m_websocketNodes}; + + for(QList *model: models) { + for (FeatherNode &_node: *model) { + _node.isConnecting = false; + _node.isActive = false; + + if (_node == m_connection) { + _node.isActive = m_connection.isActive; + _node.isConnecting = m_connection.isConnecting; + } + } + } +} + +void Nodes::exhausted() { + NodeSource nodeSource = this->source(); + auto wsMode = nodeSource == NodeSource::websocket; + if(wsMode) + this->WSNodeExhaustedWarning(); + else + this->nodeExhaustedWarning(); +} + +void Nodes::nodeExhaustedWarning(){ + if(m_customExhaustedWarningEmitted) return; + emit nodeExhausted(); + + auto msg = QString("Could not find an eligible custom node to connect to."); + qWarning() << msg; + activityLog.append(msg); + + m_customExhaustedWarningEmitted = true; + this->m_connectionTimer->stop(); +} + +void Nodes::WSNodeExhaustedWarning() { + if(m_wsExhaustedWarningEmitted) return; + emit WSNodeExhausted(); + + auto msg = QString("Could not find an eligible websocket node to connect to."); + qWarning() << msg; + activityLog.append(msg); + + m_wsExhaustedWarningEmitted = true; + this->m_connectionTimer->stop(); +} + +void Nodes::onWalletClosing() { + m_connectionTimer->stop(); +} + +QList Nodes::customNodes() { + return m_customNodes; +} + +FeatherNode Nodes::connection() { + return m_connection; +} + +void Nodes::stopTimer(){ + m_connectionTimer->stop(); +} + +NodeSource Nodes::source() { + return m_source; +} diff --git a/src/utils/nodes.h b/src/utils/nodes.h new file mode 100644 index 0000000..f15ba67 --- /dev/null +++ b/src/utils/nodes.h @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_NODES_H +#define FEATHER_NODES_H + +#include +#include +#include +#include +#include +#include +#include + +#include "model/NodeModel.h" +#include "utils/utils.h" +#include "utils/config.h" + +enum NodeSource { + websocket = 0, + custom +}; + +struct FeatherNode { + FeatherNode(QString _address, unsigned int height, bool online) : height(height), online(online){ + // wonky ipv4/host parsing, should be fine(tm)(c). + if(_address.isEmpty()) return; + _address = _address.replace("https://", ""); + _address = _address.replace("http://", ""); + if(_address.contains("@")){ // authentication, user/pass + const auto spl = _address.split("@"); + const auto &creds = spl.at(0); + if(creds.contains(":")) { + const auto _spl = creds.split(":"); + this->username = _spl.at(0).trimmed().replace(" ", ""); + this->password = _spl.at(1).trimmed().replace(" ", ""); + } + _address = spl.at(1); + } + if(!_address.contains(":")) + _address += ":18089"; + this->address = _address; + if(this->address.contains(".onion")) + tor = true; + this->full = this->generateFull(); + }; + + QString address; + QString full; + unsigned int height; + bool online = false; + QString username; + QString password; + bool cached = false; + bool custom = false; + bool tor = false; + bool isConnecting = false; + bool isActive = false; + + QString generateFull() { + QString auth; + if(!this->username.isEmpty() && !this->password.isEmpty()) + auth = QString("%1:%2@").arg(this->username).arg(this->password); + return QString("%1%2").arg(auth).arg(this->address); + } + + QString as_url() { + return QString("http://%1/get_info").arg(this->full); + } + + bool operator == (const FeatherNode &other) const { + return this->full == other.full; + } +}; + +class Nodes : public QObject { + Q_OBJECT + +public: + explicit Nodes(AppContext *ctx, QNetworkAccessManager *networkAccessManager, QObject *parent = nullptr); + void loadConfig(); + void writeConfig(); + void stopTimer(); + + NodeSource source(); + FeatherNode connection(); + QList customNodes(); + + NodeModel *modelWebsocket; + NodeModel *modelCustom; + + QStringList activityLog; + +public slots: + void onWalletClosing(); + void connectToNode(); + void connectToNode(FeatherNode node); + void onWSNodesReceived(const QList>& nodes); + void onNodeSourceChanged(NodeSource nodeSource); + void setCustomNodes(QList nodes); + +private slots: + void onConnectionTimer(); + +signals: + void WSNodeExhausted(); + void nodeExhausted(); + void updateStatus(const QString &msg); + +private: + AppContext *m_ctx = nullptr; + NodeSource m_source = NodeSource::websocket; + QNetworkAccessManager *m_networkAccessManager = nullptr; + QJsonObject m_configJson; + + QList m_customNodes; + QList m_websocketNodes; + + FeatherNode m_connection; // current active connection, if any + QTimer *m_connectionTimer = new QTimer(this); + time_t m_connectionAttemptTime = 0; + QStringList m_connectionAttempts; + + bool m_wsNodesReceived = false; + + bool m_wsExhaustedWarningEmitted = true; + bool m_customExhaustedWarningEmitted = true; + + FeatherNode pickEligibleNode(); + + void updateModels(); + void resetLocalState(); + void exhausted(); + void WSNodeExhaustedWarning(); + void nodeExhaustedWarning(); +}; + +#endif //FEATHER_NODES_H diff --git a/src/utils/prices.cpp b/src/utils/prices.cpp new file mode 100644 index 0000000..32d25eb --- /dev/null +++ b/src/utils/prices.cpp @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include + +#include "utils/prices.h" + +Prices::Prices(QObject *parent) : QObject(parent) { + this->rates = QMap(); + this->markets = QMap(); + this->fiat = QMap(); + fiat["USD"] = "$"; + fiat["EUR"] = "€"; + fiat["JPY"] = "¥"; + fiat["KRW"] = "₩"; + fiat["MXN"] = "$"; + fiat["RUB"] = "\u20BD"; + fiat["CAD"] = "$"; + fiat["GBP"] = "£"; + fiat["SEK"] = "kr"; + fiat["ZAR"] = "R"; + fiat["THB"] = "฿"; + fiat["TRY"] = "₺"; + fiat["CHF"] = "Fr"; + fiat["CNY"] = "¥"; + fiat["CZK"] = "Kč"; +} + +void Prices::cryptoPricesReceived(const QJsonArray &data) { + QStringList filter = QStringList() << "XMR" << "ZEC" << "BTC" << "ETH" << "BCH" << "LTC"; + filter << "EOS" << "ADA" << "XLM" << "TRX" << "DASH" << "DCR" << "VET" << "DOGE" << "XRP" << "WOW"; + + QMap msMap; + for(auto &&entry: data) { + marketStruct ms; + QJsonObject obj = entry.toObject(); + ms.symbol = obj.value("symbol").toString(); + ms.image = obj.value("image").toString(); + ms.name = obj.value("name").toString(); + ms.price_usd = obj.value("current_price").toDouble(); + ms.price_usd_change_pct_24h = obj.value("price_change_percentage_24h").toDouble(); + + if(ms.price_usd <= 0) continue; + if(filter.contains(ms.symbol.toUpper())) + msMap.insert(ms.symbol.toUpper(), ms); + } + + if(msMap.count() > 0) + this->markets = msMap; + + emit cryptoPricesUpdated(); +} + +double Prices::convert(const QString &symbolFrom, const QString &symbolTo, double amount) { + if(symbolFrom == symbolTo) return amount; + if(amount <= 0.0) return 0.0; + + double usd_from; + QString from = symbolFrom.toUpper(); + QString to = symbolTo.toUpper(); + + if(this->markets.contains(from)) + usd_from = this->markets[from].price_usd * amount; + else if(this->rates.contains(from)) { + if(from == "USD") + usd_from = amount; + else + usd_from = amount / this->rates[from]; + } else + return 0.0; + + if(to == "USD") + return usd_from; + + if(this->markets.contains(to)) + return usd_from / this->markets[to].price_usd; + else if(this->rates.contains(to)) + return usd_from * this->rates[to]; + + return 0.0; +} + +void Prices::fiatPricesReceived(const QJsonObject &data) { + QJsonObject rates = data.value("rates").toObject(); + for(const auto ¤cy: fiat.keys()) + if(rates.contains(currency)) + this->rates.insert(currency, rates.value(currency).toDouble()); + emit fiatPricesUpdated(); +} diff --git a/src/utils/prices.h b/src/utils/prices.h new file mode 100644 index 0000000..c33382f --- /dev/null +++ b/src/utils/prices.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_PRICES_H +#define FEATHER_PRICES_H + +#include +#include +#include + +#include "utils/utils.h" + +struct marketStruct { + QString symbol; + QString name; + QString image; + double price_usd; + double price_usd_change_pct_24h; +}; + +class Prices : public QObject +{ +Q_OBJECT + +public: + explicit Prices(QObject *parent = nullptr); + QMap rates; + QMap markets; + QMap fiat; // symbol:sign + +public slots: + void cryptoPricesReceived(const QJsonArray &data); + void fiatPricesReceived(const QJsonObject &data); + + double convert(const QString &symbolFrom, const QString &symbolTo, double amount); + +signals: + void fiatPricesUpdated(); + void cryptoPricesUpdated(); +}; + +#endif //FEATHER_PRICES_H diff --git a/src/utils/scheduler.cpp b/src/utils/scheduler.cpp new file mode 100644 index 0000000..323fe58 --- /dev/null +++ b/src/utils/scheduler.cpp @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#include "scheduler.h" + +FutureScheduler::FutureScheduler(QObject *parent) + : QObject(parent), Alive(0), Stopping(false) +{ +} + +FutureScheduler::~FutureScheduler() +{ + shutdownWaitForFinished(); +} + +void FutureScheduler::shutdownWaitForFinished() noexcept +{ + QMutexLocker locker(&Mutex); + + Stopping = true; + while (Alive > 0) + { + Condition.wait(&Mutex); + } +} + +QPair> FutureScheduler::run(std::function function) noexcept +{ + return execute([this, function](QFutureWatcher *) { + return QtConcurrent::run([this, function] { + try + { + function(); + } + catch (const std::exception &exception) + { + qWarning() << "Exception thrown from async function: " << exception.what(); + } + done(); + }); + }); +} + +//QPair> FutureScheduler::run(std::function function, const QJSValue &callback) +//{ +// if (!callback.isCallable()) +// { +// throw std::runtime_error("js callback must be callable"); +// } + +// return execute([this, function, callback](QFutureWatcher *watcher) { +// connect(watcher, &QFutureWatcher::finished, [watcher, callback] { +// QJSValue(callback).call(watcher->future().result()); +// }); +// return QtConcurrent::run([this, function] { +// QJSValueList result; +// try +// { +// result = function(); +// } +// catch (const std::exception &exception) +// { +// qWarning() << "Exception thrown from async function: " << exception.what(); +// } +// done(); +// return result; +// }); +// }); +//} + +bool FutureScheduler::add() noexcept +{ + QMutexLocker locker(&Mutex); + + if (Stopping) + { + return false; + } + + ++Alive; + return true; +} + +void FutureScheduler::done() noexcept +{ + { + QMutexLocker locker(&Mutex); + --Alive; + } + + Condition.wakeAll(); +} diff --git a/src/utils/scheduler.h b/src/utils/scheduler.h new file mode 100644 index 0000000..e13c3f5 --- /dev/null +++ b/src/utils/scheduler.h @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2014-2020, The Monero Project. + +#ifndef FUTURE_SCHEDULER_H +#define FUTURE_SCHEDULER_H + +#include + +#include +#include +//#include +#include +#include +#include +#include + +class FutureScheduler : public QObject +{ + Q_OBJECT + +public: + FutureScheduler(QObject *parent); + ~FutureScheduler(); + + void shutdownWaitForFinished() noexcept; + + QPair> run(std::function function) noexcept; + // QPair> run(std::function function, const QJSValue &callback); + +private: + bool add() noexcept; + void done() noexcept; + + template + QPair> execute(std::function(QFutureWatcher *)> makeFuture) noexcept + { + if (add()) + { + try + { + auto *watcher = new QFutureWatcher(); + connect(watcher, &QFutureWatcher::finished, [watcher] { + watcher->deleteLater(); + }); + watcher->setFuture(makeFuture(watcher)); + return qMakePair(true, watcher->future()); + } + catch (const std::exception &exception) + { + qCritical() << "Failed to schedule async function: " << exception.what(); + done(); + } + } + + return qMakePair(false, QFuture()); + } + + QFutureWatcher schedule(std::function function); + //QFutureWatcher schedule(std::function function, const QJSValue &callback); + +private: + size_t Alive; + QWaitCondition Condition; + QMutex Mutex; + bool Stopping; +}; + +#endif // FUTURE_SCHEDULER_H diff --git a/src/utils/seeds.h b/src/utils/seeds.h new file mode 100644 index 0000000..c3805f1 --- /dev/null +++ b/src/utils/seeds.h @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_SEEDS_H +#define FEATHER_SEEDS_H + +#include +#include +#include +#include + +#include + +#include "networktype.h" +#include "libwalletqt/WalletManager.h" +#include "libwalletqt/Wallet.h" +#include "utils/utils.h" + + +struct RestoreHeightLookup { + NetworkType::Type type; + QMap data; + explicit RestoreHeightLookup(NetworkType::Type type) : type(type) {} + + unsigned int dateToRestoreHeight(unsigned int date) { + // restore height based on a given timestamp using a lookup + // table. If it cannot find the date in the lookup table, it + // will calculate the blockheight based off the last known + // date: ((now - lastKnownDate) / blockTime) - clearance + + if(this->type == NetworkType::TESTNET) return 1; + unsigned int blockTime = 120; + unsigned int blocksPerDay = 86400 / blockTime; + unsigned int blockCalcClearance = blocksPerDay * 5; + QList values = this->data.keys(); + if(date <= values.at(0)) + return this->data[values.at(0)]; + for(unsigned int i = 0; i != values.count(); i++) { + if(values[i] > date) { + return i - 1 < 0 ? this->data[values[i]] : this->data[values[i-1]] - blockCalcClearance; + } + } + + // lookup failed, calculate blockheight from last known checkpoint + unsigned int lastBlockHeightTime = values.at(values.count() - 1); + unsigned int lastBlockHeight = this->data[lastBlockHeightTime]; + unsigned int deltaTime = date - lastBlockHeightTime; + unsigned int deltaBlocks = deltaTime / blockTime; + unsigned int blockHeight = (lastBlockHeight + deltaBlocks) - blockCalcClearance; + qDebug() << "Calculated blockheight: " << blockHeight << " from epoch " << date; + return blockHeight; + } + + unsigned int restoreHeightToDate(unsigned int height) { + // @TODO: most likely inefficient, refactor + QMap::iterator i; + unsigned int timestamp = 0; + for (i = this->data.begin(); i != this->data.end(); ++i) { + unsigned int ts = i.key(); + if (i.value() > height) + return timestamp; + timestamp = ts; + } + return timestamp; + } + + static RestoreHeightLookup *fromFile(const QString &fn, NetworkType::Type type) { + // initialize this class using a lookup table, e.g `:/assets/restore_heights_monero_mainnet.txt`/ + auto rtn = new RestoreHeightLookup(type); + auto data = Utils::barrayToString(Utils::fileOpen(fn)); + QMap _data; + for(const auto &line: data.split('\n')) { + if(line.trimmed().isEmpty()) continue; + auto spl = line.trimmed().split(':'); + rtn->data[spl.at(0).toUInt()] = spl.at(1).toUInt(); + } + return rtn; + } +}; + +struct FeatherSeed { + QString mnemonicSeed; + QString spendKey; + time_t time = 0; + unsigned int restoreHeight = 0; + RestoreHeightLookup *lookup = nullptr; + QString language = "English"; + std::string coinName; + explicit FeatherSeed(RestoreHeightLookup *lookup, const std::string &coinName = "monero") : lookup(lookup), coinName(coinName) {} + + static FeatherSeed fromSeed(RestoreHeightLookup *lookup, + const std::string &coinName, + const std::string &mnemonicSeed) { + + auto rtn = FeatherSeed(lookup, coinName); + rtn.coinName = coinName; + rtn.lookup = lookup; + rtn.mnemonicSeed = QString::fromStdString(mnemonicSeed); + + if(QString::fromStdString(mnemonicSeed).split(" ").count() == 14) { + monero_seed seed(mnemonicSeed, coinName); + std::stringstream buffer; + buffer << seed.key(); + rtn.time = seed.date(); + rtn.setRestoreHeight(); + rtn.spendKey = QString::fromStdString(buffer.str()); + } + return rtn; + } + + static FeatherSeed generate(RestoreHeightLookup *lookup, const std::string &coinName) { + auto rtn = FeatherSeed(lookup, coinName); + time_t _time = std::time(nullptr); + monero_seed seed(_time, coinName); + + std::stringstream buffer; + buffer << seed; + rtn.mnemonicSeed = QString::fromStdString(buffer.str()); + buffer.str(std::string()); + buffer << seed.key(); + rtn.spendKey = QString::fromStdString(buffer.str()); + rtn.time = _time; + rtn.setRestoreHeight(); + return rtn; + } + + Wallet *writeWallet(WalletManager *manager, NetworkType::Type type, const QString &path, const QString &password, unsigned int kdfRounds) { + // writes both 14/25 word mnemonic seeds. + Wallet *wallet = nullptr; + if(this->lookup == nullptr) return wallet; + if(this->mnemonicSeed.split(" ").count() == 14) { + if(this->spendKey.isEmpty()) { + auto _seed = FeatherSeed::fromSeed(this->lookup, this->coinName, this->mnemonicSeed.toStdString()); + _seed.setRestoreHeight(); + this->time = _seed.time; + this->restoreHeight = _seed.restoreHeight; + this->spendKey = _seed.spendKey; + } + wallet = manager->createDeterministicWalletFromSpendKey(path, password, this->language, type, this->spendKey, this->restoreHeight, (quint64)kdfRounds); + wallet->setCacheAttribute("feather.seed", this->mnemonicSeed); + } else { + wallet = manager->recoveryWallet(path, password, this->mnemonicSeed, "", type, this->restoreHeight, (quint64) kdfRounds); + } + + wallet->setPassword(password); + return wallet; + } + + unsigned int setRestoreHeight() { + if(this->lookup == nullptr) return 1; + if(this->time == 0) return 1; + this->restoreHeight = this->lookup->dateToRestoreHeight((unsigned int)this->time); + return this->restoreHeight; + } + + unsigned int setRestoreHeight(unsigned int height) { + auto now = (unsigned int)std::time(nullptr); + auto nowClearance = 3600 * 24; + auto currentBlockHeight = this->lookup->dateToRestoreHeight(now - nowClearance); + if(height >= currentBlockHeight + nowClearance) { + qCritical() << "unrealistic restore height detected, setting to current blockheight instead: " << currentBlockHeight; + this->restoreHeight = currentBlockHeight; + } else + this->restoreHeight = height; + + return this->restoreHeight; + } +}; + +#endif //FEATHER_SEEDS_H diff --git a/src/utils/tails.cpp b/src/utils/tails.cpp new file mode 100644 index 0000000..8e90149 --- /dev/null +++ b/src/utils/tails.cpp @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include +#include + +#include "tails.h" +#include "utils.h" + +const QString TailsOS::tailsPathData = QString("/live/persistence/TailsData_unlocked/"); + +bool TailsOS::detect() +{ + if (!Utils::fileExists("/etc/os-release")) + return false; + + QByteArray data = Utils::fileOpen("/etc/os-release"); + QRegularExpression re("TAILS_PRODUCT_NAME=\"Tails\""); + QRegularExpressionMatch os_match = re.match(data); + bool matched = os_match.hasMatch(); + + if (matched) + qDebug() << "Tails OS detected"; + + return matched; +} + +bool TailsOS::detectDataPersistence() +{ + return QDir(QDir::homePath() + "/Persistent").exists(); +} + +bool TailsOS::detectDotPersistence() +{ + return QDir(tailsPathData + "dotfiles").exists(); +} + +void TailsOS::showDataPersistenceDisabledWarning() +{ + QMessageBox msgBox; + msgBox.setText(QObject::tr("Warning: persistence disabled")); + msgBox.setWindowTitle(QObject::tr("Warning: persistence disabled")); + msgBox.setInformativeText( + QObject::tr("Feather has detected that Tails persistence is " + "currently disabled. Any configurations and wallets you make inside " + "Feather will not be permanently saved." + "\n\n" + "Make sure to not save your wallet on the " + "filesystem, as it will be lost at shutdown." + "\n\n" + "To enable Tails persistence, setup an encrypted volume " + "and restart Tails. To gain a startup menu item, " + "enable dotfiles persistence.")); + + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.setIconPixmap(QPixmap(":/images/tails-grey.png")); + msgBox.exec(); +} + +void TailsOS::persistXdgMime(const QString &filePath, const QString &data) +{ + QFileInfo file(filePath); + QString tailsPath = tailsPathData + "dotfiles/.local/share/applications/"; + + // write to persistent volume +#ifdef QT_DEBUG + qDebug() << "Writing xdg mime: " << tailsPath + file.fileName(); +#endif + + QDir().mkpath(tailsPath); // ensure directory exists + Utils::fileWrite(tailsPath + file.fileName(), data); + + // write to current session +#ifdef QT_DEBUG + qDebug() << "Writing xdg mime: " << file.filePath(); +#endif + + QDir().mkpath(file.path()); // ensure directory exists + Utils::fileWrite(file.filePath(), data); +} diff --git a/src/utils/tails.h b/src/utils/tails.h new file mode 100644 index 0000000..068c59a --- /dev/null +++ b/src/utils/tails.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef TAILSOS_H +#define TAILSOS_H + +#include + + +class TailsOS +{ +public: + static bool detect(); + static bool detectDataPersistence(); + static bool detectDotPersistence(); + + static void showDataPersistenceDisabledWarning(); + static void askPersistence(); + static void persistXdgMime(const QString& filePath, const QString& data); + + static bool usePersistence; + static bool rememberChoice; + static const QString tailsPathData; +}; + +#endif // TAILSOS_H diff --git a/src/utils/textedit.cpp b/src/utils/textedit.cpp new file mode 100644 index 0000000..3fd7de5 --- /dev/null +++ b/src/utils/textedit.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "textedit.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +TextEdit::TextEdit(QWidget *parent) : QTextEdit(parent) { } + +TextEdit::~TextEdit() { } + +void TextEdit::setCompleter(QCompleter *completer) { + if (c) + c->disconnect(this); + + c = completer; + + if (!c) + return; + + c->setWidget(this); + c->setCompletionMode(QCompleter::PopupCompletion); + c->setCaseSensitivity(Qt::CaseInsensitive); + QObject::connect(c, QOverload::of(&QCompleter::activated), + this, &TextEdit::insertCompletion); +} + +QCompleter *TextEdit::completer() const { + return c; +} + +void TextEdit::insertCompletion(const QString &completion) { + if (c->widget() != this) + return; + QTextCursor tc = textCursor(); + int extra = completion.length() - c->completionPrefix().length(); + tc.movePosition(QTextCursor::Left); + tc.movePosition(QTextCursor::EndOfWord); + tc.insertText(completion.right(extra)); + setTextCursor(tc); +} + +QString TextEdit::textUnderCursor() const { + QTextCursor tc = textCursor(); + tc.select(QTextCursor::WordUnderCursor); + return tc.selectedText(); +} + +void TextEdit::focusInEvent(QFocusEvent *e) { + if (c) + c->setWidget(this); + QTextEdit::focusInEvent(e); +} + +void TextEdit::keyPressEvent(QKeyEvent *e) { + if (c && c->popup()->isVisible()) { + // The following keys are forwarded by the completer to the widget + switch (e->key()) { + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Escape: + case Qt::Key_Tab: + case Qt::Key_Backtab: + e->ignore(); + return; // let the completer do default behavior + default: + break; + } + } + + const bool isShortcut = (e->modifiers().testFlag(Qt::ControlModifier) && e->key() == Qt::Key_E); // CTRL+E + if (!c || !isShortcut) // do not process the shortcut when we have a completer + QTextEdit::keyPressEvent(e); + + const bool ctrlOrShift = e->modifiers().testFlag(Qt::ControlModifier) || + e->modifiers().testFlag(Qt::ShiftModifier); + if (!c || (ctrlOrShift && e->text().isEmpty())) + return; + + static QString eow("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); // end of word + const bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift; + QString completionPrefix = textUnderCursor(); + + if (!isShortcut && (hasModifier || e->text().isEmpty()|| completionPrefix.length() < 3 + || eow.contains(e->text().right(1)))) { + c->popup()->hide(); + return; + } + + if (completionPrefix != c->completionPrefix()) { + c->setCompletionPrefix(completionPrefix); + c->popup()->setCurrentIndex(c->completionModel()->index(0, 0)); + } + QRect cr = cursorRect(); + cr.setWidth(c->popup()->sizeHintForColumn(0) + + c->popup()->verticalScrollBar()->sizeHint().width()); + c->complete(cr); // popup it up! +} + +QAbstractItemModel *TextEdit::modelFromFile(const QString& fileName, QCompleter *completer) { + QFile file(fileName); + if (!file.open(QFile::ReadOnly)) + return new QStringListModel(completer); + + QStringList words; + + while (!file.atEnd()) { + QByteArray line = file.readLine(); + if (!line.isEmpty()) + words << QString::fromUtf8(line.trimmed()); + } + + return new QStringListModel(words, completer); +} diff --git a/src/utils/textedit.h b/src/utils/textedit.h new file mode 100644 index 0000000..d4e067e --- /dev/null +++ b/src/utils/textedit.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTEDIT_H +#define TEXTEDIT_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QCompleter; +QT_END_NAMESPACE + + +class TextEdit : public QTextEdit { + Q_OBJECT + +public: + TextEdit(QWidget *parent = nullptr); + ~TextEdit(); + + void setCompleter(QCompleter *c); + QCompleter *completer() const; + static QAbstractItemModel *modelFromFile(const QString& fileName, QCompleter *completer); + +protected: + void keyPressEvent(QKeyEvent *e) override; + void focusInEvent(QFocusEvent *e) override; + +private slots: + void insertCompletion(const QString &completion); + +private: + QString textUnderCursor() const; + +private: + QCompleter *c = nullptr; +}; + +#endif // TEXTEDIT_H + diff --git a/src/utils/tor.cpp b/src/utils/tor.cpp new file mode 100644 index 0000000..280a989 --- /dev/null +++ b/src/utils/tor.cpp @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include +#include +#include "utils/utils.h" +#include "utils/tor.h" +#include "appcontext.h" + +QString Tor::torHost = "127.0.0.1"; +quint16 Tor::torPort = 9050; + +Tor::Tor(AppContext *ctx, QObject *parent) + : QObject(parent) + , m_ctx(ctx) + , m_checkConnectionTimer(new QTimer(this)) +{ + connect(m_checkConnectionTimer, &QTimer::timeout, this, &Tor::checkConnection); + + this->torDir = QDir(m_ctx->configDirectory).filePath("tor"); + this->torDataPath = QDir(this->torDir).filePath("data"); + + if (m_ctx->cmdargs->isSet("tor-port")) { + Tor::torPort = m_ctx->cmdargs->value("tor-port").toUShort(); + this->localTor = true; + if (!Utils::portOpen(Tor::torHost, Tor::torPort)) { + this->errorMsg = QString("--tor-port was specified but no running Tor instance was found on port %1.").arg(QString::number(Tor::torPort)); + } + return; + } + + // Assume Tor is already running + this->localTor = m_ctx->cmdargs->isSet("use-local-tor"); + if (this->localTor && !Utils::portOpen(Tor::torHost, Tor::torPort)) { + this->errorMsg = "--use-local-tor was specified but no running Tor instance found."; + } + if (m_ctx->isTorSocks || m_ctx->isTails || m_ctx->isWhonix || Utils::portOpen(Tor::torHost, Tor::torPort)) + this->localTor = true; + if (this->localTor) { + return; + } + + bool unpacked = this->unpackBins(); + if (!unpacked) { + qCritical() << "Feather built without embedded Tor. Assuming --use-local-tor"; + this->localTor = true; + return; + } + + qDebug() << "Using embedded tor instance"; + m_process.setProcessChannelMode(QProcess::MergedChannels); + + connect(&m_process, &QProcess::readyReadStandardOutput, this, &Tor::handleProcessOutput); + connect(&m_process, &QProcess::errorOccurred, this, &Tor::handleProcessError); + connect(&m_process, &QProcess::stateChanged, this, &Tor::stateChanged); +} + +void Tor::start() { + if (this->localTor) { + this->checkConnection(); + m_checkConnectionTimer->start(5000); + return; + } + + // Don't spawn Tor on default port to avoid conflicts + Tor::torPort = 19450; + + auto state = m_process.state(); + if (state == QProcess::ProcessState::Running || state == QProcess::ProcessState::Starting) { + this->errorMsg = "Can't start Tor, already running or starting"; + return; + } + + if (Utils::portOpen(Tor::torHost, Tor::torPort)) { + this->errorMsg = QString("Unable to start Tor on %1:%2. Port already in use.").arg(Tor::torHost, Tor::torPort); + return; + } + + qDebug() << QString("Start process: %1").arg(this->torPath); + + m_restarts += 1; + if (m_restarts > 4) { + this->errorMsg = "Tor failed to start: maximum retries exceeded"; + return; + } + + QStringList arguments; + + arguments << "--ignore-missing-torrc"; + arguments << "--SocksPort" << QString("%1:%2").arg(Tor::torHost, QString::number(Tor::torPort)); + arguments << "--TruncateLogFile" << "1"; + arguments << "--DataDirectory" << this->torDataPath; + arguments << "--Log" << "notice"; + arguments << "--pidfile" << QDir(this->torDataPath).filePath("tor.pid"); + + qDebug() << QString("%1 %2").arg(this->torPath, arguments.join(" ")); + + m_process.start(this->torPath, arguments); +} + +void Tor::stop() { + m_process.terminate(); +} + +void Tor::checkConnection() { + // We might not be able to connect to localhost if torsocks is used to start feather + if (m_ctx->isTorSocks) + this->setConnectionState(true); + + else if (m_ctx->isWhonix) + this->setConnectionState(true); + + else if (m_ctx->isTails) { + QStringList args = QStringList() << "--quiet" << "is-active" << "tails-tor-has-bootstrapped.target"; + int code = QProcess::execute("/bin/systemctl", args); + + this->setConnectionState(code == 0); + } + + else if (Utils::portOpen(Tor::torHost, Tor::torPort)) + this->setConnectionState(true); + + else + this->setConnectionState(false); +} + +void Tor::setConnectionState(bool connected) { + this->torConnected = connected; + emit connectionStateChanged(connected); +} + +void Tor::stateChanged(QProcess::ProcessState state) { + if(state == QProcess::ProcessState::Running) + qWarning() << "Tor started, awaiting bootstrap"; + else if (state == QProcess::ProcessState::NotRunning) { + this->setConnectionState(false); + + if (m_stopRetries) + return; + + QTimer::singleShot(1000, [=] { + this->start(); + }); + } +} + +void Tor::handleProcessOutput() { + QByteArray output = m_process.readAllStandardOutput(); + this->torLogs.append(Utils::barrayToString(output)); + emit logsUpdated(); + if(output.contains(QByteArray("Bootstrapped 100%"))) { + qDebug() << "Tor OK"; + this->setConnectionState(true); + } + + qDebug() << output; +} + +void Tor::handleProcessError(QProcess::ProcessError error) { + if (error == QProcess::ProcessError::Crashed) + qWarning() << "Tor crashed or killed"; + else if (error == QProcess::ProcessError::FailedToStart) { + this->errorMsg = "Tor binary failed to start: " + this->torPath; + this->m_stopRetries = true; + } +} + +bool Tor::unpackBins() { + QString torFile; +#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) + torFile = ":/tor/tor"; +#elif defined(Q_OS_WIN) + torFile = ":/tor/tor.exe"; +#endif + + if (!Utils::fileExists(torFile)) + return false; + QFile f(torFile); + QFileInfo fileInfo(f); + this->torPath = QDir(this->torDir).filePath(fileInfo.fileName()); + qDebug() << this->torPath; + f.copy(torPath); + f.close(); + +#if defined(Q_OS_UNIX) + QFile torBin(this->torPath); + torBin.setPermissions(QFile::ExeGroup | QFile::ExeOther | QFile::ExeOther | QFile::ExeUser); +#endif + + return true; +} + +networkPeer Tor::getPeerFromConfig(const QString &path) { + // parse Tor bind addr from given Tor config + QRegularExpression re("^SocksPort ([\\d|.|:]+)"); + + networkPeer peer; + peer.host = "127.0.0.1"; + peer.port = 9050; + + if(!Utils::fileExists(path)) { + peer.active = Utils::portOpen(peer.host, peer.port); + return peer; + } + + for(const auto &line: Utils::fileOpen(path).split('\n')) { + QRegularExpressionMatch match = re.match(line); + if(!match.hasMatch()) + continue; + + QString match_group = match.captured(1); + int host_idx = match_group.indexOf(':'); + if(host_idx >= 1){ + peer.host = match_group.mid(0, host_idx); + QString port = match_group.mid(host_idx + 1); + if(!Utils::isDigit(port)) + continue; + + peer.port = (quint16)port.toInt(); + qDebug() << "Parsed port from local Tor config"; + break; + } + + if(Utils::isDigit(match_group)) { + peer.port = (quint16)match_group.toInt(); + qDebug() << "Parsed port from local Tor config"; + break; + } + } + + peer.active = Utils::portOpen(peer.host, peer.port); + return peer; +} + +QString Tor::getVersion() { + QProcess process; + process.setProcessChannelMode(QProcess::MergedChannels); + process.start(this->torPath, QStringList() << "--version"); + process.waitForFinished(-1); + QString output = process.readAllStandardOutput(); + + if(output.isEmpty()) { + qWarning() << "Could not grab Tor version"; + return ""; + } + QString version = output.split('\n').at(0); + if(version.startsWith("Tor version")){ + return version; + } else { + qWarning() << "Could not parse Tor version"; + return ""; + } +} diff --git a/src/utils/tor.h b/src/utils/tor.h new file mode 100644 index 0000000..1b33aed --- /dev/null +++ b/src/utils/tor.h @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_TOR_H +#define FEATHER_TOR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils/childproc.h" + +class Tor : public QObject +{ +Q_OBJECT + +public: + explicit Tor(AppContext *ctx, QObject *parent = nullptr); + + void start(); + void stop(); + bool unpackBins(); + QString getVersion(); + networkPeer getPeerFromConfig(const QString &path); + + bool torConnected = false; + bool localTor = false; + QString torDir; + QString torPath; + QString torDataPath; + + static QString torHost; + static quint16 torPort; + + QString torLogs; + QString errorMsg = ""; + +signals: + void connectionStateChanged(bool connected); + void startupFailure(QString reason); + void logsUpdated(); + +private slots: + void stateChanged(QProcess::ProcessState); + void handleProcessOutput(); + void handleProcessError(QProcess::ProcessError error); + void checkConnection(); + +private: + void setConnectionState(bool connected); + + ChildProcess m_process; + AppContext *m_ctx; + int m_restarts = 0; + bool m_stopRetries = false; + QTimer *m_checkConnectionTimer; +}; + +class AppContext; // forward declaration + +#endif //FEATHER_TOR_H \ No newline at end of file diff --git a/src/utils/txfiathistory.cpp b/src/utils/txfiathistory.cpp new file mode 100644 index 0000000..8d82271 --- /dev/null +++ b/src/utils/txfiathistory.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include + +#include "txfiathistory.h" +#include "utils/utils.h" + +TxFiatHistory::TxFiatHistory(unsigned int genesis_timestamp, const QString &configDirectory, QObject *parent) : + QObject(parent), + m_genesis_timestamp(genesis_timestamp), + m_configDirectory(configDirectory) { + m_databasePath = QString("%1fiatHistory.db").arg(configDirectory); + this->loadDatabase(); +} + +double TxFiatHistory::get(unsigned int timestamp) { + QDateTime ts; + ts.setTime_t(timestamp); + auto key = ts.toString("yyyyMMdd"); + return this->get(key); // USD +} + +double TxFiatHistory::get(const QString &date) { + if(m_database.contains(date)) + return m_database[date]; // USD + return 0.0; +} + +void TxFiatHistory::loadDatabase() { + if(!Utils::fileExists(m_databasePath)) + return; + + m_database.clear(); + QString contents = Utils::barrayToString(Utils::fileOpen(m_databasePath)); + for(auto &line: contents.split("\n")){ + line = line.trimmed(); + if(line.isEmpty()) continue; + auto spl = line.split(":"); + m_database[spl.at(0)] = spl.at(1).toDouble(); + } +} + +void TxFiatHistory::writeDatabase() { + QString data; + for(const auto &line: m_database.toStdMap()) + data += QString("%1:%2\n").arg(line.first).arg(QString::number(line.second)); + Utils::fileWrite(m_databasePath, data); +} + +void TxFiatHistory::onUpdateDatabase() { + // update local txFiatHistory database + if(m_initialized) return; + + QDateTime genesis; + genesis.setTime_t(m_genesis_timestamp); + auto genesis_date = genesis.date(); + + auto now = QDate::currentDate(); + auto nowKey = now.toString("yyyyMMdd"); + unsigned int year = genesis.toString("yyyy").toUInt(); + auto yearCurrent = now.year(); + + // if current year is genesis year we'll refresh regardless. + if(yearCurrent == genesis_date.year()) { + emit requestYear(year); + m_initialized = true; + return; + } + + // keep local fiatTxHistory database up to date, loop for missing dates + for(year; year != yearCurrent + 1; year += 1){ + for(unsigned int month = 1; month != 13; month++) { + if(year == yearCurrent && month == now.month() && now.day() == 1) break; + QDateTime _now; + _now.setDate(QDate(year, month, 1)); + if(_now.toSecsSinceEpoch() < m_genesis_timestamp) continue; + if(_now.toSecsSinceEpoch() > std::time(nullptr) - 86400) continue; + QString key = ""; + + // genesis year we'll only fetch once + if(year == genesis_date.year()){ + key = QString("%1%2%3").arg(year).arg(12).arg("31"); + if(!m_database.contains(key)) + emit requestYear(year); + break; + } + + auto _month = QString::number(month); + if(_month.length() == 1) + _month = QString("0%1").arg(_month); // how2fill + + key = QString("%1%2%3").arg(year).arg(_month).arg("01"); + if(!m_database.contains(key)){ + if(year != yearCurrent) { + emit requestYear(year); + break; + } else + emit requestYearMonth(year, month); + } else if (year == yearCurrent && month == now.month() && !m_database.contains(nowKey)) + emit requestYearMonth(year, month); + } + } + + m_initialized = true; +} + +void TxFiatHistory::onWSData(const QJsonObject &data) { + foreach(const QString &key, data.keys()) { + QJsonValue value = data.value(key); + m_database[key] = value.toDouble(); + } + + this->writeDatabase(); +} diff --git a/src/utils/txfiathistory.h b/src/utils/txfiathistory.h new file mode 100644 index 0000000..632c581 --- /dev/null +++ b/src/utils/txfiathistory.h @@ -0,0 +1,31 @@ +#ifndef FEATHER_TXFIATHISTORY_H +#define FEATHER_TXFIATHISTORY_H + + +class TxFiatHistory : public QObject { + Q_OBJECT + +public: + explicit TxFiatHistory(unsigned int genesis_timestamp, const QString &configDirectory, QObject *parent = nullptr); + double get(const QString &date); + double get(unsigned int timestamp); + +public slots: + void onUpdateDatabase(); + void onWSData(const QJsonObject &data); + +signals: + void requestYear(unsigned int year); + void requestYearMonth(unsigned int year, unsigned int month); + +private: + void loadDatabase(); + void writeDatabase(); + QString m_databasePath; + QString m_configDirectory; + bool m_initialized = false; + QMap m_database; + unsigned int m_genesis_timestamp; +}; + +#endif //FEATHER_TXFIATHISTORY_H diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp new file mode 100644 index 0000000..0ee8f1e --- /dev/null +++ b/src/utils/utils.cpp @@ -0,0 +1,552 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "utils/config.h" +#include "utils/tails.h" + +// Application log for current session +QVector applicationLog = QVector(); // todo: replace with ring buffer +QMutex logMutex; + +void Utils::openWindow(QWidget *w) { + auto first_screen = QApplication::screens()[0]; + w->setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, w->size(), first_screen->availableGeometry())); + w->show(); +} + +bool Utils::fileExists(const QString &path) { + QFileInfo check_file(path); + return check_file.exists() && check_file.isFile(); +} + +bool Utils::dirExists(const QString &path) { + QDir pathDir(path); + return pathDir.exists(); +} + +QByteArray Utils::fileOpen(const QString &path) { + QFile file(path); + if(!file.open(QFile::ReadOnly | QFile::Text)) { + return QByteArray(); + } + + QByteArray data = file.readAll(); + file.close(); + return data; +} + +QByteArray Utils::fileOpenQRC(const QString &path) { + QFile file(path); + if(!file.open(QIODevice::ReadOnly)) { + qDebug() << "error: " << file.errorString(); + } + + QByteArray data = file.readAll(); + file.close(); + return data; +} + +bool Utils::fileWrite(const QString &path, const QString &data) { + QFile file(path); + if(file.open(QIODevice::WriteOnly)){ + QTextStream out(&file); out << data << endl; + file.close(); + return true; + } + return false; +} + +QString Utils::systemAccountName(){ + QString accountName = qgetenv("USER"); // mac/linux + if (accountName.isEmpty()) + return qgetenv("USERNAME"); // Windows + if (accountName.isEmpty()) + qDebug() << "accountName was empty"; + + return ""; +} + +bool Utils::validateJSON(const QByteArray &blob) { + QJsonDocument doc = QJsonDocument::fromJson(blob); + QString jsonString = doc.toJson(QJsonDocument::Indented); + return !jsonString.isEmpty(); +} + +bool Utils::readJsonFile(QIODevice &device, QSettings::SettingsMap &map) { + QJsonDocument json = QJsonDocument::fromJson(device.readAll()); + map = json.object().toVariantMap(); + return true; +} + +bool Utils::writeJsonFile(QIODevice &device, const QSettings::SettingsMap &map) { + device.write(QJsonDocument(QJsonObject::fromVariantMap(map)).toJson()); + return true; +} + +QStringList Utils::readJsonStringToQStringList(const QString &input) { + QStringList data; + + QJsonDocument doc = QJsonDocument::fromJson(input.toUtf8()); + QJsonObject object = doc.object(); + QJsonArray array = doc.array(); + + for(auto &&entry: array) + data << entry.toString(); + return data; +} + +void Utils::applicationLogHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { + const QString fn = context.function ? QString::fromUtf8(context.function) : ""; + const QString date = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); + QString line; + + switch (type) { + case QtDebugMsg: + line = QString("[%1 D] %2(:%3) %4\n").arg(date).arg(fn).arg(context.line).arg(msg); + fprintf(stderr, "%s", line.toLatin1().data()); + break; + case QtInfoMsg: + line = QString("[%1 I] %2\n").arg(date).arg(msg); + fprintf(stdout, "%s", line.toLatin1().data()); + break; + case QtWarningMsg: + line = QString("[%1 W] %2(:%3) %4\n").arg(date).arg(fn).arg(context.line).arg(msg); + fprintf(stdout, "%s", line.toLatin1().data()); + break; + case QtCriticalMsg: + line = QString("[%1 C] %2(:%3) %4\n").arg(date).arg(fn).arg(context.line).arg(msg); + fprintf(stderr, "%s", line.toLatin1().data()); + break; + case QtFatalMsg: + line = QString("[%1 F] %2(:%3) %4\n").arg(date).arg(fn).arg(context.line).arg(msg); + fprintf(stderr, "%s", line.toLatin1().data()); + break; + } + + auto message = logMessage(type, line, fn); + + { + QMutexLocker locker(&logMutex); + applicationLog.append(message); + } + + + //emit applicationLogUpdated(message); +} + +QByteArray Utils::zipExtract(const QString &path, const QString& destination) { + Q_UNUSED(path) + Q_UNUSED(destination) + return QByteArray(); +} + +bool Utils::isDigit(const QString& inp) { + for (auto &&i : inp) { + if(!i.isDigit()) return false; + } + return true; +} + +void Utils::desktopNotify(const QString &title, const QString &message, int duration) { + QStringList notify_send = QStringList() << title << message << "-t" << QString::number(duration); + QStringList kdialog = QStringList() << title << message; + QStringList macos = QStringList() << "-e" << QString(R"(display notification "%1" with title "%2")").arg(message).arg(title); +#if defined(Q_OS_LINUX) + QProcess process; + if (Utils::fileExists("/usr/bin/kdialog")) + process.start("/usr/bin/kdialog", kdialog); + else if (Utils::fileExists("/usr/bin/notify-send")) + process.start("/usr/bin/notify-send", notify_send); + process.waitForFinished(-1); + QString stdout = process.readAllStandardOutput(); + QString stderr = process.readAllStandardError(); +#elif defined(Q_OS_MACOS) + QProcess process; + // @TODO: need to escape special chars with \ + process.start("osascript", macos); + process.waitForFinished(-1); + QString stdout = process.readAllStandardOutput(); + QString stderr = process.readAllStandardError(); +#endif +} + +bool Utils::portOpen(const QString &hostname, quint16 port){ + QTcpSocket socket; + socket.connectToHost(hostname, port); + return socket.waitForConnected(600); +} + +QString Utils::barrayToString(const QByteArray &data) { + return QString(QTextCodec::codecForMib(106)->toUnicode(data)); +} + +QByteArray Utils::readSocket(QTcpSocket &socket, int buffer_size) { + QByteArray data; + if(!socket.waitForReadyRead(6000)) + return data; + + while(buffer_size > 0 && socket.bytesAvailable() > 0){ + QByteArray _data = socket.read(buffer_size); + buffer_size -= _data.size(); + data += _data; + } + + return data; +} + +bool Utils::testSocks5(const QString &host, quint16 port){ + // synchronous socks5 tester + QByteArray data; + QTcpSocket socket; + socket.connectToHost(host, port); + if (!socket.waitForConnected(1000)) { + qDebug() << QString("could not connect to %1 %2") + .arg(host).arg(port); + socket.close(); + return false; + } + + // latest & greatest + socket.write(QByteArray("\x05\x02", 2)); + socket.flush(); + + // no auth pl0x + socket.write(QByteArray("\x00\x01", 2)); + socket.flush(); + + // cool story + if(Utils::readSocket(socket, 2).isEmpty()){ + qDebug() << "socks response timeout"; + socket.close(); + return false; + } + + // pls sir + socket.write(QByteArray("\x05\x01\x00\x03", 4)); + + // here we go!! + socket.write(QByteArray("\x16", 1)); // len + socket.write(QByteArray("kebjllr47c2ouoly.onion")); + socket.write(QByteArray("\x00\x50", 2)); // port + socket.flush(); + + // fingers crossed + auto result = Utils::readSocket(socket, 10); + qDebug() << result; + if(result.length() != 10 || result.at(1) != 0) { + qDebug() << "bad socks response"; + socket.close(); + return false; + } + + // can haz? + QByteArray http("GET /api/v1/ping HTTP/1.1\r\nHost: kebjllr47c2ouoly.onion\r\nConnection: close\r\n\r\n"); + socket.write(http); + + auto resp = Utils::readSocket(socket, 555); + QRegularExpression re(R"(^HTTP\/\d.\d 200 OK)"); + QRegularExpressionMatch match = re.match(resp); + if(match.hasMatch()){ + socket.close(); + return true; + } + + qDebug() << resp; + + socket.close(); + return false; +} + +void Utils::externalLinkWarning(const QString &url){ + if(!config()->get(Config::warnOnExternalLink).toBool()) { + QDesktopServices::openUrl(QUrl(url)); + return; + } + + QString body = "You are about to open the following link:\n\n"; + body += QString("%1\n\n").arg(url); + body += "You will NOT be using Tor."; + + switch (Utils::showMessageBox("External link warning", body, true)) { + case QMessageBox::Cancel: + break; + default: + QDesktopServices::openUrl(QUrl(url)); + break; + } +} + +QStringList Utils::fileFind(const QRegExp &pattern, const QString &baseDir, int level, int depth, const int maxPerDir) { + // like `find /foo -name -maxdepth 2 "*.jpg"` + QStringList rtn; + QDir dir(baseDir); + dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoSymLinks | QDir::NoDot | QDir::NoDotDot); + + int fileCount = 0; + for(const auto &fileInfo: dir.entryInfoList({"*"})) { + fileCount += 1; + if(fileCount > maxPerDir) return rtn; + if(!fileInfo.isReadable()) + continue; + + const auto fn = fileInfo.fileName(); + const auto path = fileInfo.filePath(); + + if (fileInfo.isDir()) { + if (level + 1 <= depth) + rtn << Utils::fileFind(pattern, path, level + 1, depth, maxPerDir); + } + else if (pattern.exactMatch(fn)) + rtn << path; + } + return rtn; +} + +bool Utils::walletExists(QString name, const QString &path) { + name = name.replace(".keys", ""); + auto walletPath = QDir(path).filePath(name + ".keys"); + return Utils::fileExists(walletPath); +} + +int Utils::showMessageBox(const QString &windowTitle, const QString &body, bool warning){ + QMessageBox msgBox(QApplication::activeWindow()); + msgBox.setWindowTitle(windowTitle); + msgBox.setText(body); + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Ok); + + QPixmap iconWarning = QPixmap(":/assets/images/ghost.png") + .scaled(QSize(48,48), Qt::KeepAspectRatio, Qt::SmoothTransformation); + QPixmap iconInfo = QPixmap(":/assets/images/info.png") + .scaled(QSize(48,48), Qt::KeepAspectRatio, Qt::SmoothTransformation); + + if(warning) + msgBox.setIconPixmap(iconWarning); + else + msgBox.setIconPixmap(iconInfo); + + return msgBox.exec(); +} + +void Utils::copyToClipboard(const QString &string){ + QClipboard * clipboard = QApplication::clipboard(); + if (!clipboard) { + qWarning() << "Unable to access clipboard"; + return; + } + clipboard->setText(string, QClipboard::Clipboard); + if (clipboard->supportsSelection()) + clipboard->setText(string, QClipboard::Selection); + +#if defined(Q_OS_LINUX) + QThread::msleep(1); +#endif +} + +QString Utils::blockExplorerLink(const QString &blockExplorer, NetworkType::Type nettype, const QString &txid) { + if (blockExplorer == "exploremonero.com") { + if (nettype == NetworkType::MAINNET) { + return QString("https://exploremonero.com/transaction/%1").arg(txid); + } + } + else if (blockExplorer == "moneroblocks.info") { + if (nettype == NetworkType::MAINNET) { + return QString("https://moneroblocks.info/tx/%1").arg(txid); + } + } + + switch (nettype) { + case NetworkType::MAINNET: + return QString("https://xmrchain.net/tx/%1").arg(txid); + case NetworkType::STAGENET: + return QString("https://stagenet.xmrchain.net/tx/%1").arg(txid); + case NetworkType::TESTNET: + return QString("https://testnet.xmrchain.net/tx/%1").arg(txid); + } + + return QString(""); +} + +QList Utils::procList() { + // windows maybe: https://stackoverflow.com/a/13635377/2054778 + QList rtn; + QProcess process; +#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) +#if defined(Q_OS_MAC) + process.start("ps", QStringList() << "-wwaxo" << "pid,command"); +#elif defined(Q_OS_LINUX) + process.start("ps", QStringList() << "-wwaxo" << "pid,command"); +#endif + process.waitForFinished(-1); + + QString stdout = process.readAllStandardOutput(); + QString stderr = process.readAllStandardError(); + + if(stdout.isEmpty()) + return rtn; + + QStringList spl = stdout.split("\n"); + if(spl.count() >= 1) + spl.removeAt(0); + + for (auto& line: spl) { + line = line.trimmed(); + if(line.isEmpty()) + continue; + + QStringList _spl = line.split(" "); + processStruct ps; + if(_spl.length() >= 2) { + ps.pid = _spl.at(0).toInt(); + ps.command = _spl.at(1); + rtn.append(ps); + } + } +#endif + return rtn; +} + +QStandardItem *Utils::qStandardItem(const QString& text) { + auto font = QApplication::font(); + return Utils::qStandardItem(text, font); +} + +QStandardItem *Utils::qStandardItem(const QString& text, QFont &font) { + // stupid Qt doesnt set font sizes correctly on OSX + // @TODO: memleak + auto item = new QStandardItem(text); + item->setFont(font); + return item; +} + +QString Utils::getUnixAccountName() { + QString accountName = qgetenv("USER"); // mac/linux + if (accountName.isEmpty()) + accountName = qgetenv("USERNAME"); // Windows + if (accountName.isEmpty()) + throw std::runtime_error("Could derive system account name from env vars: USER or USERNAME"); + return accountName; +} + +QString Utils::xdgDesktopEntry(){ + return QString( + "[Desktop Entry]\n" + "Name=Feather\n" + "GenericName=Feather\n" + "X-GNOME-FullName=Feather\n" + "Comment=a free Monero desktop wallet\n" + "Keywords=Monero;\n" + "Exec=\"%1\" %u\n" + "Terminal=false\n" + "Type=Application\n" + "Icon=monero\n" + "Categories=Network;GNOME;Qt;\n" + "StartupNotify=true\n" + "X-GNOME-Bugzilla-Bugzilla=GNOME\n" + "X-GNOME-UsesNotifications=true\n" + ).arg(QApplication::applicationFilePath()); +} + +bool Utils::xdgDesktopEntryWrite(const QString &path){ + QString mime = xdgDesktopEntry(); + QFileInfo file(path); + QDir().mkpath(file.path()); + qDebug() << "Writing xdg desktop entry: " << path; + return Utils::fileWrite(path, mime); +} + +void Utils::xdgRefreshApplications(){ + QStringList args = {QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)}; + QProcess process; + process.start("update-desktop-database", args); + process.waitForFinished(2500); + process.close(); +} + +bool Utils::xdgDesktopEntryRegister() { +#if defined(Q_OS_MACOS) + return false; +#endif +#if defined(Q_OS_WIN) + // @TODO: implement + return false; +#endif + // no support for Tails here + if(TailsOS::detect()) return false; + + QString writeLocations = "Write locations:\n"; + writeLocations += QString("- %1\n").arg(xdgPaths.pathApp); + writeLocations += QString("- %1\n").arg(xdgPaths.pathIcon); + + QPixmap appIcon(":assets/images/feather.png"); + if (!Utils::fileExists(xdgPaths.pathIcon)) + Utils::pixmapWrite(xdgPaths.pathIcon, appIcon); + Utils::xdgDesktopEntryWrite(xdgPaths.pathApp); + Utils::xdgRefreshApplications(); + return true; +} + +bool Utils::pixmapWrite(const QString &path, const QPixmap &pixmap) { + qDebug() << "Writing xdg icon: " << path; + QFile file(path); + QFileInfo iconInfo(file); + QDir().mkpath(iconInfo.path()); + if(file.open(QIODevice::WriteOnly)){ + pixmap.save(&file, "PNG"); + file.close(); + return true; + } + return false; +} + +QFont Utils::relativeFont(int delta) { + auto font = QApplication::font(); + font.setPointSize(font.pointSize() + delta); + return font; +} + +double Utils::roundSignificant(double N, double n) +{ + int h; + double l, a, b, c, d, e, i, j, m, f, g; + b = N; + c = floor(N); + + for (i = 0; b >= 1; ++i) + b = b / 10; + + d = n - i; + b = N; + b = b * pow(10, d); + e = b + 0.5; + if ((float)e == (float)ceil(b)) { + f = (ceil(b)); + h = f - 2; + if (h % 2 != 0) { + e = e - 1; + } + } + j = floor(e); + m = pow(10, d); + j = j / m; + return j; +} \ No newline at end of file diff --git a/src/utils/utils.h b/src/utils/utils.h new file mode 100644 index 0000000..a91c539 --- /dev/null +++ b/src/utils/utils.h @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_UTILS_H +#define FEATHER_UTILS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "networktype.h" + +struct logMessage +{ + logMessage(const QtMsgType &type, const QString &message, const QString &fn){ + logMessage::type = type; + logMessage::message = message; + logMessage::fn = fn; + } + QtMsgType type; + QString message; + QString fn; +}; + +struct networkPeer { + QString host; + quint16 port; + bool active = false; +}; + +struct processStruct { + int pid = 0; + QString command; + QFileInfo fileInfo; +}; + +struct xdgDesktopEntryPaths { + QString pathApp; + QString pathIcon; + QString PathMime; +}; + +const xdgDesktopEntryPaths xdgPaths = { + QString("%1/monero-gui.desktop").arg(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)), + QString("%1/.local/share/icons/monero.png").arg(QDir::homePath()), + QString("/") +}; + +class Utils +{ + +public: + static bool portOpen(const QString &hostname, quint16 port); + static bool isDigit(const QString &inp); + static bool fileExists(const QString &path); + static QByteArray fileOpen(const QString &path); + static QByteArray fileOpenQRC(const QString &path); + static void desktopNotify(const QString &title, const QString &message, int duration); + static bool fileWrite(const QString &path, const QString &data); + static QStringList fileFind(const QRegExp &pattern, const QString &baseDir, int level, int depth, int maxPerDir); + static QString systemAccountName(); + static QByteArray zipExtract(const QString &path, const QString& destination); + static bool validateJSON(const QByteArray &blob); + static bool readJsonFile(QIODevice &device, QSettings::SettingsMap &map); + static bool walletExists(QString name, const QString &path); + static bool writeJsonFile(QIODevice &device, const QSettings::SettingsMap &map); + static QStringList readJsonStringToQStringList(const QString &input); + static void applicationLogHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); + static void openWindow(QWidget *w); + static void externalLinkWarning(const QString &url); + static int showMessageBox(const QString &windowTitle, const QString &body, bool warning); + static QList procList(); + static bool dirExists(const QString &path); + static QString barrayToString(const QByteArray &data); + static QByteArray readSocket(QTcpSocket &socket, int buffer_size); + static bool testSocks5(const QString &host, quint16 port); + static QStandardItem *qStandardItem(const QString &text); + static QStandardItem *qStandardItem(const QString &text, QFont &font); + static void copyToClipboard(const QString &string); + static QString blockExplorerLink(const QString &blockExplorer, NetworkType::Type nettype, const QString &txid); + static QString getUnixAccountName(); + static QString xdgDesktopEntry(); + static bool xdgDesktopEntryWrite(const QString &path); + static void xdgRefreshApplications(); + static bool xdgDesktopEntryRegister(); + static bool pixmapWrite(const QString &path, const QPixmap &pixmap); + static QFont relativeFont(int delta); + static double roundSignificant(double N, double n); + static QStringList randomHTTPAgents; + + template + static QString QtEnumToString (const QEnum value) + { + return QString::fromStdString(std::string(QMetaEnum::fromType().valueToKey(value))); + } +}; + +class AppContext; // forward declaration + + + +#endif //FEATHER_UTILS_H diff --git a/src/utils/whonix.cpp b/src/utils/whonix.cpp new file mode 100644 index 0000000..231073f --- /dev/null +++ b/src/utils/whonix.cpp @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "whonix.h" + +#include "utils/utils.h" + +bool WhonixOS::detect() { + return !QString::fromLocal8Bit(qgetenv("WHONIX")).isEmpty(); +} \ No newline at end of file diff --git a/src/utils/whonix.h b/src/utils/whonix.h new file mode 100644 index 0000000..3ad06a4 --- /dev/null +++ b/src/utils/whonix.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_WHONIX_H +#define FEATHER_WHONIX_H + + +struct WhonixOS { + static bool detect(); +}; + + +#endif //FEATHER_WHONIX_H diff --git a/src/utils/wsclient.cpp b/src/utils/wsclient.cpp new file mode 100644 index 0000000..fa3f690 --- /dev/null +++ b/src/utils/wsclient.cpp @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include +#include +#include +#include "wsclient.h" +#include "appcontext.h" + + +WSClient::WSClient(AppContext *ctx, const QUrl &url, QObject *parent) : + QObject(parent), + url(url), + m_ctx(ctx) { + connect(&this->webSocket, &QWebSocket::binaryMessageReceived, this, &WSClient::onbinaryMessageReceived); + connect(&this->webSocket, &QWebSocket::connected, this, &WSClient::onConnected); + connect(&this->webSocket, &QWebSocket::disconnected, this, &WSClient::closed); + connect(&this->webSocket, QOverload::of(&QWebSocket::error), this, &WSClient::onError); + + m_tor = url.host().endsWith(".onion"); +} + +void WSClient::sendMsg(const QByteArray &data) { + auto state = this->webSocket.state(); + if(state == QAbstractSocket::ConnectedState) + this->webSocket.sendBinaryMessage(data); +} + +void WSClient::start() { + // connect & reconnect on errors/close +#ifdef QT_DEBUG + qDebug() << "WebSocket connect:" << url.url(); +#endif + if((m_tor && this->m_ctx->tor->torConnected) || !m_tor) + this->webSocket.open(QUrl(this->url)); + + if(!this->m_connectionTimer.isActive()) { + connect(&this->m_connectionTimer, &QTimer::timeout, this, &WSClient::checkConnection); + this->m_connectionTimer.start(2000); + } +} + +void WSClient::checkConnection() { + if(m_tor && !this->m_ctx->tor->torConnected) + return; + + auto state = this->webSocket.state(); + if(state == QAbstractSocket::UnconnectedState) { +#ifdef QT_DEBUG + qDebug() << "WebSocket reconnect"; +#endif + this->start(); + } +} + +void WSClient::onConnected() { +#ifdef QT_DEBUG + qDebug() << "WebSocket connected"; +#endif + emit connectionEstablished(); +} + +void WSClient::onError(QAbstractSocket::SocketError error) { + qCritical() << "WebSocket error: " << error; + auto state = this->webSocket.state(); + if(state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState) + this->webSocket.abort(); +} + +void WSClient::onbinaryMessageReceived(const QByteArray &message) { +#ifdef QT_DEBUG + qDebug() << "WebSocket received:" << message; +#endif + if (!Utils::validateJSON(message)) { + qCritical() << "Could not interpret WebSocket message as JSON"; + return; + } + + QJsonDocument doc = QJsonDocument::fromJson(message); + QJsonObject object = doc.object(); + if(!object.contains("cmd") || !object.contains("data")) { + qCritical() << "Invalid WebSocket message received"; + return; + } + + emit WSMessage(object); +} diff --git a/src/utils/wsclient.h b/src/utils/wsclient.h new file mode 100644 index 0000000..4e90298 --- /dev/null +++ b/src/utils/wsclient.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef ECHOCLIENT_H +#define ECHOCLIENT_H + +#include +#include +#include + +class AppContext; +class WSClient : public QObject +{ + Q_OBJECT + +public: + explicit WSClient(AppContext *ctx, const QUrl &url, QObject *parent = nullptr); + void start(); + void sendMsg(const QByteArray &data); + QWebSocket webSocket; + QUrl url; + +signals: + void closed(); + void connectionEstablished(); + void WSMessage(QJsonObject message); + +private slots: + void onConnected(); + void onbinaryMessageReceived(const QByteArray &message); + void checkConnection(); + void onError(QAbstractSocket::SocketError error); + +private: + QTimer m_connectionTimer; + AppContext *m_ctx; + bool m_tor = true; +}; + +#endif // ECHOCLIENT_H \ No newline at end of file diff --git a/src/utils/xmrto.cpp b/src/utils/xmrto.cpp new file mode 100644 index 0000000..11d467c --- /dev/null +++ b/src/utils/xmrto.cpp @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "xmrto.h" + +#include "utils/xmrtoorder.h" +#include "appcontext.h" + +QMap XmrTo::stateMap; + +XmrTo::XmrTo(AppContext *ctx, QObject *parent) : + QObject(parent), + m_ctx(ctx) { + + m_baseUrl = m_ctx->networkType == NetworkType::Type::MAINNET ? "https://xmr.to" : "https://test.xmr.to"; + + m_netTor = new UtilsNetworking(this->m_ctx->network); + m_netClear = new UtilsNetworking(this->m_ctx->networkClearnet); + + m_apiTor = new XmrToApi(this, m_netTor, m_baseUrl); + m_apiClear = new XmrToApi(this, m_netClear, m_baseUrl); + + connect(m_apiTor, &XmrToApi::ApiResponse, this, &XmrTo::onApiResponse); + connect(m_apiClear, &XmrToApi::ApiResponse, this, &XmrTo::onApiResponse); + + connect(this, &XmrTo::orderPaymentRequired, this->m_ctx, QOverload::of(&AppContext::onCreateTransaction)); + + XmrTo::stateMap[OrderState::Status_Idle] = "IDLE"; + XmrTo::stateMap[OrderState::Status_OrderCreating] = "CREATING"; + XmrTo::stateMap[OrderState::Status_OrderUnpaid] = "UNPAID"; + XmrTo::stateMap[OrderState::Status_OrderToBeCreated] = "TO_BE_CREATED"; + XmrTo::stateMap[OrderState::Status_OrderUnderPaid] = "UNDERPAID"; + XmrTo::stateMap[OrderState::Status_OrderPaidUnconfirmed] = "PAID_UNCONFIRMED"; + XmrTo::stateMap[OrderState::Status_OrderPaid] = "PAID"; + XmrTo::stateMap[OrderState::Status_OrderBTCSent] = "BTC_SENT"; + XmrTo::stateMap[OrderState::Status_OrderTimedOut] = "TIMED_OUT"; + XmrTo::stateMap[OrderState::Status_OrderFailed] = "FAILED"; + XmrTo::stateMap[OrderState::Status_OrderXMRSent] = "XMR_SENT"; + + this->tableModel = new XmrToModel(&this->orders, this); +} + +void XmrTo::createOrder(double amount, const QString ¤cy, const QString &btcAddress) { + // ^[13][a-km-zA-HJ-NP-Z0-9]{26,33}$ + + XmrToOrder *order; + order = new XmrToOrder(this->m_ctx, m_netTor, m_baseUrl, false, &this->rates, this); + + connect(order, &XmrToOrder::orderFailed, this, &XmrTo::orderFailed); + connect(order, &XmrToOrder::orderPaid, this, &XmrTo::orderPaid); + connect(order, &XmrToOrder::orderPaidUnconfirmed, this, &XmrTo::orderPaidUnconfirmed); + connect(order, &XmrToOrder::orderPaymentRequired, this, &XmrTo::orderPaymentRequired); + connect(order, &XmrToOrder::orderChanged, this->tableModel, &XmrToModel::update); + + order->create(amount, currency, btcAddress); + this->orders.append(order); + tableModel->update(); +} + + +void XmrTo::onApiResponse(const XmrToResponse &resp) { + if (!resp.ok) { + this->onApiFailure(resp); + return; + } + + emit connectionSuccess(); + if (resp.endpoint == Endpoint::RATES) { + onRatesReceived(resp.obj); + } +} + +void XmrTo::onApiFailure(const XmrToResponse &resp) { + emit connectionError(resp.message); +} + +void XmrTo::onGetRates() { + m_apiTor->getRates(); +} + +void XmrTo::onRatesReceived(const QJsonObject &doc) { + this->rates.price = doc.value("price").toString().toDouble(); + this->rates.ln_lower_limit = doc.value("ln_lower_limit").toString().toDouble(); + this->rates.ln_upper_limit = doc.value("ln_upper_limit").toString().toDouble(); + this->rates.lower_limit = doc.value("lower_limit").toString().toDouble(); + this->rates.upper_limit = doc.value("upper_limit").toString().toDouble(); + this->rates.zero_conf_enabled = doc.value("zero_conf_enabled").toBool(); + this->rates.zero_conf_max_amount = doc.value("zero_conf_enabled").toString().toDouble(); + emit ratesUpdated(rates); +} + +void XmrTo::onNetworkChanged(bool clearnet) { + m_api = clearnet ? m_apiClear : m_apiTor; +} + +void XmrTo::onWalletClosed() { + // @TODO: cleanup + for(const auto &order: this->orders) + order->deleteLater(); + + this->tableModel->update(); +} + +void XmrTo::onWalletOpened() { + // @TODO: read past XMR.To orders, start pending ones +} + +void XmrTo::onViewOrder(const QString &orderId) { + QString url = QString("%1/nojs/status/%2").arg(this->m_baseUrl).arg(orderId); + emit openURL(url); +} diff --git a/src/utils/xmrto.h b/src/utils/xmrto.h new file mode 100644 index 0000000..dcd7389 --- /dev/null +++ b/src/utils/xmrto.h @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_XMRTOCONVERT_H +#define FEATHER_XMRTOCONVERT_H + +#include + +#include "model/XmrToModel.h" +#include "utils/xmrtoorder.h" +#include "utils/xmrtoapi.h" + +class AppContext; +class XmrTo: public QObject { + Q_OBJECT + +public: + explicit XmrTo(AppContext *ctx, QObject *parent = nullptr); + Q_ENUM(OrderState); + + XmrToModel *tableModel; + static QMap stateMap; + XmrToRates rates; + QList orders; + +public slots: + void createOrder(double amount, const QString ¤cy, const QString &btcAddress); + void onGetRates(); + void onRatesReceived(const QJsonObject &doc); + void onViewOrder(const QString &orderId); + void onNetworkChanged(bool clearnet); + void onWalletOpened(); + void onWalletClosed(); + +private slots: + void onApiResponse(const XmrToResponse &doc); + +signals: + void orderPaymentRequired(XmrToOrder *order); + void orderPaidUnconfirmed(XmrToOrder *order); + void orderPaid(XmrToOrder *order); + void orderFailed(XmrToOrder *order); + void ratesUpdated(XmrToRates rates); + void openURL(const QString &url); + void connectionError(const QString &err); + void connectionSuccess(); + +private: + void onApiFailure(const XmrToResponse &doc); + + QString m_baseUrl; + AppContext *m_ctx; + int m_orderTimeout = 900; // https://xmrto-api.readthedocs.io/en/latest/introduction.html#various-parameters + + UtilsNetworking *m_netTor; + UtilsNetworking *m_netClear; + + XmrToApi *m_api; + XmrToApi *m_apiTor; + XmrToApi *m_apiClear; +}; + +#endif //FEATHER_XMRTOCONVERT_H diff --git a/src/utils/xmrtoapi.cpp b/src/utils/xmrtoapi.cpp new file mode 100644 index 0000000..03bc6a3 --- /dev/null +++ b/src/utils/xmrtoapi.cpp @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "xmrtoapi.h" + +#include + +XmrToApi::XmrToApi(QObject *parent, UtilsNetworking *network, QString baseUrl) + : QObject(parent) + , m_network(network) + , m_baseUrl(std::move(baseUrl)) +{ +} + +void XmrToApi::getRates() { + QString url = QString("%1/api/v3/xmr2btc/order_parameter_query/").arg(this->m_baseUrl); + QNetworkReply *reply = m_network->getJson(url); + connect(reply, &QNetworkReply::finished, std::bind(&XmrToApi::onResponse, this, reply, Endpoint::RATES)); +} + +void XmrToApi::createOrder(double amount, const QString &amount_currency, const QString &dest_address) { + QJsonObject order; + order["amount"] = amount; + order["amount_currency"] = amount_currency; + order["btc_dest_address"] = dest_address; + + QString url = QString("%1/api/v3/xmr2btc/order_create/").arg(m_baseUrl); + QNetworkReply *reply = m_network->postJson(url, order); + connect(reply, &QNetworkReply::finished, std::bind(&XmrToApi::onResponse, this, reply, Endpoint::ORDER_CREATE)); +} + +void XmrToApi::getOrderStatus(const QString &uuid) { + QJsonObject order; + order["uuid"] = uuid; + + QString url = QString("%1/api/v3/xmr2btc/order_status_query/").arg(m_baseUrl); + QNetworkReply *reply = m_network->postJson(url, order); + connect(reply, &QNetworkReply::finished, std::bind(&XmrToApi::onResponse, this, reply, Endpoint::ORDER_STATUS)); +} + +void XmrToApi::onResponse(QNetworkReply *reply, Endpoint endpoint) { + const auto ok = reply->error() == QNetworkReply::NoError; + const auto err = reply->errorString(); + reply->deleteLater(); + + QByteArray data = reply->readAll(); + QJsonObject obj; + if (!data.isEmpty() && Utils::validateJSON(data)) { + auto doc = QJsonDocument::fromJson(data); + obj = doc.object(); + } + else if (!ok) { + emit ApiResponse(XmrToResponse(false, endpoint, err)); + return; + } + else { + emit ApiResponse(XmrToResponse(false, endpoint, "Invalid response from XMR.to")); + return; + } + + XmrToError xmrto_err = XmrToApi::getApiError(obj); + if (!xmrto_err.code.isEmpty()) { + emit ApiResponse(XmrToResponse(false, endpoint, m_errorMap.contains(xmrto_err.code) ? m_errorMap[xmrto_err.code] : "", xmrto_err)); + return; + } + + emit ApiResponse(XmrToResponse(true, endpoint, "", obj)); +} + +XmrToError XmrToApi::getApiError(const QJsonObject &obj) { + if (!obj.contains("error")) + return XmrToError(); + + QString code = obj.value("error").toString(); + QString msg = obj.value("error_msg").toString(); + + return XmrToError(code, msg); +} diff --git a/src/utils/xmrtoapi.h b/src/utils/xmrtoapi.h new file mode 100644 index 0000000..1fa983a --- /dev/null +++ b/src/utils/xmrtoapi.h @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_XMRTOAPI_H +#define FEATHER_XMRTOAPI_H + +#include +#include + +#include "utils/networking.h" + +enum Endpoint { + RATES = 0, + ORDER_CREATE, + ORDER_STATUS +}; + +struct XmrToError { + explicit XmrToError(QString code = "", QString msg = "") + : code(std::move(code)), msg(std::move(msg)) {}; + + QString code; + QString msg; +}; + +struct XmrToResponse { + explicit XmrToResponse(bool ok, Endpoint endpoint, QString message, XmrToError error = XmrToError(), QJsonObject obj = {}) + : ok(ok), endpoint(endpoint), message(std::move(message)), error(std::move(error)), obj(std::move(obj)) {}; + + explicit XmrToResponse(bool ok, Endpoint endpoint, QString message, QJsonObject obj) + : ok(ok), endpoint(endpoint), message(std::move(message)), obj(std::move(obj)) {}; + + bool ok; + Endpoint endpoint; + QString message; + XmrToError error = XmrToError(); + QJsonObject obj; +}; + +class XmrToApi : public QObject { + Q_OBJECT + +public: + explicit XmrToApi(QObject *parent, UtilsNetworking *network, QString baseUrl = "https://xmr.to"); + + void getRates(); + void createOrder(double amount, const QString &amount_currency, const QString &dest_address); + void getOrderStatus(const QString &uuid); + +signals: + void ApiResponse(XmrToResponse resp); + +private slots: + void onResponse(QNetworkReply *reply, Endpoint endpoint); + +private: + static XmrToError getApiError(const QJsonObject &obj); + + QString m_baseUrl; + UtilsNetworking *m_network; + + // https://xmrto-api.readthedocs.io/en/latest/introduction.html#list-of-all-error-codes + const QMap m_errorMap = { + {"XMRTO-ERROR-001", "internal services not available, try again later."}, + {"XMRTO-ERROR-002", "malformed bitcoin address, check address validity."}, + {"XMRTO-ERROR-003", "invalid bitcoin amount, check amount data type."}, + {"XMRTO-ERROR-004", "bitcoin amount out of bounds, check min and max amount."}, + {"XMRTO-ERROR-005", "unexpected validation error, contact support."}, + {"XMRTO-ERROR-006", "requested order not found, check order UUID."}, + {"XMRTO-ERROR-007", "third party service not available, try again later."}, + {"XMRTO-ERROR-008", "insufficient funds available, try again later."}, + {"XMRTO-ERROR-009", "invalid request, check request parameters."}, + {"XMRTO-ERROR-010", "payment protocol failed, invalid or outdated data served by URL."}, + {"XMRTO-ERROR-011", "malformed payment protocol url, URL is malformed or cannot be contacted."}, + {"XMRTO-ERROR-012", "too many requests, try less often."}, + {"XMRTO-ERROR-013", "access forbidden."}, + {"XMRTO-ERROR-014", "service is not available in your region."}, + {"XMRTO-ERROR-015", "invalid monero amount, check amount data type."}, + {"XMRTO-ERROR-016", "invalid currency, check available currency options."}, + {"XMRTO-ERROR-017", "malformed lightning network invoice, provide a correct invoice for the main network."}, + {"XMRTO-ERROR-018", "lightning payment unlikely to succeed, check first if xmr.to has routes available."}, + {"XMRTO-ERROR-019", "lightning invoice preimage already known, don’t use the same invoice more than once."} + }; +}; + + +#endif //FEATHER_XMRTOAPI_H diff --git a/src/utils/xmrtoorder.cpp b/src/utils/xmrtoorder.cpp new file mode 100644 index 0000000..b5556d6 --- /dev/null +++ b/src/utils/xmrtoorder.cpp @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "xmrtoorder.h" + +#include + +#include "libwalletqt/Wallet.h" +#include "appcontext.h" +#include "utils/xmrto.h" + +XmrToOrder::XmrToOrder(AppContext *ctx, UtilsNetworking *network, QString baseUrl, bool clearnet, XmrToRates *rates, QObject *parent) : + QObject(parent), + m_ctx(ctx), + m_network(network), + m_baseUrl(std::move(baseUrl)), + m_rates(rates), + m_clearnet(clearnet) { + this->state = OrderState::Status_Idle; + + m_baseUrl = m_ctx->networkType == NetworkType::Type::MAINNET ? "https://xmr.to" : "https://test.xmr.to"; + m_api = new XmrToApi(this, network, m_baseUrl); + + connect(m_api, &XmrToApi::ApiResponse, this, &XmrToOrder::onApiResponse); + connect(m_ctx, &AppContext::transactionCommitted, this, &XmrToOrder::onTransactionCommitted); + connect(m_ctx, &AppContext::createTransactionCancelled, this, &XmrToOrder::onTransactionCancelled); +} + +void XmrToOrder::onTransactionCancelled(const QString &address, double amount) { + // listener for all cancelled transactions - will try to match the exact amount to this order. + if(this->incoming_amount_total != amount || this->receiving_subaddress != address) return; + + this->errorMsg = "TX cancelled by user"; + this->changeState(OrderState::Status_OrderFailed); + this->stop(); +} + +void XmrToOrder::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid) { + // listener for all outgoing transactions - will try to match the exact amount to this order. + if(this->state == OrderState::Status_OrderUnpaid){ + if(tx->amount() / AppContext::cdiv == this->incoming_amount_total) { + if(!status) { + this->errorMsg = "TX failed to commit"; + this->changeState(OrderState::Status_OrderFailed); + this->stop(); + return; + } + + this->xmr_txid = txid.at(0); + this->m_paymentSent = true; + this->changeState(OrderState::Status_OrderXMRSent); + } + } +} + +void XmrToOrder::onApiFailure(const XmrToResponse &resp) { + this->errorCode = resp.error.code; + this->errorMsg = resp.message; + + switch (resp.endpoint) { + case ORDER_CREATE: + this->onCreatedError(); + break; + case ORDER_STATUS: + this->onCheckedError(resp.error); + break; + default: + return; + } +} + +void XmrToOrder::onApiResponse(const XmrToResponse& resp) { + if (!resp.ok) { + this->onApiFailure(resp); + return; + } + + switch (resp.endpoint) { + case ORDER_CREATE: + this->onCreated(resp.obj); + break; + case ORDER_STATUS: + this->onChecked(resp.obj); + break; + default: + return; + } +} + +void XmrToOrder::create(double amount, const QString ¤cy, const QString &btcAddress) { + if(this->m_ctx->currentWallet == nullptr) { + this->errorMsg = "No wallet opened"; + this->changeState(OrderState::Status_OrderFailed); + return; + } + + m_api->createOrder(amount, currency, btcAddress); + this->changeState(OrderState::Status_OrderCreating); +} + +void XmrToOrder::onCreatedError() { + this->changeState(OrderState::Status_OrderFailed); +} + +void XmrToOrder::onCreated(const QJsonObject &object) { + if(!object.contains("state")) + this->errorMsg = "Could not parse 'state' from JSON response"; + if(object.value("state").toString() != "TO_BE_CREATED") + this->errorMsg = "unknown state from response, should be \"TO_BE_CREATED\""; + + if(!this->errorMsg.isEmpty()) { + this->changeState(OrderState::Status_OrderFailed); + return; + } + + if(m_created) return; + m_created = true; + this->btc_amount = object.value("btc_amount").toDouble(); + this->btc_dest_address = object.value("btc_dest_address").toString(); + this->uses_lightning = object.value("uses_lightning").toBool(); + this->uuid = object.value("uuid").toString(); + m_checkTimer.start(1000*5); + m_countdownTimer.start(1000); + connect(&m_checkTimer, &QTimer::timeout, this, &XmrToOrder::check); + connect(&m_countdownTimer, &QTimer::timeout, this, &XmrToOrder::onCountdown); + + this->changeState(OrderState::Status_OrderToBeCreated); + this->check(); +} + +void XmrToOrder::check() { + if(this->m_ctx->currentWallet == nullptr) + return; + + m_api->getOrderStatus(this->uuid); +} + +void XmrToOrder::onCheckedError(const XmrToError& err) { + if (!err.code.isEmpty()) + this->changeState(OrderState::Status_OrderFailed); + + m_checkFailures += 1; + if(m_checkFailures > 15){ + this->errorMsg = "Too many failed attempts"; + this->changeState(OrderState::Status_OrderFailed); + } +} + +void XmrToOrder::onChecked(const QJsonObject &object) { + if(object.contains("btc_amount")) + this->btc_amount = object.value("btc_amount").toString().toDouble(); + if(object.contains("btc_dest_address")) + this->btc_dest_address = object.value("btc_dest_address").toString(); + if(object.contains("seconds_till_timeout")) { + this->seconds_till_timeout = object.value("seconds_till_timeout").toInt(); + this->countdown = this->seconds_till_timeout; + } + if(object.contains("created_at")) + this->created_at = object.value("created_at").toString(); + if(object.contains("expires_at")) + this->expires_at = object.value("expires_at").toString(); + if(object.contains("incoming_amount_total")) + this->incoming_amount_total = object.value("incoming_amount_total").toString().toDouble(); + if(object.contains("remaining_amount_incoming")) + this->remaining_amount_incoming = object.value("remaining_amount_incoming").toString().toDouble(); + if(object.contains("incoming_price_btc")) + { + qDebug() << object.value("incoming_price_btc").toString(); + this->incoming_price_btc = object.value("incoming_price_btc").toString().toDouble(); + } + if(object.contains("receiving_subaddress")) + this->receiving_subaddress = object.value("receiving_subaddress").toString(); + + if(object.contains("payments")) { + // detect btc txid, xmr.to api can output several - we'll just grab the first #yolo + auto payments = object.value("payments").toArray(); + for(const auto &payment: payments){ + auto obj = payment.toObject(); + if(obj.contains("tx_id")) { + this->btc_txid = obj.value("tx_id").toString(); + break; + } + } + } + + this->changeState(object.value("state").toString()); +} + +void XmrToOrder::changeState(const QString &_state) { + for(const auto &key: XmrTo::stateMap.keys()) { + const auto &val = XmrTo::stateMap[key]; + if(_state == val){ + this->changeState(key); + return; + } + } +} + +void XmrToOrder::changeState(OrderState _state) { + if(this->m_ctx->currentWallet == nullptr) + return; + + if(_state == OrderState::Status_OrderUnderPaid && m_paymentSent) { + this->state = OrderState::Status_OrderXMRSent; + emit orderChanged(); + return; + } + + if(_state == this->state) return; + switch(_state){ + case OrderState::Status_Idle: + break; + case OrderState::Status_OrderCreating: + break; + case OrderState::Status_OrderToBeCreated: + break; + case OrderState::Status_OrderUnderPaid: + emit orderFailed(this); + this->stop(); + break; + case OrderState::Status_OrderUnpaid: + // need to send Monero + if(!m_paymentRequested) { + auto unlocked_balance = m_ctx->currentWallet->unlockedBalance() / AppContext::cdiv; + if (this->incoming_amount_total >= unlocked_balance) { + this->state = OrderState::Status_OrderFailed; + emit orderFailed(this); + this->stop(); + break; + } + m_paymentRequested = true; + emit orderPaymentRequired(this); + } + break; + case OrderState::Status_OrderFailed: + emit orderFailed(this); + this->stop(); + break; + case OrderState::Status_OrderPaidUnconfirmed: + emit orderPaidUnconfirmed(this); + break; + case OrderState::Status_OrderPaid: + emit orderPaid(this); + break; + case OrderState::Status_OrderTimedOut: + emit orderFailed(this); + this->stop(); + break; + case OrderState::Status_OrderBTCSent: + emit orderPaid(this); + this->stop(); + break; + default: + break; + } + + this->state = _state; + emit orderChanged(); +} + +void XmrToOrder::onCountdown() { + if(this->countdown <= 0) return; + this->countdown -= 1; + emit orderChanged(); +} + +void XmrToOrder::stop(){ + this->m_checkTimer.stop(); + this->m_countdownTimer.stop(); +} + +XmrToOrder::~XmrToOrder(){ + this->stop(); + this->disconnect(); + this->m_network->deleteLater(); +} \ No newline at end of file diff --git a/src/utils/xmrtoorder.h b/src/utils/xmrtoorder.h new file mode 100644 index 0000000..c05c71d --- /dev/null +++ b/src/utils/xmrtoorder.h @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_XMRTOORDER_H +#define FEATHER_XMRTOORDER_H + +#include + +#include "utils/networking.h" +#include "PendingTransaction.h" +#include "utils/xmrtoapi.h" + +enum OrderState { + Status_Idle, + Status_OrderCreating, + Status_OrderToBeCreated, + Status_OrderUnpaid, + Status_OrderXMRSent, + Status_OrderUnderPaid, + Status_OrderPaidUnconfirmed, + Status_OrderPaid, + Status_OrderBTCSent, + Status_OrderTimedOut, + Status_OrderFailed +}; + +struct XmrToRates { + double price; + double upper_limit; + double lower_limit; + double ln_upper_limit; + double ln_lower_limit; + double zero_conf_max_amount; + bool zero_conf_enabled; +}; + +class XmrToOrder : public QObject { + Q_OBJECT + +public: + explicit XmrToOrder(AppContext *ctx, UtilsNetworking *network, QString baseUrl, bool clearnet, XmrToRates *rates, QObject *parent = nullptr); + void create(double btcAmount, const QString ¤cy, const QString &btcAddress); + void changeState(OrderState state); + void changeState(const QString &state); + void stop(); + + int state; + int countdown = -1; // seconds remaining calculated from `seconds_till_timeout` + QString uuid; + QString errorMsg; + QString errorCode; + + double btc_amount = 0; + QString btc_dest_address; + QString btc_txid; + QString xmr_txid; + bool uses_lightning = false; + + QString receiving_subaddress; + QString created_at; + QString expires_at; + int seconds_till_timeout = -1; + double incoming_amount_total = 0; // amount_in_incoming_currency_for_this_order_as_string + double remaining_amount_incoming; // amount_in_incoming_currency_that_the_user_must_still_send_as_string + double incoming_price_btc = 0; // price_of_1_incoming_in_btc_currency_as_offered_by_service + +public slots: + void onCountdown(); + void onTransactionCancelled(const QString &address, double amount); + void onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid); + + void onCreatedError(); + void onChecked(const QJsonObject &object); + void onCheckedError(const XmrToError& err); + void check(); + +private: + bool m_created = false; + QString m_baseUrl; + QTimer m_checkTimer; + QTimer m_countdownTimer; + int m_checkFailures = 0; + bool m_clearnet; + bool m_paymentSent = false; + bool m_paymentRequested = false; + UtilsNetworking *m_network; + AppContext *m_ctx; + XmrToRates *m_rates; + XmrToApi *m_api; + + ~XmrToOrder(); + +signals: + void orderChanged(); + void orderPaymentRequired(XmrToOrder *order); + void orderPaid(XmrToOrder *order); + void orderPaidUnconfirmed(XmrToOrder *order); + void orderFailed(XmrToOrder *order); + +private slots: + void onCreated(const QJsonObject &object); + void onApiFailure(const XmrToResponse &resp); + void onApiResponse(const XmrToResponse &resp); +}; + +#endif //FEATHER_XMRTOORDER_H diff --git a/src/widgets/CCSEntry.h b/src/widgets/CCSEntry.h new file mode 100644 index 0000000..c2ec1f3 --- /dev/null +++ b/src/widgets/CCSEntry.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_CCSENTRY_H +#define FEATHER_CCSENTRY_H + +#include + +struct CCSEntry { + CCSEntry()= default;; + + QString title = ""; + QString date = ""; + QString address = ""; + QString author = ""; + QString state = ""; + QString url = ""; + double target_amount = 0; + double raised_amount = 0; + double percentage_funded = 0; + int contributions = 0; +}; + +#endif //FEATHER_CCSENTRY_H diff --git a/src/widgets/RedditPost.h b/src/widgets/RedditPost.h new file mode 100644 index 0000000..b7d3e48 --- /dev/null +++ b/src/widgets/RedditPost.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_REDDITPOST_H +#define FEATHER_REDDITPOST_H + +#include + +struct RedditPost { + RedditPost(const QString &title, const QString &author, const QString &url, int comments) : title(title), author(author), url(url), comments(comments){}; + + QString title; + QString author; + QString url; + int comments; +}; + +#endif //FEATHER_REDDITPOST_H diff --git a/src/widgets/ccswidget.cpp b/src/widgets/ccswidget.cpp new file mode 100644 index 0000000..b162539 --- /dev/null +++ b/src/widgets/ccswidget.cpp @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include +#include + +#include "ccswidget.h" +#include "ui_csswidget.h" +#include "utils/utils.h" +#include "cssprogressdelegate.h" + +CCSWidget::CCSWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::CSSWidget), + m_model(new CCSModel(this)), + m_contextMenu(new QMenu(this)) +{ + ui->setupUi(this); + auto progressDelegate = new CCSProgressDelegate(m_model, this); + ui->tableView->setModel(m_model); +#ifndef Q_OS_MACOS + ui->tableView->setItemDelegateForColumn(2, progressDelegate); +#endif + this->setupTable(); + + m_contextMenu->addAction("View proposal", this, &CCSWidget::linkClicked); + m_contextMenu->addAction("Donate", this, &CCSWidget::donateClicked); + connect(ui->tableView, &QHeaderView::customContextMenuRequested, this, &CCSWidget::showContextMenu); + + connect(ui->tableView, &QTableView::doubleClicked, this, &CCSWidget::linkClicked); +} + +CCSModel* CCSWidget::model() { + return m_model; +} + +void CCSWidget::linkClicked() { + QModelIndex index = ui->tableView->currentIndex(); + auto entry = m_model->entry(index.row()); + + if (entry) + Utils::externalLinkWarning(entry->url); +} + +void CCSWidget::donateClicked() { + QModelIndex index = ui->tableView->currentIndex(); + auto entry = m_model->entry(index.row()); + + if (entry) + emit selected(*entry); +} + +void CCSWidget::setupTable() { + ui->tableView->verticalHeader()->setVisible(false); + ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + + ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + ui->tableView->setColumnWidth(2, 160); +} + +void CCSWidget::showContextMenu(const QPoint &pos) { + QModelIndex index = ui->tableView->indexAt(pos); + if (!index.isValid()) { + return; + } + + m_contextMenu->exec(ui->tableView->viewport()->mapToGlobal(pos)); +} + +CCSWidget::~CCSWidget() { + delete ui; +} diff --git a/src/widgets/ccswidget.h b/src/widgets/ccswidget.h new file mode 100644 index 0000000..747195c --- /dev/null +++ b/src/widgets/ccswidget.h @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef CSSWIDGET_H +#define CSSWIDGET_H + +#include +#include +#include +#include +#include + +#include "widgets/CCSEntry.h" +#include "model/CCSModel.h" +#include "appcontext.h" + +namespace Ui { + class CSSWidget; +} + +class CCSWidget : public QWidget +{ +Q_OBJECT + +public: + explicit CCSWidget(QWidget *parent = nullptr); + ~CCSWidget(); + CCSModel *model(); + +signals: + void selected(CCSEntry entry); + +public slots: + void donateClicked(); + +private slots: + void linkClicked(); + +private: + void setupTable(); + void showContextMenu(const QPoint &pos); + + Ui::CSSWidget *ui; + CCSModel *m_model; + QMenu *m_contextMenu; +}; + +#endif // CSSWIDGET_H diff --git a/src/widgets/cssprogressdelegate.cpp b/src/widgets/cssprogressdelegate.cpp new file mode 100644 index 0000000..de7268a --- /dev/null +++ b/src/widgets/cssprogressdelegate.cpp @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "cssprogressdelegate.h" + +#include + +CCSProgressDelegate::CCSProgressDelegate(CCSModel *model, QWidget *parent) + : m_model(model) + , QStyledItemDelegate(parent) +{ + +} + +void CCSProgressDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const { + + if (index.column() != CCSModel::Progress) { + QStyledItemDelegate::paint(painter, option, index); + return; + } + + QStyleOptionProgressBar progressBarOption; + progressBarOption.state = QStyle::State_Enabled; + progressBarOption.direction = QApplication::layoutDirection(); + progressBarOption.rect = option.rect; + progressBarOption.fontMetrics = QApplication::fontMetrics(); + progressBarOption.minimum = 0; + progressBarOption.maximum = 100; + progressBarOption.textAlignment = Qt::AlignCenter; + progressBarOption.textVisible = true; + + QSharedPointer entry = m_model->entry(index.row()); + auto target = QString("%1/%2 XMR").arg(entry->raised_amount).arg(entry->target_amount); + auto progress = (int)entry->percentage_funded; + progressBarOption.progress = progress < 0 ? 0 : progress; + progressBarOption.text = target; + + QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); // Draw the progress bar onto the view. +} \ No newline at end of file diff --git a/src/widgets/cssprogressdelegate.h b/src/widgets/cssprogressdelegate.h new file mode 100644 index 0000000..b0a7c0f --- /dev/null +++ b/src/widgets/cssprogressdelegate.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_CSSPROGRESSDELEGATE_H +#define FEATHER_CSSPROGRESSDELEGATE_H + +#include +#include "model/CCSModel.h" + +class CCSProgressDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + explicit CCSProgressDelegate(CCSModel *model, QWidget *parent = nullptr); + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + +private: + CCSModel *m_model; +}; + + +#endif //FEATHER_CSSPROGRESSDELEGATE_H diff --git a/src/widgets/csswidget.ui b/src/widgets/csswidget.ui new file mode 100644 index 0000000..2292c34 --- /dev/null +++ b/src/widgets/csswidget.ui @@ -0,0 +1,92 @@ + + + CSSWidget + + + + 0 + 0 + 893 + 396 + + + + Form + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::CustomContextMenu + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + false + + + false + + + + + + + 0 + + + + + false + + + Powered by css.getmonero.org + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + donateClicked() + linkClicked() + + diff --git a/src/widgets/nodewidget.cpp b/src/widgets/nodewidget.cpp new file mode 100644 index 0000000..c1adaab --- /dev/null +++ b/src/widgets/nodewidget.cpp @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "model/NodeModel.h" +#include "nodewidget.h" +#include "ui_nodewidget.h" +#include "utils/utils.h" +#include "utils/nodes.h" +#include "mainwindow.h" + +NodeWidget::NodeWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::NodeWidget), + m_contextMenu(new QMenu(this)) { + ui->setupUi(this); + + connect(ui->btn_add_custom, &QPushButton::clicked, this, &NodeWidget::onCustomAddClicked); + + connect(ui->nodeBtnGroup, QOverload::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *button) { + auto name = button->objectName(); + if (name == "radioButton_websocket") { + emit nodeSourceChanged(NodeSource::websocket); + } else if (name == "radioButton_custom") { + emit nodeSourceChanged(NodeSource::custom); + } + }); + + ui->wsView->setContextMenuPolicy(Qt::CustomContextMenu); + ui->customView->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->wsView, &QTreeView::customContextMenuRequested, this, &NodeWidget::onShowWSContextMenu); + connect(ui->customView, &QTreeView::customContextMenuRequested, this, &NodeWidget::onShowCustomContextMenu); +} + +void NodeWidget::onShowWSContextMenu(const QPoint &pos) { + QModelIndex index = ui->wsView->indexAt(pos); + if (!index.isValid()) return; + + FeatherNode node = m_wsModel->node(index.row()); + this->showContextMenu(pos, node); +} + +void NodeWidget::onShowCustomContextMenu(const QPoint &pos) { + QModelIndex index = ui->customView->indexAt(pos); + if (!index.isValid()) return; + + FeatherNode node = m_customModel->node(index.row()); + this->showContextMenu(pos, node); +} + + +void NodeWidget::showContextMenu(const QPoint &pos, const FeatherNode &node) { + bool custom = node.custom; + m_activeView = custom ? ui->customView : ui->wsView; + + m_contextActionRemove = new QAction("Remove"); + m_contextActionConnect = new QAction("Connect to node"); + m_contextActionConnect->setIcon(QIcon(":/assets/images/connect.svg")); + m_contextActionOpenStatusURL = new QAction("Visit status page"); + m_contextActionOpenStatusURL->setIcon(QIcon(":/assets/images/network.png")); + m_contextActionCopy = new QAction("Copy"); + m_contextActionCopy->setIcon(QIcon(":/assets/images/copy.png")); + + if(!node.isActive) { + connect(m_contextActionConnect, &QAction::triggered, this, &NodeWidget::onContextConnect); + m_contextMenu->addAction(m_contextActionConnect); + } + + m_contextMenu->addAction(m_contextActionOpenStatusURL); + m_contextMenu->addAction(m_contextActionCopy); + + if(custom) { + connect(m_contextActionRemove, &QAction::triggered, this, &NodeWidget::onContextCustomNodeRemove); + m_contextMenu->addAction(m_contextActionRemove); + + connect(m_contextActionOpenStatusURL, &QAction::triggered, this, &NodeWidget::onContextCustomStatusURL); + connect(m_contextActionCopy, &QAction::triggered, this, &NodeWidget::onContextCustomNodeCopy); + } else { + connect(m_contextActionOpenStatusURL, &QAction::triggered, this, &NodeWidget::onContextWSStatusURL); + connect(m_contextActionCopy, &QAction::triggered, this, &NodeWidget::onContextWSNodeCopy); + } + + m_contextMenu->exec(m_activeView->viewport()->mapToGlobal(pos)); + m_contextActionRemove->deleteLater(); + m_contextActionConnect->deleteLater(); + m_contextActionOpenStatusURL->deleteLater(); + m_contextActionCopy->deleteLater(); +} + +void NodeWidget::onContextConnect() { + QModelIndex index = m_activeView->currentIndex(); + if (!index.isValid()) return; + + if(m_activeView->objectName() == "wsView"){ + FeatherNode node = m_wsModel->node(index.row()); + emit connectToNode(node); + } else { + FeatherNode node = m_customModel->node(index.row()); + emit connectToNode(node); + } +} + +void NodeWidget::onContextWSStatusURL() { + QModelIndex index = ui->wsView->currentIndex(); + if (!index.isValid()) return; + FeatherNode node = m_wsModel->node(index.row()); + Utils::externalLinkWarning(node.as_url()); +} + +void NodeWidget::onContextCustomStatusURL() { + QModelIndex index = ui->customView->currentIndex(); + if (!index.isValid()) return; + FeatherNode node = m_customModel->node(index.row()); + Utils::externalLinkWarning(node.as_url()); +} + +void NodeWidget::onContextDisconnect() { + QModelIndex index = ui->customView->currentIndex(); + if (!index.isValid()) return; + FeatherNode node = m_customModel->node(index.row()); + + Utils::copyToClipboard(node.full); +} + +void NodeWidget::onContextWSNodeCopy() { + QModelIndex index = ui->wsView->currentIndex(); + if (!index.isValid()) return; + FeatherNode node = m_wsModel->node(index.row()); + + Utils::copyToClipboard(node.full); +} + +void NodeWidget::onContextCustomNodeCopy() { + +} + +void NodeWidget::onContextCustomNodeRemove() { + QModelIndex index = ui->customView->currentIndex(); + if (!index.isValid()) return; + FeatherNode node = m_customModel->node(index.row()); + + auto nodes = m_ctx->nodes->customNodes(); + QMutableListIterator i(nodes); + while (i.hasNext()) + if (i.next() == node) + i.remove(); + + m_ctx->nodes->setCustomNodes(nodes); +} + +void NodeWidget::onCustomAddClicked(){ + auto currentNodes = m_ctx->nodes->customNodes(); + auto currentNodesText = QString(""); + + for(auto &entry: currentNodes) + currentNodesText += QString("%1\n").arg(entry.full); + + bool ok; + QString text = QInputDialog::getMultiLineText(this, "Add custom node(s).", "E.g: user:password@127.0.0.1:18081", currentNodesText, &ok); + if (!ok || text.isEmpty()) + return; + + QList nodesList; + auto newNodesList = text.split("\n"); + for(auto &newNodeText: newNodesList) { + newNodeText = newNodeText.replace("\r", "").trimmed(); + if(newNodeText.isEmpty()) + continue; + + auto node = FeatherNode(newNodeText, 0, false); + node.custom = true; + nodesList.append(node); + } + + m_ctx->nodes->setCustomNodes(nodesList); +} + +void NodeWidget::setupUI(AppContext *ctx) { + m_ctx = ctx; + + auto nodeSource = m_ctx->nodes->source(); + qCritical() << nodeSource; + + if(nodeSource == NodeSource::websocket){ + ui->radioButton_websocket->setChecked(true); + } else if(nodeSource == NodeSource::custom) { + ui->radioButton_custom->setChecked(true); + } + + this->setWSModel(m_ctx->nodes->modelWebsocket); + this->setCustomModel(m_ctx->nodes->modelCustom); +} + +void NodeWidget::setWSModel(NodeModel *model) { + m_wsModel = model; + ui->wsView->setModel(m_wsModel); + ui->wsView->header()->setSectionResizeMode(NodeModel::URL, QHeaderView::Stretch); + ui->wsView->header()->setSectionResizeMode(NodeModel::Height, QHeaderView::ResizeToContents); +} + +void NodeWidget::setCustomModel(NodeModel *model) { + m_customModel = model; + ui->customView->setModel(m_customModel); + ui->customView->header()->setSectionResizeMode(NodeModel::URL, QHeaderView::Stretch); +} + +NodeModel* NodeWidget::model() { + return m_wsModel; +} + +NodeWidget::~NodeWidget() { + delete ui; +} diff --git a/src/widgets/nodewidget.h b/src/widgets/nodewidget.h new file mode 100644 index 0000000..2f81fbd --- /dev/null +++ b/src/widgets/nodewidget.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef NODEWIDGET_H +#define NODEWIDGET_H + +#include +#include +#include +#include "appcontext.h" +#include "model/NodeModel.h" +#include "utils/nodes.h" + +namespace Ui { + class NodeWidget; +} + +class NodeModel; +class NodeWidget : public QWidget +{ + Q_OBJECT + +public: + explicit NodeWidget(QWidget *parent = nullptr); + ~NodeWidget(); + void setWSModel(NodeModel *model); + void setCustomModel(NodeModel *model); + void setupUI(AppContext *ctx); + NodeModel* model(); + +public slots: + void onCustomAddClicked(); + void onShowWSContextMenu(const QPoint &pos); + void onShowCustomContextMenu(const QPoint &pos); + +private slots: + void onContextConnect(); + void onContextDisconnect(); + void onContextCustomNodeRemove(); + void onContextWSStatusURL(); + void onContextCustomStatusURL(); + void onContextWSNodeCopy(); + void onContextCustomNodeCopy(); + +signals: + void connectToNode(FeatherNode node); + void nodeSourceChanged(NodeSource nodeSource); + +private: + AppContext *m_ctx; + Ui::NodeWidget *ui; + NodeModel* m_customModel; + NodeModel* m_wsModel; + + QTreeView *m_activeView; + + QMenu *m_contextMenu; + QAction *m_contextActionConnect; + QAction *m_contextActionDisconnect; + QAction *m_contextActionRemove; + QAction *m_contextActionOpenStatusURL; + QAction *m_contextActionCopy; + + void showContextMenu(const QPoint &pos, const FeatherNode &node); +}; + +#endif // NODEWIDGET_H diff --git a/src/widgets/nodewidget.ui b/src/widgets/nodewidget.ui new file mode 100644 index 0000000..e107d32 --- /dev/null +++ b/src/widgets/nodewidget.ui @@ -0,0 +1,109 @@ + + + NodeWidget + + + + 0 + 0 + 604 + 271 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + + + + + + + From websocket (recommended) + + + true + + + nodeBtnGroup + + + + + + + false + + + false + + + + + + + + + + + From custom list + + + nodeBtnGroup + + + + + + + false + + + + + + + Add custom node(s) + + + + + + + + + + + 0 + + + + + + + + + + + + + diff --git a/src/widgets/redditwidget.cpp b/src/widgets/redditwidget.cpp new file mode 100644 index 0000000..a8f046f --- /dev/null +++ b/src/widgets/redditwidget.cpp @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include +#include + +#include "model/RedditModel.h" +#include "redditwidget.h" +#include "ui_redditwidget.h" +#include "utils/utils.h" + +RedditWidget::RedditWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::RedditWidget), + m_model(new RedditModel(this)), + m_contextMenu(new QMenu(this)) +{ + ui->setupUi(this); + ui->tableView->setModel(m_model); + this->setupTable(); + + m_contextMenu->addAction("View thread", this, &RedditWidget::linkClicked); + connect(ui->tableView, &QHeaderView::customContextMenuRequested, this, &RedditWidget::showContextMenu); + + connect(ui->tableView, &QTableView::doubleClicked, this, &RedditWidget::linkClicked); +} + +RedditModel* RedditWidget::model() { + return m_model; +} + +void RedditWidget::linkClicked() { + QModelIndex index = ui->tableView->currentIndex(); + auto post = m_model->post(index.row()); + + if (post) { + Utils::externalLinkWarning(post->url); + } +} + +void RedditWidget::setupTable() { + ui->tableView->verticalHeader()->setVisible(false); + ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + + ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui->tableView->horizontalHeader()->setSectionResizeMode( 0, QHeaderView::Stretch); +} + +void RedditWidget::showContextMenu(const QPoint &pos) { + QModelIndex index = ui->tableView->indexAt(pos); + if (!index.isValid()) { + return; + } + + m_contextMenu->exec(ui->tableView->viewport()->mapToGlobal(pos)); +} + +RedditWidget::~RedditWidget() { + delete ui; +} diff --git a/src/widgets/redditwidget.h b/src/widgets/redditwidget.h new file mode 100644 index 0000000..cb5b09f --- /dev/null +++ b/src/widgets/redditwidget.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef REDDITWIDGET_H +#define REDDITWIDGET_H + +#include +#include +#include + +#include "model/RedditModel.h" + +namespace Ui { + class RedditWidget; +} + +class RedditWidget : public QWidget +{ + Q_OBJECT + +public: + explicit RedditWidget(QWidget *parent = nullptr); + ~RedditWidget(); + RedditModel* model(); + +public slots: + void linkClicked(); + +private: + void setupTable(); + void showContextMenu(const QPoint &pos); + + Ui::RedditWidget *ui; + RedditModel* const m_model; + QMenu *m_contextMenu; +}; + +#endif // REDDITWIDGET_H diff --git a/src/widgets/redditwidget.ui b/src/widgets/redditwidget.ui new file mode 100644 index 0000000..4521378 --- /dev/null +++ b/src/widgets/redditwidget.ui @@ -0,0 +1,91 @@ + + + RedditWidget + + + + 0 + 0 + 492 + 409 + + + + Form + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::CustomContextMenu + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + + + + + + + false + + + Powered by Reddit + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + linkClicked() + + diff --git a/src/widgets/restoreheightwidget.cpp b/src/widgets/restoreheightwidget.cpp new file mode 100644 index 0000000..e9fa4a8 --- /dev/null +++ b/src/widgets/restoreheightwidget.cpp @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include +#include +#include +#include +#include + +#include "restoreheightwidget.h" +#include "ui_restoreheightwidget.h" +#include "utils/utils.h" + +RestoreHeightWidget::RestoreHeightWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::RestoreHeightWidget) +{ + ui->setupUi(this); + ui->lineEdit_restoreHeight->setValidator(new QIntValidator(0, 2147483647, this)); + connect(ui->lineEdit_restoreHeight, &QLineEdit::textEdited, [=](const QString &val){ + // update slider on lineEdit change + if(val.isEmpty()) return; + auto height = val.toUInt(); + if(height <= 1) return; + auto timestamp = m_restoreHeightLookup->restoreHeightToDate(height); + ui->restoreSlider->blockSignals(true); + ui->restoreSlider->setValue(timestamp); + ui->restoreSlider->blockSignals(false); + }); +} + +void RestoreHeightWidget::hideSlider(){ + ui->restoreGrid->hide(); +} + +void RestoreHeightWidget::initRestoreHeights(RestoreHeightLookup *lookup) { + // init slider + m_restoreHeightLookup = lookup; + auto now = (unsigned int)std::time(nullptr); + QList blockDates = m_restoreHeightLookup->data.keys(); + ui->restoreSlider->setMinimum(blockDates[0]); + ui->restoreSlider->setMaximum(now); + connect(ui->restoreSlider, &QSlider::valueChanged, this, &RestoreHeightWidget::onValueChanged); +} + +void RestoreHeightWidget::onValueChanged(int date) { + QDateTime timestamp; + timestamp.setTime_t((unsigned int) date); + ui->label_restoreHeightDate->setText(timestamp.toString("yyyy-MM-dd")); + auto blockHeight = m_restoreHeightLookup->dateToRestoreHeight((unsigned int) date); + ui->lineEdit_restoreHeight->setText(QString::number(blockHeight)); +} + +unsigned int RestoreHeightWidget::getHeight() { + return ui->lineEdit_restoreHeight->text().toUInt(); +} + +RestoreHeightWidget::~RestoreHeightWidget() { + delete ui; +} diff --git a/src/widgets/restoreheightwidget.h b/src/widgets/restoreheightwidget.h new file mode 100644 index 0000000..7235943 --- /dev/null +++ b/src/widgets/restoreheightwidget.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef RESTOREHEIGHTWIDGET_H +#define RESTOREHEIGHTWIDGET_H + +#include +#include + +#include "appcontext.h" + +namespace Ui { + class RestoreHeightWidget; +} + +class RestoreHeightWidget : public QWidget +{ + Q_OBJECT + +public: + explicit RestoreHeightWidget(QWidget *parent = nullptr); + void initRestoreHeights(RestoreHeightLookup *lookup); + unsigned int getHeight(); + void hideSlider(); + ~RestoreHeightWidget(); + +private slots: + void onValueChanged(int date); + +private: + RestoreHeightLookup *m_restoreHeightLookup = nullptr; + Ui::RestoreHeightWidget *ui; +}; + +#endif // RESTOREHEIGHTWIDGET_H diff --git a/src/widgets/restoreheightwidget.ui b/src/widgets/restoreheightwidget.ui new file mode 100644 index 0000000..00cb7d3 --- /dev/null +++ b/src/widgets/restoreheightwidget.ui @@ -0,0 +1,112 @@ + + + RestoreHeightWidget + + + + 0 + 0 + 360 + 89 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 2014-04-18 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Restore height + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + diff --git a/src/widgets/tickerwidget.cpp b/src/widgets/tickerwidget.cpp new file mode 100644 index 0000000..c601d1c --- /dev/null +++ b/src/widgets/tickerwidget.cpp @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "tickerwidget.h" +#include "ui_tickerwidget.h" + +#include "appcontext.h" +#include "utils/config.h" +#include "mainwindow.h" + +TickerWidget::TickerWidget(QWidget *parent, QString symbol, QString title, bool convertBalance) : + QWidget(parent), + ui(new Ui::TickerWidget), + m_symbol(std::move(symbol)), + m_convertBalance(convertBalance) +{ + ui->setupUi(this); + + // default values before API data + if (title == "") title = m_symbol; + this->ui->tickerBox->setTitle(title); + QString defaultPct = "0.0"; + QString defaultFiat = "..."; + + this->setFontSizes(); + this->setPctText(defaultPct, true); + this->setFiatText(defaultFiat, 0.0, true); + + connect(AppContext::prices, &Prices::fiatPricesUpdated, this, &TickerWidget::init); + connect(AppContext::prices, &Prices::cryptoPricesUpdated, this, &TickerWidget::init); + if (convertBalance) + connect(MainWindow::getContext(), &AppContext::balanceUpdated, this, &TickerWidget::init); +} + +void TickerWidget::init() { + if(!AppContext::prices->markets.count() || !AppContext::prices->rates.count()) + return; + + QString fiatCurrency = config()->get(Config::preferredFiatCurrency).toString(); + + if(!AppContext::prices->rates.contains(fiatCurrency)){ + config()->set(Config::preferredFiatCurrency, "USD"); + return; + } + + double amount = m_convertBalance ? AppContext::balance : 1.0; + double conversion = AppContext::prices->convert(m_symbol, fiatCurrency, amount); + if (conversion < 0) return; + setPercentHidden(conversion == 0); + + auto markets = AppContext::prices->markets; + if(!markets.contains(m_symbol)) return; + + auto pct24h = markets[m_symbol].price_usd_change_pct_24h; + auto pct24hText = QString::number(pct24h, 'f', 2); + + this->setPctText(pct24hText, pct24h >= 0.0); + this->setFiatText(fiatCurrency, conversion, true); +} + +void TickerWidget::setFiatText(QString &fiatCurrency, double amount, bool round) { + QString number; + if(round) + number = QString::number(amount, 'f', 2); + else + number = QString::number(amount); + + auto conversionText = QString("%1 %2")\ + .arg(number) + .arg(fiatCurrency); + ui->tickerFiat->setText(conversionText); +} + +void TickerWidget::setPctText(QString &text, bool positive) { + QString pctText = "

"; + if(positive) { + pctText = pctText.replace("red", "green"); + pctText += QString("+%1%").arg(text); + } else + pctText += QString("%1%").arg(text); + + pctText += "

"; + ui->tickerPct->setText(pctText); +} + +void TickerWidget::setFontSizes() { + ui->tickerPct->setFont(Utils::relativeFont(-2)); + ui->tickerFiat->setFont(Utils::relativeFont(0)); +} + +void TickerWidget::removePctContainer() { + ui->tickerPct->deleteLater(); +} + +void TickerWidget::setPercentHidden(bool hidden) { + ui->tickerPct->setVisible(!hidden); +} + +TickerWidget::~TickerWidget() { + delete ui; +} diff --git a/src/widgets/tickerwidget.h b/src/widgets/tickerwidget.h new file mode 100644 index 0000000..b0b8055 --- /dev/null +++ b/src/widgets/tickerwidget.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef TICKERWIDGET_H +#define TICKERWIDGET_H + +#include + +#include "appcontext.h" + +namespace Ui { + class TickerWidget; +} + +class TickerWidget : public QWidget +{ + Q_OBJECT + +public: + explicit TickerWidget(QWidget *parent, QString symbol, QString title = "", bool convertBalance = false); + void removePctContainer(); + void setFiatText(QString &fiatCurrency, double amount, bool round); + void setPctText(QString &text, bool positive); + void setFontSizes(); + ~TickerWidget() override; + + +public slots: + void init(); + +private: + void setPercentHidden(bool hidden); + + Ui::TickerWidget *ui; + QString m_symbol; + bool m_convertBalance; +}; + +#endif // TICKERWIDGET_H diff --git a/src/widgets/tickerwidget.ui b/src/widgets/tickerwidget.ui new file mode 100644 index 0000000..c37e49b --- /dev/null +++ b/src/widgets/tickerwidget.ui @@ -0,0 +1,84 @@ + + + TickerWidget + + + + 0 + 0 + 281 + 107 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + + + - + + + + 6 + + + 6 + + + 6 + + + 4 + + + + + 6 + + + + + + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + <html><head/><body><p><br/></p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + + + + diff --git a/src/wizard/createwallet.cpp b/src/wizard/createwallet.cpp new file mode 100644 index 0000000..b9e42fb --- /dev/null +++ b/src/wizard/createwallet.cpp @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "utils/utils.h" +#include "wizard/createwallet.h" +#include "wizard/walletwizard.h" +#include "ui_createwallet.h" +#include "appcontext.h" + +#include +#include +#include +#include + +#include "libwalletqt/WalletManager.h" + +CreateWalletPage::CreateWalletPage(AppContext *ctx, QWidget *parent) : + QWizardPage(parent), + ui(new Ui::CreateWalletPage), + m_ctx(ctx) { + ui->setupUi(this); + this->setTitle("Create wallet"); + this->setButtonText(QWizard::FinishButton, "Open wallet"); + + // hide ui element, we only need it for registerField + this->registerField("walletName*", ui->walletName); + this->registerField("walletDirectory", ui->directory); + this->registerField("walletPasswd", ui->password); + this->registerField("walletPath", ui->walletPath); + ui->walletPath->hide(); + + ui->directory->setText(m_ctx->defaultWalletDir); + m_walletDir = m_ctx->defaultWalletDir; + connect(ui->btnChange, &QPushButton::clicked, [=] { + QString walletDir = QFileDialog::getExistingDirectory(this, "Select wallet directory ", m_ctx->defaultWalletDir, QFileDialog::ShowDirsOnly); + if(walletDir.isEmpty()) return; + ui->directory->setText(walletDir); + }); + + connect(ui->directory, &QLineEdit::textChanged, [=](const QString &data) { + m_walletDir = data; + this->validateWidgets(); + }); + + connect(ui->walletName, &QLineEdit::textChanged, [=](QString data) { + this->validateWidgets(); + }); +} + +bool CreateWalletPage::validateWidgets(){ + ui->walletName->setStyleSheet(""); + ui->directory->setStyleSheet(""); + auto walletPass = ui->password->text(); + auto errStyle = "QLineEdit{border: 1px solid red;}"; + if(m_walletDir.isEmpty()){ + ui->walletName->setStyleSheet(errStyle); + ui->directory->setStyleSheet(errStyle); + return false; + } + + if(!Utils::dirExists(m_walletDir)) { + ui->walletName->setStyleSheet(errStyle); + ui->directory->setStyleSheet(errStyle); + return false; + } + + ui->directory->setStyleSheet(""); + auto walletName = ui->walletName->text().replace(".keys", ""); + if(walletName.isEmpty()) { + ui->walletName->setStyleSheet(errStyle); + return false; + } + + auto walletPath = QDir(m_walletDir).filePath(walletName + ".keys"); + if(Utils::fileExists(walletPath)) { + ui->walletName->setStyleSheet(errStyle); + return false; + } + + return true; +} + +int CreateWalletPage::nextId() const { + auto restoredSeed = this->field("mnemonicRestoredSeed").toString(); + return restoredSeed.isEmpty() ? WalletWizard::Page_CreateWalletSeed : -1; +} + +bool CreateWalletPage::validatePage() { + if(!this->validateWidgets()) return false; + auto walletName = ui->walletName->text().replace(".keys", ""); + auto walletPath = QDir(m_walletDir).filePath(walletName + ".keys"); + this->setField("walletPath", walletPath); + ui->walletName->setStyleSheet(""); + + auto restoredSeed = this->field("mnemonicRestoredSeed").toString(); + if(!restoredSeed.isEmpty()) emit createWallet(); + return true; +} diff --git a/src/wizard/createwallet.h b/src/wizard/createwallet.h new file mode 100644 index 0000000..730f0c9 --- /dev/null +++ b/src/wizard/createwallet.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_CREATEWALLET_H +#define FEATHER_CREATEWALLET_H + +#include +#include +#include + +#include "appcontext.h" + +namespace Ui { + class CreateWalletPage; +} + +class CreateWalletPage : public QWizardPage +{ + Q_OBJECT + +public: + explicit CreateWalletPage(AppContext *ctx, QWidget *parent = nullptr); + bool validatePage() override; + int nextId() const override; + +signals: + void createWallet(); + +private: + AppContext *m_ctx; + QLabel *topLabel; + Ui::CreateWalletPage *ui; + QString m_walletDir; + bool validateWidgets(); +}; + +#endif //FEATHER_CREATEWALLET_H diff --git a/src/wizard/createwallet.ui b/src/wizard/createwallet.ui new file mode 100644 index 0000000..783d517 --- /dev/null +++ b/src/wizard/createwallet.ui @@ -0,0 +1,103 @@ + + + CreateWalletPage + + + + 0 + 0 + 400 + 335 + + + + Create Wallet + + + + + + + + + Password (Optional) + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Name + + + + + + + + + + Directory + + + + + + + + 180 + 16777215 + + + + Change directory + + + + + + + + + + QLineEdit::Password + + + + + + + + label_3 + label_9 + password + btnChange + directory + label + verticalSpacer + walletName + walletPath + + + walletName + walletPath + password + directory + btnChange + + + + diff --git a/src/wizard/createwalletseed.cpp b/src/wizard/createwalletseed.cpp new file mode 100644 index 0000000..e1c02d7 --- /dev/null +++ b/src/wizard/createwalletseed.cpp @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "wizard/createwalletseed.h" +#include "wizard/walletwizard.h" +#include "ui_createwalletseed.h" +#include "appcontext.h" + +#include +#include +#include + +CreateWalletSeedPage::CreateWalletSeedPage(AppContext *ctx, QWidget *parent) : + QWizardPage(parent), + m_ctx(ctx), + ui(new Ui::CreateWalletSeedPage) { + ui->setupUi(this); + this->setFinalPage(true); + this->setTitle("Wallet seed"); + + // hide ui element, we only need it for registerField + this->registerField("mnemonicSeed", ui->hiddenMnemonicSeed); + ui->hiddenMnemonicSeed->hide(); + + auto fontApp = QApplication::font(); + auto fontFamily = fontApp.family(); + auto fontSize = fontApp.pointSize() + 2; + m_seedFontFamily = fontFamily; + m_seedFontSize = fontSize; + + connect(ui->btnRoulette, &QPushButton::clicked, [=]{ + this->seedRoulette(0); + }); + + this->setButtonText(QWizard::FinishButton, "Create/Open wallet"); + + // generate new seed + this->seedRoulette(m_rouletteSpin - 1); +} + +void CreateWalletSeedPage::seedRoulette(int count) { + count += 1; + if(count > m_rouletteSpin) return; + auto seed = FeatherSeed::generate(m_ctx->restoreHeights[m_ctx->networkType], m_ctx->coinName.toStdString()); + m_mnemonic = seed.mnemonicSeed; + m_restoreHeight = seed.restoreHeight; + + this->displaySeed(m_mnemonic); + QTimer::singleShot(10, [=] { + this->seedRoulette(count); + }); +} + +void CreateWalletSeedPage::displaySeed(const QString &seed){ + auto html = R"(

%3

)"; + ui->seed->setText(QString(html).arg(m_seedFontFamily).arg(m_seedFontSize).arg(seed)); +} + +int CreateWalletSeedPage::nextId() const { + return -1; +} + +bool CreateWalletSeedPage::validatePage() { + if(m_mnemonic.isEmpty()) return false; + if(!m_restoreHeight) return false; + this->setField("mnemonicSeed", m_mnemonic); + this->setField("restoreHeight", m_restoreHeight); + emit createWallet(); + return true; +} \ No newline at end of file diff --git a/src/wizard/createwalletseed.h b/src/wizard/createwalletseed.h new file mode 100644 index 0000000..7ac90d3 --- /dev/null +++ b/src/wizard/createwalletseed.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_CREATEWALLETSEED_H +#define FEATHER_CREATEWALLETSEED_H + +#include +#include +#include + +#include "utils/utils.h" +#include "appcontext.h" + +namespace Ui { + class CreateWalletSeedPage; +} + +class CreateWalletSeedPage : public QWizardPage +{ + Q_OBJECT + +public: + explicit CreateWalletSeedPage(AppContext *ctx, QWidget *parent = nullptr); + bool validatePage() override; + int nextId() const override; +// bool isFinalPage() const; + +public slots: + void displaySeed(const QString &seed); + +private: + void seedRoulette(int count); + +signals: + void createWallet(); + +private: + AppContext *m_ctx; + QLabel *topLabel; + Ui::CreateWalletSeedPage *ui; + + QString m_mnemonic; + unsigned int m_restoreHeight; + + int m_seedFontSize; + QString m_seedFontFamily; + bool m_roulette = false; + int m_rouletteSpin = 15; +}; + +#endif //FEATHER_CREATEWALLETSEED_H diff --git a/src/wizard/createwalletseed.ui b/src/wizard/createwalletseed.ui new file mode 100644 index 0000000..571cc0b --- /dev/null +++ b/src/wizard/createwalletseed.ui @@ -0,0 +1,142 @@ + + + CreateWalletSeedPage + + + + 0 + 0 + 439 + 425 + + + + WizardPage + + + + + + + 75 + true + + + + WARNING: + + + + + + + + 0 + 0 + + + + Please save these 14 words on paper (order is important). This seed will allow you to recover your wallet in case of computer failure. + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Generate + + + + + + + + + <html><head/><body><style>p{margin:0}</style><p>• Never disclose your seed.</p><p>• Never type it on a website.</p><p>• Store it safely (offline).</p><p>• <b>Do not lose your seed!</b></p></body></html> + + + true + + + + + + + Your wallet generation seed is: + + + + + + + + 0 + 0 + + + + + 16777215 + 80 + + + + QFrame::Box + + + QFrame::Plain + + + 1 + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"><br /></p></body></html> + + + + + + + + + + + diff --git a/src/wizard/menu.cpp b/src/wizard/menu.cpp new file mode 100644 index 0000000..c927ce3 --- /dev/null +++ b/src/wizard/menu.cpp @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "wizard/menu.h" +#include "wizard/walletwizard.h" +#include "ui_menu.h" + +#include +#include +#include + +#include "libwalletqt/WalletManager.h" + +MenuPage::MenuPage(AppContext *ctx, QWidget *parent) : + QWizardPage(parent), + ui(new Ui::MenuPage), + m_ctx(ctx) { + ui->setupUi(this); + this->setTitle("Welcome to feather"); + this->setButtonText(QWizard::FinishButton, "Open recent wallet"); + ui->radioCreate->setChecked(true); +} + +int MenuPage::nextId() const { + if (ui->radioOpen->isChecked()) + return WalletWizard::Page_OpenWallet; + if (ui->radioCreate->isChecked()) + return WalletWizard::Page_CreateWallet; + if(ui->radioSeed->isChecked()) + return WalletWizard::Page_Restore; + return 0; +} + +bool MenuPage::validatePage() { + // Check if file exists + // Check if wallet has password + // Check if wallet can be decrypted with entered password + + // TODO: Check if password is correct, otherwise show error message + return true; +} \ No newline at end of file diff --git a/src/wizard/menu.h b/src/wizard/menu.h new file mode 100644 index 0000000..3b1c7bb --- /dev/null +++ b/src/wizard/menu.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_WIZARDMENU_H +#define FEATHER_WIZARDMENU_H + +#include +#include +#include + +#include "appcontext.h" + +namespace Ui { + class MenuPage; +} + +class MenuPage : public QWizardPage +{ + Q_OBJECT + +public: + explicit MenuPage(AppContext *ctx, QWidget *parent = nullptr); + bool validatePage() override; + int nextId() const override; + +private: + AppContext *m_ctx; + QLabel *topLabel; + Ui::MenuPage *ui; +}; + +#endif //FEATHER_WIZARDMENU_H diff --git a/src/wizard/menu.ui b/src/wizard/menu.ui new file mode 100644 index 0000000..2c6180e --- /dev/null +++ b/src/wizard/menu.ui @@ -0,0 +1,78 @@ + + + MenuPage + + + + 0 + 0 + 424 + 245 + + + + WizardPage + + + + + + + 400 + 0 + + + + Select option: + + + + + + + Create new wallet + + + + + + + Open wallet file + + + + + + + Restore wallet from seed + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + false + + + by dsc & thotbot + + + + + + + + diff --git a/src/wizard/network.cpp b/src/wizard/network.cpp new file mode 100644 index 0000000..3ceaec0 --- /dev/null +++ b/src/wizard/network.cpp @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "wizard/network.h" +#include "wizard/walletwizard.h" +#include "ui_network.h" + +#include +#include +#include + +#include "libwalletqt/WalletManager.h" + +NetworkPage::NetworkPage(AppContext *ctx, QWidget *parent) : + QWizardPage(parent), + ui(new Ui::NetworkPage), + m_ctx(ctx) { + ui->setupUi(this); + this->setTitle("Welcome to Feather!"); + this->setButtonText(QWizard::FinishButton, "walletKeysFilesModel"); + + ui->customFrame->hide(); + + QPixmap p(":assets/images/feather.png"); + ui->featherImage->setText(""); + ui->featherImage->setPixmap(p.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + ui->label_eg->setText("Examples:\n- http://127.0.0.1:18089\n- my.node.com\n- my.node.com:18089\n- user:pass@my.node.com:18089"); + + auto nodeSourceUInt = config()->get(Config::nodeSource).toUInt(); + auto nodeSource = static_cast(nodeSourceUInt); + if(nodeSource == NodeSource::websocket){ + ui->radioRemote->setChecked(true); + ui->customFrame->hide(); + ui->remoteFrame->show(); + } else if(nodeSource == NodeSource::custom) { + ui->radioCustom->setChecked(true); + ui->remoteFrame->hide(); + ui->customFrame->show(); + } + + connect(ui->networkBtnGroup, QOverload::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *button) { + auto name = button->objectName(); + if(name == "radioRemote") { + ui->customFrame->hide(); + ui->remoteFrame->show(); + } else if(name == "radioCustom") { + ui->remoteFrame->hide(); + ui->customFrame->show(); + } + }); +} + +int NetworkPage::nextId() const { + return 0; +} + +bool NetworkPage::validatePage() { + auto cfg = config()->get(Config::nodeSource); + if(ui->radioRemote->isChecked()) { + if(cfg != NodeSource::websocket) + m_ctx->nodeSourceChanged(NodeSource::websocket); + } else if (ui->radioCustom->isChecked()) { + if(cfg != NodeSource::custom) + m_ctx->nodeSourceChanged(NodeSource::custom); + auto nodeText = ui->lineEdit_customNode->text().trimmed(); + if(!nodeText.isEmpty()) { + auto customNodes = m_ctx->nodes->customNodes(); + auto node = FeatherNode(nodeText, 0, false); + customNodes.append(node); + m_ctx->setCustomNodes(customNodes); + } + + } + return true; +} \ No newline at end of file diff --git a/src/wizard/network.h b/src/wizard/network.h new file mode 100644 index 0000000..9a28652 --- /dev/null +++ b/src/wizard/network.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_WIZARDNETWORK_H +#define FEATHER_WIZARDNETWORK_H + +#include +#include +#include + +#include "appcontext.h" +#include "utils/nodes.h" + +namespace Ui { + class NetworkPage; +} + +class NetworkPage : public QWizardPage +{ + Q_OBJECT + +public: + explicit NetworkPage(AppContext *ctx, QWidget *parent = nullptr); + bool validatePage() override; + int nextId() const override; + +private: + AppContext *m_ctx; + QLabel *topLabel; + Ui::NetworkPage *ui; +}; + +#endif //FEATHER_WIZARDNETWORK_H diff --git a/src/wizard/network.ui b/src/wizard/network.ui new file mode 100644 index 0000000..62a5460 --- /dev/null +++ b/src/wizard/network.ui @@ -0,0 +1,237 @@ + + + NetworkPage + + + + 0 + 0 + 521 + 639 + + + + WizardPage + + + + + + How would you like to connect to the Monero network? + + + true + + + + + + + + + + + + 128 + 128 + + + + + 128 + 128 + + + + logo + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + + + + + + + + + + + Remote node (Automatic) + + + true + + + networkBtnGroup + + + + + + + Manually connect + + + networkBtnGroup + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 127.0.0.1:18089 + + + + + + + Custom node + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + e.g: + + + true + + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Automatically connect to a remote node, hosted by the feather team and various trusted Monero community members. These nodes are provided as "best effort". + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + diff --git a/src/wizard/openwallet.cpp b/src/wizard/openwallet.cpp new file mode 100644 index 0000000..4d5436a --- /dev/null +++ b/src/wizard/openwallet.cpp @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "wizard/openwallet.h" +#include "ui_openwallet.h" +#include "appcontext.h" +#include "utils/config.h" + +#include +#include + +// @TODO: rescan wallet dir on wizard open + +OpenWalletPage::OpenWalletPage(AppContext *ctx, QWidget *parent) : + QWizardPage(parent), + ui(new Ui::OpenWalletPage), + m_ctx(ctx) { + ui->setupUi(this); + + connect(ui->btnBrowse, &QPushButton::clicked, [=]{ + // manually browsing for wallet + auto walletPath = config()->get(Config::walletPath).toString(); + if(walletPath.isEmpty()) + walletPath = m_ctx->defaultWalletDir; + QString path = QFileDialog::getOpenFileName(this, "Select your wallet file", walletPath, "Wallet file (*.keys)"); + if(path.isEmpty()) return; + + QFileInfo infoPath(path); + if(!infoPath.isReadable()) { + Utils::showMessageBox("Cannot read wallet file", "Permission error.", true); + return; + } + + setField("walletPath", path); + + if(ui->openOnStartup->isChecked()) + config()->set(Config::autoOpenWalletPath, QString("%1%2").arg(m_ctx->networkType).arg(path)); + + emit openWallet(path); + }); + + this->setTitle("Open wallet file"); + this->setButtonText(QWizard::FinishButton, "Open wallet"); + + ui->walletTable->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->walletTable->setContextMenuPolicy(Qt::CustomContextMenu); + + this->walletKeysFilesModel = new WalletKeysFilesModel(m_ctx); + this->walletKeysFilesModel->refresh(); + + m_keysProxy = new WalletKeysFilesProxyModel(); + m_keysProxy->setSourceModel(this->walletKeysFilesModel); + m_keysProxy->setSortRole(Qt::UserRole); + + ui->walletTable->setModel(m_keysProxy); + ui->walletTable->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui->walletTable->header()->setSectionResizeMode(WalletKeysFilesModel::Path, QHeaderView::Stretch); + ui->walletTable->setSortingEnabled(true); + ui->walletTable->sortByColumn(WalletKeysFilesModel::Modified, Qt::AscendingOrder); // @TODO: this does not work + ui->walletTable->show(); +} + +int OpenWalletPage::nextId() const { + return -1; +} + +bool OpenWalletPage::validatePage() { + QModelIndex index = ui->walletTable->currentIndex(); + QString walletPath = index.model()->data(index.siblingAtColumn(WalletKeysFilesModel::ModelColumns::Path), Qt::UserRole).toString(); + + auto autoWallet = ui->openOnStartup->isChecked() ? QString("%1%2").arg(m_ctx->networkType).arg(walletPath) : ""; + config()->set(Config::autoOpenWalletPath, autoWallet); + + emit openWallet(walletPath); + return true; +} diff --git a/src/wizard/openwallet.h b/src/wizard/openwallet.h new file mode 100644 index 0000000..b9f1929 --- /dev/null +++ b/src/wizard/openwallet.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_OPENWALLET_H +#define FEATHER_OPENWALLET_H + +#include +#include +#include + +#include "appcontext.h" +#include "utils/keysfiles.h" + +namespace Ui { + class OpenWalletPage; +} + +class OpenWalletPage : public QWizardPage +{ + Q_OBJECT + +public: + explicit OpenWalletPage(AppContext *ctx, QWidget *parent = nullptr); + bool validatePage() override; + int nextId() const override; + +signals: + void openWallet(QString path); + +private: + AppContext *m_ctx; + WalletKeysFilesModel *walletKeysFilesModel; + WalletKeysFilesProxyModel *m_keysProxy; + QSortFilterProxyModel *ll; + QLabel *topLabel; + Ui::OpenWalletPage *ui; + QStandardItemModel *m_model; +}; + +#endif //FEATHER_OPENWALLET_H diff --git a/src/wizard/openwallet.ui b/src/wizard/openwallet.ui new file mode 100644 index 0000000..1010470 --- /dev/null +++ b/src/wizard/openwallet.ui @@ -0,0 +1,62 @@ + + + OpenWalletPage + + + + 0 + 0 + 729 + 414 + + + + WizardPage + + + + + + false + + + false + + + + + + + + + Open on startup + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Browse + + + + + + + + + + diff --git a/src/wizard/restorewallet.cpp b/src/wizard/restorewallet.cpp new file mode 100644 index 0000000..0f37a05 --- /dev/null +++ b/src/wizard/restorewallet.cpp @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "wizard/restorewallet.h" +#include "wizard/walletwizard.h" +#include "ui_restorewallet.h" + +#include +#include +#include +#include +#include + +#include // tevador 14 word + +#include "libwalletqt/WalletManager.h" + +RestorePage::RestorePage(AppContext *ctx, QWidget *parent) : + QWizardPage(parent), + ui(new Ui::RestorePage), + m_ctx(ctx) { + ui->setupUi(this); + this->setTitle("Restore wallet"); + this->setButtonText(QWizard::FinishButton, "walletKeysFilesModel"); + ui->restoreFrame->hide(); + ui->label_errorString->hide(); + + QFont f("feather"); + f.setStyleHint(QFont::Monospace); + + auto data = Utils::fileOpen(":/assets/mnemonic_25_english.txt"); + for(const auto &seed_word: data.split('\n')) + m_words25 << seed_word; + for(unsigned int i = 0; i != 2048; i++) + m_words14 << QString::fromStdString(wordlist::english.get_word(i)); + + // + m_completer14Model = new QStringListModel(m_words14, m_completer14); + m_completer14 = new QCompleter(this); + m_completer14->setModel(m_completer14Model); + m_completer14->setModelSorting(QCompleter::CaseInsensitivelySortedModel); + m_completer14->setCaseSensitivity(Qt::CaseInsensitive); + m_completer14->setWrapAround(false); + // + m_completer25Model = new QStringListModel(m_words25, m_completer25); + m_completer25 = new QCompleter(this); + m_completer25->setModel(m_completer25Model); + m_completer25->setModelSorting(QCompleter::CaseInsensitivelySortedModel); + m_completer25->setCaseSensitivity(Qt::CaseInsensitive); + m_completer25->setWrapAround(false); + // + ui->seedEdit->setCompleter(m_completer14); + ui->seedEdit->setAcceptRichText(false); + ui->seedEdit->setMaximumHeight(80); + ui->seedEdit->setFrameShape(QFrame::Box); + ui->seedEdit->setFrameShadow(QFrame::Plain); + ui->seedEdit->setFont(f); + ui->seedEdit->setPlaceholderText("Insert your mnemonic 14 word seed..."); + // + + auto *dummyRestoredSeed = new QLineEdit(this); + dummyRestoredSeed->setVisible(false); + auto *restoreHeightEdit = new QLineEdit(this); + restoreHeightEdit->setVisible(false); + + this->registerField("mnemonicRestoredSeed", dummyRestoredSeed); + this->registerField("restoreHeight", restoreHeightEdit); + +#ifndef QT_NO_CURSOR + QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + QGuiApplication::restoreOverrideCursor(); +#endif + + connect(ui->seedBtnGroup, QOverload::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *button){ + auto name = button->objectName(); + if(name == "radio25") { + m_mode = 25; + ui->label_errorString->hide(); + ui->seedEdit->setStyleSheet(""); + ui->seedEdit->setCompleter(m_completer25); + ui->restoreFrame->show(); + ui->seedEdit->setPlaceholderText("Insert your mnemonic 25 word seed..."); + } else if (name == "radio14") { + m_mode = 14; + ui->label_errorString->hide(); + ui->seedEdit->setStyleSheet(""); + ui->seedEdit->setCompleter(m_completer14); + ui->restoreFrame->hide(); + ui->seedEdit->setPlaceholderText("Insert your mnemonic 14 word seed..."); + } + + ui->seedEdit->setText(""); + }); + + if(m_ctx->networkType == NetworkType::Type::TESTNET) { + ui->restoreHeightWidget->hideSlider(); + } else { + // load restoreHeight lookup db + ui->restoreHeightWidget->initRestoreHeights(m_ctx->restoreHeights[m_ctx->networkType]); + } +} + +int RestorePage::nextId() const { + return WalletWizard::Page_CreateWallet; +} + +void RestorePage::cleanupPage() const {} + +bool RestorePage::validatePage() { + ui->label_errorString->hide(); + auto errStyle = "QTextEdit{border: 1px solid red;}"; + unsigned int restoreHeight = ui->restoreHeightWidget->getHeight(); + auto seed = ui->seedEdit->toPlainText().replace("\n", "").replace("\r", "").trimmed(); + auto seedSplit = seed.split(" "); + + if(m_mode == 14) { + if(seedSplit.length() != 14) { + ui->label_errorString->show(); + ui->label_errorString->setText("The mnemonic seed should be 14 words."); + ui->seedEdit->setStyleSheet(errStyle); + return false; + } + + for(const auto &word: seedSplit) { + if(!m_words14.contains(word)) { + ui->label_errorString->show(); + ui->label_errorString->setText(QString("Mnemonic seed contains an unknown word: %1").arg(word)); + ui->seedEdit->setStyleSheet(errStyle); + return false; + } + } + + auto _seed = FeatherSeed::fromSeed(m_ctx->restoreHeights[m_ctx->networkType], "monero", seed.toStdString()); + restoreHeight = _seed.restoreHeight; + + this->setField("restoreHeight", restoreHeight); + this->setField("mnemonicRestoredSeed", seed); + return true; + } else if(m_mode == 25) { + if(seedSplit.length() != 25) { + ui->label_errorString->show(); + ui->label_errorString->setText("The mnemonic seed should be 25 words."); + ui->seedEdit->setStyleSheet(errStyle); + return false; + } + + for(const auto &word: seedSplit) { + if(!m_words25.contains(word)) { + ui->label_errorString->show(); + ui->label_errorString->setText(QString("Mnemonic seed contains an unknown word: %1").arg(word)); + ui->seedEdit->setStyleSheet(errStyle); + return false; + } + } + + auto _seed = FeatherSeed::fromSeed(m_ctx->restoreHeights[m_ctx->networkType], "monero", seed.toStdString()); + _seed.setRestoreHeight(restoreHeight); + this->setField("restoreHeight", restoreHeight); + this->setField("mnemonicSeed", seed); + this->setField("mnemonicRestoredSeed", seed); + return true; + } + + ui->seedEdit->setStyleSheet(errStyle); + return false; +} diff --git a/src/wizard/restorewallet.h b/src/wizard/restorewallet.h new file mode 100644 index 0000000..3a3049d --- /dev/null +++ b/src/wizard/restorewallet.h @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef FEATHER_WIZARDRESTORE_H +#define FEATHER_WIZARDRESTORE_H + +#include +#include +#include +#include +#include +#include + +#include "utils/textedit.h" +#include "appcontext.h" + +namespace Ui { + class RestorePage; +} + +class RestorePage : public QWizardPage +{ + Q_OBJECT + +public: + explicit RestorePage(AppContext *ctx, QWidget *parent = nullptr); + bool validatePage() override; + int nextId() const override; + void cleanupPage() const; + +private: + AppContext *m_ctx; + QLabel *topLabel; + Ui::RestorePage *ui; + + unsigned int m_mode = 14; + QStringList m_words14; + QStringList m_words25; + QStringListModel *m_completer14Model = nullptr; + QStringListModel *m_completer25Model = nullptr; + QCompleter *m_completer14 = nullptr; + QCompleter *m_completer25 = nullptr; +}; + +#endif diff --git a/src/wizard/restorewallet.ui b/src/wizard/restorewallet.ui new file mode 100644 index 0000000..dbd9122 --- /dev/null +++ b/src/wizard/restorewallet.ui @@ -0,0 +1,172 @@ + + + RestorePage + + + + 0 + 0 + 502 + 506 + + + + RestorePage + + + + + + 14 word mnemonic seed + + + true + + + seedBtnGroup + + + + + + + 25 word mnemonic seed + + + seedBtnGroup + + + + + + + + 0 + 0 + + + + + 16777215 + 120 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + false + + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + You may specify the "restore height". This is the moment you first created your wallet, expressed through a blockheight (number). This speeds up wallet refreshes. If you don't know, leave it empty. + + + true + + + + + + + + + + errorString + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + RestoreHeightWidget + QWidget +
widgets/restoreheightwidget.h
+ 1 +
+ + TextEdit + QTextEdit +
utils/textedit.h
+
+
+ + + + + +
diff --git a/src/wizard/walletwizard.cpp b/src/wizard/walletwizard.cpp new file mode 100644 index 0000000..112aad7 --- /dev/null +++ b/src/wizard/walletwizard.cpp @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "utils/utils.h" +#include "wizard/walletwizard.h" +#include "wizard/menu.h" +#include "wizard/openwallet.h" +#include "wizard/createwallet.h" +#include "wizard/network.h" +#include "wizard/createwalletseed.h" +#include "wizard/restorewallet.h" + +#include +#include +#include +#include +#include + +WalletWizard::WalletWizard(AppContext *ctx, WalletWizard::Page startPage, QWidget *parent) : QWizard(parent), + m_ctx(ctx) { + this->setWindowTitle("Welcome to feather"); + this->setWindowIcon(QIcon(":/assets/images/appicons/64x64.png")); + auto openWalletPage = new OpenWalletPage(m_ctx); + auto createWallet = new CreateWalletPage(m_ctx); + auto createWalletSeed = new CreateWalletSeedPage(m_ctx); + setPage(Page_Menu, new MenuPage(m_ctx)); + setPage(Page_CreateWallet, createWallet); + setPage(Page_OpenWallet, openWalletPage); + setPage(Page_CreateWalletSeed, createWalletSeed); + setPage(Page_Network, new NetworkPage(m_ctx)); + setPage(Page_Restore, new RestorePage(m_ctx)); + + if(config()->get(Config::firstRun).toUInt()) + setStartId(Page_Network); + else + setStartId(Page_Menu); + + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/assets/images/photos/1.png")); + setWizardStyle(WizardStyle::ModernStyle); + setOption(QWizard::NoBackButtonOnStartPage); + + connect(this, &QWizard::rejected, [=]{ + return QApplication::exit(1); + }); + + connect(createWalletSeed, &CreateWalletSeedPage::createWallet, this, &WalletWizard::createWallet); + connect(createWallet, &CreateWalletPage::createWallet, this, &WalletWizard::createWallet); + + connect(openWalletPage, &OpenWalletPage::openWallet, [=](const QString &path){ + const auto walletPasswd = this->field("walletPasswd").toString(); + emit openWallet(path, walletPasswd); + }); +} + +void WalletWizard::createWallet() { + auto mnemonicSeed = this->field("mnemonicSeed").toString(); + const auto walletPath = this->field("walletPath").toString(); + const auto walletPasswd = this->field("walletPasswd").toString(); + auto restoreHeight = this->field("restoreHeight").toUInt(); + + auto seed = FeatherSeed::fromSeed(m_ctx->restoreHeights[m_ctx->networkType], m_ctx->coinName.toStdString(), mnemonicSeed.toStdString()); + if(restoreHeight > 0) + seed.setRestoreHeight(restoreHeight); + m_ctx->createWallet(seed, walletPath, walletPasswd); +} \ No newline at end of file diff --git a/src/wizard/walletwizard.h b/src/wizard/walletwizard.h new file mode 100644 index 0000000..1d54ffd --- /dev/null +++ b/src/wizard/walletwizard.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef WALLETWIZARD_H +#define WALLETWIZARD_H + +#include +#include +#include + +#include "appcontext.h" +#include "utils/seeds.h" +#include "utils/config.h" + +class WalletWizard : public QWizard +{ + Q_OBJECT + +public: + enum Page { Page_Menu, Page_CreateWallet, Page_CreateWalletSeed, Page_OpenWallet, Page_Network, Page_Restore }; + + explicit WalletWizard(AppContext *ctx, WalletWizard::Page startPage = WalletWizard::Page::Page_Menu, QWidget *parent = nullptr); +signals: + void openWallet(QString path, QString password); + +private: + AppContext *m_ctx; + void createWallet(); +}; + +#endif // WALLETWIZARD_H diff --git a/src/xmrtowidget.cpp b/src/xmrtowidget.cpp new file mode 100644 index 0000000..fb930a2 --- /dev/null +++ b/src/xmrtowidget.cpp @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#include "xmrtowidget.h" +#include "ui_xmrtowidget.h" +#include "dialog/xmrtoinfodialog.h" +#include "libwalletqt/WalletManager.h" +#include "mainwindow.h" + +#include +#include + +XMRToWidget::XMRToWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::XMRToWidget) +{ + ui->setupUi(this); + + QString amount_rx = R"(^\d*\.\d*$)"; + QRegExp rx; + rx.setPattern(amount_rx); + QValidator *validator = new QRegExpValidator(rx, this); + ui->lineAmount->setValidator(validator); + + // xmrto logo (c) binaryFate et. al. :-D + QPixmap p(":assets/images/xmrto_big.png"); + ui->logo->setPixmap(p.scaled(112, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + ui->ratesLayout->hide(); + + // context menu + m_contextMenu = new QMenu(); + m_showDetailsAction = m_contextMenu->addAction("Details"); + m_viewOnXmrToAction = m_contextMenu->addAction("View order on XMR.to"); + m_viewOnXmrToAction->setIcon(QIcon(":/assets/images/xmrto.png")); + connect(m_showDetailsAction, &QAction::triggered, [&](){ + QModelIndex index = ui->historyTable->currentIndex(); + XmrToOrder *order = this->tableModel->orders->at(index.row()); + auto * dialog = new XmrToInfoDialog(order, this); + dialog->exec(); + }); + connect(m_viewOnXmrToAction, &QAction::triggered, [&](){ + QModelIndex index = ui->historyTable->currentIndex(); + XmrToOrder *order = this->tableModel->orders->at(index.row()); + emit viewOrder(order->uuid); + }); + + // connects + connect(ui->btnGetRates, &QPushButton::pressed, this, &XMRToWidget::onGetRates); + connect(ui->lineAmount, &QLineEdit::textChanged, this, &XMRToWidget::updateConversionLabel); + connect(ui->comboBox_currency, &QComboBox::currentTextChanged, this, &XMRToWidget::updateConversionLabel); + connect(ui->torCheckBox, &QCheckBox::stateChanged, this, &XMRToWidget::onTorCheckBoxToggled); + connect(ui->btnCreate, &QPushButton::clicked, this, &XMRToWidget::onCreateOrder); + + ui->historyTable->header()->setStretchLastSection(true); + ui->historyTable->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui->historyTable->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->historyTable->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->historyTable, &QTreeView::customContextMenuRequested, [&](const QPoint & point){ + QModelIndex index = ui->historyTable->indexAt(point); + if (index.isValid()) { + m_contextMenu->popup(ui->historyTable->viewport()->mapToGlobal(point)); + } + }); +} + +void XMRToWidget::setHistoryModel(XmrToModel *model) { + this->tableModel = model; + this->ui->historyTable->setModel(model); +} + +void XMRToWidget::onBalanceUpdated(double balance, double unlocked, const QString &balance_str, const QString &unlocked_str) { + this->m_unlockedBalance = unlocked; +} + +void XMRToWidget::onWalletClosed() { + ui->lineAddress->clear(); + ui->lineAmount->clear(); + ui->xmrLabelEstimate->setText("0.00 XMR"); +} + +void XMRToWidget::onCreateOrder() { + // @TODO: regex verify + if(m_ctx == nullptr) + this->m_ctx = MainWindow::getContext(); + + auto amount = ui->lineAmount->text(); + if(amount.isEmpty()) { + Utils::showMessageBox("Cannot create XMR.To order", "Invalid amount", false); + return; + } + + double amount_num = amount.toDouble(); + QString amount_cur = (ui->comboBox_currency->currentIndex() == curr::BTC) ? "BTC" : "XMR"; + double amount_xmr = amount_num; + if (ui->comboBox_currency->currentIndex() == curr::BTC) { + amount_xmr = AppContext::prices->convert("BTC", "XMR", amount_num); + } + + auto available = m_unlockedBalance; + if(amount_xmr > available){ + Utils::showMessageBox("Cannot create XMR.To order", "Not enough Monero to create order.", false); + return; + } + + ui->btnGetRates->setEnabled(false); + ui->btnCreate->setEnabled(false); + + auto btc_address = ui->lineAddress->text(); + emit createOrder(amount_num, amount_cur, btc_address); + + QTimer::singleShot(2000, [=] { + ui->lineAmount->clear(); + ui->lineAddress->clear(); + ui->btnGetRates->setEnabled(true); + }); +} + +void XMRToWidget::onTorCheckBoxToggled(int state) { + ui->btnGetRates->setEnabled(true); + ui->btnCreate->setEnabled(false); + emit networkChanged(!state); +} + +void XMRToWidget::updateConversionLabel() { + if(m_ctx == nullptr) + this->m_ctx = MainWindow::getContext(); + + QString amount = ui->lineAmount->text(); + + int curIndex = ui->comboBox_currency->currentIndex(); + QString symbolFrom = (curIndex == curr::XMR) ? "XMR" : "BTC"; + QString symbolTo = (curIndex == curr::XMR) ? "BTC" : "XMR"; + + if(amount.isEmpty()) { + ui->xmrLabelEstimate->setText(QString("0.00 %1").arg(symbolTo)); + return; + } + auto amount_num = amount.toDouble(); + auto amount_converted = AppContext::prices->convert(symbolFrom, symbolTo, amount_num); + auto amount_converted_str = QString::number(amount_converted, 'f', 2); + + auto fiat_cur = config()->get(Config::preferredFiatCurrency).toString(); + auto amount_fiat = AppContext::prices->convert(symbolFrom, fiat_cur, amount_num); + auto amount_fiat_str = QString::number(amount_fiat, 'f', 2); + + ui->xmrLabelEstimate->setText(QString("%1 %2, %3 %4").arg(amount_converted_str, symbolTo, amount_fiat_str, fiat_cur)); +} + +void XMRToWidget::onGetRates() { + ui->btnGetRates->setEnabled(false); + ui->btnCreate->setEnabled(false); + emit getRates(); +} + +void XMRToWidget::onConnectionError(QString msg) { + ui->btnGetRates->setEnabled(true); + ui->btnCreate->setEnabled(false); + msg = QString("%1\n\n%2").arg(msg).arg(m_regionBlockMessage); + QMessageBox::warning(this, "XMR.To Connection Error", msg); +} + +void XMRToWidget::onConnectionSuccess() { + ui->btnGetRates->setEnabled(true); + ui->btnCreate->setEnabled(true); +} + +void XMRToWidget::onRatesUpdated(XmrToRates rates) { + ui->label_rate->setText(QString("%1 BTC").arg(QString::number(rates.price))); + ui->label_minimum->setText(QString("%1 BTC").arg(QString::number(rates.lower_limit))); + ui->label_maximum->setText(QString("%1 BTC").arg(QString::number(rates.upper_limit))); + + if(!m_ratesDisplayed) { + ui->ratesLayout->setVisible(true); + m_ratesDisplayed = true; + } +} + +void XMRToWidget::onInitiateTransaction() { + ui->btnCreate->setEnabled(false); +} + +void XMRToWidget::onEndTransaction() { + ui->btnCreate->setEnabled(true); +} + +XMRToWidget::~XMRToWidget() { + delete ui; +} diff --git a/src/xmrtowidget.h b/src/xmrtowidget.h new file mode 100644 index 0000000..8d33d7a --- /dev/null +++ b/src/xmrtowidget.h @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020, The Monero Project. + +#ifndef XMRTOWIDGET_H +#define XMRTOWIDGET_H + +#include +#include "widgets/tickerwidget.h" +#include "utils/xmrto.h" +#include "appcontext.h" + +namespace Ui { + class XMRToWidget; +} + +class XMRToWidget : public QWidget +{ +Q_OBJECT + +public: + explicit XMRToWidget(QWidget *parent = nullptr); + void setHistoryModel(XmrToModel *model); + ~XMRToWidget(); + +public slots: + void onWalletClosed(); + void onGetRates(); + void onConnectionError(QString msg); + void onConnectionSuccess(); + void onRatesUpdated(XmrToRates rates); + void onTorCheckBoxToggled(int state); + void onCreateOrder(); + void onBalanceUpdated(double balance, double unlocked, const QString &balance_str, const QString &unlocked_str); + void updateConversionLabel(); + + void onInitiateTransaction(); + void onEndTransaction(); + +signals: + void getRates(); + void networkChanged(bool clearnet); + void createOrder(double btnAmount, QString currency, QString btnAddress); + void viewOrder(const QString &orderId); + +private: + QMap m_tickerWidgets; + QMenu *m_contextMenu; + QAction *m_viewOnXmrToAction; + QAction *m_showDetailsAction; + + Ui::XMRToWidget *ui; + AppContext *m_ctx; + bool m_ratesDisplayed = false; + const QString m_regionBlockMessage = "Beware that XMR.To region blocks certain IPs, which can be problematic in combination with Tor. Use the clearnet option if this is a problem."; + double m_unlockedBalance = 0; + XmrToModel *tableModel; + + enum curr { + BTC = 0, + XMR + }; +}; + +#endif diff --git a/src/xmrtowidget.ui b/src/xmrtowidget.ui new file mode 100644 index 0000000..8726ea7 --- /dev/null +++ b/src/xmrtowidget.ui @@ -0,0 +1,327 @@ + + + XMRToWidget + + + + 0 + 0 + 896 + 472 + + + + Form + + + + + + + + + + Relay over Tor + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Get Rates + + + + + + + false + + + Create Order + + + + + + + + + Amount + + + + + + + + + 0 + + + + + + 0 + 0 + + + + + + + + + + + + + + + BTC + + + + + XMR + + + + + + + + + + 0.00 XMR + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + + + BTC address + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 169 + 48 + + + + - + + + + + + + + + Pay to + + + + + + + + + QFrame::Sunken + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + + 0 + + + 1 + + + 0 + + + 6 + + + + + Rate (1 XMR) + + + + 6 + + + 6 + + + 6 + + + 4 + + + + + Rate + + + + + + + + + + Minimum + + + + 6 + + + 6 + + + 6 + + + 4 + + + + + Minimum + + + + + + + + + + Maximum + + + + 6 + + + 6 + + + 6 + + + 4 + + + + + Maximum + + + + + + + + + + + + + false + + + + + + + + diff --git a/utils/Info.plist b/utils/Info.plist new file mode 100644 index 0000000..00d3929 --- /dev/null +++ b/utils/Info.plist @@ -0,0 +1,61 @@ + + + + + LSMinimumSystemVersion + 10.10.0 + + NSPrincipalClass + NSApplication + + CFBundleIconFile + appicon.icns + + CFBundlePackageType + APPL + + CFBundleSignature + ???? + + CFBundleExecutable + feather + + CFBundleName + Feather + + NSHumanReadableCopyright + Copyright © 2014-2021 The Monero Project + + CFBundleIdentifier + org.monero-project.feather + + CFBundleVersion + @VERSION_LONG@ + + CFBundleShortVersionString + @VERSION@ + + NSSupportsAutomaticGraphicsSwitching + + + CFBundleURLTypes + + + CFBundleURLName + monero Handler + CFBundleURLSchemes + + monero + + + + CFBundleURLName + moneroseed Handler + CFBundleURLSchemes + + moneroseed + + + + + diff --git a/utils/build_macos.sh b/utils/build_macos.sh new file mode 100644 index 0000000..11234aa --- /dev/null +++ b/utils/build_macos.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Used for macos buildbot +HASH="$1" +echo "[+] hash: $HASH" + +echo "[+] Building" + +rm ~/feather.zip 2>&1 >/dev/null +cd ~/feather +git fetch +git reset --hard "$HASH" +git submodule update --init --depth 50 contrib/tor +git submodule update --init --depth 50 contrib/torsocks +git submodule update --init --depth 120 monero +git submodule update --init --depth 120 --recursive monero + +CMAKE_PREFIX_PATH=~/Qt/5.15.1/clang_64 make -j3 mac-release + +if [[ $? -eq 0 ]]; then + echo "[+] Feather built OK" + cd ~/feather/build/bin + zip -qr ~/feather.zip feather.app +else + echo "[+] Error!" + exit 1; +fi diff --git a/utils/images/feather-home.png b/utils/images/feather-home.png new file mode 100644 index 0000000..85dcc67 Binary files /dev/null and b/utils/images/feather-home.png differ diff --git a/utils/pubkeys/dsc.asc b/utils/pubkeys/dsc.asc new file mode 100644 index 0000000..17fdca2 --- /dev/null +++ b/utils/pubkeys/dsc.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBF9rWTkBEADBPAXEavUHpXVBchV+UF3i8S1p1ElFxxc4+JNMP0HSclz/5TVW +7RFxs1Os9p2BKgcXlwRbpnoa37KtpgSslPsduzS9VSwPC/Ve4qyX+xOcZlu3uCVc +FKpx33sUvSHrbHzK5tPsShebO+Hs41xMod3pE95/DjJL8Lwe0k0iXvUqeFGFrOw1 +qOzM2LRSTaliPjGYG2ZkanOkQKNN/QZECqSFMeWbqa+/Tisk7/6UotmDxv8d7rZN +wmCPb1P1mi3MmP9Alg1as+IlunQMB4s9iF9iWk7DwgIeFCMFHfj/Ay8hIuCIzmJW +91+x83Z7imWKKdynN7bldRsUMvxOS4yFhJ58dQqrkeFFPyZhqpcpJx1QX1NC/2Kg +R169nkxNAQznpo4BphHqIKlA2C3RWA8AeXPGMpgiNP1cr2k93EpSPcIUHeGNNPHK +20uGY0tLzuvZEGD1GdrRTclQ/RBcL5hcWjx8Cey2kXX4scaH2mvNgJIpG7UoHbXs +HgHPIm4OvYQClJ01k3G9a8sL/rkZBpL4y0D0LJIM/hML5jRc88d+NIsWfz+SRMlR +2mRf2t7SknX9ToIJJzklx9LHoox5MQQs5eFOU+jLa/3qXavsCo7eBrO0d87T54GY +EHI8ezyvybtonN+nkhK0qaPebCt5CdECO2W4D0HoCe7/hPFxRZ2I3AXP/QARAQAB +tBRkc2MgZHNjIDxkc2NAeG1yLnBtPokCTgQTAQoAOBYhBBv9QPmw4rQNyMf9SlIf +HnmRqkLcBQJfa1k5AhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEFIfHnmR +qkLcWswQAJRh0ahgRw7grn6t7VtrOlGTRJt8Qi2KVwg31elV2PiU5qSv2aOjnbnM +ZCWkP+WKuDI7eiXNWVrIZzqzVT4BNHW0HgZ5C6UR2IR+9ktwvXOfPBocf5PbaYpu +zUeDtv7AprvKAgKYIcKBzdXc/1ng6eN3eBFXHHWNQnYjO7TAdpWlxb8sGXgWaFEZ +qkW89CXWneJK+RRHEP1EnY9ounvrR81E6VF4L8QIL9Yuf1OOYWAUAghh23ZRljvN +VYbpN31jyzQNBw3J+NJtCWGqFNn5n7nbVhvl0DDFefuDXM1W8JExeup/kxE4reRk +Kn20h3O5+xkS0qqqcFQSQpUtURO0WrZ4L22jcaUOlF/ZfB5G4SyW/E/vHQ/OYv2W +VTKZbUhpJtHJBJUWHYn6/XCEosiGnf2OIbpyaPxT+wQs8RIZp8xYSKeY0/yH7D7L +rT3ZNYL6EPIyxeH4jqHy3rw5NVnAGSEzx7YgwIMn8KMlPu1q8e0R5T/jYZoPuGQ3 +/7EklardAP/JH4VDzV3ci7vjhLhMfb8jVPUVrMAYyKMUrmHWuZPIBN3wylVjBh+2 +BbOk1uVC4iflBDKHVmjG+2QgDmsSFWPSS/MBwVoiPBT97/UupTbj5/q4cUYdZYEK +qGG7CIteg5kl7cRAhQ6tX4pl1bt0I9x/KchowjTlhxRsRKVp7SfZuQINBF9rWTkB +EAC18h7GBg3vBCGBx5BfvGRh1Lfids/Kk6jSCzkKpbWG8rCQJ+g45l9hNLXQWrt5 +nXzyoIHdqtF5Cr6OMOmcz5oWjlW+7yp5MR7whuvi6weiAlY+3k4cPYJ/+PAhVf5E +hBbYBcuSSMZ53dGMBxqwzb8uAiZ2eznLGsA4dbYjidEg6dTfViW5fteHYl0pJb/J +j1285Bn21ZjOxqpRDFm0noaZseFotBzs+i2UC5uhTfn0dDf4QOjeLxBl5IXnirts +nwwFV3hYghkcHKxp8umk8NJZD+hC6czT21ROyNF4O3OLUNpp2AmqVrGggiVusXUS +IPqO34M1Sylkmswm18U7qjFWgj1WZW3QmVRdCP8WW+7THWYPI5F/bVLaOyMgsUkU +aB+OB51OgDWPZ3p7zvXYKQNyUEpN5IOf9SAiCTXmOewYo7W6r6YtTp4EE8Ctx8zQ +vMdTViJlJFsI5vEMwlORmGUgTFnODpeb3ZtvxcGCUJWFzMKHadm5+CHpOBUzfZwU +BduFGisAeQAhHIrH3jSvxEmU4jsX+EGqOHZsv7UIiL7jixEN9TDo8x5pfUrL9f4Q +MdnzxTc3ZWP7KTR4cc4SsY/bKmzSe3pPnx/dwPd6cyUrW3OX3m6u8zoLi8FETm3N +ZfT7IhPMmcLZCkjP0ek4AQ3jb8M3oFtzf+N/4qyX6nLUrwARAQABiQI2BBgBCgAg +FiEEG/1A+bDitA3Ix/1KUh8eeZGqQtwFAl9rWTkCGwwACgkQUh8eeZGqQtz23w/+ +Ply0wBUIqdfivegQh9xstYyBq2koXCIwBnfmaUgP6huhM0lEe7DVY2bchydDQLQ2 +Di4eLA1ZL24Ml48c5so6Fwk+3zwQJlX6NauT7ZHR52E4I9LgrcnImT7mlflPUQnV +UWR1fTqEMwbx976Id2Jb3LZC8iKCuOXpvr8BPJr1uonVtSeCY7fYYwAt/X8BJlO4 +49lRONKcb2YJ/EVD+9oVON7NfhwblQB3LDbVkHt4wkKdO51jFy0HVi7+k5PTlWTF +d1z8znbPvuWKBbY8+NvLoq0ZUyeLtYxVaIqfSZHrfMlkB2kluTOxvwEMvVD4p4CJ +fis80xYyHDRUAvDC2nUVCVBQ4qamzCC3iFAz6SL1M6cguHLBL57/3pbgoqP7O9Cl +QHop65+PEeNNtX0BTmJ+yGnnBW9qEyeTDF3wC0XT9NWQxfzrHS5gpRI4PWtyfrnT +ysb6TUHXBRG98LF5OU3ekLwTVwT5eMcCRPIfd2boiFDB3X8bXRrKhjjqYxbsbsr5 +yGPeA/UpzD3ve0ILWiFVwwXHIz2tAWvM5esRPiqxaqXEStvOhZN28Z14aqxztrKX +1COT21URKf5zyr2I7i2/Pb2OLsOEv83/AssYPU8b5XyB/ZHreo/K3l910BCtrVoL +3y6GeqgXcpt2av0dp5SHDOf86I3y0Ep2yNVXnzUSLd0= +=YJQh +-----END PGP PUBLIC KEY BLOCK----- + diff --git a/utils/pubkeys/kitware.asc b/utils/pubkeys/kitware.asc new file mode 100644 index 0000000..2e6c3b0 --- /dev/null +++ b/utils/pubkeys/kitware.asc @@ -0,0 +1,64 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBF0bjnMBEADVgQr04Lg258KpWi42rzGemFGkzHCx7SXDWVqHApx34HUxF63s +RnknCTt42Thqcv78CJ9WQYjjvT5+FZOlxA+0kwkeatFoKNeVvBkyYFgU6gxSuVQ+ +a1ZEw2IYdqRH+vUC1AKGY88KlrteTAqtqYsaGimiF5ry3y3bLBySyxLHfltCaENy +uKPJEHHvHxTZsZAD3iwVysNZkw2V/V4IS8wy8m9rq1U7OU40KMJ3EUan89DzD1qt +8sroEThsjE9IG6QMf1H9pvNIIz/QhwqSKQkGqt8obdf0W+EB4cef6ka98a+E6slc +Otw2AVB2B47ljnp5AyLwZPiYxeIXPZsO8cZbx1uBOkOZ1OkqHlk4tgJEqg+v6APO +cm625fk4iftsB+U/3MZvm4QH4Y5xfAFb3aDL2zkxN/EUCWW5tUn+Z+RaegGaojTE +N2laH91ncpeZh1M9GPvXGT/efDg3a/Nv9UNUtv9lhNn35VyVgBNaaYwNScq5+ApV +pG8b/j18x8mQR8kk7bXvOXjc/4NdCrY7QcIExA9DTWemLsDVeDM62lBvOKZGED4X +fgGehGGPtu862kf4vvCZKrrEeVkVBrTiOsxFMdHshnKqtQyyJQKXXVjl9//jhMGM +cZHJ5+D9O4JNE/aZC4h2F7hL0NpO0AVGJ0Ly5N7B07yMBZGGJaH4QXCoHwARAQAB +tEVLaXR3YXJlIEFwdCBBcmNoaXZlIEF1dG9tYXRpYyBTaWduaW5nIEtleSAoMjAy +MCkgPGRlYmlhbkBraXR3YXJlLmNvbT6JAlQEEwEKAD4WIQRtkDmVQkqDpI1C1T2o +5e86AmACaAUCXRuOcwIbAwUJBaOagAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAK +CRCo5e86AmACaLJ9D/9ly840Ko3F0HgIAAxAeWE7BzQOD09BbnL/is6F0lquXd/W +fZXUbVhONv7Q3FK9IDwzKoYHmRrwo6IpDIsy7AqiHHkWWxCdpIzVWQfE7rFg4UWa +2bNXoFBGRImYmQHaG/02EJiNnTDnsYgN7y9zzAAvz63dnSsm6GOUp9pkIoxHnt9D +WxMlM05GgVRjSeNvi4OLuPE6jHhHvAGGrMS8g9oU6TtCj9WVNryFpROchdmTteS4 +P16FP4n5NczXjYXFch3S+cOfijHnsfuFzB4JanrZ+JlBd21BDfhO/VLFx8+Ljdj0 +axKpwa86oHc5ALnMHPnGM2EVN+NNS88PDBngvJEpRUkECpEy4cwZ3zjCJ0jMeiRv +cFf/FjZBFeqrAapwWNFjIH0El7dJq+XYDKuA0kakMDo6GZlfTNDRobGj9vR/HA0j +/a7VD9tfW2dLr61qsQwynn6S+9B4XY/fYwc4AyYCp+FNm4ONFFjQ6ytCgdLdBEWK +X+xCMifTqDx9nm/1u/95ZqwcayAqwhKDb01hQhSTlozybz8B4trfeHJdXYoH7/s4 +TLnt5R68bc2Fm0ikk4tndSTH4SUtnEeIv+nap5RkCmHI6URJ4P4kFT3C30Ooeafv +GOa18HYxhb/qnU2DvWXL1rnKoKB51p2nhrkjliDPSfMMIf6AgyZSZR4BpMoz47kC +DQRdG49RARAAyX+HK4Xh0RiiqPd0DDbgHV+8UvY1gihObyK/cqpRQzewSKEw/jwM +abwav3oqisI7IFp4FmupqhSi7uqB54eUF44LHeGZiUedZm5pAreX2ygQASr2It3g +kWr58J0ZOas6cRqUzga1mCL1eljfff9T9+1syIWiUWTjXDzEwsMgksHIn9ZGaxM0 +zvkbXfTCmlzmCbvBwokHRrw9cvmXZIKaGdvAEg/S9asmkRBeA/0GgX2Tlr1H6mv5 +0ZYF25t0n2IYiVuvXTOrz9OCuWxv0NQiweMFTi62sN6myjB4PC499ySTQkIhWVsf +2oa5+rvcCg6j3jpUFy4MoDA9cXl47/0ccpim+mwJo4uY4ysIsDq7mKqjN7honj45 +zosvs7yd2UXrKWKay+P1e1vdsSOVP8PSSJCJV8HvdKCRfcYYdlTq3PSeloVrWC/4 +PCKlnp16AzPzL+CBWtj5ruhAFTaoKveEjUnQD5IiKD4hvt9nnX6C9RT2yhKDHnoi +uup+nXOEn78UWxmoPJKu5wE1c5ZZhw81bYByEkLjHt5Bl+FS8CJN3G+56kVuBc9v +Kqa90EThcLr6bIEx3LU3mK3FBxBCh+7xEPYI4Cx/NGyrszirRkzIIM6wIxc983l5 ++BtdKn14b2yDhfw2wOBsxo4aLWhGzqJGQAxuUo4sdNbElT5mpwpDxJEAEQEAAYkE +cgQYAQoAJhYhBG2QOZVCSoOkjULVPajl7zoCYAJoBQJdG49RAhsCBQkFo5qAAkAJ +EKjl7zoCYAJowXQgBBkBCgAdFiEEWbJ5MHJjJForbwaGKR+f9v04V4MFAl0bj1EA +CgkQKR+f9v04V4Mz9Q/9E0KmNCJC95HfP46enwASVnBZ7ntlHvtqQgNVZ8r0W69v +qg+FdsKK2109lR3RvRe5TAwHi4ryFW6YazmvH4k7Bd1pGxAtc5VSuehgs8lPGObo +SKI8S9EH+v3G4IAm25vaRDtnVdDpcfn5A6RrSDyTTDjdhyTp9w/f62SfMryf/0fv +yg5HS5JQSHBJdxN6mnRDqM66Ey4plfFbt4yKJIPnj5xsa19wx72Zw8hED1O6FZAV +URQ8ffE521R9wzQAfX3746pdEQ+S21Ht0lEsNjmU/HDq0WeOBElIN6S09XQyL0zG +0HrOZkByI5683v+cp6clJKxnBX7hsR0+4AxQK0+eNJEtLwLPcwObBi2ACeUG49cA +ms+BaSAvjbyCW4M7ye42zdEFbWS9hfK6T5Ry85Pv6IxgpUHAX7kvtqHxguDobuUZ +4CmSdRyBCEAN7dgjWrqrtmq7cF3Kwz5kLwzB0AeQTArLoYlBSlcx/eT/jDLZdFjQ +Ol6uqVdv63BADNriYExz++g4A02LzAfk+C0J/7syKeEs5nonIFwTfrS7VJbcs7Cn +8HkuCPuH9u1nYSJV8U7xYNCbRK3JNBr20IlO+TXAuf7M3z5IuZjED7EtG0kMyl41 +vbBYCFbKMpEEjFAUUO5CsbyL4IoYJRptJij10RsDI9jRY+YfOQ+WxP4txPDv1Eei +eBAAs2PDWG7MvubB1wE3QcRUEQqvDbEIdvRfz9YIOXfGlaDfiuhBpcxsgsDG/IjQ +3c0PnJqpLpivfOMMyfynwPRW4ZiwIUSrOYJ6xhOt3zUzqf/GfIB39pCz3AI0EBxp +uicL4PJ4OeA0V3XT+IEcjbqBaVz5UCS/sVuYTykxwk8BPYaJOFlHtp4kEtn43kpL +kQHPMQCC1+skI85d0YG7Yn1w5qSqtwYJBPFU2OWpyLHtxL55S8dAWmvlkKmA1I6W +WyOPM/Y5WWdG8BUphXmv67wdeVdxp4s5V8oXKy3QQ0FA5Wt/z6l7Ei8tXcOIgDYw +nYgTgjOprZPXOY+L+6gED3YVWUvAJ6xhdYVsJazu3Ulwr4dwkHrBd1qXe7NGA3Ib +7VAkzkPzRtdPJ+OT/YX0vfh3a4VvYepoTAHIf0J6Uo2vcqBFA/Ztiby3bM4T4C30 +c5AqQkLDZ/2UbBW9Yu4f9oiw7/gDdNI7C8xHaQNLFzzRzhjnEpjwBhlpeballXoU +6ShFo6T0CzZ1N46iumJ5nTor40dY2EcX+dXxGCJ2ihifIeHrbx6fKFOB9VLV3VpW +SzLJTT9ARIgvqVg5lhTFiKRiZNp5MAu9NFw5wgyCJxUjASLOWshMwkhKHHe13AZD +2Hxmkp7Qwjg6kihr/j03NQIBhOK+M068Urew/dbndYwIzsI= +=0GnF +-----END PGP PUBLIC KEY BLOCK----- diff --git a/utils/pubkeys/tobtoht.asc b/utils/pubkeys/tobtoht.asc new file mode 100644 index 0000000..8fa20f4 --- /dev/null +++ b/utils/pubkeys/tobtoht.asc @@ -0,0 +1,59 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBF2zfmoBEACrlG7MvTd0QpmSelCDHjO/speQpS34Up+PlJmtRqKXaTKap4ex +RmG0rEfJtaybkckrxJvl+niphLZeQfuxukyUGiqhRsjQLpSD2y3CXqfHkAQYY8Kl +ZGPRhRWCjGG9kbz+yoXz27/anszObHZwlK/JoBdn2u+O9tw8el+zaS5uewYCwEOn +ixrUdRhPLCLqz9rpO8YAwdEOk83ENr6U4xAwKBo2rhWPNBlNtG2KJAz+mS/Yarpz +vr/KFV09sDIgypJkkD+h6YpZ6xIRHa4mlDk6UvK2sGupMh6LU/LRMywaDurNMqOt +F4ja1abmyR5zZclLtx8fNqgRM9/EdKFL4+N1fp5CbJqIbI5kEYeyHtrGZCNQYP1m +yz8AcFIqd0BF9R0Fr0SYmnePqJWdIszE9JC+G0VccGzssHc30JUbvV4YyqlRq2m/ +ypb24Wr52ttHWVi+I+/LvRsfrRKpIG4VjQKAQ3FZF/MoY9YbPuZusVgx2X9RwtuO +AxgsTCNnkqXg2FC/NkeYluHRwSFMSMX2lFQcMK0+qo7xQCZ6Wx+GXTPSk6NLmnqt +l0J6fDUXLdKEr/wdVmeiyMcxjZGYOHLJOJ39QwxBiq11Y4BboYz4WUKtFDZJCkLJ +YoMkFNgoiDqPher9TZ3xcPRdvfuoDcn9GCcAjs0RRFNGskjdx4ujfbxHgQARAQAB +tEx0aG90Ym90ICgvdS9UaG90Ym90IG9uIERyZWFkLCAvdS90b2J0b2h0IG9uIFJl +ZGRpdCkgPHRob3Rib3RAcHJvdG9ubWFpbC5jb20+iQJOBBMBCAA4FiEExavlwOUP +orPxSrktHK3Sf0H0XDwFAl2zfmoCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AA +CgkQHK3Sf0H0XDxtXQ//Uw7SAH2tlwTTE/ehJbg2fZG4Jfn91XKtpEE8yMtqIHQc +QiGAp7pe/c851TTJ2aug6y0/9/usp4qMPhx4l/vNOHwe5sk+a2jm/Wxh+lfJqv6Q ++En7JmKRE7ZFCaTirEY5u4Qxepg/tSqD29ZN2uHeAVx3RTHSO05R6RMe6PPjEvsB +4xTOK7pKXI1Oxy0RJwRZSum8wwBUvmfeE78colyBekbl1A2TuIfEmfzPY+UjaxQj +28DUYsZ6RqFGBRnf6cMWm2iZx9FaLEZhqZUFL746vxIGwADgJmanI+f25UMPQfTP +EAlHZxpI/0oQb2QOGSJyFMQHgXVvR+u/QNbU0Uju/gW3/nqDRnPlBs5cwFcgjbPa +Txvkak/sgXYb30Ed47OXSH/VBR19QN8gMl3uMnTBWxC3z0Ps8TCgAS3K8tFuuRNs +eB2oLFlySbC3uFzDgh9DXmybF4MEdKckrjM4gGGf7uChjLBncUpGobsVDYTJuduJ +7ZLWPwvaFMXMcXQuHlJjf8qW54TQFYikZHx1uSU5j4xvT5F9k0HofJQQqbamIo/0 +nsxdufZs4fH1f8uDXKt7sWOw+TZlJPI6lqewys+3JVHkp/ByaSYn/a9R6ZHMkRb+ +RI1ezumoBAuA8JQd0X6VeiW0HOCEQekFlPZcf0obtdiY/bZrLjYOA+g5ZRMT3T2J +ATMEEAEIAB0WIQSDBDsI3YEB8o1xf+nlk5P7rJc+IAUCXbN/RQAKCRDlk5P7rJc+ +ICflB/9qji/RY09rTlUTLfXiKltQAEPjMvmmTIdNXHd+P5HsuZxn+dgJX8Vfk2R6 +GMF6XmUPTGe817/fnwzr+zU6rWwjLi/EATq8QlK1oJQ1H5proBHfRmDgnQRXB3JI +mfUUvSpt7keiDkH0/s/xbr7L2v6bYlEGssShsL51tHHfLn5mon/6pRC3szWvzN77 +KpUAFRy7Q7gTifCEKO0rjzfOd7aE01bj6FMftSlSqiDrf8SZMhdgn6+RkPu1nggx +Pf9pRSfhcaVWpZn9Y/DpESiLkHVo1WmgR7/TSjgmWTtWEeCe07X4bp2OCu5oFvfq +XXWbekH8MOyeLN1FHL58uqdBg+wCuQINBF2zfmoBEADMsraEqzx8HSS+1lRfb15U +T4yeIVNI5C58Z4WELxXzAYdeinlKgSIs0+fQf45UAR3q7gWQgxQZB8ojQPn1QfJE +tQ60tpzLlY8pCZhnuhtqM164OLkVThu5wJABbv5zRaohLVTNykYoVD2t/syAgMgn +1UuPPXBcG+I1fbAtclRyq3HnIcRkfym+adM08b7V6YEr4lHJOh8vGWmYuEzMpDnn +gRyWcuTvaHnJ3LGX49TDdL0OXeiL557Vvv1tQKcyGEmA+Su/QArBEfVK5FUK7EgB +gDxLVtqNOkaCSQykFr75ujXwTXV4VDFzsHXLA4js/robPkbaSFgn/NpFUuu82RPJ +7T5YoMXliiV8flYsdZyVlMq9nMbUbZ8yjJAIuGT/I/Q1KbWNK1cKS8co8RirjxlW +bS29Jak11f3XVqDg/Y1lT1LzQfDHSFY0c0hTjIWSOscGK4aQoNUJadwbuMBz2rSu +BXoeIpj5c8W5fNGx3CU1N34eIH6DbLzuhz/Ofhg1y/33hDaIu2EB87pYcWBHsLWy +6apmf8GctR4f8XtZrnfvaJTQkH05lP/d6uJr8bksPeUd6cM31eCX6DB/0MS2zY9i +5bKPPt3SPqZXu7aVObh/wNBkkMD2Zq76/aDDoXrYpHG1mW0Eo6m6vye5aFuqWy16 +5kLfIbolignWOBR2b6frfwARAQABiQI2BBgBCAAgFiEExavlwOUPorPxSrktHK3S +f0H0XDwFAl2zfmoCGwwACgkQHK3Sf0H0XDyM0hAAqcNPs83sLJcjMhIPIiLT7s1p +ghe+/+New+e+CI+vTjAYMWe38CbDxUzHxnuirpnbThu73CU5YeEirNOTqKsd3wBL +0xIHU/UtsBMX2TeRVUp4EzinbUJopP7wzTgLWEdSak9b0atuD6e9WRpgliL4fshu +aQJo0muM8uYjXTPpxUPG96F1dDvxenKC7b1B0J/Rwd5Ok0srHyvvgzVejX3M+Jg4 +E0bAY0agkY0kIX2odYrB+sG8X/zrjeI/B2wgAq1hzXQ6lGz70te3vP2/0hyUVrsb +TSnZB+2KWnveV3d8tBZBXzmYomIdgb+rOiDXQ5pccRq1+cf7X5ugwy4dNk7WbbQc +imYk0e40NeNjbWTeiMa0MRiytuatPs9N7OnhWrdEsvznmFHwp1P7kOpKzivPJu5Z +ijNMoBA+VDJN6L8Tz8M7efdUjOfz+Ak4GqjyFDy8VPomFS3PAz/7v2yhD+UjUl7o +r5JEOdSE0ksqK1OpnShoFXrAXwVQAyqmU2yKey2tfPlGpJQeJBdMSUJDNgaIb8mj +XZ0ls0fXknJfxhEZIdRGXT3m3GA6+AVELvlN94cY+1802h2bW/T2jKkzdor/AC6j +FCdMtwLy/TkxMq50/Nomjqz/CzLpyTQhAc6KWJC09lYsRG47qQ0Vel0pt74TO2kF +RR9alvpX5jGtupg5+1E= +=hD7u +-----END PGP PUBLIC KEY BLOCK-----