code:
CMakeCache.txt
CMakeFiles
Debug
Release
x64
*.sln
*.vcxproj
*.vcxproj.filters
*.vcxproj.user
libcef_dll_wrapper
.vs
cmake_install.cmake
*.VC.db
GPUCache

license: mit


code:
BUILD REQUIREMENTS

The below requirements must be met to build this project.

 - Chromium Embedded Framework (CEF) 76.1.5 or newer.  The windows build is
   currently configured to operate with the X64 binary distribution of CEF.

 - CMake version 2.8.12.1 or newer.

 - Linux/MacOS requirements:
   I haven't tested these platforms, and there is platform-specific code missing.
   Shouldn't be too hard to add, check the CEF distribution and treat FCHost
   as a derivative of tests/cefsimple.

 - Windows requirements:
   Visual Studio 2015 or newer.

BUILD STEPS

You must have the environment variable CEF_ROOT set to the root of your
CEF distribution.

If you are running Windows, execute cmake_vs2015.bat, open FCHost.sln, and
build from there.  Resulting binary and support files will be in
FCHost/fchost/Debug, or FCHost/fchost/Release depending on the configuration
selected in Visual Studio.  You should be able to zip up the contents of the
Release folder and distribute them to another machine or user if desired.

If you are not running Windows or you need something else special, please
familiarize yourself with CMake and see the detailed information in CMakeLists.txt.

path: FCHost/Building FCHost.txt


code:
# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.

# OVERVIEW
#
# CMake is a cross-platform open-source build system that can generate project
# files in many different formats. It can be downloaded from
# http://www.cmake.org or installed via a platform package manager.
#
# CMake-generated project formats that have been tested with this CEF binary
# distribution include:
#
# Linux:      Ninja, Unix Makefiles
# Mac OS X:   Ninja, Xcode 5+
# Windows:    Ninja, Visual Studio 2010+
#
# Ninja is a cross-platform open-source tool for running fast builds using
# pre-installed platform toolchains (GNU, clang, Xcode or MSVC). It can be
# downloaded from http://martine.github.io/ninja/ or installed via a platform
# package manager.
#
# BUILD REQUIREMENTS
#
# The below requirements must be met to build this project.
#
# - Chromium Embedded Framework (CEF) 76.1.5 or newer.
#
# - CMake version 2.8.12.1 or newer.
#
# - Linux/MacOS requirements:
#   I haven't tested these platforms. Shouldn't be too hard to add, check the CEF
#   distribution and treat FCHost like tests/cefsimple (from which it is derived).
#
# - Windows requirements:
#   Visual Studio 2015 or newer.
#
# BUILD EXAMPLES
#
# The below commands will generate project files and create a Debug build of all
# CEF targets using CMake and the platform toolchain.
#
# Start by creating and entering the CMake build output directory:
# > cd path/to/cef_binary_*
# > mkdir build && cd build
#
# To perform a Linux build using a 32-bit CEF binary distribution on a 32-bit
# Linux platform or a 64-bit CEF binary distribution on a 64-bit Linux platform:
#   Using Unix Makefiles:
#     > cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug ..
#     > make -j4 cefclient cefsimple
#
#   Using Ninja:
#     > cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug ..
#     > ninja cefclient cefsimple
#
# To perform a Mac OS X build using a 64-bit CEF binary distribution:
#   Using the Xcode IDE:
#     > cmake -G "Xcode" -DPROJECT_ARCH="x86_64" ..
#     Open build\cef.xcodeproj in Xcode and select Product > Build.
#
#   Using Ninja:
#     > cmake -G "Ninja" -DPROJECT_ARCH="x86_64" -DCMAKE_BUILD_TYPE=Debug ..
#     > ninja cefclient cefsimple
#
# To perform a Windows build using a 32-bit CEF binary distribution:
#   Using the Visual Studio 2015 IDE:
#     > cmake -G "Visual Studio 14" ..
#     Open build\cef.sln in Visual Studio and select Build > Build Solution.
#
#   Using Ninja with Visual Studio 2015 command-line tools:
#     (this path may be different depending on your Visual Studio installation)
#     > "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat"
#     > cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug ..
#     > ninja cefclient cefsimple
#
# To perform a Windows build using a 64-bit CEF binary distribution:
#   Using the Visual Studio 2015 IDE:
#     > cmake -G "Visual Studio 14 Win64" ..
#     Open build\cef.sln in Visual Studio and select Build > Build Solution.
#
#   Using Ninja with Visual Studio 2015 command-line tools:
#     (this path may be different depending on your Visual Studio installation)
#     > "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
#     > cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug ..
#     > ninja cefclient cefsimple

#
# Global setup.
#

cmake_minimum_required(VERSION 2.8.12.1)

# Only generate Debug and Release configuration types.
set(CMAKE_CONFIGURATION_TYPES Debug Release)

# Project name.
project(fchost)

# Use folders in the resulting project files.
set_property(GLOBAL PROPERTY OS_FOLDERS ON)

#
# CEF_ROOT setup.
# This variable must be set to locate the binary distribution.
#

# The binary distribution is in a separate directory from your
# project. Locate the binary distribution using the CEF_ROOT
# environment variable.
#
# Set the CEF_ROOT environment variable before executing CMake. For example:
#    > set CEF_ROOT=c:\path\to\cef_binary_3.2704.xxxx.gyyyyyyy_windows32
#
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

#
# Load the CEF configuration.
#

# Execute FindCEF.cmake which must exist in CMAKE_MODULE_PATH.
find_package(CEF REQUIRED)

#
# Define CEF-based targets.
#

# Include the libcef_dll_wrapper target.
# Comes from the libcef_dll/CMakeLists.txt file in the binary distribution
# directory.
add_subdirectory(${CEF_LIBCEF_DLL_WRAPPER_PATH} libcef_dll_wrapper)

# Include application targets.
# Comes from the <target>/CMakeLists.txt file in the current directory.
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/fchost")
  add_subdirectory(fchost)
endif()

# Display configuration settings.
PRINT_CEF_CONFIG()


code:
# Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.

#
# This file is the CEF CMake configuration entry point and should be loaded
# using `find_package(CEF REQUIRED)`. See the top-level CMakeLists.txt file
# included with the CEF binary distribution for usage information.
#

# Find the CEF binary distribution root directory.
set(_CEF_ROOT "")
if(CEF_ROOT AND IS_DIRECTORY "${CEF_ROOT}")
  set(_CEF_ROOT "${CEF_ROOT}")
  set(_CEF_ROOT_EXPLICIT 1)
else()
  set(_ENV_CEF_ROOT "")
  if(DEFINED ENV{CEF_ROOT})
    file(TO_CMAKE_PATH "$ENV{CEF_ROOT}" _ENV_CEF_ROOT)
  endif()
  if(_ENV_CEF_ROOT AND IS_DIRECTORY "${_ENV_CEF_ROOT}")
    set(_CEF_ROOT "${_ENV_CEF_ROOT}")
    set(_CEF_ROOT_EXPLICIT 1)
  endif()
  unset(_ENV_CEF_ROOT)
endif()

if(NOT DEFINED _CEF_ROOT_EXPLICIT)
  message(FATAL_ERROR "Must specify a CEF_ROOT value via CMake or environment variable.")
endif()

if(NOT IS_DIRECTORY "${_CEF_ROOT}/cmake")
  message(FATAL_ERROR "No CMake bootstrap found for CEF binary distribution at: ${CEF_ROOT}.")
endif()

# Execute additional cmake files from the CEF binary distribution.
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${_CEF_ROOT}/cmake")
include("cef_variables")
include("cef_macros")


code:
# Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.

# Must be loaded via FindCEF.cmake.
if(NOT DEFINED _CEF_ROOT_EXPLICIT)
  message(FATAL_ERROR "Use find_package(CEF) to load this file.")
endif()

#
# Shared macros.
#

# Print the current CEF configuration.
macro(PRINT_CEF_CONFIG)
  message(STATUS "*** CEF CONFIGURATION SETTINGS ***")
  message(STATUS "Generator:                    ${CMAKE_GENERATOR}")
  message(STATUS "Platform:                     ${CMAKE_SYSTEM_NAME}")
  message(STATUS "Project architecture:         ${PROJECT_ARCH}")

  if(GEN_NINJA OR GEN_MAKEFILES)
    message(STATUS "Build type:                   ${CMAKE_BUILD_TYPE}")
  endif()

  message(STATUS "Binary distribution root:     ${_CEF_ROOT}")

  if(OS_MACOSX)
    message(STATUS "Base SDK:                     ${CMAKE_OSX_SYSROOT}")
    message(STATUS "Target SDK:                   ${CEF_TARGET_SDK}")
  endif()

  if(OS_WINDOWS)
    message(STATUS "Visual Studio ATL support:    ${USE_ATL}")
  endif()

  message(STATUS "CEF sandbox:                  ${USE_SANDBOX}")

  set(_libraries ${CEF_STANDARD_LIBS})
  if(OS_WINDOWS AND USE_SANDBOX)
    list(APPEND _libraries ${CEF_SANDBOX_STANDARD_LIBS})
  endif()
  message(STATUS "Standard libraries:           ${_libraries}")

  message(STATUS "Compile defines:              ${CEF_COMPILER_DEFINES}")
  message(STATUS "Compile defines (Debug):      ${CEF_COMPILER_DEFINES_DEBUG}")
  message(STATUS "Compile defines (Release):    ${CEF_COMPILER_DEFINES_RELEASE}")
  message(STATUS "C compile flags:              ${CEF_COMPILER_FLAGS} ${CEF_C_COMPILER_FLAGS}")
  message(STATUS "C compile flags (Debug):      ${CEF_COMPILER_FLAGS_DEBUG} ${CEF_C_COMPILER_FLAGS_DEBUG}")
  message(STATUS "C compile flags (Release):    ${CEF_COMPILER_FLAGS_RELEASE} ${CEF_C_COMPILER_FLAGS_RELEASE}")
  message(STATUS "C++ compile flags:            ${CEF_COMPILER_FLAGS} ${CEF_CXX_COMPILER_FLAGS}")
  message(STATUS "C++ compile flags (Debug):    ${CEF_COMPILER_FLAGS_DEBUG} ${CEF_CXX_COMPILER_FLAGS_DEBUG}")
  message(STATUS "C++ compile flags (Release):  ${CEF_COMPILER_FLAGS_RELEASE} ${CEF_CXX_COMPILER_FLAGS_RELEASE}")
  message(STATUS "Exe link flags:               ${CEF_LINKER_FLAGS} ${CEF_EXE_LINKER_FLAGS}")
  message(STATUS "Exe link flags (Debug):       ${CEF_LINKER_FLAGS_DEBUG} ${CEF_EXE_LINKER_FLAGS_DEBUG}")
  message(STATUS "Exe link flags (Release):     ${CEF_LINKER_FLAGS_RELEASE} ${CEF_EXE_LINKER_FLAGS_RELEASE}")
  message(STATUS "Shared link flags:            ${CEF_LINKER_FLAGS} ${CEF_SHARED_LINKER_FLAGS}")
  message(STATUS "Shared link flags (Debug):    ${CEF_LINKER_FLAGS_DEBUG} ${CEF_SHARED_LINKER_FLAGS_DEBUG}")
  message(STATUS "Shared link flags (Release):  ${CEF_LINKER_FLAGS_RELEASE} ${CEF_SHARED_LINKER_FLAGS_RELEASE}")

  if(OS_LINUX OR OS_WINDOWS)
    message(STATUS "CEF Binary files:             ${CEF_BINARY_FILES}")
    message(STATUS "CEF Resource files:           ${CEF_RESOURCE_FILES}")
  endif()
endmacro()

# Append platform specific sources to a list of sources.
macro(APPEND_PLATFORM_SOURCES name_of_list)
  if(OS_LINUX AND ${name_of_list}_LINUX)
    list(APPEND ${name_of_list} ${${name_of_list}_LINUX})
  endif()
  if(OS_POSIX AND ${name_of_list}_POSIX)
    list(APPEND ${name_of_list} ${${name_of_list}_POSIX})
  endif()
  if(OS_WINDOWS AND ${name_of_list}_WINDOWS)
    list(APPEND ${name_of_list} ${${name_of_list}_WINDOWS})
  endif()
  if(OS_MACOSX AND ${name_of_list}_MACOSX)
    list(APPEND ${name_of_list} ${${name_of_list}_MACOSX})
  endif()
