#pragma once
/*
 * (C) Copyright 2020-2021 UCAR
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 */
/*! \addtogroup ioda_cxx_attribute
 *
 * @{
 * \file Attribute_Creator.h
 * \brief Flywheel creation of ioda::Attribute. Used by ioda::Has_Attributes and
 * ioda::VariableCreationParameters.
 */

#include <gsl/gsl-lite.hpp>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

#include "ioda/Attributes/Attribute.h"
#include "ioda/Attributes/Has_Attributes.h"
#include "ioda/Misc/Dimensions.h"
#include "ioda/Types/Type.h"
#include "ioda/defs.h"

namespace ioda {
namespace detail {
/// \brief Flywheel creation of ioda::Attribute.
/// \ingroup ioda_cxx_attribute
class IODA_DL Attribute_Creator_Base {
protected:
  std::string name_;

public:
  virtual ~Attribute_Creator_Base();
  virtual void apply(Has_Attributes& obj) const = 0;
  Attribute_Creator_Base(const std::string& name);
};
}  // namespace detail

/// \brief Flywheel creation of ioda::Attribute.
/// \ingroup ioda_cxx_attribute
template <class DataType>
class Attribute_Creator : public detail::Attribute_Creator_Base {
private:
  ::std::vector<Dimensions_t> dimensions_;
  ::std::vector<DataType> data_;

public:
  virtual ~Attribute_Creator() {}
  void apply(Has_Attributes& obj) const override { obj.add<DataType>(name_, data_, dimensions_); }

  /// \details Totally taking advantage of vector constructors.
  template <class DataInput, class DimensionInput>
  Attribute_Creator(const std::string& name, DataInput data, DimensionInput dimensions)
      : Attribute_Creator_Base(name), data_(data.begin(), data.end()), dimensions_(dimensions) {}

  template <class DimensionInput>
  Attribute_Creator(const std::string& name, DimensionInput dimensions)
      : Attribute_Creator_Base(name), dimensions_(dimensions) {}

  template <class DataInput_junk_param = DataType>
  void write(const ::gsl::span<const DataType>& data) {
    data_ = ::std::vector<DataType>(data.begin(), data.end());
  }
};

/// \brief Flywheel creation of ioda::Attribute objects.
/// \ingroup ioda_cxx_attribute
/// This is needed because you might want to make the same Attribute in multiple places.
class IODA_DL Attribute_Creator_Store : public detail::CanAddAttributes<Attribute_Creator_Store> {
  std::vector<std::shared_ptr<detail::Attribute_Creator_Base>> atts_;

public:
  Attribute_Creator_Store();
  virtual ~Attribute_Creator_Store();

  void apply(Has_Attributes& obj) const;

  /// @name Convenience functions for adding attributes
  /// @{
  /// \see CanAddAttributes
  /// \see CanAddAttributes::add

  template <class DataType>
  Attribute_Creator_Store& create(const std::string& attrname, ::gsl::span<const DataType> data,
                                  ::std::initializer_list<Dimensions_t> dimensions) {
    atts_.push_back(std::make_shared<Attribute_Creator<DataType>>(attrname, data, dimensions));
    return *this;
  }

  template <class DataType>
  Attribute_Creator_Store& create(const std::string& attrname,
                                  ::std::initializer_list<DataType> data,
                                  ::std::initializer_list<Dimensions_t> dimensions) {
    atts_.push_back(std::make_shared<Attribute_Creator<DataType>>(attrname, data, dimensions));
    return *this;
  }

  template <class DataType2>
  struct AttWrapper {
    std::shared_ptr<Attribute_Creator<DataType2>> inner;
    AttWrapper(std::shared_ptr<Attribute_Creator<DataType2>> d) : inner(d) {}
    template <class DataInput_junk_param = DataType2>
    void write(const ::gsl::span<const DataType2>& data) {
      inner->write(data);
    }
  };

  template <class DataType>
  AttWrapper<DataType> create(const std::string& attrname, ::std::vector<Dimensions_t> dimensions) {
    auto res = std::make_shared<Attribute_Creator<DataType>>(attrname, dimensions);
    atts_.push_back(res);
    return AttWrapper<DataType>{res};
  }

  /// @}
};

}  // namespace ioda

/// @} // End Doxygen block


#pragma once

#include <imageview/ContinuousImageView.h>
#include <imageview/ImageView.h>

#include <gsl/assert>

namespace imageview {

template <class PixelFormat, bool Mutable>
constexpr ImageView<PixelFormat, Mutable> crop(ImageView<PixelFormat, Mutable> image, unsigned int first_row,
                                               unsigned int first_column, unsigned int num_rows,
                                               unsigned int num_columns) {
  Expects(first_row <= image.height());
  Expects(first_column <= image.width());
  Expects(first_row + num_rows <= image.height());
  Expects(first_column + num_columns <= image.width());
  const std::size_t data_offset = (first_row * image.stride() + first_column) * PixelFormat::kBytesPerPixel;
  const std::size_t new_data_size =
      (num_rows == 0) ? 0 : ((num_rows - 1) * image.stride() + num_columns) * PixelFormat::kBytesPerPixel;
  const auto data_new = image.data().subspan(data_offset, new_data_size);
  return ImageView<PixelFormat>(num_rows, num_columns, image.stride(), data_new, image.pixelFormat());
}

template <class PixelFormat, bool Mutable>
constexpr ImageView<PixelFormat, Mutable> crop(ContinuousImageView<PixelFormat, Mutable> image, unsigned int first_row,
                                               unsigned int first_column, unsigned int num_rows,
                                               unsigned int num_columns) {
  return crop(ImageView<PixelFormat, Mutable>(image), first_column, first_column, num_rows, num_columns);
}

}  // namespace imageview


#pragma once

#include <cstdint>
#include <array>
#include <gsl/gsl>

#include "halley/data_structures/maybe.h"
#include "halley/maths/vector2.h"
#include "halley/maths/colour.h"
#include "halley/file_formats/image.h"

namespace Halley {
	enum class AsepriteBlendMode;

	enum class AsepriteDepth
	{
		RGBA32,
		Greyscale16,
		Indexed8
	};

	struct AsepriteCel
	{
	public:
		Vector2i pos;
		Vector2i size;
		uint16_t layer = 0;
		uint16_t linkedFrame = 0;
		uint8_t opacity = 255;
		bool linked = false;

		Bytes rawData;
		std::unique_ptr<Image> imgData;

		void loadImage(AsepriteDepth depth, const Vector<uint32_t>& palette);
		void drawAt(Image& image, uint8_t opacity, AsepriteBlendMode blendMode) const;
	};

	struct AsepriteFrame
	{
	public:
		AsepriteFrame(uint16_t duration);

		uint16_t duration;
		Vector<AsepriteCel> cels;
	};

	enum class AsepriteLayerType
	{
		Normal,
		Group
	};

	enum class AsepriteBlendMode
	{
		Normal,
		Multiply,
		Screen,
		Overlay,
		Darken,
		Lighten,
		ColorDodge,
		ColorBurn,
		HardLight,
		SoftLight,
		Difference,
		Exclusion,
		Hue,
		Saturation,
		Color,
		Luminosity,
		Addition,
		Subtract,
		Divide
	};

	struct AsepriteLayer
	{
		AsepriteLayerType type = AsepriteLayerType::Normal;
		AsepriteBlendMode blendMode = AsepriteBlendMode::Normal;
		int childLevel = 0;
		bool visible = true;
		bool editable = true;
		bool lockMovement = false;
		bool background = false;
		bool preferLinkedCels = false;
		bool layerGroupDisplaysCollapsed = false;
		bool referenceLayer = false;
		uint8_t opacity = 255;
		String layerName;

		OptionalLite<uint32_t> parentIdx;
		bool visibleInHierarchy = true;
	};

	enum class AsepriteAnimationDirection
	{
		Forward,
		Reverse,
		PingPong
	};

	struct AsepriteTag
	{
		int fromFrame = -1;
		int toFrame = -1;
		AsepriteAnimationDirection animDirection = AsepriteAnimationDirection::Forward;

		String name;
	};

    class AsepriteFile {
    public:
		AsepriteFile();

		void load(gsl::span<const gsl::byte> data);

		const Vector<AsepriteTag>& getTags() const;
		std::map<String, std::unique_ptr<Image>> makeGroupFrameImages(int frameNumber, bool groupSeparated);
	    const AsepriteFrame& getFrame(int n) const;
	    size_t getNumberOfFrames() const;

    private:
	    void addFrame(uint16_t duration);
	    void addChunk(uint16_t chunkType, gsl::span<const gsl::byte> data);

	    void addLayerChunk(gsl::span<const gsl::byte> span);
		void addCelChunk(gsl::span<const gsl::byte> span);
		void addCelExtraChunk(gsl::span<const gsl::byte> span);
		void addPaletteChunk(gsl::span<const gsl::byte> span);
		void addTagsChunk(gsl::span<const gsl::byte> span);
    	void postProcessLayers();

		template <typename T>
		void readData(T& dst, gsl::span<const gsl::byte>& data) const
		{
			if (data.size() < T::size) {
				throw Exception("Insufficient data to decode Aseprite entry", HalleyExceptions::Tools);
			}
			memcpy(&dst, data.data(), T::size);
			data = data.subspan(T::size);
		}

		String readString(gsl::span<const gsl::byte>& data) const
		{
			if (data.size() < 2) {
				throw Exception("Insufficient data to decode Aseprite entry", HalleyExceptions::Tools);
			}
			uint16_t size;
			memcpy(&size, data.data(), 2);
			data = data.subspan(2);
			if (data.size() < size) {
				throw Exception("Insufficient data to decode Aseprite entry", HalleyExceptions::Tools);
			}
			String result = String(reinterpret_cast<const char*>(data.data()), size);
			data = data.subspan(size);
			return result;
		}

	    AsepriteCel* getCelAt(int frameNumber, int layerNumber);
	    size_t getBPP() const;