endmacro()

# Determine the target output directory based on platform and generator.
macro(SET_CEF_TARGET_OUT_DIR)
  if(GEN_NINJA OR GEN_MAKEFILES)
    # By default Ninja and Make builds don't create a subdirectory named after
    # the configuration.
    set(CEF_TARGET_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}")

    # Output binaries (executables, libraries) to the correct directory.
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CEF_TARGET_OUT_DIR})
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CEF_TARGET_OUT_DIR})
  else()
    set(CEF_TARGET_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
  endif()
endmacro()

# Copy a list of files from one directory to another. Relative files paths are maintained.
# The path component of the source |file_list| will be removed.
macro(COPY_FILES target file_list source_dir target_dir)
  foreach(FILENAME ${file_list})
    set(source_file ${source_dir}/${FILENAME})
    get_filename_component(target_name ${FILENAME} NAME)
    set(target_file ${target_dir}/${target_name})

    string(FIND ${source_file} "$<CONFIGURATION>" _pos)
    if(NOT ${_pos} EQUAL -1)
      # Must test with an actual configuration directory.
      string(REPLACE "$<CONFIGURATION>" "Release" existing_source_file ${source_file})
      if(NOT EXISTS ${existing_source_file})
        string(REPLACE "$<CONFIGURATION>" "Debug" existing_source_file ${source_file})
      endif()
    else()
      set(existing_source_file ${source_file})
    endif()

    if(IS_DIRECTORY ${existing_source_file})
      add_custom_command(
        TARGET ${target}
        POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_directory "${source_file}" "${target_file}"
        VERBATIM
        )
    else()
      add_custom_command(
        TARGET ${target}
        POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different "${source_file}" "${target_file}"
        VERBATIM
        )
    endif()
  endforeach()
endmacro()

#
# Linux macros.
#

if(OS_LINUX)

# Use pkg-config to find Linux libraries and update compiler/linker variables.
macro(FIND_LINUX_LIBRARIES libraries)
  # Read pkg-config info into variables.
  execute_process(COMMAND pkg-config --cflags ${libraries} OUTPUT_VARIABLE FLL_CFLAGS)
  execute_process(COMMAND pkg-config --libs-only-L --libs-only-other ${libraries} OUTPUT_VARIABLE FLL_LDFLAGS)
  execute_process(COMMAND pkg-config --libs-only-l ${libraries} OUTPUT_VARIABLE FLL_LIBS)

  # Strip leading and trailing whitepspace.
  STRING(STRIP "${FLL_CFLAGS}"  FLL_CFLAGS)
  STRING(STRIP "${FLL_LDFLAGS}" FLL_LDFLAGS)
  STRING(STRIP "${FLL_LIBS}"    FLL_LIBS)

  # Convert to a list.
  separate_arguments(FLL_CFLAGS)
  separate_arguments(FLL_LDFLAGS)
  separate_arguments(FLL_LIBS)

  # Update build variables.
  list(APPEND CEF_C_COMPILER_FLAGS    ${FLL_CFLAGS})
  list(APPEND CEF_CXX_COMPILER_FLAGS  ${FLL_CFLAGS})
  list(APPEND CEF_EXE_LINKER_FLAGS    ${FLL_LDFLAGS})
  list(APPEND CEF_SHARED_LINKER_FLAGS ${FLL_LDFLAGS})
  list(APPEND CEF_STANDARD_LIBS       ${FLL_LIBS})
endmacro()

# Set SUID permissions on the specified executable.
macro(SET_LINUX_SUID_PERMISSIONS target executable)
  add_custom_command(
    TARGET ${target}
    POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E echo ""
    COMMAND ${CMAKE_COMMAND} -E echo "*** Run the following command manually to set SUID permissions ***"
    COMMAND ${CMAKE_COMMAND} -E echo "EXE=\"${executable}\" && sudo -- chown root:root $EXE && sudo -- chmod 4755 $EXE"
    COMMAND ${CMAKE_COMMAND} -E echo ""
    VERBATIM
    )
endmacro()

endif(OS_LINUX)

#
# Mac OS X macros.
#

if(OS_MACOSX)

# Manually process and copy over resource files.
macro(COPY_MACOSX_RESOURCES resource_list prefix_list target source_dir app_path)
  foreach(FILENAME ${resource_list})
    # Remove one or more prefixes from the source paths.
    set(TARGET_FILENAME "${FILENAME}")
    foreach(PREFIX ${prefix_list})
      string(REGEX REPLACE "^.*${PREFIX}" "" TARGET_FILENAME ${TARGET_FILENAME})
    endforeach()

    # Determine the absolute source and target paths.
    set(TARGET_PATH "${app_path}/Contents/Resources/${TARGET_FILENAME}")
    if(IS_ABSOLUTE ${FILENAME})
      set(SOURCE_PATH ${FILENAME})
    else()
      set(SOURCE_PATH "${source_dir}/${FILENAME}")
    endif()

    if(${FILENAME} MATCHES ".xib$")
      # Change the target file extension.
      string(REGEX REPLACE ".xib$" ".nib" TARGET_PATH ${TARGET_PATH})

      get_filename_component(TARGET_DIRECTORY ${TARGET_PATH} PATH)
      add_custom_command(
        TARGET ${target}
        POST_BUILD
        # Create the target directory.
        COMMAND ${CMAKE_COMMAND} -E make_directory "${TARGET_DIRECTORY}"
        # Compile the XIB file to a NIB.
        COMMAND /usr/bin/ibtool --output-format binary1 --compile "${TARGET_PATH}" "${SOURCE_PATH}"
        VERBATIM
        )
    elseif(NOT ${TARGET_FILENAME} STREQUAL "Info.plist")
      # Copy the file as-is.
      add_custom_command(
        TARGET ${target}
        POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy "${SOURCE_PATH}" "${TARGET_PATH}"
        VERBATIM
        )
    endif()
  endforeach()
endmacro()

endif(OS_MACOSX)

#
# Windows macros.
#

if(OS_WINDOWS)

# Add custom manifest files to an executable target.
macro(ADD_WINDOWS_MANIFEST manifest_path target extension)
  add_custom_command(
    TARGET ${target}
    POST_BUILD
    COMMAND "mt.exe" -nologo
            -manifest \"${manifest_path}/${target}.${extension}.manifest\" \"${manifest_path}/compatibility.manifest\"
            -outputresource:"${CEF_TARGET_OUT_DIR}/${target}.${extension}"\;\#1
    COMMENT "Adding manifest..."
    )
endmacro()

endif(OS_WINDOWS)

#
# Target configuration macros.
#

# Add a logical target that can be used to link the specified libraries into an
# executable target.
macro(ADD_LOGICAL_TARGET target debug_lib release_lib)
  add_library(${target} ${CEF_LIBTYPE} IMPORTED)
  set_target_properties(${target} PROPERTIES
    IMPORTED_LOCATION "${release_lib}"
    IMPORTED_LOCATION_DEBUG "${debug_lib}"
    IMPORTED_LOCATION_RELEASE "${release_lib}"
    )
endmacro()

# Set common target properties. Use SET_LIBRARY_TARGET_PROPERTIES() or
# SET_EXECUTABLE_TARGET_PROPERTIES() instead of calling this macro directly.
macro(SET_COMMON_TARGET_PROPERTIES target)
  # Compile flags.
  target_compile_options(${target} PRIVATE ${CEF_COMPILER_FLAGS} ${CEF_CXX_COMPILER_FLAGS})
  target_compile_options(${target} PRIVATE $<$<CONFIG:Debug>:${CEF_COMPILER_FLAGS_DEBUG} ${CEF_CXX_COMPILER_FLAGS_DEBUG}>)
  target_compile_options(${target} PRIVATE $<$<CONFIG:Release>:${CEF_COMPILER_FLAGS_RELEASE} ${CEF_CXX_COMPILER_FLAGS_RELEASE}>)

  # Compile definitions.
  target_compile_definitions(${target} PRIVATE ${CEF_COMPILER_DEFINES})
  target_compile_definitions(${target} PRIVATE $<$<CONFIG:Debug>:${CEF_COMPILER_DEFINES_DEBUG}>)
  target_compile_definitions(${target} PRIVATE $<$<CONFIG:Release>:${CEF_COMPILER_DEFINES_RELEASE}>)

  # Include directories.
  target_include_directories(${target} PRIVATE ${CEF_INCLUDE_PATH})

  # Linker flags.
  if(CEF_LINKER_FLAGS)
    string(REPLACE ";" " " _flags_str "${CEF_LINKER_FLAGS}")
    set_property(TARGET ${target} PROPERTY LINK_FLAGS ${_flags_str})
  endif()
  if(CEF_LINKER_FLAGS_DEBUG)
    string(REPLACE ";" " " _flags_str "${CEF_LINKER_FLAGS_DEBUG}")
    set_property(TARGET ${target} PROPERTY LINK_FLAGS_DEBUG ${_flags_str})
  endif()
  if(CEF_LINKER_FLAGS_RELEASE)
    string(REPLACE ";" " " _flags_str "${CEF_LINKER_FLAGS_RELEASE}")
    set_property(TARGET ${target} PROPERTY LINK_FLAGS_RELEASE ${_flags_str})
  endif()

  if(OS_MACOSX)
    # Set Xcode target properties.
    set_target_properties(${target} PROPERTIES
      XCODE_ATTRIBUTE_ALWAYS_SEARCH_USER_PATHS                    NO
      XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD                 "gnu++11"   # -std=gnu++11
      XCODE_ATTRIBUTE_CLANG_LINK_OBJC_RUNTIME                     NO          # -fno-objc-link-runtime
      XCODE_ATTRIBUTE_CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS  YES         # -Wobjc-missing-property-synthesis
      XCODE_ATTRIBUTE_COPY_PHASE_STRIP                            NO
      XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING[variant=Release]        YES         # -Wl,-dead_strip
      XCODE_ATTRIBUTE_GCC_C_LANGUAGE_STANDARD                     "c99"       # -std=c99
      XCODE_ATTRIBUTE_GCC_CW_ASM_SYNTAX                           NO          # No -fasm-blocks
      XCODE_ATTRIBUTE_GCC_DYNAMIC_NO_PIC                          NO
      XCODE_ATTRIBUTE_GCC_ENABLE_CPP_EXCEPTIONS                   NO          # -fno-exceptions
      XCODE_ATTRIBUTE_GCC_ENABLE_CPP_RTTI                         NO          # -fno-rtti
      XCODE_ATTRIBUTE_GCC_ENABLE_PASCAL_STRINGS                   NO          # No -mpascal-strings
      XCODE_ATTRIBUTE_GCC_INLINES_ARE_PRIVATE_EXTERN              YES         # -fvisibility-inlines-hidden
      XCODE_ATTRIBUTE_GCC_OBJC_CALL_CXX_CDTORS                    YES         # -fobjc-call-cxx-cdtors
      XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN                  YES         # -fvisibility=hidden
      XCODE_ATTRIBUTE_GCC_THREADSAFE_STATICS                      NO          # -fno-threadsafe-statics
      XCODE_ATTRIBUTE_GCC_TREAT_WARNINGS_AS_ERRORS                YES         # -Werror
      XCODE_ATTRIBUTE_GCC_VERSION                                 "com.apple.compilers.llvm.clang.1_0"
      XCODE_ATTRIBUTE_GCC_WARN_ABOUT_MISSING_NEWLINE              YES         # -Wnewline-eof
      XCODE_ATTRIBUTE_USE_HEADERMAP                               NO
      OSX_ARCHITECTURES_DEBUG                                     "${CMAKE_OSX_ARCHITECTURES}"
      OSX_ARCHITECTURES_RELEASE                                   "${CMAKE_OSX_ARCHITECTURES}"
      )
  endif()
endmacro()

# Set library-specific properties.
macro(SET_LIBRARY_TARGET_PROPERTIES target)
  SET_COMMON_TARGET_PROPERTIES(${target})

  # Shared library linker flags.
  if(CEF_SHARED_LINKER_FLAGS)
    string(REPLACE ";" " " _flags_str "${CEF_SHARED_LINKER_FLAGS}")
    set_property(TARGET ${target} PROPERTY LINK_FLAGS ${_flags_str})
  endif()
  if(CEF_SHARED_LINKER_FLAGS_DEBUG)
    string(REPLACE ";" " " _flags_str "${CEF_SHARED_LINKER_FLAGS_DEBUG}")
    set_property(TARGET ${target} PROPERTY LINK_FLAGS_DEBUG ${_flags_str})
  endif()
  if(CEF_SHARED_LINKER_FLAGS_RELEASE)
    string(REPLACE ";" " " _flags_str "${CEF_SHARED_LINKER_FLAGS_RELEASE}")
    set_property(TARGET ${target} PROPERTY LINK_FLAGS_RELEASE ${_flags_str})
  endif()
endmacro()

# Set executable-specific properties.
macro(SET_EXECUTABLE_TARGET_PROPERTIES target)
  SET_COMMON_TARGET_PROPERTIES(${target})

  # Executable linker flags.
  if(CEF_EXE_LINKER_FLAGS)
    string(REPLACE ";" " " _flags_str "${CEF_EXE_LINKER_FLAGS}")
    set_property(TARGET ${target} PROPERTY LINK_FLAGS ${_flags_str})
  endif()
  if(CEF_EXE_LINKER_FLAGS_DEBUG)
    string(REPLACE ";" " " _flags_str "${CEF_EXE_LINKER_FLAGS_DEBUG}")
    set_property(TARGET ${target} PROPERTY LINK_FLAGS_DEBUG ${_flags_str})
  endif()
  if(CEF_EXE_LINKER_FLAGS_RELEASE)
    string(REPLACE ";" " " _flags_str "${CEF_EXE_LINKER_FLAGS_RELEASE}")
    set_property(TARGET ${target} PROPERTY LINK_FLAGS_RELEASE ${_flags_str})
  endif()
endmacro()


code:
# Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.

# Must be loaded via FindCEF.cmake.
if(NOT DEFINED _CEF_ROOT_EXPLICIT)
  message(FATAL_ERROR "Use find_package(CEF) to load this file.")
endif()

#
# Shared configuration.
#

# Determine the platform.
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
  set(OS_MACOSX 1)
  set(OS_POSIX 1)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
  set(OS_LINUX 1)
  set(OS_POSIX 1)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
  set(OS_WINDOWS 1)
endif()

# Determine the project architecture.
if(NOT DEFINED PROJECT_ARCH)
  if(CMAKE_SIZEOF_VOID_P MATCHES 8)
    set(PROJECT_ARCH "x86_64")
  else()
    set(PROJECT_ARCH "x86")
  endif()

  if(OS_MACOSX)
    # PROJECT_ARCH should be specified on Mac OS X.
    message(WARNING "No PROJECT_ARCH value specified, using ${PROJECT_ARCH}")
  endif()
endif()

if(${CMAKE_GENERATOR} STREQUAL "Ninja")
  set(GEN_NINJA 1)
elseif(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")
  set(GEN_MAKEFILES 1)
endif()

# Determine the build type.
if(NOT CMAKE_BUILD_TYPE AND (GEN_NINJA OR GEN_MAKEFILES))
  # CMAKE_BUILD_TYPE should be specified when using Ninja or Unix Makefiles.
  set(CMAKE_BUILD_TYPE Release)
  message(WARNING "No CMAKE_BUILD_TYPE value selected, using ${CMAKE_BUILD_TYPE}")
endif()

# Path to the include directory.
set(CEF_INCLUDE_PATH "${_CEF_ROOT}")

# Path to the libcef_dll_wrapper target.
set(CEF_LIBCEF_DLL_WRAPPER_PATH "${_CEF_ROOT}/libcef_dll")

# Shared compiler/linker flags.
list(APPEND CEF_COMPILER_DEFINES
  # Allow C++ programs to use stdint.h macros specified in the C99 standard that aren't
  # in the C++ standard (e.g. UINT8_MAX, INT64_MIN, etc)
  __STDC_CONSTANT_MACROS __STDC_FORMAT_MACROS
  )

# Configure use of the sandbox.
option(USE_SANDBOX "Enable or disable use of the sandbox." ON)

#
# Linux configuration.
#

if(OS_LINUX)
  # Platform-specific compiler/linker flags.
  set(CEF_LIBTYPE SHARED)
  list(APPEND CEF_COMPILER_FLAGS
    -fno-strict-aliasing            # Avoid assumptions regarding non-aliasing of objects of different types
    -fPIC                           # Generate position-independent code for shared libraries
    -fstack-protector               # Protect some vulnerable functions from stack-smashing (security feature)
    -funwind-tables                 # Support stack unwinding for backtrace()
    -fvisibility=hidden             # Give hidden visibility to declarations that are not explicitly marked as visible
    --param=ssp-buffer-size=4       # Set the minimum buffer size protected by SSP (security feature, related to stack-protector)
    -pipe                           # Use pipes rather than temporary files for communication between build stages
    -pthread                        # Use the pthread library
    -Wall                           # Enable all warnings
    -Werror                         # Treat warnings as errors
    -Wno-missing-field-initializers # Don't warn about missing field initializers
    -Wno-unused-parameter           # Don't warn about unused parameters
    -Wno-error=comment              # Don't warn about code in comments
    -Wno-comment                    # Don't warn about code in comments
    )
  list(APPEND CEF_C_COMPILER_FLAGS
    -std=c99                        # Use the C99 language standard
    )
  list(APPEND CEF_CXX_COMPILER_FLAGS
    -fno-exceptions                 # Disable exceptions
    -fno-rtti                       # Disable real-time type information
    -fno-threadsafe-statics         # Don't generate thread-safe statics
    -fvisibility-inlines-hidden     # Give hidden visibility to inlined class member functions
    -std=gnu++11                    # Use the C++11 language standard including GNU extensions
    -Wsign-compare                  # Warn about mixed signed/unsigned type comparisons
    )
  list(APPEND CEF_COMPILER_FLAGS_DEBUG
    -O0                             # Disable optimizations
    -g                              # Generate debug information
    )
  list(APPEND CEF_COMPILER_FLAGS_RELEASE
    -O2                             # Optimize for maximum speed
    -fdata-sections                 # Enable linker optimizations to improve locality of reference for data sections
    -ffunction-sections             # Enable linker optimizations to improve locality of reference for function sections
    -fno-ident                      # Ignore the #ident directive
    -U_FORTIFY_SOURCE               # Undefine _FORTIFY_SOURCE in case it was previously defined
    -D_FORTIFY_SOURCE=2             # Add memory and string function protection (security feature, related to stack-protector)
    )
  list(APPEND CEF_LINKER_FLAGS
    -fPIC                           # Generate position-independent code for shared libraries
    -pthread                        # Use the pthread library
    -Wl,--disable-new-dtags         # Don't generate new-style dynamic tags in ELF
    -Wl,--fatal-warnings            # Treat warnings as errors
    -Wl,-rpath,.                    # Set rpath so that libraries can be placed next to the executable
    -Wl,-z,noexecstack              # Mark the stack as non-executable (security feature)
    -Wl,-z,now                      # Resolve symbols on program start instead of on first use (security feature)
    -Wl,-z,relro                    # Mark relocation sections as read-only (security feature)
    )
  list(APPEND CEF_LINKER_FLAGS_RELEASE
    -Wl,-O1                         # Enable linker optimizations
    -Wl,--as-needed                 # Only link libraries that export symbols used by the binary
    -Wl,--gc-sections               # Remove unused code resulting from -fdata-sections and -function-sections
    )
  list(APPEND CEF_COMPILER_DEFINES
    _FILE_OFFSET_BITS=64            # Allow the Large File Support (LFS) interface to replace the old interface
    )
  list(APPEND CEF_COMPILER_DEFINES_RELEASE
    NDEBUG                          # Not a debug build
    )

  include(CheckCCompilerFlag)
  include(CheckCXXCompilerFlag)

  CHECK_CXX_COMPILER_FLAG(-Wno-undefined-var-template COMPILER_SUPPORTS_NO_UNDEFINED_VAR_TEMPLATE)
  if(COMPILER_SUPPORTS_NO_UNDEFINED_VAR_TEMPLATE)
    list(APPEND CEF_CXX_COMPILER_FLAGS
      -Wno-undefined-var-template   # Don't warn about potentially uninstantiated static members
      )
  endif()

  CHECK_C_COMPILER_FLAG(-Wno-unused-local-typedefs COMPILER_SUPPORTS_NO_UNUSED_LOCAL_TYPEDEFS)
  if(COMPILER_SUPPORTS_NO_UNUSED_LOCAL_TYPEDEFS)
    list(APPEND CEF_C_COMPILER_FLAGS
      -Wno-unused-local-typedefs  # Don't warn about unused local typedefs
      )
  endif()

  CHECK_CXX_COMPILER_FLAG(-Wno-literal-suffix COMPILER_SUPPORTS_NO_LITERAL_SUFFIX)
  if(COMPILER_SUPPORTS_NO_LITERAL_SUFFIX)
    list(APPEND CEF_CXX_COMPILER_FLAGS
      -Wno-literal-suffix         # Don't warn about invalid suffixes on literals
      )
  endif()

  CHECK_CXX_COMPILER_FLAG(-Wno-narrowing COMPILER_SUPPORTS_NO_NARROWING)
  if(COMPILER_SUPPORTS_NO_NARROWING)
    list(APPEND CEF_CXX_COMPILER_FLAGS
      -Wno-narrowing              # Don't warn about type narrowing
      )
  endif()

  if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
    list(APPEND CEF_CXX_COMPILER_FLAGS
      -Wno-attributes             # The cfi-icall attribute is not supported by the GNU C++ compiler
      )
  endif()

  if(PROJECT_ARCH STREQUAL "x86_64")
    # 64-bit architecture.
    list(APPEND CEF_COMPILER_FLAGS
      -m64
      -march=x86-64
      )
    list(APPEND CEF_LINKER_FLAGS
      -m64
      )
  elseif(PROJECT_ARCH STREQUAL "x86")
    # 32-bit architecture.
    list(APPEND CEF_COMPILER_FLAGS
      -msse2
      -mfpmath=sse
      -mmmx
      -m32
      )
    list(APPEND CEF_LINKER_FLAGS
      -m32
      )
  endif()

  # Standard libraries.
  set(CEF_STANDARD_LIBS
    X11
    )

  # CEF directory paths.
  set(CEF_RESOURCE_DIR        "${_CEF_ROOT}/Resources")
  set(CEF_BINARY_DIR          "${_CEF_ROOT}/${CMAKE_BUILD_TYPE}")
  set(CEF_BINARY_DIR_DEBUG    "${_CEF_ROOT}/Debug")
  set(CEF_BINARY_DIR_RELEASE  "${_CEF_ROOT}/Release")

  # CEF library paths.
  set(CEF_LIB_DEBUG   "${CEF_BINARY_DIR_DEBUG}/libcef.so")
  set(CEF_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/libcef.so")

  # List of CEF binary files.
  set(CEF_BINARY_FILES
    chrome-sandbox
    libcef.so
    libEGL.so
    libGLESv2.so
    natives_blob.bin
    snapshot_blob.bin
    v8_context_snapshot.bin
    swiftshader
    )

  # List of CEF resource files.
  set(CEF_RESOURCE_FILES
    cef.pak
    cef_100_percent.pak
    cef_200_percent.pak
    cef_extensions.pak
    devtools_resources.pak
    icudtl.dat
    locales
    )

  if(USE_SANDBOX)
    list(APPEND CEF_COMPILER_DEFINES
      CEF_USE_SANDBOX   # Used by apps to test if the sandbox is enabled
      )
  endif()
endif()

#
# Mac OS X configuration.
#

if(OS_MACOSX)
  # Platform-specific compiler/linker flags.
  # See also Xcode target properties in cef_macros.cmake.
  set(CEF_LIBTYPE SHARED)
  list(APPEND CEF_COMPILER_FLAGS
    -fno-strict-aliasing            # Avoid assumptions regarding non-aliasing of objects of different types
    -fstack-protector               # Protect some vulnerable functions from stack-smashing (security feature)
    -funwind-tables                 # Support stack unwinding for backtrace()
    -fvisibility=hidden             # Give hidden visibility to declarations that are not explicitly marked as visible
    -Wall                           # Enable all warnings
    -Werror                         # Treat warnings as errors
    -Wextra                         # Enable additional warnings
    -Wendif-labels                  # Warn whenever an #else or an #endif is followed by text
    -Wnewline-eof                   # Warn about no newline at end of file
    -Wno-missing-field-initializers # Don't warn about missing field initializers
    -Wno-unused-parameter           # Don't warn about unused parameters
    )
  list(APPEND CEF_C_COMPILER_FLAGS
    -std=c99                        # Use the C99 language standard
    )
  list(APPEND CEF_CXX_COMPILER_FLAGS
    -fno-exceptions                 # Disable exceptions
    -fno-rtti                       # Disable real-time type information
    -fno-threadsafe-statics         # Don't generate thread-safe statics
    -fobjc-call-cxx-cdtors          # Call the constructor/destructor of C++ instance variables in ObjC objects
    -fvisibility-inlines-hidden     # Give hidden visibility to inlined class member functions
    -std=gnu++11                    # Use the C++11 language standard including GNU extensions
    -Wno-narrowing                  # Don't warn about type narrowing
    -Wsign-compare                  # Warn about mixed signed/unsigned type comparisons
    )
  list(APPEND CEF_COMPILER_FLAGS_DEBUG
    -O0                             # Disable optimizations
    -g                              # Generate debug information
    )
  list(APPEND CEF_COMPILER_FLAGS_RELEASE
    -O3                             # Optimize for maximum speed plus a few extras
    )
  list(APPEND CEF_LINKER_FLAGS
    -Wl,-search_paths_first         # Search for static or shared library versions in the same pass
    -Wl,-ObjC                       # Support creation of ObjC static libraries
    -Wl,-pie                        # Generate position-independent code suitable for executables only
    )
  list(APPEND CEF_LINKER_FLAGS_RELEASE
    -Wl,-dead_strip                 # Strip dead code
    )

  include(CheckCXXCompilerFlag)

  CHECK_CXX_COMPILER_FLAG(-Wno-undefined-var-template COMPILER_SUPPORTS_NO_UNDEFINED_VAR_TEMPLATE)
  if(COMPILER_SUPPORTS_NO_UNDEFINED_VAR_TEMPLATE)
    list(APPEND CEF_CXX_COMPILER_FLAGS
      -Wno-undefined-var-template   # Don't warn about potentially uninstantiated static members
      )
  endif()

  # Standard libraries.
  set(CEF_STANDARD_LIBS
    -lpthread
    "-framework Cocoa"
    "-framework AppKit"
    )

  # Find the newest available base SDK.
  execute_process(COMMAND xcode-select --print-path OUTPUT_VARIABLE XCODE_PATH OUTPUT_STRIP_TRAILING_WHITESPACE)
  foreach(OS_VERSION 10.11 10.10 10.9)
    set(SDK "${XCODE_PATH}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${OS_VERSION}.sdk")
    if(NOT "${CMAKE_OSX_SYSROOT}" AND EXISTS "${SDK}" AND IS_DIRECTORY "${SDK}")
      set(CMAKE_OSX_SYSROOT ${SDK})
    endif()
  endforeach()

  # Target SDK.
  set(CEF_TARGET_SDK               "10.9")
  list(APPEND CEF_COMPILER_FLAGS
    -mmacosx-version-min=${CEF_TARGET_SDK}
  )
  set(CMAKE_OSX_DEPLOYMENT_TARGET  ${CEF_TARGET_SDK})

  # Target architecture.
  if(PROJECT_ARCH STREQUAL "x86_64")
    set(CMAKE_OSX_ARCHITECTURES "x86_64")
  else()
    set(CMAKE_OSX_ARCHITECTURES "i386")
  endif()

  # CEF directory paths.
  set(CEF_BINARY_DIR          "${_CEF_ROOT}/$<CONFIGURATION>")
  set(CEF_BINARY_DIR_DEBUG    "${_CEF_ROOT}/Debug")
  set(CEF_BINARY_DIR_RELEASE  "${_CEF_ROOT}/Release")

  if(USE_SANDBOX)
    list(APPEND CEF_COMPILER_DEFINES
      CEF_USE_SANDBOX   # Used by apps to test if the sandbox is enabled
      )

    # CEF sandbox library paths.
    set(CEF_SANDBOX_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/cef_sandbox.a")
    set(CEF_SANDBOX_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/cef_sandbox.a")
  endif()
endif()

#
# Windows configuration.
#

if(OS_WINDOWS)
  if (GEN_NINJA)
    # When using the Ninja generator clear the CMake defaults to avoid excessive
    # console warnings (see issue #2120).
    set(CMAKE_CXX_FLAGS "")
    set(CMAKE_CXX_FLAGS_DEBUG "")
    set(CMAKE_CXX_FLAGS_RELEASE "")
  endif()

  if(USE_SANDBOX)
    # Check if the current MSVC version is compatible with the cef_sandbox.lib
    # static library. For a list of all version numbers see
    # https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering
    list(APPEND supported_msvc_versions
      1900  # VS2015 and updates 1, 2, & 3
      1910  # VS2017 version 15.1 & 15.2
      1911  # VS2017 version 15.3 & 15.4
      1912  # VS2017 version 15.5
      1913  # VS2017 version 15.6
      1914  # VS2017 version 15.7
      1915  # VS2017 version 15.8
      1916  # VS2017 version 15.9
      1920  # VS2019 version 16.0
      1921  # VS2018 version 16.1
      )
    list(FIND supported_msvc_versions ${MSVC_VERSION} _index)
    if (${_index} EQUAL -1)
      message(WARNING "CEF sandbox is not compatible with the current MSVC version (${MSVC_VERSION})")
      set(USE_SANDBOX OFF)
    endif()
  endif()

  # Consumers who run into LNK4099 warnings can pass /Z7 instead (see issue #385).
  set(CEF_DEBUG_INFO_FLAG "/Zi" CACHE STRING "Optional flag specifying specific /Z flag to use")

  # Consumers using different runtime types may want to pass different flags
  set(CEF_RUNTIME_LIBRARY_FLAG "/MT" CACHE STRING "Optional flag specifying which runtime to use")
  if (CEF_RUNTIME_LIBRARY_FLAG)
    list(APPEND CEF_COMPILER_FLAGS_DEBUG ${CEF_RUNTIME_LIBRARY_FLAG}d)
    list(APPEND CEF_COMPILER_FLAGS_RELEASE ${CEF_RUNTIME_LIBRARY_FLAG})
  endif()

  # Platform-specific compiler/linker flags.
  set(CEF_LIBTYPE STATIC)
  list(APPEND CEF_COMPILER_FLAGS
    /MP           # Multiprocess compilation
    /Gy           # Enable function-level linking
    /GR-          # Disable run-time type information
    /W4           # Warning level 4
    /WX           # Treat warnings as errors
    /wd4100       # Ignore "unreferenced formal parameter" warning
    /wd4127       # Ignore "conditional expression is constant" warning
    /wd4244       # Ignore "conversion possible loss of data" warning
    /wd4481       # Ignore "nonstandard extension used: override" warning
    /wd4512       # Ignore "assignment operator could not be generated" warning
    /wd4701       # Ignore "potentially uninitialized local variable" warning
    /wd4702       # Ignore "unreachable code" warning
    /wd4996       # Ignore "function or variable may be unsafe" warning
    ${CEF_DEBUG_INFO_FLAG}
    )
  list(APPEND CEF_COMPILER_FLAGS_DEBUG
    /RTC1         # Disable optimizations
    /Od           # Enable basic run-time checks
    )
  list(APPEND CEF_COMPILER_FLAGS_RELEASE
    /O2           # Optimize for maximum speed
    /Ob2          # Inline any suitable function
    /GF           # Enable string pooling
    )
  list(APPEND CEF_LINKER_FLAGS_DEBUG
    /DEBUG        # Generate debug information
    )
  list(APPEND CEF_EXE_LINKER_FLAGS
    /MANIFEST:NO        # No default manifest (see ADD_WINDOWS_MANIFEST macro usage)
    /LARGEADDRESSAWARE  # Allow 32-bit processes to access 3GB of RAM
    )
  list(APPEND CEF_COMPILER_DEFINES
    WIN32 _WIN32 _WINDOWS             # Windows platform
    UNICODE _UNICODE                  # Unicode build
    WINVER=0x0601 _WIN32_WINNT=0x601  # Targeting Windows 7
    NOMINMAX                          # Use the standard's templated min/max
    WIN32_LEAN_AND_MEAN               # Exclude less common API declarations
    _HAS_EXCEPTIONS=0                 # Disable exceptions
    )
  list(APPEND CEF_COMPILER_DEFINES_RELEASE
    NDEBUG _NDEBUG                    # Not a debug build
    )

  # Standard libraries.
  set(CEF_STANDARD_LIBS
    comctl32.lib
    rpcrt4.lib
    shlwapi.lib
    ws2_32.lib
    )

  # CEF directory paths.
  set(CEF_RESOURCE_DIR        "${_CEF_ROOT}/Resources")
  set(CEF_BINARY_DIR          "${_CEF_ROOT}/$<CONFIGURATION>")
  set(CEF_BINARY_DIR_DEBUG    "${_CEF_ROOT}/Debug")
  set(CEF_BINARY_DIR_RELEASE  "${_CEF_ROOT}/Release")

  # CEF library paths.
  set(CEF_LIB_DEBUG   "${CEF_BINARY_DIR_DEBUG}/libcef.lib")
  set(CEF_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/libcef.lib")

  # List of CEF binary files.
  set(CEF_BINARY_FILES
    chrome_elf.dll
    d3dcompiler_47.dll
    libcef.dll
    libEGL.dll
    libGLESv2.dll
    natives_blob.bin
    snapshot_blob.bin
    v8_context_snapshot.bin
    swiftshader
    )

  # List of CEF resource files.
  set(CEF_RESOURCE_FILES
    cef.pak
    cef_100_percent.pak
    cef_200_percent.pak
    cef_extensions.pak
    devtools_resources.pak
    icudtl.dat
    locales
    )

  if(USE_SANDBOX)
    list(APPEND CEF_COMPILER_DEFINES
      PSAPI_VERSION=1   # Required by cef_sandbox.lib
      CEF_USE_SANDBOX   # Used by apps to test if the sandbox is enabled
      )

    # Libraries required by cef_sandbox.lib.
    set(CEF_SANDBOX_STANDARD_LIBS
      dbghelp.lib
      psapi.lib
      version.lib
      wbemuuid.lib
      winmm.lib
      )

    # CEF sandbox library paths.
    set(CEF_SANDBOX_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/cef_sandbox.lib")
    set(CEF_SANDBOX_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/cef_sandbox.lib")
  endif()

  # Configure use of ATL.
  option(USE_ATL "Enable or disable use of ATL." ON)
  if(USE_ATL)
    # Locate the atlmfc directory if it exists. It may be at any depth inside
    # the VC directory. The cl.exe path returned by CMAKE_CXX_COMPILER may also
    # be at different depths depending on the toolchain version
    # (e.g. "VC/bin/cl.exe", "VC/bin/amd64_x86/cl.exe",
    # "VC/Tools/MSVC/14.10.25017/bin/HostX86/x86/cl.exe", etc).
    set(HAS_ATLMFC 0)
    get_filename_component(VC_DIR ${CMAKE_CXX_COMPILER} DIRECTORY)
    get_filename_component(VC_DIR_NAME ${VC_DIR} NAME)
    while(NOT ${VC_DIR_NAME} STREQUAL "VC")
      get_filename_component(VC_DIR ${VC_DIR} DIRECTORY)
      if(IS_DIRECTORY "${VC_DIR}/atlmfc")
        set(HAS_ATLMFC 1)
        break()
      endif()
      get_filename_component(VC_DIR_NAME ${VC_DIR} NAME)
    endwhile()

    # Determine if the Visual Studio install supports ATL.
    if(NOT HAS_ATLMFC)
      message(WARNING "ATL is not supported by your VC installation.")
      set(USE_ATL OFF)
    endif()
  endif()

  if(USE_ATL)
    list(APPEND CEF_COMPILER_DEFINES
      CEF_USE_ATL   # Used by apps to test if ATL support is enabled
      )
  endif()
endif()


code:
@ECHO OFF
REM Quickly rebuild 64-bit VS2015 solution/project files from the CMake files.

cmake -G "Visual Studio 14 Win64"
pause


code:
# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.

#
# Source files.
#

# fchost sources.
set(FCHOST_SRCS
  fchost_app.cc
  fchost_app.h
  fchost_handler.cc
  fchost_handler.h
  fchost_storage.cc
  fchost_storage.h
  fchost_storage_js.cc
  fchost_storage_js.h
  )
set(FCHOST_SRCS_LINUX
  fchost_linux.cc
  fchost_handler_linux.cc
  )
set(FCHOST_SRCS_MACOSX
  fchost_mac.mm
  fchost_handler_mac.mm
  )
set(FCHOST_SRCS_WINDOWS
  fchost.exe.manifest
  fchost.rc
  fchost_win.cc
  resource.h
  fchost_handler_win.cc
  )
APPEND_PLATFORM_SOURCES(FCHOST_SRCS)
source_group(fchost FILES ${FCHOST_SRCS})

set(FCHOST_RES_SRCS_WINDOWS
  res/fchost.ico
  )
APPEND_PLATFORM_SOURCES(FCHOST_RES_SRCS)
source_group(fchost\\\\res FILES ${FCHOST_RES_SRCS})

set(FCHOST_SRCS
  ${FCHOST_SRCS}
  ${FCHOST_RES_SRCS}
  )

# fchost helper sources.
set(FCHOST_HELPER_SRCS_MACOSX
  process_helper_mac.cc
  )
APPEND_PLATFORM_SOURCES(FCHOST_HELPER_SRCS)
source_group(fchost FILES ${FCHOST_HELPER_SRCS})

# fchost resources.
set(FCHOST_RESOURCES_MAC_SRCS_MACOSX
  mac/Info.plist
  mac/fchost.icns
  )
APPEND_PLATFORM_SOURCES(FCHOST_RESOURCES_MAC_SRCS)
source_group(fchost\\\\mac FILES ${FCHOST_RESOURCES_MAC_SRCS})

set(FCHOST_RESOURCES_MAC_ENGLISH_LPROJ_SRCS_MACOSX
  mac/English.lproj/InfoPlist.strings
  mac/English.lproj/MainMenu.xib
  )
APPEND_PLATFORM_SOURCES(FCHOST_RESOURCES_MAC_ENGLISH_LPROJ_SRCS)
source_group(fchost\\\\mac\\\\English.lproj FILES ${FCHOST_RESOURCES_MAC_ENGLISH_LPROJ_SRCS})

set(FCHOST_RESOURCES_SRCS
  ${FCHOST_RESOURCES_MAC_SRCS}
  ${FCHOST_RESOURCES_MAC_ENGLISH_LPROJ_SRCS}
  )

#
# Shared configuration.
#

# Target executable names.
set(CEF_TARGET "fchost")
if(OS_MACOSX)
  set(CEF_HELPER_TARGET "fchost_Helper")
  set(CEF_HELPER_OUTPUT_NAME "fchost Helper")
else()
  # Logical target used to link the libcef library.
  ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
endif()

# Determine the target output directory.
SET_CEF_TARGET_OUT_DIR()

#
# Linux configuration.
#

if(OS_LINUX)
  # Executable target.
  add_executable(${CEF_TARGET} ${FCHOST_SRCS})
  SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
  add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
  target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS})

  # Set rpath so that libraries can be placed next to the executable.
  set_target_properties(${CEF_TARGET} PROPERTIES INSTALL_RPATH "$ORIGIN")
  set_target_properties(${CEF_TARGET} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
  set_target_properties(${CEF_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CEF_TARGET_OUT_DIR})

  # Copy binary and resource files to the target output directory.
  COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
  COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
  if (EXISTS "${CEF_BINARY_DIR}/libminigbm.so")
    COPY_FILES("${CEF_TARGET}" "libminigbm.so" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
  endif()
endif()

#
# Mac OS X configuration.
#

if(OS_MACOSX)
  option(OPTION_USE_ARC "Build with ARC (automatic Reference Counting) on macOS." ON)
  if(OPTION_USE_ARC)
    list(APPEND CEF_COMPILER_FLAGS
      -fobjc-arc
      )
    set_target_properties(${target} PROPERTIES
      CLANG_ENABLE_OBJC_ARC "YES"
      )
  endif()

  # Output paths for the app bundles.
  set(CEF_APP "${CEF_TARGET_OUT_DIR}/${CEF_TARGET}.app")
  set(CEF_HELPER_APP "${CEF_TARGET_OUT_DIR}/${CEF_HELPER_OUTPUT_NAME}.app")

  # Variable referenced from Info.plist files.
  set(PRODUCT_NAME "${CEF_TARGET}")

  # Helper executable target.
  add_executable(${CEF_HELPER_TARGET} MACOSX_BUNDLE ${FCHOST_HELPER_SRCS})
  SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_HELPER_TARGET})
  add_dependencies(${CEF_HELPER_TARGET} libcef_dll_wrapper)
  target_link_libraries(${CEF_HELPER_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS})
  set_target_properties(${CEF_HELPER_TARGET} PROPERTIES
    MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/helper-Info.plist
    OUTPUT_NAME ${CEF_HELPER_OUTPUT_NAME}
    )

  # Main executable target.
  add_executable(${CEF_TARGET} MACOSX_BUNDLE ${FCHOST_RESOURCES_SRCS} ${FCHOST_SRCS})
  SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
  add_dependencies(${CEF_TARGET} libcef_dll_wrapper "${CEF_HELPER_TARGET}")
  target_link_libraries(${CEF_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS})
  set_target_properties(${CEF_TARGET} PROPERTIES
    MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist
    )

  # Copy files into the main app bundle.
  add_custom_command(
    TARGET ${CEF_TARGET}
    POST_BUILD
    # Copy the helper app bundle into the Frameworks directory.
    COMMAND ${CMAKE_COMMAND} -E copy_directory
            "${CEF_HELPER_APP}"
            "${CEF_APP}/Contents/Frameworks/${CEF_HELPER_OUTPUT_NAME}.app"
    # Copy the CEF framework into the Frameworks directory.
    COMMAND ${CMAKE_COMMAND} -E copy_directory
            "${CEF_BINARY_DIR}/Chromium Embedded Framework.framework"
            "${CEF_APP}/Contents/Frameworks/Chromium Embedded Framework.framework"
    VERBATIM
    )

  # Manually process and copy over resource files.
  # The Xcode generator can support this via the set_target_properties RESOURCE
  # directive but that doesn't properly handle nested resource directories.
  # Remove these prefixes from input file paths.
  set(PREFIXES "mac/")
  COPY_MACOSX_RESOURCES("${FCHOST_RESOURCES_SRCS}" "${PREFIXES}" "${CEF_TARGET}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_APP}")
endif()

#
# Windows configuration.
#

if(OS_WINDOWS)
  # Executable target.
  add_executable(${CEF_TARGET} WIN32 ${FCHOST_SRCS})
  add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
  SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
  target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS})

  # Add the custom manifest files to the executable.
  ADD_WINDOWS_MANIFEST("${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_TARGET}" "exe")

  # Copy binary and resource files to the target output directory.
  COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
  COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
  COPY_FILES("${CEF_TARGET}" "FC_pregmod.html" "../../bin" "${CEF_TARGET_OUT_DIR}")
endif()


code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!--The ID below indicates application support for Windows Vista -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
      <!--The ID below indicates application support for Windows 7 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <!--The ID below indicates application support for Windows 8 -->
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <!--The ID below indicates application support for Windows 8.1 -->
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <!--The ID below indicates application support for Windows 10 -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
    </application>
  </compatibility>
</assembly>


code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

  <!--The compatibility section will be merged from build/win/compatibility.manifest -->

  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
    </dependentAssembly>
  </dependency>

  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" />
      </requestedPrivileges>
    </security>
  </trustInfo>

</assembly>


code:
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "fchost_app.h"

#include <string>

#include "include/cef_browser.h"
#include "include/cef_command_line.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_helpers.h"
#include "fchost_handler.h"
#include "fchost_storage_js.h"

namespace {

// When using the Views framework this object provides the delegate
// implementation for the CefWindow that hosts the Views-based browser.
class SimpleWindowDelegate : public CefWindowDelegate {
 public:
  explicit SimpleWindowDelegate(CefRefPtr<CefBrowserView> browser_view)
      : browser_view_(browser_view) {}

  void OnWindowCreated(CefRefPtr<CefWindow> window) OVERRIDE {
    // Add the browser view and show the window.
    window->AddChildView(browser_view_);
    window->Show();

    // Give keyboard focus to the browser view.
    browser_view_->RequestFocus();
  }

  void OnWindowDestroyed(CefRefPtr<CefWindow> window) OVERRIDE {
    browser_view_ = NULL;
  }

  bool CanClose(CefRefPtr<CefWindow> window) OVERRIDE {
    // Allow the window to close if the browser says it's OK.
    CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
    if (browser)
      return browser->GetHost()->TryCloseBrowser();
    return true;
  }

  CefSize GetPreferredSize(CefRefPtr<CefView> view) OVERRIDE {
    return CefSize(800, 600);
  }

 private:
  CefRefPtr<CefBrowserView> browser_view_;

  IMPLEMENT_REFCOUNTING(SimpleWindowDelegate);
  DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate);
};

}  // namespace

FCHostApp::FCHostApp() {}

void FCHostApp::OnContextInitialized() {
  CEF_REQUIRE_UI_THREAD();

  CefRefPtr<CefCommandLine> command_line =
      CefCommandLine::GetGlobalCommandLine();

#if defined(OS_WIN) || defined(OS_LINUX)
  // Create the browser using the Views framework if "--use-views" is specified
  // via the command-line. Otherwise, create the browser using the native
  // platform framework. The Views framework is currently only supported on
  // Windows and Linux.
  const bool use_views = command_line->HasSwitch("use-views");
#else
  const bool use_views = false;
#endif

  // FCHostHandler implements browser-level callbacks.
  CefRefPtr<FCHostHandler> handler(new FCHostHandler(use_views));

  // Specify CEF browser settings here.
  CefBrowserSettings browser_settings;

  // Persist local storage
  browser_settings.local_storage = STATE_ENABLED;

  // For now, read from external file.  Probably want to make this a resource
  // at least on Windows.
#if defined(OS_WIN)
  wchar_t target_path[_MAX_PATH];
  GetModuleFileNameW(NULL, target_path, _MAX_PATH);
  std::wstring url = target_path;
  size_t pos = url.find_last_of(L"\\/");
  url = url.substr(0, pos);
  url += L"/FC_pregmod.html";
#else
  #error "Platform-specific code needed"
#endif

  // Allow some access flexibility for our local file
  browser_settings.file_access_from_file_urls = STATE_ENABLED;
  browser_settings.universal_access_from_file_urls = STATE_ENABLED;

  if (use_views) {
    // Create the BrowserView.
    CefRefPtr<CefBrowserView> browser_view = CefBrowserView::CreateBrowserView(
        handler, url, browser_settings, NULL, NULL, NULL);

    // Create the Window. It will show itself after creation.
    CefWindow::CreateTopLevelWindow(new SimpleWindowDelegate(browser_view));
  } else {
    // Information used when creating the native window.
    CefWindowInfo window_info;

#if defined(OS_WIN)
    // On Windows we need to specify certain flags that will be passed to
    // CreateWindowEx().
    window_info.SetAsPopup(NULL, "FCHost");
#endif

    // Create the first browser window.
    CefBrowserHost::CreateBrowser(window_info, handler, url, browser_settings,
                                  NULL, NULL);
  }
}

void FCHostApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) {
	FCHostStorageRegister(GetLocalStorePath().ToWString() + L"/FCHostPersistentStorage", context->GetGlobal());
}


code:
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#pragma once

#include "include/cef_app.h"

// Implement application-level callbacks for the browser process.
class FCHostApp : public CefApp, public CefBrowserProcessHandler, public CefRenderProcessHandler {
 public:
  FCHostApp();

  // CefApp methods:
  virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()
      OVERRIDE {
    return this;
  }
  virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler()
	  OVERRIDE {
	  return this;
  }

  // CefBrowserProcessHandler methods:
  virtual void OnContextInitialized() OVERRIDE;
  virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) OVERRIDE;

  CefString GetLocalStorePath();

 private:
  // Include the default reference counting implementation.
  IMPLEMENT_REFCOUNTING(FCHostApp);
};


code:
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "fchost_handler.h"

#include <sstream>
#include <string>
#include <fstream>

#include "include/base/cef_bind.h"
#include "include/cef_app.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"

namespace {

FCHostHandler* g_instance = NULL;

}  // namespace

FCHostHandler::FCHostHandler(bool use_views)
    : use_views_(use_views), is_closing_(false) {
  DCHECK(!g_instance);
  g_instance = this;
}

FCHostHandler::~FCHostHandler() {
  g_instance = NULL;
}

// static
FCHostHandler* FCHostHandler::GetInstance() {
  return g_instance;
}

void FCHostHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
                                  const CefString& title) {
  CEF_REQUIRE_UI_THREAD();

  if (use_views_) {
    // Set the title of the window using the Views framework.
    CefRefPtr<CefBrowserView> browser_view =
        CefBrowserView::GetForBrowser(browser);
    if (browser_view) {
      CefRefPtr<CefWindow> window = browser_view->GetWindow();
      if (window)
        window->SetTitle(title);
    }
  } else {
    // Set the title of the window using platform APIs.
    PlatformTitleChange(browser, title);
  }
}

static std::string DateTime()
{
	time_t rawtime;
	struct tm* timeInfo;
	char buffer[80];

	time(&rawtime);
	timeInfo = localtime(&rawtime);

	strftime(buffer, 80, "%Y-%m-%d %I:%M:%S", timeInfo);

	return std::string(buffer);
}

bool FCHostHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser, cef_log_severity_t level,
									 const CefString& message, const CefString& source, int line)
{
	std::ofstream s("console.log", std::ios_base::app);
	s << DateTime() << " - " << source.c_str() << ":" << line << ": " << message.c_str() << "\n";
	s.flush();
	s.close();

	return false;
}

void FCHostHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  CEF_REQUIRE_UI_THREAD();

  // Add to the list of existing browsers.
  browser_list_.push_back(browser);
}

bool FCHostHandler::DoClose(CefRefPtr<CefBrowser> browser) {
  CEF_REQUIRE_UI_THREAD();

  // Closing the main window requires special handling. See the DoClose()
  // documentation in the CEF header for a detailed destription of this
  // process.
  if (browser_list_.size() == 1) {
    // Set a flag to indicate that the window close should be allowed.
    is_closing_ = true;
  }

  // Allow the close. For windowed browsers this will result in the OS close
  // event being sent.
  return false;
}

void FCHostHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
  CEF_REQUIRE_UI_THREAD();

  // Remove from the list of existing browsers.
  BrowserList::iterator bit = browser_list_.begin();
  for (; bit != browser_list_.end(); ++bit) {
    if ((*bit)->IsSame(browser)) {
      browser_list_.erase(bit);
      break;
    }
  }

  if (browser_list_.empty()) {
    // All browser windows have closed. Quit the application message loop.
    CefQuitMessageLoop();
  }
}

void FCHostHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
                                CefRefPtr<CefFrame> frame,
                                ErrorCode errorCode,
                                const CefString& errorText,
                                const CefString& failedUrl) {
  CEF_REQUIRE_UI_THREAD();

  // Don't display an error for downloaded files.
  if (errorCode == ERR_ABORTED)
    return;

  // Display a load error message.
  std::stringstream ss;
  ss << ""
        "
Failed to load URL "
     << std::string(failedUrl) << " with error " << std::string(errorText)
     << " (" << errorCode << ").
";
  frame->LoadString(ss.str(), failedUrl);
}

void FCHostHandler::OnBeforeDownload(CefRefPtr<CefBrowser> browser,
									 CefRefPtr<CefDownloadItem> download_item,
									 const CefString& suggested_name,
									 CefRefPtr< CefBeforeDownloadCallback > callback)
{
	CEF_REQUIRE_UI_THREAD();

	callback->Continue(suggested_name, true);
}

bool FCHostHandler::OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
	const CefKeyEvent& event,
	CefEventHandle os_event,
	bool* is_keyboard_shortcut)
{
	CEF_REQUIRE_UI_THREAD();

	if (event.type == cef_key_event_type_t::KEYEVENT_CHAR)
	{
		// CTRL+SHIFT+J - bring up the Javascript debugger
		if ((event.modifiers == (cef_event_flags_t::EVENTFLAG_CONTROL_DOWN | cef_event_flags_t::EVENTFLAG_SHIFT_DOWN)) && event.unmodified_character == 10 /* j? maybe only on windows? whatever */)
		{
			CefWindowInfo windowInfo;
			CefBrowserSettings settings;
			CefPoint point;
			windowInfo.SetAsPopup(browser->GetHost()->GetWindowHandle(), "DevTools");
			browser->GetHost()->ShowDevTools(windowInfo, browser->GetHost()->GetClient(), settings, point);

			return true;
		}
		// CTRL+F - bring up Find In Page
		else if (event.modifiers == cef_event_flags_t::EVENTFLAG_CONTROL_DOWN && event.unmodified_character == 6 /* f? maybe only on windows? whatever */)
		{
			// probably can do this at some point by ripping off code from the full-fat cefclient, but damn there's a lot of it...
			// return true;
		}
	}

	return false;
}