		Vector2i size;
		uint32_t flags;
		AsepriteDepth colourDepth;
		uint8_t transparentEntry;
		uint16_t numOfColours;

		Vector<AsepriteFrame> frames;
		Vector<AsepriteLayer> layers;
		Vector<AsepriteTag> tags;
		Vector<uint32_t> paletteBg;
		Vector<uint32_t> paletteTransparent;
    };
}


#ifndef __GSL_MATRIX_H__
#define __GSL_MATRIX_H__

#include <gsl/matrix/gsl_matrix_double.h>

#endif /* __GSL_MATRIX_H__ */


#ifndef CONTROLLERS_FEATURE_DETECTOR_CONTROLLER_H
#define CONTROLLERS_FEATURE_DETECTOR_CONTROLLER_H

#include <QObject>

#include <QAction>

#include <s3d/cv/features/match_finder_cv.h>
#include <s3d/cv/disparity/disparity_analyzer_stan.h>

#include <gsl/gsl>

class FeatureDetectorControllerBase : QObject {
  Q_OBJECT

public:
  FeatureDetectorControllerBase(gsl::not_null<QAction*> action,
                                gsl::not_null<s3d::DisparityAnalyzerSTAN*> disparityAnalyzer);

  virtual std::unique_ptr<s3d::MatchFinderCV> createMatchFinder() = 0;

private:
  QAction* m_action;
  s3d::DisparityAnalyzerSTAN* m_disparityAnalyzer;
};

template <class T>
class FeatureDetectorController : public FeatureDetectorControllerBase {
  FeatureDetectorController(gsl::not_null<QAction*> action,
                            gsl::not_null<s3d::DisparityAnalyzerSTAN*> disparityAnalyzer)
    : FeatureDetectorControllerBase(action, disparityAnalyzer) {}

  std::unique_ptr<s3d::MatchFinderCV> createMatchFinder() override {
    return std::make_unique<T>();
  }
};

#endif //CONTROLLERS_FEATURE_DETECTOR_CONTROLLER_H


#pragma once

#include <gsl\gsl>
#include <winrt\Windows.Foundation.h>
#include <d3d11.h>
#include "DrawableGameComponent.h"
#include "MatrixHelper.h"
#include "DirectionalLight.h"

namespace Library
{
	class ProxyModel;
}

namespace Rendering
{
	class BlinnPhongMaterial;

	class BlinnPhongDemo final : public Library::DrawableGameComponent
	{
	public:
		BlinnPhongDemo(Library::Game& game, const std::shared_ptr<Library::Camera>& camera);
		BlinnPhongDemo(const BlinnPhongDemo&) = delete;
		BlinnPhongDemo(BlinnPhongDemo&&) = default;
		BlinnPhongDemo& operator=(const BlinnPhongDemo&) = default;
		BlinnPhongDemo& operator=(BlinnPhongDemo&&) = default;
		~BlinnPhongDemo();

		bool AnimationEnabled() const;
		void SetAnimationEnabled(bool enabled);
		void ToggleAnimation();

		float AmbientLightIntensity() const;
		void SetAmbientLightIntensity(float intensity);

		float DirectionalLightIntensity() const;
		void SetDirectionalLightIntensity(float intensity);

		const DirectX::XMFLOAT3& LightDirection() const;
		void RotateDirectionalLight(const DirectX::XMFLOAT2& amount);

		float SpecularIntensity() const;
		void SetSpecularIntensity(float intensity);

		float SpecularPower() const;
		void SetSpecularPower(float power);

		virtual void Initialize() override;
		virtual void Update(const Library::GameTime& gameTime) override;
		virtual void Draw(const Library::GameTime& gameTime) override;

	private:
		inline static const float RotationRate{ DirectX::XM_PI };

		std::shared_ptr<BlinnPhongMaterial> mMaterial;
		DirectX::XMFLOAT4X4 mWorldMatrix{ Library::MatrixHelper::Identity };
		winrt::com_ptr<ID3D11Buffer> mVertexBuffer;
		winrt::com_ptr<ID3D11Buffer> mIndexBuffer;
		std::uint32_t mIndexCount{ 0 };
		Library::DirectionalLight mDirectionalLight;
		std::unique_ptr<Library::ProxyModel> mProxyModel;
		float mModelRotationAngle{ 0.0f };
		bool mAnimationEnabled{ true };
		bool mUpdateMaterial{ true };
	};
}


#if !defined(PETIGAGRID_H)
#define PETIGAGRID_H

#include <petsc.h>

#if !defined(LGMap)
#define LGMap ISLocalToGlobalMapping
#endif

typedef struct _n_IGA_Grid *IGA_Grid;

struct _n_IGA_Grid {
  MPI_Comm    comm;
  PetscInt    dim,dof;
  PetscInt    sizes[3];
  PetscInt    local_start[3];
  PetscInt    local_width[3];
  PetscInt    ghost_start[3];
  PetscInt    ghost_width[3];
  AO          ao;
  LGMap       lgmap;
  PetscLayout map;
  Vec         lvec,gvec,nvec;
  VecScatter  g2l,l2g,g2n;
};

PETSC_EXTERN PetscErrorCode IGA_Grid_Create(MPI_Comm,IGA_Grid*);
PETSC_EXTERN PetscErrorCode IGA_Grid_Init(IGA_Grid,
                                          PetscInt,PetscInt,
                                          const PetscInt[],
                                          const PetscInt[],
                                          const PetscInt[],
                                          const PetscInt[],
                                          const PetscInt[]);
PETSC_EXTERN PetscErrorCode IGA_Grid_Reset(IGA_Grid);
PETSC_EXTERN PetscErrorCode IGA_Grid_Destroy(IGA_Grid*);
PETSC_EXTERN PetscErrorCode IGA_Grid_LocalIndices(IGA_Grid,PetscInt,PetscInt*,PetscInt*[]);
PETSC_EXTERN PetscErrorCode IGA_Grid_GhostIndices(IGA_Grid,PetscInt,PetscInt*,PetscInt*[]);
PETSC_EXTERN PetscErrorCode IGA_Grid_SetAO(IGA_Grid,AO);
PETSC_EXTERN PetscErrorCode IGA_Grid_GetAO(IGA_Grid,AO*);
PETSC_EXTERN PetscErrorCode IGA_Grid_SetLGMap(IGA_Grid,LGMap);
PETSC_EXTERN PetscErrorCode IGA_Grid_GetLGMap(IGA_Grid,LGMap*);
PETSC_EXTERN PetscErrorCode IGA_Grid_GetLayout(IGA_Grid,PetscLayout*);
PETSC_EXTERN PetscErrorCode IGA_Grid_GetVecLocal  (IGA_Grid,const VecType,Vec*);
PETSC_EXTERN PetscErrorCode IGA_Grid_GetVecGlobal (IGA_Grid,const VecType,Vec*);
PETSC_EXTERN PetscErrorCode IGA_Grid_GetVecNatural(IGA_Grid,const VecType,Vec*);
PETSC_EXTERN PetscErrorCode IGA_Grid_GetScatterG2L(IGA_Grid,VecScatter*);
PETSC_EXTERN PetscErrorCode IGA_Grid_GetScatterL2G(IGA_Grid,VecScatter*);
PETSC_EXTERN PetscErrorCode IGA_Grid_GetScatterG2N(IGA_Grid,VecScatter*);

PETSC_EXTERN PetscErrorCode IGA_Grid_GlobalToLocal(IGA_Grid,Vec,Vec);
PETSC_EXTERN PetscErrorCode IGA_Grid_LocalToGlobal(IGA_Grid,Vec,Vec,InsertMode);
PETSC_EXTERN PetscErrorCode IGA_Grid_NaturalToGlobal(IGA_Grid,Vec,Vec);
PETSC_EXTERN PetscErrorCode IGA_Grid_GlobalToNatural(IGA_Grid,Vec,Vec);

PETSC_EXTERN PetscErrorCode IGA_Grid_NewScatterApp(IGA_Grid g,
                                                   const PetscInt[],
                                                   const PetscInt[],
                                                   const PetscInt[],
                                                   const PetscInt[],
                                                   Vec*,VecScatter*,VecScatter*);

#endif/*PETIGAGRID_H*/


#ifndef OPENMC_TALLIES_FILTER_CELL_INSTANCE_H
#define OPENMC_TALLIES_FILTER_CELL_INSTANCE_H

#include <cstdint>
#include <unordered_map>

#include <gsl/gsl>

#include "openmc/cell.h"
#include "openmc/tallies/filter.h"
#include "openmc/vector.h"

namespace openmc {

//==============================================================================
//! Specifies cell instances that tally events reside in.
//==============================================================================

class CellInstanceFilter : public Filter {
public:
  //----------------------------------------------------------------------------
  // Constructors, destructors

  CellInstanceFilter() = default;
  CellInstanceFilter(gsl::span<CellInstance> instances);
  ~CellInstanceFilter() = default;

  //----------------------------------------------------------------------------
  // Methods

  std::string type() const override { return "cellinstance"; }

  void from_xml(pugi::xml_node node) override;

  void get_all_bins(const Particle& p, TallyEstimator estimator,
    FilterMatch& match) const override;

  void to_statepoint(hid_t filter_group) const override;

  std::string text_label(int bin) const override;

  //----------------------------------------------------------------------------
  // Accessors

  const vector<CellInstance>& cell_instances() const { return cell_instances_; }

  const std::unordered_set<int32_t>& cells() const { return cells_; }

  void set_cell_instances(gsl::span<CellInstance> instances);

private:
  //----------------------------------------------------------------------------
  // Data members

  //! The indices of the cells binned by this filter.
  vector<CellInstance> cell_instances_;

  //! The set of cells used in this filter
  std::unordered_set<int32_t> cells_;

  //! A map from cell/instance indices to filter bin indices.
  std::unordered_map<CellInstance, gsl::index, CellInstanceHash> map_;