void FCHostHandler::CloseAllBrowsers(bool force_close) {
  if (!CefCurrentlyOn(TID_UI)) {
    // Execute on the UI thread.
    CefPostTask(TID_UI, base::Bind(&FCHostHandler::CloseAllBrowsers, this,
                                   force_close));
    return;
  }

  if (browser_list_.empty())
    return;

  BrowserList::const_iterator it = browser_list_.begin();
  for (; it != browser_list_.end(); ++it)
    (*it)->GetHost()->CloseBrowser(force_close);
}


code:
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#pragma once

#include "include/cef_client.h"

#include <list>

class FCHostHandler : public CefClient,
                      public CefDisplayHandler,
                      public CefLifeSpanHandler,
                      public CefLoadHandler,
					  public CefDownloadHandler,
					  public CefKeyboardHandler {
 public:
  explicit FCHostHandler(bool use_views);
  ~FCHostHandler();

  // Provide access to the single global instance of this object.
  static FCHostHandler* GetInstance();

  // CefClient methods:
  virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE {
    return this;
  }
  virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE {
    return this;
  }
  virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE { return this; }
  virtual CefRefPtr<CefDownloadHandler> GetDownloadHandler() OVERRIDE { return this; }
  virtual CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() OVERRIDE { return this; }

  // CefDisplayHandler methods:
  virtual void OnTitleChange(CefRefPtr<CefBrowser> browser,
                             const CefString& title) OVERRIDE;
  virtual bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
							    cef_log_severity_t level,
								const CefString& message,
								const CefString& source,
								int line) OVERRIDE;

  // CefLifeSpanHandler methods:
  virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
  virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
  virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;

  // CefLoadHandler methods:
  virtual void OnLoadError(CefRefPtr<CefBrowser> browser,
                           CefRefPtr<CefFrame> frame,
                           ErrorCode errorCode,
                           const CefString& errorText,
                           const CefString& failedUrl) OVERRIDE;

  // CefDownloadHandler methods:
  virtual void OnBeforeDownload(CefRefPtr<CefBrowser> browser,
								CefRefPtr<CefDownloadItem> download_item,
								const CefString& suggested_name,
								CefRefPtr< CefBeforeDownloadCallback > callback) OVERRIDE;

  // CefKeyboardHandler methods:
  virtual bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
							const CefKeyEvent& event,
							CefEventHandle os_event,
							bool* is_keyboard_shortcut) OVERRIDE;

  // Request that all existing browser windows close.
  void CloseAllBrowsers(bool force_close);

  bool IsClosing() const { return is_closing_; }

 private:
  // Platform-specific implementation.
  void PlatformTitleChange(CefRefPtr<CefBrowser> browser,
                           const CefString& title);

  // True if the application is using the Views framework.
  const bool use_views_;

  // List of existing browser windows. Only accessed on the CEF UI thread.
  typedef std::list<CefRefPtr<CefBrowser>> BrowserList;
  BrowserList browser_list_;

  bool is_closing_;

  // Include the default reference counting implementation.
  IMPLEMENT_REFCOUNTING(FCHostHandler);
};


code:
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "fchost_handler.h"

#include <windows.h>
#include <string>

#include "include/cef_browser.h"
#include "resource.h"

void FCHostHandler::PlatformTitleChange(CefRefPtr<CefBrowser> browser,
                                        const CefString& title) {
  CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle();

  static bool haveSetIcon = false;
  if (!haveSetIcon)
  {
	  HICON hicon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_FCHOST));
	  SendMessage(hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hicon));
	  SendMessage(hwnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hicon));
	  DestroyIcon(hicon);
	  haveSetIcon = true;
  }

  SetWindowText(hwnd, std::wstring(title).c_str());
}


code:
#include "fchost_storage.h"

#include <algorithm>
#if defined(OS_WIN)
#include "shlwapi.h"
#endif

CefRefPtr<CefV8Value> FCHostSessionStorage::keys() const
{
	// holy hell this is awful.  I hope Sugarcube doesn't actually USE this...
	CefRefPtr<CefV8Value> ret = CefV8Value::CreateArray(static_cast<int>(storage.size()));
	auto itr = storage.cbegin();
	for (int i = 0; i < static_cast<int>(storage.size()); ++i, ++itr)
	{
		ret->SetValue(i, CefV8Value::CreateString(itr->first));
	}
	return ret;
}

#if defined(OS_WIN)
/* This should't happen, so don't waste time on it.  Sugarcube really only writes simple alphanumeric keys.
static bool SanitizePath(std::wstring& inpath)
{
	std::transform(inpath.begin(), inpath.end(), inpath.begin(), [](wchar_t c)
	{
		if (PathGetCharTypeW(c) != GCT_LFNCHAR)
			return L'_';
		else
			return c;
	});
}
*/