  //! Indicates if filter uses only material-filled cells
  bool material_cells_only_;
};

} // namespace openmc

#endif // OPENMC_TALLIES_FILTER_CELL_INSTANCE_H


/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*
**                                                                                **
** This file forms part of the Underworld geophysics modelling application.         **
**                                                                                **
** For full license and copyright information, please refer to the LICENSE.md file  **
** located at the project root, or contact the authors.                             **
**                                                                                **
**~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
#ifndef __BSSCR_SUM_h__
#define __BSSCR_SUM_h__

#include <petsc.h>
#include <petscmat.h>
#include <petscvec.h>
#include <petscksp.h>
#include <petscpc.h>
#include <StGermain/libStGermain/src/StGermain.h>
#include <StgDomain/libStgDomain/src/StgDomain.h>
#include <StgFEM/libStgFEM/src/StgFEM.h>
#include <PICellerator/libPICellerator/src/PICellerator.h>
#include <Underworld/libUnderworld/src/Underworld.h>
#include "Solvers/KSPSolvers/src/KSPSolvers.h"

#include "common-driver-utils.h"
#include "BSSCR.h" /* includes StokesBlockKSPInterface.h */

//void bsscr_summary(KSP_BSSCR * bsscrp_self, KSP ksp_S, KSP ksp_inner, Mat K,Mat Korig,Mat K2,Mat D,Mat G,Mat C,Vec u,Vec p,Vec f,Vec h,Vec t,

void bsscr_summary(KSP_BSSCR * bsscrp_self, KSP ksp_S, KSP ksp_inner, Mat K,Mat K2,Mat D,Mat G,Mat C,Vec u,Vec p,Vec f,Vec h,Vec t,
		   double penaltyNumber,PetscTruth KisJustK,double mgSetupTime, double RHSSolveTime, double scrSolveTime,double a11SingleSolveTime);

#endif


#include "scripts.h"
#include "utility/fileutils.h"
#include "lua.h"
#include "lauxlib.h"
#include "subsystems.h"
#include "rendering/rendering.h"
#include <gsl/gsl_math.h>

/**
 * Retrieve the integer value in the table at the top of the stack
 * associated with the specified key.
 */
sd_result get_int_field(lua_State *L, const char *key, int *out) {
  lua_getfield(L, -1, key);
  if (!lua_isnumber(L, -1)) {
    return SD_SCRIPT_TYPE_ERROR;
  }
  *out = (int)lua_tonumber(L, -1);
  lua_pop(L, 1);
  return SD_OK;
}

/**
 * Retrieve the double value in the table at the top of the stack
 * associated with the specified key.
 */
sd_result get_double_field(lua_State *L, const char *key, double *out) {
  lua_getfield(L, -1, key);
  if (!lua_isnumber(L, -1)) {
    return SD_SCRIPT_TYPE_ERROR;
  }
  *out = lua_tonumber(L, -1);
  lua_pop(L, 1);
  return SD_OK;
}

/**
 * Retrieve the string value in the table at the top of the stack
 * associated with the specified key.
 */
sd_result get_string_field(lua_State *L, const char *key, char *out, size_t out_size) {
  lua_getfield(L, -1, key);
  if (!lua_isstring(L, -1)) {
    return SD_SCRIPT_TYPE_ERROR;
  }
  size_t max = GSL_MIN(lua_rawlen(L, -1), out_size);
  strncpy(out, lua_tostring(L, -1), max);
  lua_pop(L, 1);
  return SD_OK;
}

/**
 * Retrieve the boolean value in the table at the top of the stack
 * associated with the specified key.
 */
sd_result get_bool_field(lua_State *L, const char *key, char *out) {
  lua_getfield(L, -1, key);
  if (!lua_isboolean(L, -1)) {
    return SD_SCRIPT_TYPE_ERROR;
  }
  *out = lua_toboolean(L, -1);
  lua_pop(L, 1);
  return SD_OK;
}

sd_result read_init_info(const char *resource_path, initialization_params *out) {
  lua_State *L = luaL_newstate();
  bzero(out, sizeof(initialization_params));
  window_creation_info *winfo = calloc(1, sizeof(window_creation_info));
  out->window_info = winfo;

  char *file_path = NULL;
  fileutils.get_full_path(resource_path, &file_path);
  if (luaL_loadfile(L, file_path) || lua_pcall(L, 0, 0, 0)) {
    printf("Problem loading file %s\n", file_path);
    return SD_GEN_ERROR;
  }
  lua_getglobal(L, "timer");
  if (!lua_isstring(L, -1)) {
    printf("Timer type is not a string\n");
    return SD_SCRIPT_TYPE_ERROR;
  }
  const char *timer_type = lua_tostring(L,-1);
  if (strncasecmp("glfw", timer_type, lua_rawlen(L, -1))) {
    printf("glfw timer specified\n");
  };
  out->timer_function = glfwGetTime;
  lua_pop(L, 1);

  lua_getglobal(L, "window");
  if (!lua_istable(L, -1)) {
    printf("Window description is not a table\n");
    return SD_SCRIPT_TYPE_ERROR;
  }

  get_int_field(L, "w", &winfo->width);
  get_int_field(L, "h", &winfo->height);
  get_bool_field(L, "full_screen", &winfo->full_screen);
  get_string_field(L, "title", winfo->window_title,
                  sizeof(winfo->window_title));

  // Sub table
  lua_getfield(L, -1, "clear_color");
  double dbuffer;
  get_double_field(L, "R", &dbuffer);
  winfo->clear_color[0] = (GLfloat)dbuffer;
  get_double_field(L, "G", &dbuffer);
  winfo->clear_color[1] = (GLfloat)dbuffer;
  get_double_field(L, "B", &dbuffer);
  winfo->clear_color[2] = (GLfloat)dbuffer;
  get_double_field(L, "A", &dbuffer);
  winfo->clear_color[3] = (GLfloat)dbuffer;
  lua_pop(L, 1);

  return SD_OK;
}

scripts_struct const scripts = {
  .read_init_info=read_init_info
};


/**
* Copyright 2016 BitTorrent Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once

#include <scraps/config.h>

#include <scraps/base64.h>
#include <scraps/Byte.h>
#include <scraps/hex.h>
#include <scraps/Temp.h>
#include <scraps/random.h>
#include <scraps/hash.h>
#include <stdts/optional.h>

#include <gsl.h>

#include <cerrno>
#include <vector>
#include <iterator>
#include <random>
#include <chrono>

namespace scraps {

constexpr double kPi = 3.1415926535897932385;

/**
* Returns a string escaped according to RFC 4627.
*
* @param the string to be escaped
* @return the string escaped according to RFC 4627
*/
std::string JSONEscape(const char* str);

/**
* Returns a string in which all non-alphanumeric characters except dashes, underscores,
* spaces, and periods are replaced with a percent sign followed by their hexadecimal
* value. Spaces are replaced with plus signs.
*
* @return the url-encoded string
*/
std::string URLEncode(const char* str);

inline std::string URLEncode(const std::string& str) { return URLEncode(str.c_str()); }

/**
* Returns a string in which the effects of URLEncode have been reversed.
*
* @return the url-decoded string
*/
std::string URLDecode(const char* str);

inline std::string URLDecode(const std::string& str) { return URLDecode(str.c_str()); }

/**
 * Clamp a value between min and max, inclusive.
 */
template <typename T, typename MinT, typename MaxT>
constexpr auto Clamp(const T& value, const MinT& min, const MaxT& max) {
    return std::max<std::common_type_t<T, MinT, MaxT>>(min, std::min<std::common_type_t<T, MinT, MaxT>>(value, max));
}

/**
* Parse out an address and port from the given host string. If a port is not found, the
* defaultPort is returned.
*/
std::tuple<std::string, uint16_t> ParseAddressAndPort(const std::string& host, uint16_t defaultPort);

/**
* @return the amount of physical memory that the system has, or 0 on error
*/
size_t PhysicalMemory();

/**
* Iterates over a container, allowing for safe modification of the container at any point.
*/
template <typename T, typename F>
void NonatomicIteration(T&& iterable, F&& function) {
    auto copy = iterable;
    for (auto& element : copy) {
        auto it = std::find(iterable.begin(), iterable.end(), element);
        if (it == iterable.end()) {
            continue;
        }
        function(element);
    }
}

template <typename T, std::ptrdiff_t N>
gsl::basic_string_span<T> TrimLeft(gsl::basic_string_span<T, N> str) {
    decltype(str.size()) i = 0;
    while(i < str.size() && isspace(str[i])) { ++i; };
    return {str.data() + i, static_cast<std::ptrdiff_t>(str.size() - i)};
}

template <typename T, std::ptrdiff_t N>
gsl::basic_string_span<T> TrimRight(gsl::basic_string_span<T, N> str) {
    decltype(str.size()) i = str.size();
    while(i > 0 && isspace(str[i - 1])) { --i; };
    return {str.data(), static_cast<std::ptrdiff_t>(i)};
}

template <typename T, std::ptrdiff_t N>
auto Trim(gsl::basic_string_span<T, N> str) {
    return TrimLeft(TrimRight(str));
}

stdts::optional<std::vector<Byte>> BytesFromFile(const std::string& path);

/**
* Sets the given file descriptor to blocking or non-blocking.
*
* @param fd the file descriptor
* @param blocking true if the file descriptor should be set to blocking. false if it should be set to non-blocking
* @return true on success
*/
bool SetBlocking(int fd, bool blocking = true);

/**
* Returns a demangled symbol name. If demangling is not supported, returns original mangled name.
*/
std::string Demangle(const char* name);

/**
* Returns whether two strings are equal disregarding case
*/
inline bool CaseInsensitiveEquals(stdts::string_view l, stdts::string_view r) {
    return l.size() == r.size() && std::equal(l.begin(), l.end(), r.begin(), [](char a, char b){ return tolower(a) == tolower(b); });
}

/**
* Split a sequence on a delimiter. The SequenceType template argument should be
* specified to the type of container OutputIt should accept. By default, it is
* set OutputIt::container_type::value_type.
*
* @param begin beginning of input sequence
* @param end end of input sequence
* @param out output iterator to a container of Sequence types
* @param delimiter a single element element in the sequence
*/
template <typename InputIt, typename OutputIt, typename Delimiter, typename SequenceType = typename OutputIt::container_type::value_type>
void Split(InputIt&& begin, InputIt&& end, OutputIt&& out, Delimiter&& delimiter) {
    SequenceType current;
    auto inserter = std::back_inserter(current);
    for (auto it = begin; it != end; ++it) {
        if (*it == delimiter) {
            *(out++) = std::move(current);
            current = {};
            inserter = std::back_inserter(current);
        } else {
            inserter = *it;
        }
    }
    *out = std::move(current);
}

} // namespace scraps


#include <ceed.h>
#include <petsc.h>
#include "../problems/problems.h"

PetscErrorCode RegisterProblems(ProblemFunctions problem_functions) {
  PetscErrorCode ierr;

  PetscFunctionBegin;

  SOLIDS_PROBLEM_REGISTER(problem_functions, "Linear", ElasLinear, NH);
  SOLIDS_PROBLEM_REGISTER(problem_functions, "SS-NH", ElasSSNH, NH);
  SOLIDS_PROBLEM_REGISTER(problem_functions, "FSCurrent-NH1", ElasFSCurrentNH1,
                          NH);
  SOLIDS_PROBLEM_REGISTER(problem_functions, "FSCurrent-NH2", ElasFSCurrentNH2,
                          NH);
  SOLIDS_PROBLEM_REGISTER(problem_functions, "FSInitial-NH1", ElasFSInitialNH1,
                          NH);
  SOLIDS_PROBLEM_REGISTER(problem_functions, "FSInitial-NH2", ElasFSInitialNH2,
                          NH);
  SOLIDS_PROBLEM_REGISTER(problem_functions, "FSInitial-MR1", ElasFSInitialMR1,
                          MR);

  PetscFunctionReturn(0);
};


#pragma once

#include "CesiumUtility/Library.h"
#include <cmath>
#include <cstdint>
#include <gsl/narrow>
#include <initializer_list>
#include <map>
#include <optional>
#include <stdexcept>
#include <string>
#include <string_view>
#include <type_traits>
#include <variant>
#include <vector>

namespace CesiumUtility {

struct JsonValueMissingKey : public std::runtime_error {
  JsonValueMissingKey(const std::string& key)
      : std::runtime_error(key + " is not present in Object") {}
};

struct JsonValueNotRealValue : public std::runtime_error {
  JsonValueNotRealValue()
      : std::runtime_error("this->value was not double, uint64_t or int64_t") {}
};

template <typename T, typename U>
constexpr T losslessNarrowOrDefault(U u, T defaultValue) noexcept {
  constexpr const bool is_different_signedness =
      (std::is_signed<T>::value != std::is_signed<U>::value);

  const T t = gsl::narrow_cast<T>(u);

  if (static_cast<U>(t) != u ||
      (is_different_signedness && ((t < T{}) != (u < U{})))) {
    return defaultValue;
  }

  return t;
}

/**
 * @brief A generic implementation of a value in a JSON structure.
 *
 * Instances of this class are used to represent the common `extras` field
 * of glTF elements that extend the the {@link ExtensibleObject} class.
 */
class CESIUMUTILITY_API JsonValue final {
public:
  /**
   * @brief The type to represent a `null` JSON value.
   */
  using Null = std::nullptr_t;

  /**
   * @brief The type to represent a `Bool` JSON value.
   */
  using Bool = bool;

  /**
   * @brief The type to represent a `String` JSON value.
   */
  using String = std::string;

  /**
   * @brief The type to represent an `Object` JSON value.
   */
  using Object = std::map<std::string, JsonValue>;

  /**
   * @brief The type to represent an `Array` JSON value.
   */
  using Array = std::vector<JsonValue>;

  /**
   * @brief Default constructor.
   */
  JsonValue() : value() {}

  /**
   * @brief Creates a `null` JSON value.
   */
  JsonValue(std::nullptr_t) : value(nullptr) {}

  /**
   * @brief Creates a `Number` JSON value.
   *
   * NaN and ±Infinity are represented as {@link JsonValue::Null}.
   */
  JsonValue(double v) {
    if (std::isnan(v) || std::isinf(v)) {
      value = nullptr;
    } else {
      value = v;
    }
  }

  /**
   * @brief Creates a `std::int64_t` JSON value (Widening conversion from
   * std::int8_t).
   */
  JsonValue(std::int8_t v) : value(static_cast<std::int64_t>(v)) {}

  /**
   * @brief Creates a `std::uint64_t` JSON value (Widening conversion from
   * std::uint8_t).
   */
  JsonValue(std::uint8_t v) : value(static_cast<std::uint64_t>(v)) {}

  /**
   * @brief Creates a `std::int64_t` JSON value (Widening conversion from
   * std::int16_t).
   */
  JsonValue(std::int16_t v) : value(static_cast<std::int64_t>(v)) {}

  /**
   * @brief Creates a `std::uint64_t` JSON value (Widening conversion from
   * std::uint16_t).
   */
  JsonValue(std::uint16_t v) : value(static_cast<std::uint64_t>(v)) {}

  /**
   * @brief Creates a `std::int64_t` JSON value (Widening conversion from
   * std::int32_t).
   */
  JsonValue(std::int32_t v) : value(static_cast<std::int64_t>(v)) {}

  /**
   * @brief Creates a `std::uint64_t` JSON value (Widening conversion from
   * std::uint32_t).
   */
  JsonValue(std::uint32_t v) : value(static_cast<std::uint64_t>(v)) {}

  /**
   * @brief Creates a `std::int64_t` JSON value.
   */
  JsonValue(std::int64_t v) : value(v) {}

  /**
   * @brief Creates a `std::uint64_t` JSON value.
   */
  JsonValue(std::uint64_t v) : value(v) {}

  /**
   * @brief Creates a `Bool` JSON value.
   */
  JsonValue(bool v) : value(v) {}

  /**
   * @brief Creates a `String` JSON value.
   */
  JsonValue(const std::string& v) : value(v) {}

  /**
   * @brief Creates a `String` JSON value.
   */
  JsonValue(std::string&& v) : value(std::move(v)) {}

  /**
   * @brief Creates a `String` JSON value.
   */
  JsonValue(const char* v) : value(std::string(v)) {}

  /**
   * @brief Creates an `Object` JSON value with the given properties.
   */
  JsonValue(const std::map<std::string, JsonValue>& v) : value(v) {}

  /**
   * @brief Creates an `Object` JSON value with the given properties.
   */
  JsonValue(std::map<std::string, JsonValue>&& v) : value(std::move(v)) {}

  /**
   * @brief Creates an `Array` JSON value with the given elements.
   */
  JsonValue(const std::vector<JsonValue>& v) : value(v) {}

  /**
   * @brief Creates an `Array` JSON value with the given elements.
   */
  JsonValue(std::vector<JsonValue>&& v) : value(std::move(v)) {}

  /**
   * @brief Creates an JSON value from the given initializer list.
   */
  JsonValue(std::initializer_list<JsonValue> v)
      : value(std::vector<JsonValue>(v)) {}

  /**
   * @brief Creates an JSON value from the given initializer list.
   */
  JsonValue(std::initializer_list<std::pair<const std::string, JsonValue>> v)
      : value(std::map<std::string, JsonValue>(v)) {}

  [[nodiscard]] const JsonValue*
  getValuePtrForKey(const std::string& key) const;
  [[nodiscard]] JsonValue* getValuePtrForKey(const std::string& key);

  /**
   * @brief Gets a typed value corresponding to the given key in the
   * object represented by this instance.
   *
   * If this instance is not a {@link JsonValue::Object}, returns
   * `nullptr`. If the key does not exist in this object, returns
   * `nullptr`. If the named value does not have the type T, returns
   * nullptr.
   *
   * @tparam T The expected type of the value.
   * @param key The key for which to retrieve the value from this object.
   * @return A pointer to the requested value, or nullptr if the value
   * cannot be obtained as requested.
   */
  template <typename T>
  const T* getValuePtrForKey(const std::string& key) const {
    const JsonValue* pValue = this->getValuePtrForKey(key);
    if (!pValue) {
      return nullptr;
    }

    return std::get_if<T>(&pValue->value);
  }

  /**
   * @brief Gets a typed value corresponding to the given key in the
   * object represented by this instance.
   *
   * If this instance is not a {@link JsonValue::Object}, returns
   * `nullptr`. If the key does not exist in this object, returns
   * `nullptr`. If the named value does not have the type T, returns
   * nullptr.
   *
   * @tparam T The expected type of the value.
   * @param key The key for which to retrieve the value from this object.
   * @return A pointer to the requested value, or nullptr if the value
   * cannot be obtained as requested.
   */
  template <typename T> T* getValuePtrForKey(const std::string& key) {
    JsonValue* pValue = this->getValuePtrForKey(key);
    return std::get_if<T>(&pValue->value);
  }

  /**
   * @brief Converts the numerical value corresponding to the given key
   * to the provided numerical template type.

   * If this instance is not a {@link JsonValue::Object}, throws
   * `std::bad_variant_access`. If the key does not exist in this object, throws
   * `JsonValueMissingKey`. If the named value does not have a numerical type T,
   *  throws `JsonValueNotRealValue`, if the named value cannot be converted
   from
   * `double` / `std::uint64_t` / `std::int64_t` without precision loss, throws
   * `gsl::narrowing_error`
   * @tparam To The expected type of the value.
   * @param key The key for which to retrieve the value from this object.
   * @return The converted value.
   * @throws If unable to convert the converted value for one of the
   aforementioned reasons.
   * @remarks Compilation will fail if type 'To' is not an integral / float /
   double type.
   */
  template <
      typename To,
      typename std::enable_if<
          std::is_integral<To>::value ||
          std::is_floating_point<To>::value>::type* = nullptr>
  [[nodiscard]] To getSafeNumericalValueForKey(const std::string& key) const {
    const Object& pObject = std::get<Object>(this->value);
    const auto it = pObject.find(key);
    if (it == pObject.end()) {
      throw JsonValueMissingKey(key);
    }
    return it->second.getSafeNumber<To>();
  }