void FCHostPersistentStorage::set(const CefString& key, CefRefPtr<CefV8Value> val)
{
	__super::set(key, val);

	// only strings get persisted (should be ok, Sugarcube will serialize first)
	if (val->IsString())
	{
		// we should probably be doing this async but TBT Sugarcube is the slow part, not the file IO
		DWORD written;
		HANDLE fh = CreateFile(get_filename(key).c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
		CefString valStr = val->GetStringValue();
		if (valStr.size() > 0)
		{
			WriteFile(fh, valStr.c_str(), static_cast<DWORD>(valStr.size() * sizeof(valStr.c_str()[0])), &written, NULL);
		}
		CloseHandle(fh);
	}
}

bool FCHostPersistentStorage::remove(const CefString& key)
{
	bool retval = __super::remove(key);

	DeleteFile(get_filename(key).c_str());

	return retval;
}

void FCHostPersistentStorage::clear()
{
	__super::clear();

	WIN32_FIND_DATAW w32fd;
	HANDLE hFind = FindFirstFile((path + L"\\*").c_str(), &w32fd);
	if (hFind != INVALID_HANDLE_VALUE)
	{
		do
		{
			if (w32fd.dwFileAttributes & ~(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE))
			{
				DeleteFile(get_filename(w32fd.cFileName).c_str());
			}
		} while (FindNextFile(hFind, &w32fd));
		FindClose(hFind);
	}
}

void FCHostPersistentStorage::load()
{
	constexpr size_t bufsize = 1024 * 1024 * 1024; // 1gb should be enough
	char* readbuf = new char[bufsize];
	WIN32_FIND_DATAW w32fd;
	HANDLE hFind = FindFirstFile((path + L"\\*").c_str(), &w32fd);
	if (hFind != INVALID_HANDLE_VALUE)
	{
		do
		{
			if (w32fd.dwFileAttributes & ~(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE))
			{
				DWORD bytesread = 0;
				HANDLE fh = CreateFile(get_filename(w32fd.cFileName).c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
				if (fh)
				{
					BOOL success = ReadFile(fh, readbuf, static_cast<DWORD>(bufsize - 1), &bytesread, NULL);
					if (success)
					{
						readbuf[bytesread] = L'\0';
						readbuf[bytesread+1] = L'\0'; // null terminate
						CefString val = reinterpret_cast<wchar_t*>(readbuf);
						storage.emplace(w32fd.cFileName, CefV8Value::CreateString(val));
					}
					CloseHandle(fh);
				}
			}
		} while (FindNextFile(hFind, &w32fd));
		FindClose(hFind);
	}
	delete[] readbuf;
}

std::wstring FCHostPersistentStorage::get_filename(const CefString& key) const
{
	return path + L"\\" + key.c_str();
}

void FCHostPersistentStorage::ensure_folder_exists() const
{
	// ignore returned errors
	CreateDirectory(path.c_str(), NULL);
}
#else
#error "Platform-specific persistent storage implementation required."
#endif


code:
#pragma once

#include "include/cef_app.h" // probably excessive
#include <map>
#include <string>

// simple memory-backed session storage
class FCHostSessionStorage
{
public:
	virtual size_t size() const { return storage.size(); };
	virtual CefRefPtr<CefV8Value> /* string array */ keys() const;
	virtual bool has(const CefString& key) const { return (storage.find(key) != storage.cend()); };
	virtual CefRefPtr<CefV8Value> get(const CefString& key) const
	{
		auto itr = storage.find(key);
		if (itr == storage.cend())
			return CefV8Value::CreateNull();
		else
			return itr->second;
	};
	virtual void set(const CefString& key, CefRefPtr<CefV8Value> val) { storage.insert_or_assign(key, val); };
	virtual bool remove(const CefString& key) { return (storage.erase(key) > 0); };
	virtual void clear() { storage.clear(); };

protected:
	std::map<CefString, CefRefPtr<CefV8Value>> storage;
};

// memory-backed, disk-persistent local storage
class FCHostPersistentStorage : public FCHostSessionStorage
{
public:
	FCHostPersistentStorage(const std::wstring& _path) : path(_path) { ensure_folder_exists(); load();  };

	virtual void set(const CefString& key, CefRefPtr<CefV8Value> val) override;
	virtual bool remove(const CefString& key) override;
	virtual void clear() override;

private:
	void load();
	void ensure_folder_exists() const;
	std::wstring get_filename(const CefString& key) const;

	std::wstring path;
};


code:
#include "fchost_storage_js.h"

#include <memory>

// static storage objects (not threadsafe, probably doesn't matter, since they'll execute within a JS context)

static std::unique_ptr<FCHostPersistentStorage> persist;
static std::unique_ptr<FCHostSessionStorage> session;

// storage handler js hook implementations

#define REGJSFUNC(x) { \
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction(x, handler); \
object->SetValue(x, func, V8_PROPERTY_ATTRIBUTE_NONE); }

static void AttachStorageFunctions(CefRefPtr<CefV8Value> object, CefRefPtr<CefV8Handler> handler)
{
	REGJSFUNC("size");
	REGJSFUNC("keys");
	REGJSFUNC("has");
	REGJSFUNC("get");
	REGJSFUNC("set");
	REGJSFUNC("remove");
	REGJSFUNC("clear");
}

void FCHostStorageRegister(const CefString& persistPath, CefRefPtr<CefV8Value> object) {
	// New context, reset everything (don't try to run more than one app at once!)
	if (persist) persist.reset(NULL);
	if (session) session.reset(NULL);

	persist = std::make_unique<FCHostPersistentStorage>(persistPath);
	session = std::make_unique<FCHostSessionStorage>();

	CefRefPtr<CefV8Handler> sess_handler = new FCHostStorageHandler(false);
	CefRefPtr<CefV8Value> obj_sess = CefV8Value::CreateObject(NULL, NULL);
	object->SetValue("FCHostSession", obj_sess, V8_PROPERTY_ATTRIBUTE_NONE);
	AttachStorageFunctions(obj_sess, sess_handler);

	CefRefPtr<CefV8Handler> pers_handler = new FCHostStorageHandler(true);
	CefRefPtr<CefV8Value> obj_pers = CefV8Value::CreateObject(NULL, NULL);
	object->SetValue("FCHostPersistent", obj_pers, V8_PROPERTY_ATTRIBUTE_NONE);
	AttachStorageFunctions(obj_pers, pers_handler);
}

// individual execution objects for session/persistent storage

bool FCHostStorageHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception)
{
	// alias pointer only, no ownership
	FCHostSessionStorage* storage = persistent ? persist.get() : session.get();

	if (name == "size") {
		// no arguments
		retval = CefV8Value::CreateInt(static_cast<int32>(storage->size()));
		return true;
	}
	else if (name == "keys") {
		// no arguments
		retval = storage->keys();
		return true;
	}
	else if (name == "has") {
		// one string argument
		if (arguments.size() < 1 || !arguments[0]->IsString()) return false;

		retval = CefV8Value::CreateBool(storage->has(arguments[0]->GetStringValue()));
		return true;
	}
	else if (name == "get") {
		// one string argument
		if (arguments.size() < 1 || !arguments[0]->IsString()) return false;

		retval = storage->get(arguments[0]->GetStringValue());
		return true;
	}
	else if (name == "set") {
		// two arguments - one string, one "whatever"
		if (arguments.size() < 2 || !arguments[0]->IsString()) return false;

		storage->set(arguments[0]->GetStringValue(), arguments[1]);
		retval = CefV8Value::CreateBool(true);
		return true;
	}
	else if (name == "remove") {
		// one string argument
		if (arguments.size() < 1 || !arguments[0]->IsString()) return false;

		retval = CefV8Value::CreateBool(storage->remove(arguments[0]->GetStringValue()));
		return true;
	}
	else if (name == "clear") {
		// no arguments
		storage->clear();
		return true;
	}

	return false;
}


code:
#pragma once

#include "fchost_storage.h"

// storage handlers that can be registered directly to Javascript to enable fchost_storage backing

class FCHostStorageHandler : public CefV8Handler
{
public:
	FCHostStorageHandler(bool _persistent) : persistent(_persistent) {};

	virtual bool Execute(const CefString& name,
		CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments,
		CefRefPtr<CefV8Value>& retval,
		CefString& exception) OVERRIDE;

private:
	bool persistent;
	IMPLEMENT_REFCOUNTING(FCHostStorageHandler);
};

void FCHostStorageRegister(const CefString& persistPath, CefRefPtr<CefV8Value> object);


code:
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include <windows.h>
#include <KnownFolders.h>
#include <ShlObj.h>

#include "fchost_app.h"

CefString FCHostApp::GetLocalStorePath()
{
	PWSTR ppath;
	SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &ppath);
	std::wstring local_storage = ppath;
	local_storage += L"\\FreeCities_Pregmod";
	CoTaskMemFree(ppath);
	return local_storage.c_str();
}

// Entry point function for all processes.
int APIENTRY wWinMain(HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPTSTR lpCmdLine,
                      int nCmdShow) {
  UNREFERENCED_PARAMETER(hPrevInstance);
  UNREFERENCED_PARAMETER(lpCmdLine);

  // Enable High-DPI support on Windows 7 or newer.
  CefEnableHighDPISupport();

  // Provide CEF with command-line arguments.
  CefMainArgs main_args(hInstance);

  // It will create the first browser instance in OnContextInitialized() after
  // CEF has initialized.
  CefRefPtr<FCHostApp> app(new FCHostApp);

  // CEF applications have multiple sub-processes (render, plugin, GPU, etc)
  // that share the same executable. This function checks the command-line and,
  // if this is a sub-process, executes the appropriate logic.
  int exit_code = CefExecuteProcess(main_args, app.get(), NULL);
  if (exit_code >= 0) {
    // The sub-process has completed so return here.
    return exit_code;
  }

  // Specify CEF global settings here.
  CefSettings settings;

  // Cache location is required for local storage
  CefString local_storage = app->GetLocalStorePath();
  cef_string_from_utf16(local_storage.c_str(), local_storage.length(), &settings.cache_path);

  // Initialize CEF.
  CefInitialize(main_args, settings, app.get(), NULL);

  // Run the CEF message loop. This will block until CefQuitMessageLoop() is
  // called.
  CefRunMessageLoop();

  // Shut down CEF.
  CefShutdown();

  return 0;
}


code:
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by fchost.rc
//

#define IDI_FCHOST 100

// Avoid files associated with MacOS
#define _X86_

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 32700
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 102
#endif
#endif


code:
MAKEFLAGS += -r
export TWEEGO_PATH=devTools/tweeGo/storyFormats
HASH := $(shell git rev-list -n 1 --abbrev-commit HEAD)
COMMIT := $(shell git rev-parse --short HEAD)
TWEEGO := $(shell command -v tweego 2>/dev/null)
ifndef TWEEGO
	uname := $(shell uname -s)
	arch := $(shell uname -m)
	arch := $(shell if test $(arch) = x86_64 -o $(arch) = amd64; then echo 64; else echo 32; fi)
	ifeq ($(uname),Linux)
		ifeq ($(arch),64)
			TWEEGO := devTools/tweeGo/tweego_nix64
		else
			TWEEGO := devTools/tweeGo/tweego_nix86
		endif
	else ifeq ($(uname),Darwin)
		ifeq ($(arch),64)
			TWEEGO := devTools/tweeGo/tweego_osx64
		else
			TWEEGO := devTools/tweeGo/tweego_osx86
		endif
	endif
endif

all: bin/FC_pregmod.html bin/resources

git: bin/FC_pregmod_$(HASH).html bin/resources

bin/resources: resources
	test -L "$@" || ln -s "../$<" bin/

bin/%.html: bin/tmp
	git checkout -- src/gui/mainMenu/AlphaDisclaimer.tw
	mv $< $@

bin/fc.js: bin/
	devTools/concatFiles.sh js/ '*.js' $@

bin/tmp: bin/fc.js src/gui/mainMenu/AlphaDisclaimer.tw
	$(TWEEGO) --module=bin/fc.js --head devTools/head.html src/ > $@
	rm -f bin/fc.js

src/gui/mainMenu/AlphaDisclaimer.tw:
	sed -Ei "s/build .releaseID/\0 commit $(COMMIT)/" $@

bin/:
	mkdir -p $@

sanity:
	./sanityCheck.sh

.PHONY: all sanity git

path: Makefile


code:
Common problems:

How do I start the game?
-Run the compile file, go to folder "bin", click the "FC_Pregmod" and play. (Recommendation: Drag it into incognito mode)

I get an error on gamestart reading "Apologies! A fatal error has occurred. Aborting. Error: Unexpected token @ in JSON at position 0. Stack Trace: SyntaxError: Unexpected token @ in JSON at position 0 at JSON.parse (<anonymous>) at JSON.value" or some variant
-clear cookies

Everything is broken!
-Do not copy over your existing download as it may leave old files behind, replace it entirely

I can't save more than once or twice.
-Known issue caused by sugarcube level changes. Save to file doesn't have this problem and will likely avoid the first problem as well.
-It is possible to increase the memory utilized by your browser to delay this

I wish to report a sanityCheck issue.
-Great, however a large majority of the results are false positives coming from those specific sections being split over several lines in the name of readability and git grep's intentionally (http://git.661346.n2.nabble.com/bug-git-grep-P-and-multiline-mode-td7613900.html ) lacking support for multiline. An Attempt to add -Pzl (https://gitgud.io/pregmodfan/fc-pregmod/merge_requests/2108 ) created a sub condition black hole. What follows are examples of common false positives that can safely be ignored;

	[MissingClosingAngleBracket]src/art/vector/Generate_Stylesheet.tw:11:<<print "<style>."+_art_display_class+" {
		<<print "<style>."+_art_display_class+" {
	position: absolute;
	height: 100%;
	margin-left: auto;
	margin-right: auto;
	left: 0;
	right: 0;
	}

How to mod (basic doc):

1. All sources now in the src subdir, in separate files. 1 passage = 1 file.

2. Special files and dir's:
	- src/config		- configuration of the story is here.
	- src/config/start.tw	- contains list of .tw passage files, regenerated automatic, by building scripts. Do not change by hands. (original passage Start from pregmod renamed and moved to src/events/intro/introSummary.tw)
	- src/js/storyJS.tw		- special passage with [script] tag - contain all native JavaScript from pregmod.
	- devTools/tweeGo/targets/sugarcube-2/userlib.js - on original FC JS moved here (I deleted it after moving JS to storyJS.tw). Compare to storyJS.tw but do not copy file here. May conflict with src/js/storyJS.tw if copied.
	- src/pregmod		- I put all pregmod-only passages here.
	- .gitignore		- special file for git - to ignore some files. For example - compilation results.