  /**
   * @brief Converts the numerical value corresponding to the given key
   * to the provided numerical template type.
   *
   * If this instance is not a {@link JsonValue::Object}, the key does not exist
   * in this object, or the named value does not have a numerical type that can
   * be represented as T without precision loss, then the default value is
   * returned.
   *
   * @tparam To The expected type of the value.
   * @param key The key for which to retrieve the value from this object.
   * @return The converted value.
   * @throws If unable to convert the converted value for one of the
   * aforementioned reasons.
   * @remarks Compilation will fail if type 'To' is not an integral / float /
   * double type.
   */
  template <
      typename To,
      typename std::enable_if<
          std::is_integral<To>::value ||
          std::is_floating_point<To>::value>::type* = nullptr>
  [[nodiscard]] To getSafeNumericalValueOrDefaultForKey(
      const std::string& key,
      To defaultValue) const {
    const Object& pObject = std::get<Object>(this->value);
    const auto it = pObject.find(key);
    if (it == pObject.end()) {
      return defaultValue;
    }
    return it->second.getSafeNumberOrDefault<To>(defaultValue);
  }

  /**
   * @brief Determines if this value is an Object and has the given key.
   *
   * @param key The key.
   * @return true if this value contains the key. false if it is not an object
   * or does not contain the given key.
   */
  [[nodiscard]] inline bool hasKey(const std::string& key) const {
    const Object* pObject = std::get_if<Object>(&this->value);
    if (!pObject) {
      return false;
    }

    return pObject->find(key) != pObject->end();
  }

  /**
   * @brief Gets the numerical quantity from the value casted to the `To`
   * type. This function should be used over `getDouble()` / `getUint64()` /
   * `getInt64()` if you plan on casting that type into another smaller type or
   * different type.
   * @returns The converted type if it can be cast without precision loss.
   * @throws If the underlying value is not a numerical type or it cannot be
   *         converted without precision loss.
   */
  template <
      typename To,
      typename std::enable_if<
          std::is_integral<To>::value ||
          std::is_floating_point<To>::value>::type* = nullptr>
  [[nodiscard]] To getSafeNumber() const {
    const std::uint64_t* uInt = std::get_if<std::uint64_t>(&this->value);
    if (uInt) {
      return gsl::narrow<To>(*uInt);
    }

    const std::int64_t* sInt = std::get_if<std::int64_t>(&this->value);
    if (sInt) {
      return gsl::narrow<To>(*sInt);
    }

    const double* real = std::get_if<double>(&this->value);
    if (real) {
      return gsl::narrow<To>(*real);
    }

    throw JsonValueNotRealValue();
  }

  /**
   * @brief Gets the numerical quantity from the value casted to the `To`
   * type or returns defaultValue if unable to do so.

   * @returns The converted type if it can be cast without precision loss
   * or `defaultValue` if it cannot be converted safely.
   */
  template <
      typename To,
      typename std::enable_if<
          std::is_integral<To>::value ||
          std::is_floating_point<To>::value>::type* = nullptr>
  [[nodiscard]] To getSafeNumberOrDefault(To defaultValue) const noexcept {
    const std::uint64_t* uInt = std::get_if<std::uint64_t>(&this->value);
    if (uInt) {
      return losslessNarrowOrDefault<To>(*uInt, defaultValue);
    }

    const std::int64_t* sInt = std::get_if<std::int64_t>(&this->value);
    if (sInt) {
      return losslessNarrowOrDefault<To>(*sInt, defaultValue);
    }

    const double* real = std::get_if<double>(&this->value);
    if (real) {
      return losslessNarrowOrDefault<To>(*real, defaultValue);
    }

    return defaultValue;
  }

  /**
   * @brief Gets the object from the value.
   * @return The object.
   * @throws std::bad_variant_access if the underlying type is not a
   * JsonValue::Object
   */

  [[nodiscard]] inline const JsonValue::Object& getObject() const {
    return std::get<JsonValue::Object>(this->value);
  }

  /**
   * @brief Gets the string from the value.
   * @return The string.
   * @throws std::bad_variant_access if the underlying type is not a
   * JsonValue::String
   */
  [[nodiscard]] inline const JsonValue::String& getString() const {
    return std::get<String>(this->value);
  }

  /**
   * @brief Gets the array from the value.
   * @return The arrayj.
   * @throws std::bad_variant_access if the underlying type is not a
   * JsonValue::Array
   */
  [[nodiscard]] inline const JsonValue::Array& getArray() const {
    return std::get<JsonValue::Array>(this->value);
  }

  /**
   * @brief Gets the bool from the value.
   * @return The bool.
   * @throws std::bad_variant_access if the underlying type is not a
   * JsonValue::Bool
   */
  [[nodiscard]] inline bool getBool() const {
    return std::get<bool>(this->value);
  }

  /**
   * @brief Gets the double from the value.
   * @return The double.
   * @throws std::bad_variant_access if the underlying type is not a double
   */
  [[nodiscard]] inline double getDouble() const {
    return std::get<double>(this->value);
  }

  /**
   * @brief Gets the std::uint64_t from the value.
   * @return The std::uint64_t.
   * @throws std::bad_variant_access if the underlying type is not a
   * std::uint64_t
   */
  [[nodiscard]] std::uint64_t getUint64() const {
    return std::get<std::uint64_t>(this->value);
  }

  /**
   * @brief Gets the std::int64_t from the value.
   * @return The std::int64_t.
   * @throws std::bad_variant_access if the underlying type is not a
   * std::int64_t
   */
  [[nodiscard]] std::int64_t getInt64() const {
    return std::get<std::int64_t>(this->value);
  }

  /**
   * @brief Gets the bool from the value or returns defaultValue
   * @return The bool or defaultValue if this->value is not a bool.
   */
  [[nodiscard]] inline bool getBoolOrDefault(bool defaultValue) const {
    const auto* v = std::get_if<bool>(&this->value);
    if (v) {
      return *v;
    }

    return defaultValue;
  }

  /**
   * @brief Gets the string from the value or returns defaultValue
   * @return The string or defaultValue if this->value is not a string.
   */
  [[nodiscard]] inline const JsonValue::String
  getStringOrDefault(String defaultValue) const {
    const auto* v = std::get_if<JsonValue::String>(&this->value);
    if (v) {
      return *v;
    }

    return defaultValue;
  }

  /**
   * @brief Gets the double from the value or returns defaultValue
   * @return The double or defaultValue if this->value is not a double.
   */
  [[nodiscard]] inline double getDoubleOrDefault(double defaultValue) const {
    const auto* v = std::get_if<double>(&this->value);
    if (v) {
      return *v;
    }

    return defaultValue;
  }

  /**
   * @brief Gets the uint64_t from the value or returns defaultValue
   * @return The uint64_t or defaultValue if this->value is not a uint64_t.
   */
  [[nodiscard]] inline std::uint64_t
  getUint64OrDefault(std::uint64_t defaultValue) const {
    const auto* v = std::get_if<std::uint64_t>(&this->value);
    if (v) {
      return *v;
    }

    return defaultValue;
  }

  /**
   * @brief Gets the int64_t from the value or returns defaultValue
   * @return The int64_t or defaultValue if this->value is not a int64_t.
   */
  [[nodiscard]] inline std::int64_t
  getInt64OrDefault(std::int64_t defaultValue) const {
    const auto* v = std::get_if<std::int64_t>(&this->value);
    if (v) {
      return *v;
    }

    return defaultValue;
  }

  /**
   * @brief Returns whether this value is a `null` value.
   */
  [[nodiscard]] inline bool isNull() const noexcept {
    return std::holds_alternative<Null>(this->value);
  }

  /**
   * @brief Returns whether this value is a `double`, `std::uint64_t` or
   * `std::int64_t`. Use this function in conjunction with `getNumber` for
   *  safely casting to arbitrary types
   */
  [[nodiscard]] inline bool isNumber() const noexcept {
    return isDouble() || isUint64() || isInt64();
  }

  /**
   * @brief Returns whether this value is a `Bool` value.
   */
  [[nodiscard]] inline bool isBool() const noexcept {
    return std::holds_alternative<Bool>(this->value);
  }

  /**
   * @brief Returns whether this value is a `String` value.
   */
  [[nodiscard]] inline bool isString() const noexcept {
    return std::holds_alternative<String>(this->value);
  }

  /**
   * @brief Returns whether this value is an `Object` value.
   */
  [[nodiscard]] inline bool isObject() const noexcept {
    return std::holds_alternative<Object>(this->value);
  }

  /**
   * @brief Returns whether this value is an `Array` value.
   */
  [[nodiscard]] inline bool isArray() const noexcept {
    return std::holds_alternative<Array>(this->value);
  }

  /**
   * @brief Returns whether this value is a `double` value.
   */
  [[nodiscard]] inline bool isDouble() const noexcept {
    return std::holds_alternative<double>(this->value);
  }

  /**
   * @brief Returns whether this value is a `std::uint64_t` value.
   */
  [[nodiscard]] inline bool isUint64() const noexcept {
    return std::holds_alternative<std::uint64_t>(this->value);
  }

  /**
   * @brief Returns whether this value is a `std::int64_t` value.
   */
  [[nodiscard]] inline bool isInt64() const noexcept {
    return std::holds_alternative<std::int64_t>(this->value);
  }

  /**
   * @brief The actual value.
   *
   * The type of the value may be queried with the `isNull`, `isDouble`,
   * `isBool`, `isString`, `isObject`, `isUint64`, `isInt64`, `isNumber`, and
   * `isArray` functions.
   *
   * The actual value may be obtained with the `getNumber`, `getBool`,
   * and `getString` functions for the respective types. For
   * `Object` values, the properties may be accessed with the
   * `getValueForKey` functions.
   */
  std::variant<
      Null,
      double,
      std::uint64_t,
      std::int64_t,
      Bool,
      String,
      Object,
      Array>
      value;
};
} // namespace CesiumUtility


#pragma once
/*
 * (C) Copyright 2020-2021 UCAR
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 */
/*! \defgroup ioda_cxx_types Type System
 * \brief The data type system
 * \ingroup ioda_cxx_api
 *
 * @{
 * \file Type.h
 * \brief Interfaces for ioda::Type and related classes. Implements the type system.
 */
#include <array>
#include <cstring>
#include <functional>
#include <gsl/gsl-lite.hpp>
#include <memory>
#include <string>
#include <typeindex>
#include <typeinfo>
#include <vector>

#include "ioda/Exception.h"
#include "ioda/Types/Type_Provider.h"
#include "ioda/defs.h"

namespace ioda {
class Group;
class Type;

/// Basic pre-defined types (Python convenience wrappers)
/// \see py_ioda.cpp
/// \note Names here do not match the Python equivalents. The
///   Python names match numpy's definitions.
enum class BasicTypes {
  undefined_,  ///< Internal use only
  float_,
  double_,
  ldouble_,
  char_,
  short_,
  ushort_,
  int_,
  uint_,
  lint_,
  ulint_,
  llint_,
  ullint_,
  int32_,
  uint32_,
  int16_,
  uint16_,
  int64_,
  uint64_,
  bool_,
  str_
};

/// \brief Data Types can be grouped into a few categories. These are the categories.
/// \note  Not all backends implement all types.
enum class TypeClass {
  Unknown,    ///< Unsupported / unhandled type
  Integer,    ///< All integer types
  Float,      ///< All floating-point types
  String,     ///< All string types (fixed-length, variable, ASCII, UTF-8)
  Bitfield,   ///< All bit fields
  Opaque,     ///< All binary blobs
  Compound,   ///< All compound types (types with member elements)
  Reference,  ///< All object references
  Enum,       ///< All enumerated types
  VlenArray,  ///< All variable-length array types (not strings)
  FixedArray  ///< All fixed-length array types
};

namespace detail {
/// \brief Convenience function to safely copy a string.
IODA_DL size_t COMPAT_strncpy_s(char* dest, size_t destSz, const char* src, size_t srcSz);

class Type_Backend;

template <class Type_Implementation = Type>
class Type_Base {
  friend class ::ioda::Type;
  std::shared_ptr<Type_Backend> backend_;

protected:
  ::ioda::detail::Type_Provider* provider_;

  /// @name General Functions
  /// @{

  Type_Base(std::shared_ptr<Type_Backend> b, ::ioda::detail::Type_Provider* p)
      : backend_(b), provider_(p) {}

  /// Get the type provider.
  inline detail::Type_Provider* getTypeProvider() const { return provider_; }

public:
  virtual ~Type_Base() {}
  std::shared_ptr<Type_Backend> getBackend() const { return backend_; }
  bool isValid() const { return (backend_.use_count() > 0); }

  /// @}
  /// @name General functions
  /// @{

  /// \brief Get the size of a type, in bytes.
  /// \details This function is paired with the read and write functions to allow you to
  /// read and write data in a type-agnostic manner.
  /// This size report is a bit complicated when variable-length strings are encountered.
  /// In these cases, the size of the string pointer is returned.
  virtual size_t getSize() const;

  /// \brief Does this type represent a string, an integer, a float, an array, an
  ///   enumeration, a bitset, or any other type?
  virtual TypeClass getClass() const;

  /// \brief Save (commit) the type to a backend
  /// \details From the HDF5 docs:
  ///   Committed datatypes can be used to save space in a file where many
  ///   datasets or attributes use the same datatype or to avoid defining a complex
  ///   compound datatype more than once. Committed datatypes can also be used to ensure
  ///   that multiple instances of the same datatype are truly identical.
  ///
  ///   This is used extensively for enumerated types.
  virtual void commitToBackend(Group& d, const std::string& name) const;

  /// @}
  /// @name Numeric type functions
  /// @{

  /// \brief Is this type signed or unsigned?
  /// \returns true if signed, false if unsigned.
  /// \throws if the type is not a numeric type (i.e. not a simple integer or float).
  virtual bool isTypeSigned() const;

  /// @}
  /// @name String type functions
  /// @{

  /// \brief Is this a variable-length string type?
  /// \returns true if a variable-length string type, false if not.
  ///   False can imply either that the type is a fixed-length string type (if getClass() == TypeClass::String),
  ///   or that the type is not a string type at all.
  virtual bool isVariableLengthStringType() const;

  /// \brief Get the character set of this string type.
  /// \returns Ascii or Unicode.
  /// \throws ioda::Exception on error, or if the type is not a string type.
  /// \note Currently, there is no way to set the character set. Everything is
  ///   assumed to be a UTF-8 string in IODA.
  virtual StringCSet getStringCSet() const;

  /// @}
  /// @name Array type functions
  /// @{

  /// \brief Get the "base" type of an object. For an array, this is the type of
  ///   the array's elements. I.e. an array of int32_t has a base type of int32_t.
  ///   For an enumerated type, this is the type used for the enumeration.
  virtual Type_Implementation getBaseType() const;

  /// \brief Get the dimensions of an array type.
  /// \returns A vector of the dimensions. vector::size() is the rank (dimensionality).
  virtual std::vector<Dimensions_t> getDimensions() const;

  /// @}
};
}  // namespace detail

/// \brief Represents the "type" (i.e. integer, string, float) of a piece of data.
/// \ingroup ioda_cxx_types
///
/// Generally, you do not have to use this class directly. Attributes and Variables have
/// templated functions that convert your type into the type used internally by ioda.
/// \see Types::GetType and Types::GetType_Wrapper for functions that produce these types.
class IODA_DL Type : public detail::Type_Base<> {
public:
  Type();
  Type(std::shared_ptr<detail::Type_Backend> b, std::type_index t);
  Type(BasicTypes, gsl::not_null<::ioda::detail::Type_Provider*> t);

  virtual ~Type();

  /// @name Type-querying functions
  /// @{

  /// @deprecated This function is problematic since we cannot query a type properly
  /// when loading from a file.
  std::type_index getType() const { return as_type_index_; }
  inline std::type_index operator()() const { return getType(); }
  inline std::type_index get() const { return getType(); }