3. Compilation:

	Windows:
	Run compile.bat - result will be file bin/FC_pregmod.html
	Second run of compile.but will overwrite bin/FC_pregmod.html without prompt.

	Linux:
	Ensure executable permission on file "devTools/tweeGo/tweego" (not tweego.exe!)
	Ensure executable permission on file "compile.sh"
	In the root dir of sources (where you see src, devTools, bin...) run command "./compile.sh" from console
	Alternatively, if you have make installed, run "make all" in the root directory

	Mac:
	Not supported directly (I don't have access to Mac for testing).
	But you can use linux compilation script if you download tweego for mac from here: https://bitbucket.org/tmedwards/tweego/downloads/ and replace linux executable with mac executable in ./devTools/tweeGo/ folder. This is not tested though, so be warned.

4. Simple comparing and merging with original FC:

	Use meld tool. Place folder FreeCities (original FC sources tree) near FreeCitiesPregmod (this sources tree) and use command:
	meld FreeCities FreeCitiesPregmod
	or just select these folders in meld's GUI.

5. All modders will be very grateful if anyone who makes some changes to game with .html file also post their resulting src folder tree.

6. For contributors to pregmod: if you don't use git, then you need to post your version of src folder tree, not just produced FC_pregmod.html file!!! This html file can't be reverted to proper sources, and useless as contribution!

7. Git workflow:
	- Master branch is pregmod-master. Only Pregmodder can add something to it directly. Always contain his last public changes.
	- pregmod-dev - branch with experimental code mainly by pregmodfan.
	- Any contributions will be placed in separate branches like pregmod-mod-<something> (if it's ready to merge with master complete feature/mod) or pregmod-contrib-<something> if it's partial work until contributions is reviewed.

	Typical cycle with git:
	1. Make account on gitgud if you don't have usable one.
	2. Fork main repository through gitgud interface. (Or pull changes from main repo if you already have fork.)
	3. Clone your fork to local machine with git client (Or pull changes if already cloned.)
	4. Make you changes as you like, commit, and push result into your forked repository (with git client).
	5. (optional, but recommended) Run sanityCheck before final push to catch any errors you missed. (You can ignore errors unrelated to files you changed.)
	6. Make merge request through gitgud interface.


code:
Further Development:
- specialized slave schools
- fortifications
- more levels for militia edict (further militarize society)
- conquering other arcologies?

Events:
- famous criminal escapes to the arcology, followed by another arcology's police force

Bugs:
- sometimes troop counts breaks
- sometimes rebel numbers have fractionary parts

Rules Assistant:
- find a way for the new intense drugs to fit in
- everything mentioned in https://gitgud.io/pregmodfan/fc-pregmod/issues/81

main.tw porting:
- slaveart
- createsimpletabs
- displaybuilding
- optionssortasappearsonmain
- resetassignmentfilter
- mainlinks
- arcology description
- office description
- slave summary
- use guard
- toychest
- walk past

show exactly which organ is ready at the bottom of the main screen


code:
# How to vector art

Please read the whole document before starting to work.
Some aspects are not obvious right away.

Note: This does not actually describe how to be an artist.

## TL;DR

	killall inkscape
	artTools/vector_layer_split.py artTools/vector_source.svg tw src/art/vector/layers/
	compile
	python3 artTools/normalize_svg.py artTools/vector_source.svg
	git commit -a

## 1. Be an artist

Make changes to the vector_source.svg.
Inkscape was thoroughly tested.
Adobe Illustrator might work decently, too.

## 2. Respect the structure

While editing, keep the Layers in mind.

* In Inkscape, Layers are special "Inkscape groups".
* In Illustrator, Layers are groups with user-defined IDs.
* All Layers should have an ID that is globally unique
  (not just within their subtree).

* Please use anonymous groups only for the ease of editing. Remove all "helper" groups before finally saving the file.
* Anonymous groups can be used for continuous scaling (of e.g. boobs).

* Every asset that should go into a separate file needs to be in a labelled group
  (even if that is a group with only one shape).
* There are some globally available styles defined as CSS classes (e.g. skin, hair).
  Use them if your asset should be changed upon display.
  Do not set the style directly in the object.

## 3. Normalize the document (before committing)

**THIS IS IMPORTANT**

The various editors out there (Inkscape, Illustrator) may use different variants of formatting the SVG XML.
Use

	python3 normalize_svg.py vector_source.svg

before committing to normalize the format so git will not freak out about the changed indentation.

If you use Inkscape, please use in Edit → Settings → Input/Output → SVG-Output → Path Data → Optimized. This is the default.
In case your Editor uses another path data style which cannot be changed, please contact the other artists and developers via the issue tracker to find a new common ground.

What it does:
* Formats the SVG XML according to Pythons lxml module, regardless of editor.
* Adobe Illustrator uses group IDs as layer labels.
  Inkscape however uses layer labels and a separate, auto-generated group ID.
  normalize_svg.py overwrites the group ID with the Inkscape layer label
  so they are synchronized with Inkscape layer labels.
* Inkscape copies the global style definition into the object *every time*
  the object is edited. If an object references a CSS class AND at the same time
  has a local style, the local style is removed
  so global dynamic styling is possible later on.

Note: Behavior of Adobe Illustrator is untested.

## 4. Split the layers

For NoX original, deepmurk extensions, execute

	python3 vector_layer_split.py vector_deepmurk_primary.svg tw ../src/art/vector/layers/

For faraen revamped art (based on NoX original)

	python3 vector_revamp_layer_split.py vector_revamp_source.svg tw ../src/art/vector_revamp/layers/

. This application reads all groups in `vector_source.svg`.
Each group is stored in a separate file in the target directory `/src/art/vector/layers/`.
The group ID sets the file name. Therefore, the group ID **must not** contain spaces or any other weird characters.

Also consider:
* A group with ID ending in _ is ignored. Use Layers ending in _ to keep overview.
* A group with ID starting with "g" (Inkscape) or "XMLID" (Illustrator) is also ignored.
* Existing files are overwritten **without enquiry**.
* The target directory is not emptied. If a file is no longer needed, you should remove it manually.
* This procedure removes global definitions. This means, SVG filters are currently not supported.

Available output formats are `svg` and `tw`.
`svg` output exists for debug reasons.
`tw` embeds the SVG data into Twine files, but removes the global style definitions so they can be set during display.

## 5. Edit the code

`/src/art/` contains Twine code which shows the assets in the story.
There are many helpful comments in `/src/art/artWidgets.tw`.
The code also generates the previously removed global style definitions on the fly and per display.

## 6. Compile the story

Use the provided compile script (Windows batch or shell) for compiling.

## 7. Advanced usage

You can define multiple CSS classes to one element, e.g. "skin torso". When procedurally generating CSS, you can then set a global "skin" style, and a different one for "torso".

You can put variable text into the image using single quotes, e.g. "'+_tattooText+'". The single quotes *break* the quoting in Twine so the content of the Twine variable `_tattooText` is shown upon display. You can even align text on paths.

An anonymous group can be used for dynamic transformation. However, finding the correct parameters for the affine transformation matrix can be cumbersome. Use any method you see fit. See `src/art/vector/Boob.tw` for one example of the result.


code:
Apron
AttractiveLingerie
AttractiveLingerieForAPregnantWoman
BallGown
Battledress
Blouse
BodyOil
Bunny
Chains
ChattelHabit
Cheerleader
ClubslutNetting
ComfortableBodysuit
Conservative
Cutoffs
Cybersuit
FallenNunsHabit
FuckdollSuit
HalterTopDress
HaremGauze
Hijab
Huipil
Kimono
LatexCatsuit
Leotard
LongQipao
MaternityDress
MilitaryUniform
MiniDress
Monokini
NiceBusinessAttire
NiceMaid
NiceNurse
No
PenitentNunsHabit
RedArmyUniform
RestrictiveLatex
ScalemailBikini
SchoolgirlUniform
SchutzstaffelUniform
ShibariRopes
SlaveGown
Slutty
SluttyBusinessAttire
SluttyJewelry
SluttyMaid
SluttyNurse
SluttyQipao
SluttySchutzstaffelUniform
Spats
StretchPants
StringBikini
Succubus
Toga
UncomfortableStraps
Western


code:
#!/bin/bash

# This script reads all possible values of $slave.clothes as mentioned by the documentation.
# This script uses the actual implementation of the JS clothing2artSuffix function as defined in src/art/vector/Helper_Functions.tw
# This script outputs suffixes to be used in the SVG naming scheme
# This script is meant to be executed at the project root directory.
# This script depends on bash, grep, sed, paste and nodejs (so best executed on Linux, I guess)

# grep -Porh '(?<=\.clothes = )"[^"]+"' src/ | sort | uniq # searches sources for all clothes strings actually used in the game, even undocumented ones

(
  echo 'var window = {};'
  grep -v '^:' src/art/vector/Helper_Functions.tw
  echo -n 'Array('
  sed '/^clothes:/,/:/!d' "slave variables documentation - Pregmod.txt" | grep '"' | paste -sd,
  echo ').forEach(v => {console.log(window.clothing2artSuffix(v));});'
) | nodejs | sort


code:
#!/usr/bin/env python3

'''
Application for "normalizing" SVGs

These problems are addressed:

* Inkscape notoriously copies class styles into the object definitions.
https://bugs.launchpad.net/inkscape/+bug/167937

* Inkscape uses labels on layers. Layers are basically named groups.
  Inkscape does not sync the group id with the layer label.

Usage Example:
python3 inkscape_svg_fixup.py vector_source.svg
'''

import lxml.etree as etree
import sys
import re

color_classes = {
	'skin', 'head', 'torso', 'boob', 'penis', 'scrotum', 'belly',
	'areola', 'bellybutton', 'labia', 'hair', 'pubic_hair', 'underarm_hair',
	'eyebrow_hair', 'shoe', 'shoe_shadow', 'smart_piercing', 'steel_piercing',
	'steel_chastity', 'outfit_base', 'gag', 'shadow', 'glasses', 'eye', 'sclera'
}

def fix(tree):
	# know namespaces
	ns = {
		'svg': 'http://www.w3.org/2000/svg',
		'inkscape': 'http://www.inkscape.org/namespaces/inkscape'
	}

	# find document global style definition
	# mangle it and interpret as python dictionary
	style_element = tree.find('./svg:style', namespaces=ns)
	style_definitions = style_element.text
	pythonic_style_definitions = '{'+style_definitions.\
		replace('\t.', '"').replace('{', '":"').replace('}', '",').\
		replace('/*', '#')+'}'
	styles = eval(pythonic_style_definitions)

	# go through all SVG elements
	for elem in tree.iter():
		if (elem.tag == etree.QName(ns['svg'], 'g')):
			# compare inkscape label with group element ID
			lbl = elem.get(etree.QName(ns['inkscape'], 'label'))
			if lbl:
				i = elem.get('id')
				if (i != lbl):
					print("Overwriting ID %s with Label %s..." % (i, lbl))
					elem.set('id', lbl)

		# clean styles (for easier manual merging)
		style_string = elem.get('style')
		if style_string:
			split_styles = style_string.strip('; ').split(';')
			styles_pairs = [s.strip('; ').split(':') for s in split_styles]
			filtered_pairs = [(k, v) for k, v in styles_pairs if not (
				k.startswith('font-') or
				k.startswith('text-') or
				k.endswith('-spacing') or
				k in ["line-height", " direction", " writing", " baseline-shift", " white-space", " writing-mode"]
			)]
			split_styles = [':'.join(p) for p in filtered_pairs]
			style_string = ';'.join(sorted(split_styles))
			elem.attrib["style"] = style_string

		# remove all style attributes offending class styles
		s = elem.get('style')
		c = elem.get('class')
		if (c and s):
			s = s.lower()
			c = c.split(' ')[0]  # regard main style only
			classes = c.split(' ')
			hasColorClass = any(x in color_classes for x in classes)
			if hasColorClass:
				s_new = re.sub('fill:#[0-9a-f]+;?', '', s)
				if s != s_new:
					print("Explicit fill was removed from style string ({0}) for element with ID {1} "
											"because its class ({2}) controls the fill color".format(s, i, c))
				s = s_new
			if s == 'style=""':  # the style is empty now
				del elem.attrib["style"]
				continue
			cs = ''
			if c in styles:
				cs = styles[c].strip('; ').lower()
			if (c not in styles):
				print("Object id %s references unknown style class %s." % (i, c))
			else:
				if (cs != s.strip('; ')):
					print("Style %s removed from object id %s differed from class %s style %s." % (s, i, c, cs))
					del elem.attrib["style"]

		# remove explicit fill color if element class is one of the color_classes

if __name__ == "__main__":
	input_file = sys.argv[1]
	tree = etree.parse(input_file)
	fix(tree)
	# store SVG into file (input file is overwritten)
	svg = etree.tostring(tree, pretty_print=True)
	with open(input_file, 'wb') as f:
		f.write('<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'.encode("utf-8"))
		f.write(svg)