  /// @}
private:
  std::type_index as_type_index_;
};

namespace detail {

/// Backends inherit from this and they provide their own functions.
/// Lots of std::dynamic_cast, unfortunately.
class IODA_DL Type_Backend : public Type_Base<> {
public:
  virtual ~Type_Backend();
  StringCSet getStringCSet() const override;

protected:
  Type_Backend();
};

}  // namespace detail

/// \brief Defines the type system used for manipulating IODA objects.
namespace Types {

// using namespace ioda::Handles;

/// \brief Convenience struct to determine if a type can represent a string.
/// \ingroup ioda_cxx_types
/// \todo extend to UTF-8 strings, as HDF5 supports these. No support for UTF-16, but conversion
/// functions may be applied.
/// \todo Fix for "const std::string".
template <typename T>
struct is_string : public std::integral_constant<
                     bool, std::is_same<char*, typename std::decay<T>::type>::value
                             || std::is_same<const char*, typename std::decay<T>::type>::value> {};
/// \brief Convenience struct to determine if a type can represent a string.
/// \ingroup ioda_cxx_types
template <>
struct is_string<std::string> : std::true_type {};

/// Useful compile-time definitions.
namespace constants {
/// \note Different than ObsSpace variable-length dimension. This is for a Type.
constexpr size_t _Variable_Length = 0;
// constexpr int _Not_An_Array_type = -3;
}  // namespace constants

/// \brief For fundamental, non-string types.
/// \ingroup ioda_cxx_types
template <class DataType, int Array_Type_Dimensionality = 0>
Type GetType(gsl::not_null<const ::ioda::detail::Type_Provider*> t,
             std::initializer_list<Dimensions_t> Adims                   = {},
             typename std::enable_if<!is_string<DataType>::value>::type* = 0) {
  if (Array_Type_Dimensionality <= 0)
    throw Exception(
      "Bad assertion / unsupported type at the frontend side "
      "of the ioda type system.",
      ioda_Here());
  else
    return t->makeArrayType(Adims, typeid(DataType[]), typeid(DataType));
}
/// \brief For fundamental string types. These are either constant or variable length arrays.
/// Separate handling elsewhere.
/// \ingroup ioda_cxx_types
/// \todo Once C++20 support is added, make a distinction between std::string and std::u8string.
template <class DataType, int String_Type_Length = constants::_Variable_Length>
Type GetType(gsl::not_null<const ::ioda::detail::Type_Provider*> t,
             std::initializer_list<Dimensions_t>                        = {},
             typename std::enable_if<is_string<DataType>::value>::type* = 0) {
  return t->makeStringType(typeid(DataType), String_Type_Length);
}

// This macro just repeats a long definition

/// @def IODA_ADD_FUNDAMENTAL_TYPE
/// Macro that defines a "fundamental type" that needs to be supported
/// by the backend. These match C++11.
/// \ingroup ioda_cxx_types
/// \see https://en.cppreference.com/w/cpp/language/types
/// \since C++11: we use bool, short int, unsigned short int,
///   int, unsigned int, long int, unsigned long int,
///   long long int, unsigned long long int,
///   signed char, unsigned char, char,
///   wchar_t, char16_t, char32_t,
///   float, double, long double.
/// \since C++20: we also add char8_t.
#define IODA_ADD_FUNDAMENTAL_TYPE(x)                                                               \
  template <>                                                                                \
  inline Type GetType<x, 0>(gsl::not_null<const ::ioda::detail::Type_Provider*> t,                 \
                            std::initializer_list<Dimensions_t>, void*) {                          \
    return t->makeFundamentalType(typeid(x));                                                      \
  }

IODA_ADD_FUNDAMENTAL_TYPE(bool);
IODA_ADD_FUNDAMENTAL_TYPE(short int);
IODA_ADD_FUNDAMENTAL_TYPE(unsigned short int);
IODA_ADD_FUNDAMENTAL_TYPE(int);
IODA_ADD_FUNDAMENTAL_TYPE(unsigned int);
IODA_ADD_FUNDAMENTAL_TYPE(long int);
IODA_ADD_FUNDAMENTAL_TYPE(unsigned long int);
IODA_ADD_FUNDAMENTAL_TYPE(long long int);
IODA_ADD_FUNDAMENTAL_TYPE(unsigned long long int);
IODA_ADD_FUNDAMENTAL_TYPE(signed char);
IODA_ADD_FUNDAMENTAL_TYPE(unsigned char);
IODA_ADD_FUNDAMENTAL_TYPE(char);
IODA_ADD_FUNDAMENTAL_TYPE(wchar_t);
IODA_ADD_FUNDAMENTAL_TYPE(char16_t);
IODA_ADD_FUNDAMENTAL_TYPE(char32_t);
// IODA_ADD_FUNDAMENTAL_TYPE(char8_t); // C++20
IODA_ADD_FUNDAMENTAL_TYPE(float);
IODA_ADD_FUNDAMENTAL_TYPE(double);
IODA_ADD_FUNDAMENTAL_TYPE(long double);

#undef IODA_ADD_FUNDAMENTAL_TYPE

/*
/// Used in an example. Incomplete.
/// \todo Pop off std::array as a 1-D object
template<> inline Type GetType<std::array<int,2>, 0>
        (gsl::not_null<const ::ioda::detail::Type_Provider*> t,
        std::initializer_list<Dimensions_t>, void*) {
        return t->makeArrayType({2}, typeid(std::array<int,2>), typeid(int)); }

*/

/*
template <class DataType, int Array_Type_Dimensionality = 0>
Type GetType(
        gsl::not_null<const ::ioda::detail::Type_Provider*> t,
        std::initializer_list<Dimensions_t> Adims = {},
        typename std::enable_if<!is_string<DataType>::value>::type* = 0);
template <class DataType, int String_Type_Length = constants::_Variable_Length>
Type GetType(
        gsl::not_null<const ::ioda::detail::Type_Provider*> t,
        typename std::enable_if<is_string<DataType>::value>::type* = 0);
        */

/// \brief Wrapper struct to call GetType. Needed because of C++ template rules.
/// \ingroup ioda_cxx_types
/// \see ioda::Attribute, ioda::Has_Attributes, ioda::Variable, ioda::Has_Variables
template <class DataType,
          int Length = 0>  //, typename = std::enable_if_t<!is_string<DataType>::value>>
struct GetType_Wrapper {
  static Type GetType(gsl::not_null<const ::ioda::detail::Type_Provider*> t) {
    /// \note Currently breaks array types, but these are not yet used.
    return ::ioda::Types::GetType<DataType, Length>(t, {Length});
  }
};
/// \ingroup ioda_cxx_types
typedef std::function<Type(gsl::not_null<const ::ioda::detail::Type_Provider*>)>
  TypeWrapper_function;
/*
template <class DataType, int Length = 0, typename = std::enable_if_t<is_string<DataType>::value>>
struct GetType_Wrapper {
        Type GetType(gsl::not_null<const ::ioda::detail::Type_Provider*> t) const {
                // string split
                return ::ioda::Types::GetType<DataType, Length>(t);
        }
};
*/

// inline Encapsulated_Handle GetTypeFixedString(Dimensions_t sz);
}  // namespace Types
}  // namespace ioda

/// @}


#pragma once

#include <gsl\gsl>
#include <winrt\Windows.Foundation.h>
#include <d3d11.h>
#include "DrawableGameComponent.h"
#include "MatrixHelper.h"
#include "DirectionalLight.h"

namespace Library
{
	class Texture2D;
	class ProxyModel;
}

namespace Rendering
{
	class DisplacementMappingMaterial;

	class DisplacementMappingDemo final : public Library::DrawableGameComponent
	{
	public:
		DisplacementMappingDemo(Library::Game& game, const std::shared_ptr<Library::Camera>& camera);
		DisplacementMappingDemo(const DisplacementMappingDemo&) = delete;
		DisplacementMappingDemo(DisplacementMappingDemo&&) = default;
		DisplacementMappingDemo& operator=(const DisplacementMappingDemo&) = default;
		DisplacementMappingDemo& operator=(DisplacementMappingDemo&&) = default;
		~DisplacementMappingDemo();

		bool RealDisplacementMapEnabled() const;
		void SetRealDisplacementMapEnabled(bool enabled);
		void ToggleRealDisplacementMap();

		float AmbientLightIntensity() const;
		void SetAmbientLightIntensity(float intensity);

		float DirectionalLightIntensity() const;
		void SetDirectionalLightIntensity(float intensity);

		const DirectX::XMFLOAT3& LightDirection() const;
		void RotateDirectionalLight(DirectX::XMFLOAT2 amount);

		const float DisplacementScale() const;
		void SetDisplacementScale(float displacementScale);

		virtual void Initialize() override;
		virtual void Update(const Library::GameTime& gameTime) override;
		virtual void Draw(const Library::GameTime& gameTime) override;

	private:
		std::shared_ptr<DisplacementMappingMaterial> mMaterial;
		DirectX::XMFLOAT4X4 mWorldMatrix{ Library::MatrixHelper::Identity };
		winrt::com_ptr<ID3D11Buffer> mVertexBuffer;
		winrt::com_ptr<ID3D11Buffer> mIndexBuffer;
		std::uint32_t mIndexCount{ 0 };
		Library::DirectionalLight mDirectionalLight;
		std::unique_ptr<Library::ProxyModel> mProxyModel;
		std::shared_ptr<Library::Texture2D> mRealDisplacementMap;
		std::shared_ptr<Library::Texture2D> mDefaultDisplacementMap;
		bool mUpdateMaterial{ true };
		bool mRealDisplacementMapEnabled{ true };
	};
}


//#include <gsl/gsl>

#include "../Problem15/ipv4Base.h"

class ipv4Extend : public ipv4Base
{
public:
    ipv4Extend() : ipv4Base()
    {
    };

    ipv4Extend( std::string   aInput ) : ipv4Base( aInput )
    {
    };

    ~ipv4Extend()
    {
    };

    ipv4Extend& operator= ( const ipv4Extend & aOther )
    {
        if ( this != & aOther )
        {
            mIPAddress = aOther.mIPAddress;
        }

        return *this;
    }

    //ipv4Extend& operator= ( ipv4Extend && aOther )
    //{
    //    if ( this != &aOther )
    //    {
    //    }

    //    return *this;
    //}

    ipv4Extend& operator++()
    {
        increase();

        return *this;
    }

    ipv4Extend operator++( int )
    {
        ipv4Extend sTemp( *this );
        operator++();
        return sTemp;
    }

    friend bool operator== ( const ipv4Extend   & aLhs,
                             const ipv4Extend   & aRhs )
    {
        return (aLhs.mIPAddress == aRhs.mIPAddress);
    }

    friend bool operator!= ( const ipv4Extend   & aLhs,
                             const ipv4Extend   & aRhs )
    {
        return !( aLhs == aRhs );
    }

    friend bool operator < ( const ipv4Extend   & aLhs,
                             const ipv4Extend   & aRhs )
    {
        bool    sIsRigthBigger = false;

        for ( int i = 0; i < 4; i++ )
        {
            if ( aLhs.mIPAddress[i] < aRhs.mIPAddress[i] )
            {
                sIsRigthBigger = true;
                break;
            }
        }

        return sIsRigthBigger;
    }

    friend bool operator > ( const ipv4Extend   & aLhs,
                             const ipv4Extend   & aRhs )
    {
        return aRhs < aLhs;
    }

    friend bool operator <= ( const ipv4Extend   & aLhs,
                              const ipv4Extend   & aRhs )
    {
        return !( aLhs > aRhs );
    }

    friend bool operator >= ( const ipv4Extend   & aLhs,
                              const ipv4Extend   & aRhs )
    {
        return !( aLhs < aRhs );
    }

private:

    void increase()
    {
        bool    sIsRoundUp = false;

        mIPAddress[3]++;

        for ( auto sIt = mIPAddress.rbegin();
              sIt != mIPAddress.rend();
              sIt++ )
        {
            //std::cout << *sIt << "\n";
            if ( sIsRoundUp == true )
            {
                *sIt = *sIt + 1;
                //*sIt++;
            }

            //std::cout << *sIt << "\n";
            if ( (*sIt) > 255 )
            {
                sIsRoundUp = true;
                *sIt = 0;
            }
            else
            {
                sIsRoundUp = false;
            }
        }

        if ( sIsRoundUp == true )
        {
            mIPAddress[3]++;
        }
    }

    void decrease()
    {
        bool sIsRoundDown = false;
    }
};


//  © Shahram Talei @ 2020 The University of Alabama
//you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation; either version 3 of the License, or
//(at your option) any later version.
//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.
// This code is distributed as is and there is no warranty or technical support
// Reading stored data in a sage file
// How to run:
//first run:
//$make
//Then you can run"
// $./ExportForTracking > AllGals838.ascii
// If you have an error you may need to give permission
// $ chmod +x ExportForTracking
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
//#include <gsl/gsl_rng.h>
//#include <ctype.h>

////////////////////////////////////////////////////////////
//// Definitions and variables
char SageDir[500];
struct Path_Names
{
    char paths[100];
}*SageFilesPath;

int SageFilesCount;
int NumGalaxies;

// This structune holds all of the information from the Sage files
struct SageGalaxies
{
  int   Type;
  int   FileNr;
  long long   GalaxyIndex;
  int   HaloIndex;
  int   FOFHaloIndex; //SubhaloIndex;
  int   TreeIndex;

  int   SnapNum;
  int   CentralGal; //GalIndex;
  float CentralMvir;

   //properties of subhalo at the last time this galaxy was a central galaaxy
  float Pos[3];
  float Vel[3];
  float Spin[3];
  int   Len;
  float Mvir;
  float Rvir;
  float Vvir;
  float Vmax;
  float VelDisp;

   //baryonic reservoirs
  float ColdGas;
  float StellarMass;
  float BulgeMass;
  float HotGas;
  float EjectedMass;
  float BlackHoleMass;
  float ICS;
  //metals
 float MetalsColdGas;
 float MetalsStellarMass;
 float MetalsBulgeMass;
 float MetalsHotGas;
 float MetalsEjectedMass;
 float MetalsICS;

  //misc
 float Sfr;
 float SfrBulge;
 float SfrICS;
 float DiskScaleRadius;
 float Cooling;
 float Heating;
 float LastMajorMerger;
 float OutflowRate;

 float infallMvir;  //infall properties
 float infallVvir;
 float infallVmax;
 float r_heat;
 float Stars;

}*SageOutput;
//typedef struct SageGalaxies

////////////////////////////////////////////////////////////
//// Functions

int CountSageFiles(int snap)
{
         //int i=0;
         int n=0;
         char line[10000];
         char file1[10000];
         FILE *fd;
         sprintf(file1, "%s/sagefile_%03d.txt",SageDir, snap);
         fd = fopen(file1, "r");
         while(fgets(line, sizeof(line), fd)!=NULL)
         {
            n++;// 1;
         }
         fclose(fd);
         return n;
}
void ReadSageFNames(int snap,struct Path_Names *SageFile)
{
        //printf("Reading sage file-name(s) for snap:%d\n",snap);
    int i=0;
    char line[10000];
    char file1[10000];
    char ABSpath[10000];//2
    char model[500];
    FILE *fd;
    sprintf(file1, "%s/sagefile_%03d.txt", SageDir, snap);
    fd = fopen(file1, "r");
    while(EOF != fscanf(fd, "%s%*[^\n]", line))
    {
       strcpy(ABSpath,line);//2
       strcpy(model,strrchr(ABSpath,'/'));
       //strcpy(SageFilesPath[i].paths, line);//1
       if (model[0] == '/')
         memmove(model, model+1, strlen(model));
       sprintf(SageFile[i].paths,"%s/%s",SageDir,model);
       i++;
    }
   fclose(fd);
   return;
 }

 int ReadSageHeader(int FileCount,struct Path_Names *SageFile)
 {
      int Ntrees;
          int NtotGal;
          int totmal;
          int i;
          FILE *fd;
          char file1[1000];
          totmal = 0;
          for(i=0; i<FileCount; i++)
             {
                  sprintf(file1, "%s", SageFile[i].paths);
                  fd = fopen(file1, "rb");
                  if(NULL == fd)
                  {
                     printf("Cannot open sage file");
                     return(-1);
                  }
                  fread(&Ntrees, sizeof(int), 1, fd);
                  fread(&NtotGal, sizeof(int), 1, fd);
                  totmal = totmal + NtotGal;
                  fclose(fd);
             }
 return totmal;
 }

void LoadSageFiles(int snap)
{
        SageFilesCount = CountSageFiles(snap);
        SageFilesPath = (struct Path_Names*)malloc(SageFilesCount * sizeof(struct Path_Names));
        ReadSageFNames(snap,SageFilesPath);
        return;
    }

    void ReadSageModel(int FileCount,struct Path_Names *SageFile,struct SageGalaxies *Output)
    {
    int Ntrees;
               int NtotGal;
               int *galpertree;
               char file1[1000];
               int offset;
               int i;
               FILE *fd;
               offset = 0;
               for(i=0; i<FileCount; i++)
               {
                  sprintf(file1, "%s", SageFile[i].paths);
                  fd = fopen(file1, "rb");
                        if(NULL == fd)
                        {
                           printf("Cannot open sage for reading");
                           return;
                        }
                        fread(&Ntrees, sizeof(int), 1, fd);
                        fread(&NtotGal, sizeof(int), 1, fd);
                        galpertree = (int*)malloc(Ntrees*sizeof(int));
                        fread(&galpertree[0], sizeof(int), Ntrees, fd);
                        fread(&Output[offset], sizeof(struct SageGalaxies), NtotGal, fd);
                        fclose(fd);
                        offset = offset + NtotGal;
                }
                        free(galpertree);
                        return;
    }

void ReadSage(int snap)
{

//printf("Extracting information from the sage file.\n");
LoadSageFiles(snap);
fflush(stdout);
NumGalaxies = ReadSageHeader(SageFilesCount,SageFilesPath);

if(( SageOutput = (struct SageGalaxies*)malloc(NumGalaxies * sizeof(struct SageGalaxies))) == NULL)
    {
        printf("Failed to allocate for target sage...");
        return;
    }
ReadSageModel(SageFilesCount, SageFilesPath, SageOutput);
return;
}

void PrintGalaxyInfo(struct SageGalaxies *Output,int index)
{
  int i;
  i=index;
printf("~~~~~~~~~~~~~~~~~~~~~~∮∮∮∮∮∮∮∮∮∮∮∮~~~~~~~~~~~~~~~~~~~~~~\n");
printf("Galaxy Information- galaxy:%d, Type:%d, FileNr:%d\n",i,Output[i].Type,Output[i].FileNr);
printf("GalIndex:%lld,HaloIndex:%d,TreeIndex:%d,CentralGal:%d,CentralMvir:%f\n",Output[i].GalaxyIndex,Output[i].HaloIndex,
Output[i].TreeIndex,Output[i].CentralGal,Output[i].CentralMvir);
printf("Pos(x,y,z):(%f,%f,%f)\nVel(vx,vy,vz):(%f,%f,%f)\nSpin:(%f,%f,%f),Len:%d\n",Output[i].Pos[0],Output[i].Pos[1],
Output[i].Pos[2],Output[i].Vel[0],Output[i].Vel[1],Output[i].Vel[2],Output[i].Spin[0],Output[i].Spin[1],Output[i].Spin[2],Output[i].Len);

printf("Mvir:%f,Rvir:%f,Vvir:%f,Vmax:%f,VelDisp:%f\n",Output[i].Mvir,Output[i].Rvir,Output[i].Vvir,Output[i].Vmax,Output[i].VelDisp);

printf("ColdGas:%f,StellarMass:%f,BulgeMass:%f,HotGas:%f\nEjectedMass:%f,BHMass:%f,ICS:%f\n",Output[i].ColdGas,Output[i].StellarMass,
Output[i].BulgeMass,Output[i].HotGas,Output[i].EjectedMass,Output[i].BlackHoleMass,Output[i].ICS);

printf("\nMetals:\nColdGas:%f,StellarMass:%f,BulgeMass:%f,HotGas:%f\nEjectedMass:%f,ICS:%f\n\n",Output[i].MetalsColdGas,
Output[i].MetalsStellarMass,Output[i].MetalsBulgeMass,Output[i].MetalsHotGas,Output[i].MetalsEjectedMass,Output[i].MetalsICS);
printf("Sfr:%f,SfrBulge:%f,SfrICS:%f\nRd:%f,Cooling:%f,Heating:%f\nLastMajorMerger:%f,OutflowRate:%f\n",Output[i].Sfr,
Output[i].SfrBulge,Output[i].SfrICS,Output[i].DiskScaleRadius,Output[i].Cooling,Output[i].Heating,Output[i].LastMajorMerger,Output[i].OutflowRate);

printf("infallMvir:%f,infallVvir:%f,infallVmax:%f,r_heat:%f\n",Output[i].infallMvir,Output[i].infallVvir,Output[i].infallVmax,Output[i].r_heat);
//printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
//printf("∮∮∮∮∮∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮ ∮∮∮∮∮∮\n");
printf("~~~~~~~~~~~~~~~~~~~~~~∮∮∮∮∮∮∮∮∮∮∮∮~~~~~~~~~~~~~~~~~~~~~~\n");

return;

}
void ExportGalaxy(int snap,struct SageGalaxies *Output, int id)
{
  //snap=161;
  printf("%g,%g,%g,%g,%g,%d,%g,%d,%d,%d,%g\n",Output[id].Pos[0], Output[id].Pos[1],Output[id].Pos[2],Output[id].Mvir*(1.0e10),Output[id].Rvir,snap,Output[id].StellarMass*1.0e10,Output[id].GalaxyIndex,Output[id].HaloIndex,Output[id].CentralGal, Output[id].MetalsStellarMass*(1.0e10));//,Output[id].Stars, Output[id].DiskScaleRadius); //should remove stars for current tagging

}

int main(int argc, char * argv[])
{
//sprintf(SageDir,"/home/shahram/Desktop/Research/3_Tagging/ReadSage/sage_out");
//838: 49-264
//717: 36-264 -> new run error on 149
//16406:40-264
//19880: 41-264
//32251: 46-264
//High5M:
//  /media/shahram/SD/Sample100Mpc/32251/High5M/r2/sage_out
//  /media/shahram/SD/Sample100Mpc/m12f/sage_out

sprintf(SageDir,"/media/shahram/SD/Sample100Mpc/m12i/sage_out"); //49-264
int i,s, LastSnap,FirstSnap;
LastSnap= atoi(argv[2]);
FirstSnap=atoi(argv[1]);
for(s=FirstSnap;s<=LastSnap;s++)
{
  ReadSage(s);
  //printf("snap:%d\n",s);
for(i=0;i<NumGalaxies;i++)
  ExportGalaxy(s,SageOutput,i);
}
  return 0;
}