text:
package com.github.dynamo.core.model;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.MatchResult;

import com.github.dynamo.core.manager.ErrorManager;

import liquibase.util.StringUtils;

public class MapperUtils {

	public static List<String> getStringList( String value ) {
		List<String> collection = null;
		if (StringUtils.isNotEmpty(value)) {
			collection = StringUtils.splitAndTrim( value, ";" );
		}
		return collection;
	}

	public static List<? extends Enum> getEnumList( String value, Class<? extends Enum> enumClass ) {
		List<String> collection = getStringList(value);
		List<Enum> returnValue = null;
		if (collection != null) {
			returnValue = new ArrayList<>( collection.size() );
			for (String val : collection) {
				if (!org.apache.commons.lang3.StringUtils.isBlank(val)) {
					returnValue.add( Enum.valueOf(enumClass, val));
				}
			}
		}
		return returnValue;
	}

	public static Set<? extends Enum> getEnumSet( String value, Class<? extends Enum> enumClass ) {
		List<String> collection = getStringList(value);
		Set<Enum> returnValue = null;
		if (collection != null) {
			returnValue = new HashSet<>( collection.size() );
			for (String val : collection) {
				if (!org.apache.commons.lang3.StringUtils.isBlank(val)) {
					try {
						returnValue.add( Enum.valueOf(enumClass, val));
					} catch (Exception e) {
						ErrorManager.getInstance().logThrowable( e );
					}
				}
			}
		}
		return returnValue;
	}

	public static Path getPath(ResultSet r, String columnName) throws SQLException {
		String val = r.getString(columnName);
		return val != null ? Paths.get(val) : null;
	}

	public static <T extends Enum<T>> T getEnum(ResultSet r, String columnName, Class<T> enumType) throws SQLException {
		String name = r.getString(columnName);
		T val = null;
		if (name != null) {
			try {
				val = Enum.valueOf(enumType, name);
			} catch (java.lang.IllegalArgumentException e) {
				val = null;
			}
		}
		return val;
	}

	public static Set<Locale> getLocales(String value) {
		List<String> collection = getStringList(value);
		Set<Locale> locales = new HashSet<>();
		if (collection != null) {
			for (String string : collection) {
				try (Scanner scanner = new Scanner( string )) {

					Locale locale;

					if (scanner.findInLine("(\\w{2})_(\\w{2})") != null) {
						MatchResult result = scanner.match();

						String language = result.group(1);
						String country = result.group(2);

						locale = new Locale(language, country);
					} else {
						locale = new Locale( string );
					}

					locales.add(locale);

				}
			}
		}
		return locales;
	}

}


text:
<!doctype html>

	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<title>ICDCatalog | medCodeSearch</title>
	<meta name="description" content="">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="../assets/css/main.css">

						Search
						<input id="tsd-search-field" type="text" />

Preparing search index...

The search index is not available

					medCodeSearch

						Options

								All

Public

Public/Protected

All

							<input type="checkbox" id="tsd-filter-inherited" checked />
							Inherited
							<input type="checkbox" id="tsd-filter-only-exported" />
							Only exported

					Menu

					Globals

					"app/catalog/icd.catalog"

					ICDCatalog

Class ICDCatalog

Concrete implementation of catalog class for the ICD catalog.

Hierarchy

						Catalog

								ICDCatalog

Index

Constructors

constructor

Properties

config

name

Methods

get<wbr>ByCode

get<wbr>Name

search

send<wbr>Analytics

Constructors

constructor

new ICDCatalog(service: ICatalogService, logger: ILoggerService): ICDCatalog

Overrides Catalog.constructor

Defined in app/catalog/icd.catalog.ts:11

Parameters

service: ICatalogService

logger: ILoggerService

Returns ICDCatalog

Properties

Protected config

config: CatalogConfiguration

Inherited from Catalog.config

Defined in app/catalog/catalog.ts:26

name

name: string

Inherited from Catalog.name

Defined in app/catalog/catalog.ts:25

The name of the catalog.

Methods

get<wbr>ByCode

get<wbr>ByCode(type: string, code: string, version: string, language?: string): Promise<CatalogElement>

Inherited from Catalog.getByCode

Defined in app/catalog/catalog.ts:44

Get a specific element from the catalog

Parameters

type: string

the type of the CatalogElement to load

code: string

the code of the CatalogElement to load

version: string

Optional language: string

Returns Promise<CatalogElement>

get<wbr>Name

get<wbr>Name(): string

Inherited from Catalog.getName

Defined in app/catalog/catalog.ts:53

Returns string

search

search(version: string, query: string): Promise<CatalogElement[]>

Inherited from Catalog.search

Defined in app/catalog/catalog.ts:34

Searches elements within the catalog.

Parameters

version: string

the version of the catalog to use

query: string

the query to search for

Returns Promise<CatalogElement[]>

send<wbr>Analytics

send<wbr>Analytics(type: string, code: string, query: string, version?: string): void

Inherited from Catalog.sendAnalytics

Defined in app/catalog/catalog.ts:62

Sends an analytic notification to eonum

Parameters

type: string

code: string

query: string

Optional version: string

Returns void

						Globals

						"app/catalog/icd.catalog"

						ICDCatalog

								constructor

								config

								name

								get<wbr>ByCode

								get<wbr>Name

								search

								send<wbr>Analytics

Legend

Module

Object literal

Variable

Function

Function with type parameter

Index signature

Type alias

Enumeration

Enumeration member

Property

Method

Interface

Interface with type parameter

Constructor

Property

Method

Index signature

Class

Class with type parameter

Constructor

Property

Method

Accessor

Index signature

Inherited constructor

Inherited property

Inherited method

Inherited accessor

Protected property

Protected method

Protected accessor

Private property

Private method

Private accessor

Static property

Static method

Generated using TypeDoc

redpajama_set_name: RedPajamaGithub


text:
package ucar.nc2.internal.dataset.conv;

import java.io.IOException;
import ucar.ma2.Array;
import ucar.ma2.ArrayDouble;
import ucar.ma2.ArrayFloat;
import ucar.ma2.DataType;
import ucar.ma2.IndexIterator;
import ucar.nc2.Attribute;
import ucar.nc2.AttributeContainer;
import ucar.nc2.Dimension;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.CDM;
import ucar.nc2.constants._Coordinate;
import ucar.nc2.dataset.NetcdfDataset;
import ucar.nc2.dataset.VariableDS;
import ucar.nc2.dataset.VariableEnhanced;
import ucar.nc2.dataset.spi.CoordSystemBuilderFactory;
import ucar.nc2.internal.dataset.CoordSystemBuilder;
import ucar.nc2.util.CancelTask;

/** Cosmic data - version 1 and 3 */
public class Cosmic1Convention extends CoordSystemBuilder {
  private static final String CONVENTION_NAME = "Cosmic1";

  public static class Factory implements CoordSystemBuilderFactory {
    @Override
    public String getConventionName() {
      return CONVENTION_NAME;
    }

    @Override
    public boolean isMine(NetcdfFile ncfile) {
      if ((null == ncfile.findDimension("MSL_alt")) && (null == ncfile.findDimension("time"))) {
        return false;
      }

      String center = ncfile.getRootGroup().attributes().findAttributeString("center", null);
      return "UCAR/CDAAC".equals(center);
    }

    @Override
    public CoordSystemBuilder open(NetcdfDataset.Builder datasetBuilder) {
      return new Cosmic1Convention(datasetBuilder);
    }
  }

  private Cosmic1Convention(NetcdfDataset.Builder datasetBuilder) {
    super(datasetBuilder);
    this.conventionName = CONVENTION_NAME;
  }

  @Override
  public void augmentDataset(CancelTask cancelTask) throws IOException {
    AttributeContainer gatts = rootGroup.getAttributeContainer();

    Attribute leoAtt = gatts.findAttribute("leoId");
    if (leoAtt == null) {
      if (!rootGroup.findVariableLocal("time").isPresent()) {
        // create a time Variable.Builder - assume its linear along the vertical dimension
        double start = gatts.findAttributeDouble("start_time", Double.NaN);
        double stop = gatts.findAttributeDouble("stop_time", Double.NaN);

        if (Double.isNaN(start) && Double.isNaN(stop)) {
          double top = gatts.findAttributeDouble("toptime", Double.NaN);
          double bot = gatts.findAttributeDouble("bottime", Double.NaN);

          this.conventionName = "Cosmic2";
          if (top > bot) {
            stop = top;
            start = bot;
          } else {
            stop = bot;
            start = top;
          }
        }

        Dimension dim = rootGroup.findDimension("MSL_alt").get();
        VariableDS.Builder dimV = (VariableDS.Builder) rootGroup.findVariableLocal("MSL_alt").get();
        Array dimU = dimV.orgVar.read();
        int inscr = (dimU.getFloat(1) - dimU.getFloat(0)) > 0 ? 1 : 0;
        int n = dim.getLength();
        double incr = (stop - start) / n;

        String timeUnits = "seconds since 1980-01-06 00:00:00";
        VariableDS.Builder timeVar = VariableDS.builder().setName("time").setDataType(DataType.DOUBLE)
            .setParentGroupBuilder(rootGroup).setDimensionsByName(dim.getShortName()).setUnits(timeUnits);
        rootGroup.addVariable(timeVar);
        timeVar.setUnits(timeUnits);
        timeVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Time.toString()));
        int dir = gatts.findAttributeInteger("irs", 1);
        ArrayDouble.D1 data = (ArrayDouble.D1) Array.factory(DataType.DOUBLE, new int[] {n});
        if (inscr == 0) {
          if (dir == 1) {
            for (int i = 0; i < n; i++) {
              data.set(i, start + i * incr);
            }
          } else {
            for (int i = 0; i < n; i++) {
              data.set(i, stop - i * incr);
            }
          }
        } else {
          for (int i = 0; i < n; i++) {
            data.set(i, stop - i * incr);
          }
        }
        timeVar.setCachedData(data, false);
      }

      Variable.Builder lat =
          rootGroup.findVariableLocal("Lat").orElse(rootGroup.findVariableLocal("GEO_lat").orElse(null));
      lat.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Lat.toString()));
      Variable.Builder lon =
          rootGroup.findVariableLocal("Lon").orElse(rootGroup.findVariableLocal("GEO_lon").orElse(null));
      lon.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Lon.toString()));
      Variable.Builder alt = rootGroup.findVariableLocal("MSL_alt").orElse(null);
      alt.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Height.toString()));
    } else {
      Dimension dim = rootGroup.findDimension("time").get();
      int n = dim.getLength();
      Variable.Builder latVar = VariableDS.builder().setName("Lat").setDataType(DataType.FLOAT)
          .setParentGroupBuilder(rootGroup).setDimensionsByName(dim.getShortName()).setUnits("degree");
      latVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Lat.toString()));
      rootGroup.addVariable(latVar);
      Variable.Builder lonVar = VariableDS.builder().setName("Lon").setDataType(DataType.FLOAT)
          .setParentGroupBuilder(rootGroup).setDimensionsByName(dim.getShortName()).setUnits("degree");
      lonVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Lon.toString()));
      rootGroup.addVariable(lonVar);
      Variable.Builder altVar = VariableDS.builder().setName("MSL_alt").setDataType(DataType.FLOAT)
          .setParentGroupBuilder(rootGroup).setDimensionsByName(dim.getShortName()).setUnits("meter");
      altVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Height.toString()));
      rootGroup.addVariable(altVar);

      // cal data array
      ArrayFloat.D1 latData = (ArrayFloat.D1) Array.factory(DataType.FLOAT, new int[] {n});
      ArrayFloat.D1 lonData = (ArrayFloat.D1) Array.factory(DataType.FLOAT, new int[] {n});
      ArrayFloat.D1 altData = (ArrayFloat.D1) Array.factory(DataType.FLOAT, new int[] {n});
      ArrayDouble.D1 timeData = (ArrayDouble.D1) Array.factory(DataType.DOUBLE, new int[] {n});
      this.conventionName = "Cosmic3";

      int iyr = gatts.findAttributeInteger("year", 2009);
      int mon = gatts.findAttributeInteger("month", 0);
      int iday = gatts.findAttributeInteger("day", 0);
      int ihr = gatts.findAttributeInteger("hour", 0);
      int min = gatts.findAttributeInteger("minute", 0);
      int sec = gatts.findAttributeInteger("second", 0);

      double start = gatts.findAttributeDouble("startTime", Double.NaN);
      double stop = gatts.findAttributeDouble("stopTime", Double.NaN);
      double incr = (stop - start) / n;
      int t = 0;
      // double julian = juday(mon, iday, iyr);
      // cal the dtheta based pm attributes
      double dtheta = gast(iyr, mon, iday, ihr, min, sec, t);

      VariableDS.Builder tVar = (VariableDS.Builder) rootGroup.findVariableLocal("time").get();
      String timeUnits = "seconds since 1980-01-06 00:00:00"; // dtime.getUnit().toString();
      tVar.getAttributeContainer().removeAttributeIgnoreCase(CDM.VALID_RANGE);
      tVar.getAttributeContainer().removeAttributeIgnoreCase(CDM.UNITS);
      tVar.setUnits(timeUnits);
      tVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Time.toString()));

      VariableDS.Builder xLeoVar = (VariableDS.Builder) rootGroup.findVariableLocal("xLeo").get();
      Array xLeoData = xLeoVar.orgVar.read();
      VariableDS.Builder yLeoVar = (VariableDS.Builder) rootGroup.findVariableLocal("yLeo").get();
      Array yLeoData = yLeoVar.orgVar.read();
      VariableDS.Builder zLeoVar = (VariableDS.Builder) rootGroup.findVariableLocal("zLeo").get();
      Array zLeoData = zLeoVar.orgVar.read();

      double a = 6378.1370;
      double b = 6356.7523142;
      IndexIterator xLeoIter = xLeoData.getIndexIterator();
      IndexIterator yLeoIter = yLeoData.getIndexIterator();
      IndexIterator zLeoIter = zLeoData.getIndexIterator();

      int i = 0;
      while (xLeoIter.hasNext()) {
        double[] v_inertial = new double[3];
        v_inertial[0] = xLeoIter.getDoubleNext();
        v_inertial[1] = yLeoIter.getDoubleNext();
        v_inertial[2] = zLeoIter.getDoubleNext();
        double[] uvz = new double[3];
        uvz[0] = 0.0;
        uvz[1] = 0.0;
        uvz[2] = 1.0;
        // v_ecef should be in the (approximate) ECEF frame
        // double[] v_ecf = execute(v_inertial, julian);
        double[] v_ecf = spin(v_inertial, uvz, -1 * dtheta);

        // cal lat/lon here
        // double [] llh = ECFtoLLA(v_ecf[0]*1000, v_ecf[1]*1000, v_ecf[2]*1000, a, b);
        double[] llh = xyzell(a, b, v_ecf);
        latData.set(i, (float) llh[0]);
        lonData.set(i, (float) llh[1]);
        altData.set(i, (float) llh[2]);
        timeData.set(i, start + i * incr);
        i++;
      }

      latVar.setCachedData(latData, false);
      lonVar.setCachedData(lonData, false);
      altVar.setCachedData(altData, false);
      tVar.setCachedData(timeData, false);
    }
  }

  protected AxisType getAxisType(NetcdfDataset ncDataset, VariableEnhanced v) {
    String name = v.getShortName();
    if (name.equals("time")) {
      return AxisType.Time;
    }
    if (name.equals("Lat") || name.equals("GEO_lat")) {
      return AxisType.Lat;
    }
    if (name.equals("Lon") || name.equals("GEO_lon")) {
      return AxisType.Lon;
    }
    // if (name.equals("xLeo") ) return AxisType.GeoX;
    // if (name.equals("yLeo") ) return AxisType.GeoY;
    if (name.equals("MSL_alt")) {
      return AxisType.Height;
    }
    return null;
  }

  /**
   * NAME : XYZELL
   *

   * CALL XYZELL(A,B,XSTAT,XSTELL)
   *

   * PURPOSE : COMPUTATION OF ELLIPSOIDAL COORDINATES "XSTELL"
   * GIVEN THE CARTESIAN COORDINATES "XSTAT"
   *

   * PARAMETERS :
   * IN : A : SEMI-MAJOR AXIS OF THE REFERENCE R*8
   * ELLIPSOID IN METERS
   * B : SEMI-MINOR AXIS OF THE REFERENCE R*8
   * ELLIPSOID IN METERS
   * DXELL(3): TRANSLATION COMPONENTS FROM THE R*8
   * ORIGIN OF THE CART. COORD. SYSTEM
   * (X,Y,Z) TO THE CENTER OF THE REF.
   * ELLIPSOID (IN METRES)
   * SCELL : SCALE FACTOR BETWEEN REF. ELLIPSOID R*8
   * AND WGS-84
   * XSTAT(3): CARTESIAN COORDINATES (M) R*8
   * OUT : XSTELL(3): ELLIPSOIDAL COORDINATES R*8
   * XSTELL(1): ELL. LATITUDE (RADIAN)
   * XSTELL(2): ELL. LONGITUDE (RADIAN)
   * XSTELL(3): ELL. HEIGHT (M)
   *

   * SR CALLED : DMLMTV
   *

   * REMARKS : ---
   *

   * AUTHOR : M. ROTHACHER
   *

   * VERSION : 3.4 (JAN 93)
   *

   * CREATED : 87/11/03 12:32 LAST MODIFIED : 88/11/21 17:36
   *

   * COPYRIGHT : ASTRONOMICAL INSTITUTE
   * 1987 UNIVERSITY OF BERNE
   * SWITZERLAND
   */
  private double[] xyzell(double a, double b, double[] xstat) {
    double[] xstell = new double[3];
    double e2, s, rlam, zps, h, phi, n, hp, phip;
    int i, niter;

    e2 = (a * a - b * b) / (a * a);
    s = Math.sqrt(xstat[0] * xstat[0] + xstat[1] * xstat[1]);
    rlam = Math.atan2(xstat[1], xstat[0]);
    zps = xstat[2] / s;
    h = Math.sqrt(xstat[0] * xstat[0] + xstat[1] * xstat[1] + xstat[2] * xstat[2]) - a;
    phi = Math.atan(zps / (1.0 - e2 * a / (a + h)));

    niter = 0;
    for (i = 1; i <= 10000000; i++) {
      n = a / Math.sqrt(1.0 - e2 * Math.sin(phi) * Math.sin(phi));
      hp = h;
      phip = phi;
      h = s / Math.cos(phi) - n;
      phi = Math.atan(zps / (1.0 - e2 * n / (n + h)));
      niter = niter + 1;
      if ((Math.abs(phip - phi) <= 1.e-11) && (Math.abs(hp - h) <= 1.e-5)) {
        break;
      }
      if (niter >= 10) {
        phi = -999.0;
        rlam = -999.0;
        h = -999.0;
        break;
      }
    }

    xstell[0] = phi * 180 / 3.1415926;
    xstell[1] = rlam * 180 / 3.1415926;
    xstell[2] = h;

    return xstell;
  }

  /*
   * gast.f
   * Compute hour angle dtheta
   *
   * ! iyr, mon, iday, ihr, min and sec form a base (epoch) time,
   * ! t is an offset from the base time in seconds
   * ! dtheta is the output hour angle in radians
   *
   * Calculation of local time
   *
   * ! glon -- East longitude in degrees, -180 to 180
   *
   * call vprod.f spin.f rnorm.f
   * Calculation of the unit vector normal to the occultation plane
   * (clockwise rotated from GPS to LEO)
   */
  /*
   * double dtheta = gast(iyr,mon,iday,ihr,min,sec,t)
   * utc=ihr*1.d0+min/60.d0
   * timloc=utc+24.d0*glon/360.d0
   * if (timloc.gt.24.d0) timloc=timloc-24.d0
   * if (timloc.lt.0.d0) timloc=timloc+24.d0
   */

  // In the inertial reference frame
  /*
   * v_inertial(1)= ! Inertial GPS position vectors, XYZ
   * v_inertial(2)=
   * v_inertial(3)=
   */
  // In the Earth-fixed reference frame

  // Z axis to rotate around (unit vector Z)
  /*
   * uvz(1)=0.0;
   * uvz(2)=0.0;
   * uvz(3)=1.0;
   *
   * double [] v_ecf = spin(v_inertial,uvz,-180.d0*dtheta/pi)
   */
  // after this call, v_ecef should be in the (approximate) ECEF frame

  /**
   * ----------------------------------------------------------------------
   * gast.f
   *

   * This subroutine computes the Greenwich Apparent Siderial
   * Time angle given a UTC date and time.
   *

   * parameter Input parameters:
   * Inputs:
   *
   * @param iyr integer year 1995
   * @param imon integer month 5
   * @param iday integer day 5
   * @param ihr integer hour 5
   * @param imin integer minute 5
   * @param sec double second 31.0
   * @param dsec double second 0.0
   *        Outputs:
   * @return theta GAST angle in radians
   *

   *         author Bill Schreiner
   * @since May 1995
   *        version $URL: svn://ursa.cosmic.ucar.edu/trunk/src/roam/gast.f $ $Id: gast.f 10129 2008-07-30 17:10:52Z
   *        dhunt $
   */

  private double gast(int iyr, int imon, int iday, int ihr, int imin, double sec, double dsec) {
    //
    // implicit double precision (a-h,o-z)
    // character(len=*), parameter :: header = '$URL: svn://ursa.cosmic.ucar.edu/trunk/src/roam/gast.f $ $Id: gast.f
    // 10129 2008-07-30 17:10:52Z dhunt $'
    //
    // Coordinate transform from the celestial inertial reference frame to the geo-
    // centered Greenwich reference frame.
    // Call a subroutine to calculate the Julian day "djd":
    double djd = juday(imon, iday, iyr); // djd=julean day.
    double tu = (djd - 2451545.0) / 36525.0;
    double gmst = 24110.548410 + 8640184.8128660 * tu + 0.093104 * tu * tu - 6.2E-6 * Math.pow(tu, 3); // !gmst=Greenwich
                                                                                // mean...
    double utco = (ihr * 3600) + (imin * 60) + sec;

    return togreenw(dsec, utco, gmst);
  }

  /**
   * JDAY calculates the Julian Day number (JD) from the Gregorian month day, and year (M,D,Y). (NOT VALID BEFORE
   * 10/15/1582)
   */
  private double juday(int M, int D, int Y) {
    double JD;

    double IY = Y - (12 - M) / 10.0;
    double IM = M + 1 + 12 * ((12 - M) / 10.0);
    double I = IY / 100;
    double J = 2 - I + I / 4 + Math.round(365.25 * IY) + Math.round(30.6001 * IM);
    JD = (J + D + 1720994.50);
    return JD;
  }

  /**
   * This subroutine is to transform the locations and velocities of the GPS and
   * LEO satellites from the celestial inertial reference frame to the Earth
   * centered Greenwich reference frame.
   * The dummy arguments iyear, month and iday are the calender year, month and
   * day of the occultation event. The dummy arguments ihour, minute and sec
   * are the UTC time.
   * Reference: Astronomical Alamanus, 1993
   *

   * Modified subroutine from Dasheng's code.
   */
  private double togreenw(double rectt, double utco, double gmst) {

    double pi = Math.acos(-1.00);
    //
    // For each occultation ID, its TU and GMST are the same. However, every
    // occultation event takes place at gmst+uts, uts is progressively increasing
    // with every occultation event.
    double utc = (utco + rectt) * 1.0027379093;
    gmst = gmst + utc; // in seconds, without eoe correction.
    // gmst may be a positive number or may be a negative number.
    while (gmst < 0.0) {
      gmst = gmst + 86400.00;
    }

    while (gmst > 86400.00) {
      gmst = gmst - 86400.00;
    }

    // gmst = the Greenwich mean sidereal time.
    // This gmst is without the corrections from the equation of equinoxes. For
    // GPS/MET applications, the corrections from equation of equinoxes is not
    // necessary because of the accurary needed.
    return gmst * 2.0 * pi / 86400.0; // !*** This is the THETA in radian.
  }

  /**
   * ----------------------------------------------------------------------
   * file spin.f
   *

   * This subroutine rotates vector V1 around vector VS
   * at angle A. V2 is the vector after the rotation.
   *

   *

   * parameter Input parameters:
   * v1 - Vector to be rotated
   * vs - Vector around which to rotate v1
   * a - angle of rotation
   * Output parameters:
   * v2 - output vector
   *

   * S.V.Sokolovskiy
   * URL: svn://ursa.cosmic.ucar.edu/trunk/src/roam/spin.f $ $Id: spin.f 10129 2008-07-30 17:10:52Z dhunt $
   * -----------------------------------------------------------------------
   *
   * @param v1 - Vector to be rotated
   * @param vs - Vector around which to rotate v1
   * @param a - angle of rotation
   * @return _more_
   */

  public double[] spin(double[] v1, double[] vs, double a) {

    // implicit real*8(a-h,o-z)
    // dimension v1(3),vs(3),vsn(3),v2(3),v3(3),s(3,3)
    // Calculation of the unit vector around which
    // the rotation should be done.
    double[] v2 = new double[3];
    double[] vsn = new double[3];
    double[] v3 = new double[3];

    double vsabs = Math.sqrt(vs[0] * vs[0] + vs[1] * vs[1] + vs[2] * vs[2]);

    for (int i = 0; i < 3; i++) {
      vsn[i] = vs[i] / vsabs;
    }

    // Calculation of the rotation matrix.

    double a1 = Math.cos(a);
    double a2 = 1.0 - a1;
    double a3 = Math.sin(a);
    double[][] s = new double[3][3];

    s[0][0] = a2 * vsn[0] * vsn[0] + a1;
    s[0][1] = a2 * vsn[0] * vsn[1] - a3 * vsn[2];
    s[0][2] = a2 * vsn[0] * vsn[2] + a3 * vsn[1];
    s[1][0] = a2 * vsn[1] * vsn[0] + a3 * vsn[2];
    s[1][1] = a2 * vsn[1] * vsn[1] + a1;
    s[1][2] = a2 * vsn[1] * vsn[2] - a3 * vsn[0];
    s[2][0] = a2 * vsn[2] * vsn[0] - a3 * vsn[1];
    s[2][1] = a2 * vsn[2] * vsn[1] + a3 * vsn[0];
    s[2][2] = a2 * vsn[2] * vsn[2] + a1;

    // Calculation of the rotated vector.

    for (int i = 0; i < 3; i++) {
      v3[i] = s[i][0] * v1[0] + s[i][1] * v1[1] + s[i][2] * v1[2];
    }

    System.arraycopy(v3, 0, v2, 0, 3);

    return v2;
  }

  private static final double RTD = 180. / Math.PI;
  private static final double DTR = Math.PI / 180.;

  public double[] execute(double[] eci, double julian) {
    double Xi = eci[0];
    double Yi = eci[1];
    double Zi = eci[2];

    double c, s;
    double GHA;

    double[] ecef = new double[3];
    // Compute GHAD
    /* System generated locals */
    double d__1, d__2, d__3;

    /* Local variables */
    double tsec, tday, gmst, t, omega, tfrac, tu, dat;

    /* INPUT IS TIME "secondsSince1970" IN SECONDS AND "TDAY" */
    /* WHICH IS WHOLE DAYS FROM 1970 JAN 1 0H */
    /* THE OUTPUT IS GREENWICH HOUR ANGLE IN DEGREES */
    /* XOMEGA IS ROTATION RATE IN DEGREES/SEC */

    /* FOR COMPATABILITY */

    tday = (double) ((int) (julian / 86400.));
    tsec = julian - tday * 86400;

    /* THE NUMBER OF DAYS FROM THE J2000 EPOCH */
    /* TO 1970 JAN 1 0H UT1 IS -10957.5 */
    t = tday - (float) 10957.5;
    tfrac = tsec / 86400.;
    dat = t;
    tu = dat / 36525.;

    /* Computing 2nd power */
    d__1 = tu;

    /* Computing 3rd power */
    d__2 = tu;
    d__3 = d__2;
    gmst = tu * 8640184.812866 + 24110.54841 + d__1 * d__1 * .093104 - d__3 * (d__2 * d__2) * 6.2e-6;

    /* COMPUTE THE EARTH'S ROTATION RATE */
    /* Computing 2nd power */
    d__1 = tu;
    omega = tu * 5.098097e-6 + 86636.55536790872 - d__1 * d__1 * 5.09e-10;

    /* COMPUTE THE GMST AND GHA */
    // da is earth nutation - currently unused
    double da = 0.0;
    gmst = gmst + omega * tfrac + da * RTD * 86400. / 360.;
    gmst = gmst % 86400;
    if (gmst < 0.) {
      gmst += 86400.;
    }
    gmst = gmst / 86400. * 360.;
    // ghan = gmst;
    // returns gha in radians
    gmst = gmst * DTR;
    GHA = gmst;

    // RotateZ
    c = Math.cos(GHA);
    s = Math.sin(GHA);
    double X = c * Xi + s * Yi;
    double Y = -s * Xi + c * Yi;

    // Set outputs
    ecef[0] = X;
    ecef[1] = Y;
    ecef[2] = Zi;

    return ecef;
  }

  /** comparing api to others */
  public static double[] ECFtoLLA(double x, double y, double z, double a, double b) {

    double longitude = Math.atan2(y, x);
    double ePrimeSquared = (a * a - b * b) / (b * b);
    double p = Math.sqrt(x * x + y * y);
    double theta = Math.atan((z * a) / (p * b));
    double sineTheta = Math.sin(theta);
    double cosTheta = Math.cos(theta);
    double f = 1 / 298.257223563;
    double e2 = 2 * f - f * f;
    double top = z + ePrimeSquared * b * sineTheta * sineTheta * sineTheta;
    double bottom = p - e2 * a * cosTheta * cosTheta * cosTheta;
    double geodeticLat = Math.atan(top / bottom);
    double sineLat = Math.sin(geodeticLat);
    double N = a / Math.sqrt(1 - e2 * sineLat * sineLat);
    double altitude = (p / Math.cos(geodeticLat)) - N;

    // maintain longitude btw -PI and PI
    if (longitude > Math.PI) {
      longitude -= 2 * Math.PI;

    } else if (longitude < -Math.PI) {
      longitude += 2 * Math.PI;
    }

    return new double[] {geodeticLat, longitude, altitude};
  }

}


text:
<?xml version="1.0" encoding="UTF-8" ?>
<class xmlns="http://xml.phpdox.net/src" full="RecursiveFilterIterator" namespace="" name="RecursiveFilterIterator">
  <implements name="OuterIterator" full="OuterIterator"/>
  <constructor name="__construct" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact="Create a RecursiveFilterIterator from a RecursiveIterator"/>
      <return type="void"/>
    </docblock>
    <parameter name="iterator" optional="false" byreference="false" type="object" class="RecursiveIterator"/>
  </constructor>
  <method name="getChildren" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact="Return the inner iterator's children contained in a RecursiveFilterIterator"/>
      <return type="void"/>
    </docblock>
  </method>
  <method name="hasChildren" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact="Check whether the inner iterator's current element has children"/>
      <return type="void"/>
    </docblock>
  </method>
  <method name="accept" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact=""/>
      <return type="bool"/>
    </docblock>
  </method>
  <constructor name="__construct" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact=""/>
      <return type="void"/>
    </docblock>
    <parameter name="iterator" optional="false" byreference="false" type="object" class="Iterator"/>
  </constructor>
  <method name="current" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact=""/>
      <return type="mixed"/>
    </docblock>
  </method>
  <method name="getInnerIterator" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact=""/>
      <return type="Iterator"/>
    </docblock>
  </method>
  <method name="key" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact=""/>
      <return type="mixed"/>
    </docblock>
  </method>
  <method name="next" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact=""/>
      <return type="void"/>
    </docblock>
  </method>
  <method name="rewind" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact=""/>
      <return type="void"/>
    </docblock>
  </method>
  <method name="valid" abstract="false" static="false" visibility="public" final="false">
    <docblock>
      <description compact=""/>
      <return type="bool"/>
    </docblock>
  </method>
</class>


text:
@implementation FHSViewSnapshot

+ (instancetype)snapshotWithView:(FHSView *)view {
    NSArray *children = [view.children flex_mapped:^id(FHSView *v, NSUInteger idx) {
        return [self snapshotWithView:v];
    }];
    return [[self alloc] initWithView:view children:children];
}

- (id)initWithView:(FHSView *)view children:(NSArray<FHSViewSnapshot *> *)children {
    NSParameterAssert(view); NSParameterAssert(children);

    self = [super init];
    if (self) {
        _view = view;
        _title = view.title;
        _important = view.important;
        _frame = view.frame;
        _hidden = view.hidden;
        _snapshotImage = view.snapshotImage;
        _children = children;
        _summary = view.summary;
    }

    return self;
}

- (UIColor *)headerColor {
    if (self.important) {
        return [UIColor colorWithRed: 0.000 green: 0.533 blue: 1.000 alpha: 0.900];
    } else {
        return [UIColor colorWithRed:0.961 green: 0.651 blue: 0.137 alpha: 0.900];
    }
}

- (FHSViewSnapshot *)snapshotForView:(UIView *)view {
    if (view == self.view.view) {
        return self;
    }

    for (FHSViewSnapshot *child in self.children) {
        FHSViewSnapshot *snapshot = [child snapshotForView:view];
        if (snapshot) {
            return snapshot;
        }
    }

    return nil;
}

@end


text:
namespace media {
class CdmFactory;
class MediaPermission;
struct CdmConfig;
}  // namespace media

namespace blink {
class WebContentDecryptionModuleResult;
class WebSecurityOrigin;
struct WebMediaKeySystemConfiguration;

class BLINK_PLATFORM_EXPORT WebEncryptedMediaClientImpl
    : public WebEncryptedMediaClient {
 public:
  WebEncryptedMediaClientImpl(
      media::CdmFactory* cdm_factory,
      media::MediaPermission* media_permission,
      std::unique_ptr<KeySystemConfigSelector::WebLocalFrameDelegate>
          web_frame_delegate);
  ~WebEncryptedMediaClientImpl() override;

  // WebEncryptedMediaClient implementation.
  void RequestMediaKeySystemAccess(WebEncryptedMediaRequest request) override;

  // Create the CDM for |security_origin| and |cdm_config|. The caller owns
  // the created cdm (passed back using |result|).
  void CreateCdm(const WebSecurityOrigin& security_origin,
                 const media::CdmConfig& cdm_config,
                 std::unique_ptr<WebContentDecryptionModuleResult> result);

 private:
  // Report usage of key system to UMA. There are 2 different counts logged:
  // 1. The key system is requested.
  // 2. The requested key system and options are supported.
  // Each stat is only reported once per renderer frame per key system.
  class Reporter;

  // Callback for `KeySystemConfigSelector::SelectConfig()`.
  // `accumulated_configuration` and `cdm_config` are non-null iff `status` is
  // `kSupported`. `cdm_config->key_system` is the same as the requested key
  // system in most cases unless a sub key system is queried and the base key
  // system should be used.
  void OnConfigSelected(
      WebEncryptedMediaRequest request,
      KeySystemConfigSelector::Status status,
      WebMediaKeySystemConfiguration* accumulated_configuration,
      media::CdmConfig* cdm_config);

  // Gets the Reporter for |key_system|. If it doesn't already exist,
  // create one.
  Reporter* GetReporter(const WebString& key_system);

  // Reporter singletons.
  std::unordered_map<std::string, std::unique_ptr<Reporter>> reporters_;

  media::CdmFactory* cdm_factory_;
  KeySystemConfigSelector key_system_config_selector_;
  base::WeakPtrFactory<WebEncryptedMediaClientImpl> weak_factory_{this};
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MEDIA_WEB_ENCRYPTED_MEDIA_CLIENT_IMPL_H_


text:
module.exports = function (router) {

    var User = require('./../models/user'),
        jwt = require('jsonwebtoken'),
        config = require('./../../config');

    router.route('/auth')
        .post(function(req, res) {

            // find the user
            User.findOne({
                name: req.body.name
            }, function(err, user) {

                if (err) throw err;

                if (!user) {
                    res.status(403).json({ success: false, message: 'Authentication failed. User not found.' });
                } else if (user) {

                    // check if password matches
                    if (user.password != req.body.password) {
                        res.json({ success: false, message: 'Authentication failed. Wrong password.' });
                    } else {

                        // if user is found and password is right
                        // create a token
                        var token = jwt.sign(user, config.secret, {
                            expiresInMinutes: 1440 // expires in 24 hours
                        });

                        // return the information including token as JSON
                        res.json({
                            success: true,
                            message: 'Enjoy your token!',
                            token: token
                        });
                    }

                }

            });
        });
}


text:
%!TeX jobNames = bibtex-1, bibtex-2, biber-1, biber-2
%!TeX bibtex-2:outputDirectory = output
%!TeX biber-2:outputDirectory = output
%!TeX tests = bibtex -version, biber -version
\documentclass{article}

\usepackage{xstring}

\StrBefore*{\jobname}{-}[\backend]

\usepackage[backend=\backend]{biblatex}

\bibliography{foo}{}

\begin{document}
  foo, wibble, wibble \cite{Angle:2003}, gronk.
  \printbibliography
\end{document}


text:
import axios from 'axios';

export const PRELOAD_WEATHER = 'PRELOAD_WEATHER';

export function fetchIP() {
  const ipURL = 'https://freegeoip.net/json/';

  const request = axios.get(ipURL)
      .catch((e) => {
        console.log(e.message);
      });

  return {
    type: PRELOAD_WEATHER,
    payload: request
  }
}


text:
const ChangeLogs = require('@warp-works/warpjs-change-logs');
// const debug = require('debug')('W2:studio:remove-relationship');
const Promise = require('bluebird');
const warpjsUtils = require('@warp-works/warpjs-utils');

const { actions } = require('./../../../lib/constants');
const DocLevel = require('./../../../lib/doc-level');
const logger = require('./../../loggers');
const utils = require('./../utils');
const warpCore = require('./../../../lib/core');

const ACTION = actions.REMOVE_CHILD;

module.exports = (req, res) => {
    const { domain, type, id, relationship } = req.params;
    const { body } = req;

    const resource = warpjsUtils.createResource(req, {
        title: `Remove child for relationship ${domain} - ${type} - ${id} - ${relationship}`,
        domain,
        type,
        id,
        relationship
    });

    return Promise.resolve()
        .then(() => logger(req, `Trying ${ACTION}`, body))
        .then(() => warpCore.getPersistence())
        .then((persistence) => Promise.resolve()
            .then(() => utils.getInstance(persistence, type, id))
            .then((instanceData) => Promise.resolve()
                .then(() => DocLevel.fromString(body.docLevel))
                .then((docLevel) => docLevel.getData(persistence, instanceData.entity, instanceData.instance, 1))
                .then((docLevelData) => Promise.resolve()
                    .then(() => docLevelData.model.getTargetReferences(docLevelData.instance))
                    .then((references) => {
                        const first = docLevelData.docLevel.first();
                        if (first) {
                            const { value } = first;
                            const indexOf = references.findIndex((ref) => ref._id === value);
                            if (indexOf !== -1) {
                                references.splice(indexOf, 1);
                                return instanceData.entity.updateDocument(persistence, instanceData.instance, false);
                            }
                        }
                    })
                )
                .then(() => ChangeLogs.add(ChangeLogs.ACTIONS.EMBEDDED_REMOVED, req.warpjsUser, instanceData.instance, {
                    key: body.docLevel
                }))
            )
            .then(() => warpCore.removeDomainFromCache(domain))
            .then(() => logger(req, `Success ${ACTION}`))
            .finally(() => persistence.close())
        )
        .then(() => utils.sendHal(req, res, resource))
        .catch((err) => {
            // eslint-disable-next-line no-console
            console.error(`Error removing relationship child. err=`, err);
            logger(req, `Failed ${ACTION}`, { err });
            utils.sendErrorHal(req, res, resource, err);
        })
    ;
};


text:
Exercise 2 - Clear Rant Text
================

# Goal
Page should clear draft rant text when cleared.

# Evidence
- User enters some text into the rant box.
- User select-all, and deletes the text
- User reloads the page, see original text in the rant box.

# Concepts
- Chrome DOM Event Listeners
- Chrome Application Storage
- Chrome Source debugger and stepping

# Spoilers (Try Yourself First)

## Key Files

- `/src/public/scripts/addRantView.js:onChange()` Empty text value will be falsy

```
onChange: function(evt) {
  var text = (evt.target || {}).value;
  if (typeof text === 'string') { // <-- Change this to check for string
    localStorage.setItem('next-rant', text);
  }
},
```

## Solution Links

- [Falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy)


text:
<title> / linq.collections.LinqListFunctions.Take</title>
<link rel="stylesheet" href="..\..\style.css">

linq.collections / LinqListFunctions / Take

Take

fun <ElementType> Take(list: AbstractList<ElementType?>, amount: Int): ArrayList<ElementType?>

Returns amount items from the list

Parameters

list - the list to return items from

amount - the amount of items to return

Exceptions

Exception - when there are less than amount items in the list

Return

the first amount items in the list


text:
#include "VoxelTools/VoxelDataTools.h"
#include "VoxelTools/VoxelToolHelpers.h"
#include "VoxelRender/IVoxelLODManager.h"
#include "VoxelData/VoxelDataIncludes.h"
#include "VoxelData/VoxelSaveUtilities.h"
#include "VoxelAssets/VoxelHeightmapAsset.h"
#include "VoxelAssets/VoxelHeightmapAssetSamplerWrapper.h"
#include "VoxelFeedbackContext.h"

#define VOXEL_DATA_TOOL_PREFIX const FVoxelIntBox Bounds(Position);

void UVoxelDataTools::GetValue(float& Value, AVoxelWorld* World, FIntVector Position)
{
	VOXEL_TOOL_HELPER(Read, DoNotUpdateRender, VOXEL_DATA_TOOL_PREFIX, Value = Data.GetValue(Position, 0).ToFloat());
}

void UVoxelDataTools::GetInterpolatedValue(float& Value, AVoxelWorld* World, FVector Position)
{
	const FVoxelIntBox Bounds = FVoxelIntBox(Position).Extend(2);
	VOXEL_TOOL_HELPER(Read, DoNotUpdateRender, NO_PREFIX, Value = FVoxelDataUtilities::MakeBilinearInterpolatedData(Data).GetValue(Position, 0));
}

void UVoxelDataTools::SetValue(AVoxelWorld* World, FIntVector Position, float Value)
{
	VOXEL_TOOL_HELPER(Write, UpdateRender, VOXEL_DATA_TOOL_PREFIX, Data.SetValue(Position, FVoxelValue(Value)));
}

void UVoxelDataTools::GetMaterial(FVoxelMaterial& Material, AVoxelWorld* World, FIntVector Position)
{
	VOXEL_TOOL_HELPER(Read, DoNotUpdateRender, VOXEL_DATA_TOOL_PREFIX, Material = Data.GetMaterial(Position, 0));
}

void UVoxelDataTools::SetMaterial(AVoxelWorld* World, FIntVector Position, FVoxelMaterial Material, int32 Mask)
{
	const auto Lambda = [=](FVoxelMaterial& InMaterial)
	{
		InMaterial.CopyFrom(Material, Mask);
	};
	VOXEL_TOOL_HELPER(Write, UpdateRender, VOXEL_DATA_TOOL_PREFIX, Data.Edit<FVoxelMaterial>(Position, Lambda));
}

void UVoxelDataTools::CacheValues(AVoxelWorld* World, FVoxelIntBox Bounds, bool bMultiThreaded)
{
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.CacheBounds<FVoxelValue>(Bounds, bMultiThreaded));
}

void UVoxelDataTools::CacheMaterials(AVoxelWorld* World, FVoxelIntBox Bounds, bool bMultiThreaded)
{
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.CacheBounds<FVoxelMaterial>(Bounds, bMultiThreaded));
}

///////////////////////////////////////////////////////////////////////////////

void UVoxelDataTools::GetValueAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	float& Value,
	AVoxelWorld* World,
	FIntVector Position,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER_WITH_VALUE(Value, Read, DoNotUpdateRender, VOXEL_DATA_TOOL_PREFIX, InValue = Data.GetValue(Position, 0).ToFloat());
}

void UVoxelDataTools::SetValueAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FIntVector Position,
	float Value,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, UpdateRender, VOXEL_DATA_TOOL_PREFIX, Data.SetValue(Position, FVoxelValue(Value)));
}

void UVoxelDataTools::GetMaterialAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	FVoxelMaterial& Material,
	AVoxelWorld* World,
	FIntVector Position,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER_WITH_VALUE(Material, Read, DoNotUpdateRender, VOXEL_DATA_TOOL_PREFIX, InMaterial = Data.GetMaterial(Position, 0));
}

void UVoxelDataTools::SetMaterialAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FIntVector Position,
	FVoxelMaterial Material,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, UpdateRender, VOXEL_DATA_TOOL_PREFIX, Data.SetMaterial(Position, Material));
}

void UVoxelDataTools::CacheValuesAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox Bounds,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.CacheBounds<FVoxelValue>(Bounds, false));
}

void UVoxelDataTools::CacheMaterialsAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox Bounds,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.CacheBounds<FVoxelMaterial>(Bounds, false));
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

template<typename T>
inline bool CheckSave(const FVoxelData& Data, const T& Save)
{
	if (Save.GetDepth() == -1)
	{
		FVoxelMessages::Error("LoadFromSave: Invalid save (Depth == -1). You're trying to load a save object that wasn't initialized");
		return false;
	}
	if (Save.GetDepth() > Data.Depth)
	{
		LOG_VOXEL(Warning, TEXT("LoadFromSave: Save depth is bigger than world depth, the save data outside world bounds will be ignored"));
	}
	return true;
}

#define CHECK_SAVE() \
if (!CheckSave(World->GetSubsystemChecked<FVoxelData>(), Save)) \
{ \
	return false; \
}

void UVoxelDataTools::GetSave(AVoxelWorld* World, FVoxelUncompressedWorldSave& OutSave)
{
	GetSave(World, OutSave.NewMutable(), OutSave.Objects);
}

void UVoxelDataTools::GetSave(AVoxelWorld* World, FVoxelUncompressedWorldSaveImpl& OutSave, TArray<FVoxelObjectArchiveEntry>& OutObjects)
{
	CHECK_VOXELWORLD_IS_CREATED_VOID();
	World->GetSubsystemChecked<FVoxelData>().GetSave(OutSave, OutObjects);
}

void UVoxelDataTools::GetCompressedSave(AVoxelWorld* World, FVoxelCompressedWorldSave& OutSave)
{
	GetCompressedSave(World, OutSave.NewMutable(), OutSave.Objects);
}

void UVoxelDataTools::GetCompressedSave(AVoxelWorld* World, FVoxelCompressedWorldSaveImpl& OutSave, TArray<FVoxelObjectArchiveEntry>& OutObjects)
{
	CHECK_VOXELWORLD_IS_CREATED_VOID();
	FVoxelUncompressedWorldSaveImpl Save;
	World->GetSubsystemChecked<FVoxelData>().GetSave(Save, OutObjects);
	UVoxelSaveUtilities::CompressVoxelSave(Save, OutSave);
}

void UVoxelDataTools::GetSaveAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelUncompressedWorldSave& OutSave,
	bool bHideLatentWarnings)
{
	VOXEL_FUNCTION_COUNTER();

	FVoxelToolHelpers::StartAsyncLatentAction_WithWorld_WithValue(
		WorldContextObject,
		LatentInfo,
		World,
		FUNCTION_FNAME,
		bHideLatentWarnings,
		OutSave,
		[](FVoxelData& Data, FVoxelUncompressedWorldSave& Save)
		{
			Data.GetSave(Save.NewMutable(), Save.Objects);
		},
		EVoxelUpdateRender::DoNotUpdateRender,
		{});
}

void UVoxelDataTools::GetCompressedSaveAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelCompressedWorldSave& OutSave,
	bool bHideLatentWarnings)
{
	VOXEL_FUNCTION_COUNTER();

	FVoxelToolHelpers::StartAsyncLatentAction_WithWorld_WithValue(
		WorldContextObject,
		LatentInfo,
		World,
		FUNCTION_FNAME,
		bHideLatentWarnings,
		OutSave,
		[](FVoxelData& Data, FVoxelCompressedWorldSave& CompressedSave)
		{
			FVoxelUncompressedWorldSaveImpl Save;
			Data.GetSave(Save, CompressedSave.Objects);
			UVoxelSaveUtilities::CompressVoxelSave(Save, CompressedSave.NewMutable());
		},
		EVoxelUpdateRender::DoNotUpdateRender,
		{});
}

bool UVoxelDataTools::LoadFromSave(const AVoxelWorld* World, const FVoxelUncompressedWorldSave& Save)
{
	return LoadFromSave(World, Save.Const(), Save.Objects);
}

bool UVoxelDataTools::LoadFromSave(const AVoxelWorld* World, const FVoxelUncompressedWorldSaveImpl& Save, const TArray<FVoxelObjectArchiveEntry>& Objects)
{
	CHECK_VOXELWORLD_IS_CREATED();
	CHECK_SAVE();

	TArray<FVoxelIntBox> BoundsToUpdate;
	auto& Data = World->GetSubsystemChecked<FVoxelData>();

	const FVoxelGeneratorInit WorldInit = World->GetGeneratorInit();
	const FVoxelPlaceableItemLoadInfo LoadInfo{ &WorldInit, &Objects };

	const bool bSuccess = Data.LoadFromSave(Save, LoadInfo, &BoundsToUpdate);

	World->GetSubsystemChecked<IVoxelLODManager>().UpdateBounds(BoundsToUpdate);

	return bSuccess;
}

bool UVoxelDataTools::LoadFromCompressedSave(const AVoxelWorld* World, const FVoxelCompressedWorldSave& Save)
{
	return LoadFromCompressedSave(World, Save.Const(), Save.Objects);
}

bool UVoxelDataTools::LoadFromCompressedSave(const AVoxelWorld* World, const FVoxelCompressedWorldSaveImpl& Save, const TArray<FVoxelObjectArchiveEntry>& Objects)
{
	CHECK_VOXELWORLD_IS_CREATED();
	CHECK_SAVE();

	FVoxelUncompressedWorldSaveImpl UncompressedSave;
	UVoxelSaveUtilities::DecompressVoxelSave(Save, UncompressedSave);

	return LoadFromSave(World, UncompressedSave, Objects);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

void UVoxelDataTools::RoundVoxelsImpl(FVoxelData& Data, const FVoxelIntBox& Bounds)
{
	VOXEL_ASYNC_FUNCTION_COUNTER();

	int32 NumDirtyLeaves = 0;
	uint64 NumVoxels = 0;
	{
		VOXEL_ASYNC_SCOPE_COUNTER("Record stats");
		FVoxelOctreeUtilities::IterateLeavesInBounds(Data.GetOctree(), Bounds, [&](FVoxelDataOctreeLeaf& Leaf)
		{
			if (Leaf.GetData<FVoxelValue>().IsDirty() && Leaf.GetData<FVoxelValue>().HasAllocation())
			{
				NumDirtyLeaves++;
				NumVoxels += VOXELS_PER_DATA_CHUNK;
			}
		});
	}

	FVoxelScopedSlowTask SlowTask(NumDirtyLeaves, VOXEL_LOCTEXT("Rounding voxels"));
	FScopeToolsTimeLogger ToolsLogger(__FUNCTION__, NumVoxels);

	FVoxelMutableDataAccelerator OctreeAccelerator(Data, Bounds.Extend(2));
	FVoxelOctreeUtilities::IterateLeavesInBounds(Data.GetOctree(), Bounds, [&](FVoxelDataOctreeLeaf& Leaf)
	{
		if (Leaf.GetData<FVoxelValue>().IsDirty() && Leaf.GetData<FVoxelValue>().HasAllocation())
		{
			SlowTask.EnterProgressFrame();

			const FVoxelIntBox LeafBounds = Leaf.GetBounds();
			LeafBounds.Iterate([&](int32 X, int32 Y, int32 Z)
			{
				const FVoxelCellIndex Index = FVoxelDataOctreeUtilities::IndexFromGlobalCoordinates(LeafBounds.Min, X, Y, Z);
				const FVoxelValue& Value = Leaf.GetData<FVoxelValue>().Get(Index);

				if (Value.IsTotallyEmpty() || Value.IsTotallyFull()) return;

				const bool bEmpty = Value.IsEmpty();
				for (int32 OtherX = X - 2; OtherX <= X + 2; OtherX++)
				{
					for (int32 OtherY = Y - 2; OtherY <= Y + 2; OtherY++)
					{
						for (int32 OtherZ = Z - 2; OtherZ <= Z + 2; OtherZ++)
						{
							if (OtherX == X && OtherY == Y && OtherZ == Z) continue;
							const auto OtherValue = OctreeAccelerator.GetValue(OtherX, OtherY, OtherZ, 0);
							if (OtherValue.IsEmpty() != bEmpty) return;
						}
					}
				}
				OctreeAccelerator.SetValue(X, Y, Z, bEmpty ? FVoxelValue::Empty() : FVoxelValue::Full());
			});
		}
	});
}

void UVoxelDataTools::RoundVoxels(AVoxelWorld* World, FVoxelIntBox InBounds)
{
	const FVoxelIntBox Bounds = InBounds.Extend(2);
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX, RoundVoxelsImpl(Data, InBounds));
}

void UVoxelDataTools::RoundVoxelsAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox InBounds,
	bool bHideLatentWarnings)
{
	const FVoxelIntBox Bounds = InBounds.Extend(2);
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX, RoundVoxelsImpl(Data, InBounds));
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

void UVoxelDataTools::ClearUnusedMaterialsImpl(FVoxelData& Data, const FVoxelIntBox& Bounds)
{
	VOXEL_ASYNC_FUNCTION_COUNTER();

	int32 NumDirtyLeaves = 0;
	uint64 NumVoxels = 0;
	{
		VOXEL_ASYNC_SCOPE_COUNTER("Record stats");
		FVoxelOctreeUtilities::IterateLeavesInBounds(Data.GetOctree(), Bounds, [&](FVoxelDataOctreeLeaf& Leaf)
		{
			if (Leaf.GetData<FVoxelMaterial>().IsDirty() && Leaf.GetData<FVoxelMaterial>().HasAllocation())
			{
				NumDirtyLeaves++;
				NumVoxels += VOXELS_PER_DATA_CHUNK;
			}
		});
	}

	FVoxelScopedSlowTask SlowTask(NumDirtyLeaves, VOXEL_LOCTEXT("Clearing unused materials"));
	FScopeToolsTimeLogger ToolsLogger(__FUNCTION__, NumVoxels);

	FVoxelMutableDataAccelerator OctreeAccelerator(Data, Bounds.Extend(2));
	FVoxelOctreeUtilities::IterateLeavesInBounds(Data.GetOctree(), Bounds, [&](FVoxelDataOctreeLeaf& Leaf)
	{
		if (Leaf.GetData<FVoxelMaterial>().IsDirty() && Leaf.GetData<FVoxelMaterial>().HasAllocation())
		{
			SlowTask.EnterProgressFrame();

			bool bEdited = false;

			const FVoxelIntBox LeafBounds = Leaf.GetBounds();
			LeafBounds.Iterate([&](int32 X, int32 Y, int32 Z)
			{
				const FVoxelCellIndex Index = FVoxelDataOctreeUtilities::IndexFromGlobalCoordinates(LeafBounds.Min, X, Y, Z);
				const FVoxelMaterial Material = Leaf.GetData<FVoxelMaterial>().Get(Index);

				if (Material == FVoxelMaterial::Default()) return;

				const FVoxelValue Value = OctreeAccelerator.GetValue(X, Y, Z, 0);
				if (!Value.IsEmpty()) // Only not empty voxels materials can affect the surface
				{
					for (int32 OtherX = X - 1; OtherX <= X + 1; OtherX++)
					{
						for (int32 OtherY = Y - 1; OtherY <= Y + 1; OtherY++)
						{
							for (int32 OtherZ = Z - 1; OtherZ <= Z + 1; OtherZ++)
							{
								if (OtherX == X && OtherY == Y && OtherZ == Z) continue;
								const auto OtherValue = OctreeAccelerator.GetValue(OtherX, OtherY, OtherZ, 0);
								if (OtherValue.IsEmpty()) return;
							}
						}
					}
				}
				OctreeAccelerator.SetMaterial(X, Y, Z, FVoxelMaterial::Default());
				bEdited = true;
			});

			if (bEdited)
			{
				Leaf.GetData<FVoxelMaterial>().Compress(Data);
			}
		}
	});
}

void UVoxelDataTools::ClearUnusedMaterials(AVoxelWorld* World, FVoxelIntBox InBounds)
{
	const FVoxelIntBox Bounds = InBounds.Extend(1);
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX, ClearUnusedMaterialsImpl(Data, InBounds));
}

void UVoxelDataTools::ClearUnusedMaterialsAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox InBounds,
	bool bHideLatentWarnings)
{
	const FVoxelIntBox Bounds = InBounds.Extend(1);
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX, ClearUnusedMaterialsImpl(Data, InBounds));
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

void UVoxelDataTools::GetVoxelsValueAndMaterialImpl(
	FVoxelData& Data,
	TArray<FVoxelValueMaterial>& Voxels,
	const FVoxelIntBox& Bounds,
	const TArray<FIntVector>& Positions)
{
	VOXEL_TOOL_FUNCTION_COUNTER(Positions.Num());
	const FVoxelMutableDataAccelerator OctreeAccelerator(Data, Bounds);
	for (auto& Position : Positions)
	{
		if (Data.IsInWorld(Position))
		{
			FVoxelValueMaterial Voxel;
			Voxel.Position = Position;
			Voxel.Value = OctreeAccelerator.GetValue(Position, 0).ToFloat();
			Voxel.Material = OctreeAccelerator.GetMaterial(Position, 0);
			Voxels.Add(Voxel);
		}
	}
}

void UVoxelDataTools::GetVoxelsValueAndMaterial(
	TArray<FVoxelValueMaterial>& Voxels,
	AVoxelWorld* World,
	const TArray<FIntVector>& Positions)
{
	VOXEL_FUNCTION_COUNTER();
	CHECK_VOXELWORLD_IS_CREATED_VOID();

	if (Positions.Num() == 0)
	{
		Voxels.Reset();
		return;
	}

	const FVoxelIntBox Bounds(Positions);
	CHECK_BOUNDS_ARE_VALID_VOID();
	VOXEL_TOOL_HELPER_BODY(Read, DoNotUpdateRender, GetVoxelsValueAndMaterialImpl(Data, Voxels, Bounds, Positions));
}

void UVoxelDataTools::GetVoxelsValueAndMaterialAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	TArray<FVoxelValueMaterial>& Voxels,
	AVoxelWorld* World,
	const TArray<FIntVector>& Positions,
	bool bHideLatentWarnings)
{
	VOXEL_FUNCTION_COUNTER();
	CHECK_VOXELWORLD_IS_CREATED_VOID();

	if (Positions.Num() == 0)
	{
		Voxels.Reset();
		return;
	}

	const FVoxelIntBox Bounds(Positions);
	VOXEL_TOOL_LATENT_HELPER_WITH_VALUE(Voxels, Read, DoNotUpdateRender, NO_PREFIX, GetVoxelsValueAndMaterialImpl(Data, InVoxels, Bounds, Positions));
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

FVoxelDataMemoryUsageInMB UVoxelDataTools::GetDataMemoryUsageInMB(AVoxelWorld* World)
{
	CHECK_VOXELWORLD_IS_CREATED();
	VOXEL_FUNCTION_COUNTER();

	constexpr double OneMB = double(1 << 20);

	auto& Data = World->GetSubsystemChecked<FVoxelData>();

	FVoxelDataMemoryUsageInMB MemoryUsage;

	MemoryUsage.DirtyValues = Data.GetDirtyMemory().Values.GetValue() / OneMB;
	MemoryUsage.DirtyMaterials = Data.GetDirtyMemory().Materials.GetValue() / OneMB;

	MemoryUsage.CachedValues = Data.GetCachedMemory().Values.GetValue() / OneMB;
	MemoryUsage.CachedMaterials = Data.GetCachedMemory().Materials.GetValue() / OneMB;

	return MemoryUsage;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

void UVoxelDataTools::ClearCachedValues(
	AVoxelWorld* World,
	FVoxelIntBox Bounds)
{
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.ClearCacheInBounds<FVoxelValue>(Bounds));
}

void UVoxelDataTools::ClearCachedValuesAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox Bounds,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.ClearCacheInBounds<FVoxelValue>(Bounds));
}

void UVoxelDataTools::ClearCachedMaterials(
	AVoxelWorld* World,
	FVoxelIntBox Bounds)
{
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.ClearCacheInBounds<FVoxelMaterial>(Bounds));
}

void UVoxelDataTools::ClearCachedMaterialsAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox Bounds,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.ClearCacheInBounds<FVoxelMaterial>(Bounds));
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

void UVoxelDataTools::CheckForSingleValues(
	AVoxelWorld* World,
	FVoxelIntBox Bounds)
{
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.CheckIsSingle<FVoxelValue>(Bounds));
}

void UVoxelDataTools::CheckForSingleValuesAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox Bounds,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.CheckIsSingle<FVoxelValue>(Bounds));
}

void UVoxelDataTools::CheckForSingleMaterials(
	AVoxelWorld* World,
	FVoxelIntBox Bounds)
{
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.CheckIsSingle<FVoxelMaterial>(Bounds));
}

void UVoxelDataTools::CheckForSingleMaterialsAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox Bounds,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX, Data.CheckIsSingle<FVoxelMaterial>(Bounds));
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

template<typename T>
void UVoxelDataTools::CompressIntoHeightmapImpl(FVoxelData& Data, TVoxelHeightmapAssetSamplerWrapper<T>& Wrapper, const bool bCheckAllLeaves)
{
	VOXEL_ASYNC_FUNCTION_COUNTER();

	ensure(Wrapper.Scale == 1.f);

	FVoxelScopedSlowTask SlowTask(2, VOXEL_LOCTEXT("Compressing into heightmap"));
	SlowTask.EnterProgressFrame();

	TMap<FIntPoint, TMap<int32, FVoxelDataOctreeLeaf*>> LeavesColumns;
	{
		if (bCheckAllLeaves)
		{
			// Need to subdivide
			FVoxelOctreeUtilities::IterateEntireTree(Data.GetOctree(), [&](FVoxelDataOctreeBase& Tree)
			{
				if (!Tree.IsLeaf())
				{
					auto& Parent = Tree.AsParent();
					if (!Parent.HasChildren())
					{
						ensureThreadSafe(Parent.IsLockedForWrite());
						Parent.CreateChildren();
					}
				}
			});
		}

		int32 NumLeaves = 0;
		FVoxelOctreeUtilities::IterateAllLeaves(Data.GetOctree(), [&](FVoxelDataOctreeLeaf& Leaf)
		{
			if (Leaf.GetData<FVoxelValue>().IsDirty() || bCheckAllLeaves)
			{
				NumLeaves++;
			}
		});

		FVoxelScopedSlowTask LocalSlowTask(NumLeaves, VOXEL_LOCTEXT("Caching data"));

		FVoxelOctreeUtilities::IterateAllLeaves(Data.GetOctree(), [&](FVoxelDataOctreeLeaf& Leaf)
		{
			ensureThreadSafe(Leaf.IsLockedForWrite());

			auto& DataHolder = Leaf.GetData<FVoxelValue>();
			if (bCheckAllLeaves)
			{
				if (!DataHolder.HasData())
				{
					DataHolder.CreateData(Data, [&](auto* DataPtr)
					{
						TVoxelQueryZone<FVoxelValue> QueryZone(Leaf.GetBounds(), DataPtr);
						Leaf.GetFromGeneratorAndAssets(*Data.Generator, QueryZone, 0);
					});
					// Reduce memory usage
					DataHolder.Compress(Data);
				}
			}
			else
			{
				if (!DataHolder.IsDirty())
				{
					// Flush cache
					DataHolder.ClearData(Data);
					return;
				}
			}

			LocalSlowTask.EnterProgressFrame();

			const FIntVector Min = Leaf.GetMin();

			auto& Column = LeavesColumns.FindOrAdd(FIntPoint(Min.X, Min.Y));
			check(!Column.Contains(Min.Z));
			Column.Add(Min.Z, &Leaf);
		});
	}

	SlowTask.EnterProgressFrame();
	FVoxelScopedSlowTask LocalSlowTask(LeavesColumns.Num(), VOXEL_LOCTEXT("Finding heights"));

	FVoxelMutableDataAccelerator Accelerator(Data, FVoxelIntBox::Infinite);
	for (auto& ColumnsIt : LeavesColumns)
	{
		LocalSlowTask.EnterProgressFrame();

		const FIntPoint LeafMinXY = ColumnsIt.Key;
		auto& Leaves = ColumnsIt.Value;

		int32 MinLeafMinZ = MAX_int32;
		int32 MaxLeafMinZ = MIN_int32;
		for (auto& LeavesIt : Leaves)
		{
			MinLeafMinZ = FMath::Min(LeavesIt.Key, MinLeafMinZ);
			MaxLeafMinZ = FMath::Max(LeavesIt.Key, MaxLeafMinZ);
		}
		check(MinLeafMinZ != MAX_int32);
		check(MaxLeafMinZ != MIN_int32);

		const auto GetHeightmapPosition = [&](int32 X, int32 Y)
		{
			// Note: HeightmapAssets are offset by (-Wrapper.GetWidth() / 2, -Wrapper.GetHeight() / 2)
			return FIntPoint(LeafMinXY.X + X + Wrapper.GetWidth() / 2, LeafMinXY.Y + Y + Wrapper.GetHeight() / 2);
		};
		const auto IsInBounds = [&](const FIntPoint& HeightmapPosition)
		{
			return
				HeightmapPosition.X >= 0 &&
				HeightmapPosition.Y >= 0 &&
				HeightmapPosition.X < Wrapper.GetWidth() &&
				HeightmapPosition.Y < Wrapper.GetHeight();
		};

		TStaticArray<float, DATA_CHUNK_SIZE * DATA_CHUNK_SIZE> NewHeights;
		for (int32 X = 0; X < DATA_CHUNK_SIZE; X++)
		{
			for (int32 Y = 0; Y < DATA_CHUNK_SIZE; Y++)
			{
				const FIntPoint HeightmapPosition = GetHeightmapPosition(X, Y);
				if (!IsInBounds(HeightmapPosition)) continue;

				const auto GetNewHeight = [&]()
				{
					const float HeightmapHeight = Wrapper.GetHeight(HeightmapPosition.X, HeightmapPosition.Y, EVoxelSamplerMode::Clamp);
					if (HeightmapHeight >= MaxLeafMinZ + DATA_CHUNK_SIZE)
					{
						// Heightmap is above all leaves, can't do anything
						return HeightmapHeight;
					}

					// Go down chunk by chunk until we find the height
					for (int32 LeafMinZ = MaxLeafMinZ; LeafMinZ >= MinLeafMinZ; LeafMinZ -= DATA_CHUNK_SIZE)
					{
						auto* Leaf = Leaves.FindRef(LeafMinZ);
						if (!Leaf)
						{
							checkVoxelSlow(HeightmapHeight <= LeafMinZ + DATA_CHUNK_SIZE);
							if (LeafMinZ < HeightmapHeight)
							{
								// HeightmapHeight above all remaining leaves, can't do anything
								return HeightmapHeight;
							}
						}
						else
						{
							// Go down until we find the height
							auto& DataHolder = Leaf->GetData<FVoxelValue>();
							if (DataHolder.IsSingleValue() && !DataHolder.GetSingleValue().IsEmpty())
							{
								// Fast path
								continue;
							}

							for (int32 Z = DATA_CHUNK_SIZE - 1; Z >= 0; Z--)
							{
								const FVoxelValue Value = DataHolder.Get(FVoxelDataOctreeUtilities::IndexFromCoordinates(X, Y, Z));
								if (!Value.IsEmpty())
								{
									FVoxelValue ValueAbove;
									if (Z + 1 < DATA_CHUNK_SIZE)
									{
										ValueAbove = DataHolder.Get(FVoxelDataOctreeUtilities::IndexFromCoordinates(X, Y, Z + 1));
									}
									else
									{
										ValueAbove = Accelerator.GetValue(Leaf->GetMin() + FIntVector(X, Y, Z + 1), 0);
									}
									// Note: not true on world upper bound
									ensure(ValueAbove.IsEmpty());

									const float NewHeight = LeafMinZ + Z + FVoxelUtilities::GetAbsDistanceFromDensities(Value.ToFloat(), ValueAbove.ToFloat());
									const float OldHeight = HeightmapHeight;

									// Mark leaves that will have their value changed by the new height as dirty so that they don't change
									const int32 StartLeafMinZ = FMath::FloorToInt(FMath::Min(NewHeight, OldHeight) / DATA_CHUNK_SIZE) * DATA_CHUNK_SIZE;
									const int32 EndLeafMinZ = FMath::CeilToInt(FMath::Max(NewHeight, OldHeight) / DATA_CHUNK_SIZE) * DATA_CHUNK_SIZE;
									for (int32 ItLeafMinZ = StartLeafMinZ; ItLeafMinZ <= EndLeafMinZ; ItLeafMinZ += DATA_CHUNK_SIZE)
									{
										if (Leaves.Contains(ItLeafMinZ)) continue; // Values already correctly stored

										// Leaf is defaulting to generator value, but this value is going to change
										// Mark the leaf as dirty

										const FIntVector LeafPosition = FIntVector(LeafMinXY.X, LeafMinXY.Y, ItLeafMinZ) + DATA_CHUNK_SIZE / 2;
										if (!Data.IsInWorld(LeafPosition)) continue;

										auto* ItLeaf = FVoxelOctreeUtilities::GetLeaf<EVoxelOctreeLeafQuery::CreateIfNull>(Data.GetOctree(), LeafPosition);
										check(ItLeaf);
										check(!ItLeaf->GetData<FVoxelValue>().HasData());

										ItLeaf->InitForEdit<FVoxelValue>(Data);
										ItLeaf->GetData<FVoxelValue>().SetIsDirty(true, Data);

										// & Add it to the map
										Leaves.Add(ItLeafMinZ, ItLeaf);

										// Update min/max as well
										MinLeafMinZ = FMath::Min(ItLeafMinZ, MinLeafMinZ);
										MaxLeafMinZ = FMath::Max(ItLeafMinZ, MaxLeafMinZ);
									}
									return NewHeight;
								}
							}
						}
					}
					// Not found anything, default to old height
					return HeightmapHeight;
				};
				NewHeights[X + DATA_CHUNK_SIZE * Y] = GetNewHeight();
			}
		}

		// Write the heights
		for (int32 X = 0; X < DATA_CHUNK_SIZE; X++)
		{
			for (int32 Y = 0; Y < DATA_CHUNK_SIZE; Y++)
			{
				const FIntPoint HeightmapPosition = GetHeightmapPosition(X, Y);
				if (!IsInBounds(HeightmapPosition)) continue;

				Wrapper.SetHeight(HeightmapPosition.X, HeightmapPosition.Y, NewHeights[X + DATA_CHUNK_SIZE * Y]);
			}
		}
	}
}

template VOXEL_API void UVoxelDataTools::CompressIntoHeightmapImpl<uint16>(FVoxelData& Data, TVoxelHeightmapAssetSamplerWrapper<uint16>& Wrapper, bool bCheckAllLeaves);
template VOXEL_API void UVoxelDataTools::CompressIntoHeightmapImpl<float>(FVoxelData& Data, TVoxelHeightmapAssetSamplerWrapper<float>& Wrapper, bool bCheckAllLeaves);

void UVoxelDataTools::CompressIntoHeightmap(
	AVoxelWorld* World,
	UVoxelHeightmapAsset* HeightmapAsset,
	bool bHeightmapAssetMatchesWorld)
{
	VOXEL_FUNCTION_COUNTER();
	CHECK_VOXELWORLD_IS_CREATED_VOID();

	auto& Data = World->GetSubsystemChecked<FVoxelData>();
	FVoxelWriteScopeLock Lock(Data, FVoxelIntBox::Infinite, "");

	bool bCheckAllLeaves = false;
	if (!HeightmapAsset)
	{
		if (World->Generator.IsObject()) // We don't want to edit the default object otherwise
		{
			HeightmapAsset = Cast<UVoxelHeightmapAsset>(World->Generator.Object);
		}
	}
	else
	{
		if (!bHeightmapAssetMatchesWorld)
		{
			bCheckAllLeaves = true;

			const int32 Size = FVoxelUtilities::GetSizeFromDepth(DATA_CHUNK_SIZE, Data.Depth);
			if (Size > 20000)
			{
				FVoxelMessages::Error(FUNCTION_ERROR("Heightmap size would be too large!"));
				return;
			}
			if (auto* Heightmap = Cast<UVoxelHeightmapAssetUINT16>(HeightmapAsset))
			{
				HeightmapAsset->HeightOffset = -Size / 2; // Height = 0 should be bottom of the world since all heights are positive
				HeightmapAsset->HeightScale = float(Size) / MAX_uint16; // Distribute the heights
				HeightmapAsset->AdditionalThickness = Size; // Just to be safe

				// Init the heightmap data
				Heightmap->GetData().SetSize(Size, Size, false, {});
				Heightmap->GetData().SetAllHeightsTo(0);
			}
			if (auto* Heightmap = Cast<UVoxelHeightmapAssetFloat>(HeightmapAsset))
			{
				HeightmapAsset->HeightOffset = 0; // Heights can be negative too here
				HeightmapAsset->HeightScale = 1.f; // No need to distribute
				HeightmapAsset->AdditionalThickness = Size; // Fill below

				// Init the heightmap data
				Heightmap->GetData().SetSize(Size, Size, false, {});
				Heightmap->GetData().SetAllHeightsTo(0);
			}
		}
	}

	if (auto* UINT16Heightmap = Cast<UVoxelHeightmapAssetUINT16>(HeightmapAsset))
	{
		TVoxelHeightmapAssetSamplerWrapper<uint16> Wrapper(UINT16Heightmap);
		CompressIntoHeightmapImpl(Data, Wrapper, bCheckAllLeaves);
		UINT16Heightmap->Save();
	}
	else if (auto* FloatHeightmap = Cast<UVoxelHeightmapAssetFloat>(HeightmapAsset))
	{
		TVoxelHeightmapAssetSamplerWrapper<float> Wrapper(FloatHeightmap);
		CompressIntoHeightmapImpl(Data, Wrapper, bCheckAllLeaves);
		FloatHeightmap->Save();
	}
	else
	{
		FVoxelMessages::Error(FUNCTION_ERROR("Generator is not an heightmap!"));
	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

void UVoxelDataTools::RoundToGeneratorImpl(FVoxelData& Data, const FVoxelIntBox& Bounds, bool bPreserveNormals)
{
	VOXEL_ASYNC_FUNCTION_COUNTER();

	int32 NumDirtyLeaves = 0;
	FVoxelOctreeUtilities::IterateLeavesInBounds(Data.GetOctree(), Bounds, [&](FVoxelDataOctreeLeaf& Leaf)
	{
		if (Leaf.GetData<FVoxelValue>().IsDirty())
		{
			NumDirtyLeaves++;
		}
	});

	FVoxelScopedSlowTask SlowTask(NumDirtyLeaves, VOXEL_LOCTEXT("Round To Generator"));

	FVoxelMutableDataAccelerator OctreeAccelerator(Data, Bounds.Extend(2));
	FVoxelOctreeUtilities::IterateLeavesInBounds(Data.GetOctree(), Bounds, [&](FVoxelDataOctreeLeaf& Leaf)
	{
		if (!Leaf.GetData<FVoxelValue>().IsDirty())
		{
			return;
		}

		SlowTask.EnterProgressFrame();

		// Do not try to round if single value
		if (!Leaf.GetData<FVoxelValue>().IsSingleValue())
		{
			const FVoxelIntBox LeafBounds = Leaf.GetBounds();
			LeafBounds.Iterate([&](int32 X, int32 Y, int32 Z)
			{
				const FVoxelCellIndex Index = FVoxelDataOctreeUtilities::IndexFromGlobalCoordinates(LeafBounds.Min, X, Y, Z);
				const FVoxelValue Value = Leaf.GetData<FVoxelValue>().Get(Index);
				const FVoxelValue GeneratorValue = Data.Generator->Get<FVoxelValue>(X, Y, Z, 0, FVoxelItemStack::Empty);

				if (Value == GeneratorValue) return;
				if (Value.IsEmpty() != GeneratorValue.IsEmpty()) return;

				const auto CheckNeighbor = [&](int32 DX, int32 DY, int32 DZ)
				{
					const FVoxelValue OtherValue = OctreeAccelerator.GetValue(X + DX, Y + DY, Z + DZ, 0);
					const FVoxelValue OtherGeneratorValue = Data.Generator->Get<FVoxelValue>(X + DX, Y + DY, Z + DZ, 0, FVoxelItemStack::Empty);
					return OtherValue.IsEmpty() == OtherGeneratorValue.IsEmpty();
				};

				if (bPreserveNormals)
				{
					for (int32 DX = -1; DX <= 1; DX++)
					{
						for (int32 DY = -1; DY <= 1; DY++)
						{
							for (int32 DZ = -1; DZ <= 1; DZ++)
							{
								if (DX == 0 && DY == 0 && DZ == 0) continue;
								if (!CheckNeighbor(DX, DY, DZ)) return;
							}
						}
					}
				}
				else
				{
					if (!CheckNeighbor(-1, 0, 0)) return;
					if (!CheckNeighbor(+1, 0, 0)) return;
					if (!CheckNeighbor(0, -1, 0)) return;
					if (!CheckNeighbor(0, +1, 0)) return;
					if (!CheckNeighbor(0, 0, -1)) return;
					if (!CheckNeighbor(0, 0, +1)) return;
				}

				OctreeAccelerator.SetValue(X, Y, Z, GeneratorValue);
			});
		}

		// But always check this, as else we get a lot of space used by single values!
		FVoxelDataUtilities::CheckIfSameAsGenerator<FVoxelValue>(Data, Leaf);
	});
}

void UVoxelDataTools::RoundToGenerator(AVoxelWorld* World, FVoxelIntBox Bounds, bool bPreserveNormals)
{
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX, RoundToGeneratorImpl(Data, Bounds, bPreserveNormals));
}

void UVoxelDataTools::RoundToGeneratorAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox Bounds,
	bool bPreserveNormals,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX, RoundToGeneratorImpl(Data, Bounds, bPreserveNormals));
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

void UVoxelDataTools::CheckIfSameAsGeneratorImpl(FVoxelData& Data, const FVoxelIntBox& Bounds)
{
	VOXEL_ASYNC_FUNCTION_COUNTER();

	int32 NumLeaves = 0;
	FVoxelOctreeUtilities::IterateLeavesInBounds(Data.GetOctree(), Bounds, [&](FVoxelDataOctreeLeaf& Leaf)
	{
		NumLeaves++;
	});

	FVoxelScopedSlowTask SlowTask(NumLeaves, VOXEL_LOCTEXT("Check If Same As Generator"));
	FVoxelOctreeUtilities::IterateLeavesInBounds(Data.GetOctree(), Bounds, [&](FVoxelDataOctreeLeaf& Leaf)
	{
		SlowTask.EnterProgressFrame();
		ensureThreadSafe(Leaf.IsLockedForWrite());
		if (Leaf.GetData<FVoxelValue>().IsDirty())
		{
			FVoxelDataUtilities::CheckIfSameAsGenerator<FVoxelValue>(Data, Leaf);
		}
		if (Leaf.GetData<FVoxelMaterial>().IsDirty())
		{
			FVoxelDataUtilities::CheckIfSameAsGenerator<FVoxelMaterial>(Data, Leaf);
		}
	});
}

void UVoxelDataTools::CheckIfSameAsGenerator(AVoxelWorld* World, FVoxelIntBox Bounds)
{
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX, CheckIfSameAsGeneratorImpl(Data, Bounds));
}

void UVoxelDataTools::CheckIfSameAsGeneratorAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox Bounds,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX, CheckIfSameAsGeneratorImpl(Data, Bounds));
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

template<typename T>
void UVoxelDataTools::SetBoxAsDirtyImpl(FVoxelData& Data, const FVoxelIntBox& Bounds, bool bCompress)
{
	VOXEL_ASYNC_FUNCTION_COUNTER();

	const int32 Count = Bounds.Overlap(Data.WorldBounds).MakeMultipleOfRoundUp(DATA_CHUNK_SIZE).Count() / int64(VOXELS_PER_DATA_CHUNK);
	FVoxelScopedSlowTask SlowTask(Count, VOXEL_LOCTEXT("Set Box as Dirty"));
	FVoxelOctreeUtilities::IterateTreeInBounds(Data.GetOctree(), Bounds, [&](FVoxelDataOctreeBase& Tree)
	{
		if (Tree.IsLeaf())
		{
			SlowTask.EnterProgressFrame();

			auto& Leaf = Tree.AsLeaf();
			ensureThreadSafe(Leaf.IsLockedForWrite());

			Leaf.InitForEdit<T>(Data);
			if (bCompress)
			{
				// Else memory usage explodes
				Leaf.GetData<T>().Compress(Data);
			}
			Leaf.GetData<T>().SetIsDirty(true, Data);
		}
		else
		{
			auto& Parent = Tree.AsParent();
			if (!Parent.HasChildren())
			{
				ensureThreadSafe(Parent.IsLockedForWrite());
				Parent.CreateChildren();
			}
		}
	});
}

template VOXEL_API void UVoxelDataTools::SetBoxAsDirtyImpl<FVoxelValue>(FVoxelData&, const FVoxelIntBox&, bool);
template VOXEL_API void UVoxelDataTools::SetBoxAsDirtyImpl<FVoxelMaterial>(FVoxelData&, const FVoxelIntBox&, bool);

void UVoxelDataTools::SetBoxAsDirty(
	AVoxelWorld* World,
	FVoxelIntBox Bounds,
	bool bDirtyValues,
	bool bDirtyMaterials)
{
	VOXEL_TOOL_HELPER(Write, DoNotUpdateRender, NO_PREFIX,
		if (bDirtyValues)
		{
			SetBoxAsDirtyImpl<FVoxelValue>(Data, Bounds, true);
		}
		if (bDirtyMaterials)
		{
			SetBoxAsDirtyImpl<FVoxelMaterial>(Data, Bounds, true);
		});
}

void UVoxelDataTools::SetBoxAsDirtyAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	AVoxelWorld* World,
	FVoxelIntBox Bounds,
	bool bDirtyValues,
	bool bDirtyMaterials,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER(Write, DoNotUpdateRender, NO_PREFIX,
		if (bDirtyValues)
		{
			SetBoxAsDirtyImpl<FVoxelValue>(Data, Bounds, true);
		}
		if (bDirtyMaterials)
		{
			SetBoxAsDirtyImpl<FVoxelMaterial>(Data, Bounds, true);
		});
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

#define FINDCLOSESTNONEMPTYVOXEL_PREFIX \
	const FVoxelVector Position = FVoxelToolHelpers::GetRealTemplate(World, InPosition, bConvertToVoxelSpace); \
	const FVoxelIntBox Bounds = FVoxelIntBox(Position, Position + 1);

FVoxelFindClosestNonEmptyVoxelResult UVoxelDataTools::FindClosestNonEmptyVoxelImpl(
	FVoxelData& Data,
	const FVoxelVector& Position,
	bool bReadMaterial)
{
	FVoxelFindClosestNonEmptyVoxelResult Result;

	const FVoxelConstDataAccelerator Accelerator(Data);

	v_flt Distance = MAX_vflt;
	for (auto& Neighbor : FVoxelUtilities::GetNeighbors(Position))
	{
		const FVoxelValue Value = Accelerator.GetValue(Neighbor, 0);
		if (!Value.IsEmpty())
		{
			const v_flt PointDistance = (FVoxelVector(Neighbor) - Position).SizeSquared();
			if (PointDistance < Distance)
			{
				Distance = PointDistance;
				Result.bSuccess = true;
				Result.Position = Neighbor;
				Result.Value = Value.ToFloat();
			}
		}
	}

	if (Result.bSuccess && bReadMaterial)
	{
		Result.Material = Accelerator.GetMaterial(Result.Position, 0);
	}

	return Result;
}

void UVoxelDataTools::FindClosestNonEmptyVoxel(
	FVoxelFindClosestNonEmptyVoxelResult& Result,
	AVoxelWorld* World,
	FVector InPosition,
	bool bReadMaterial,
	bool bConvertToVoxelSpace)
{
	VOXEL_TOOL_HELPER(Read, DoNotUpdateRender, FINDCLOSESTNONEMPTYVOXEL_PREFIX, Result = FindClosestNonEmptyVoxelImpl(Data, Position, bReadMaterial));
}

void UVoxelDataTools::FindClosestNonEmptyVoxelAsync(
	UObject* WorldContextObject,
	FLatentActionInfo LatentInfo,
	FVoxelFindClosestNonEmptyVoxelResult& Result,
	AVoxelWorld* World,
	FVector InPosition,
	bool bReadMaterial,
	bool bConvertToVoxelSpace,
	bool bHideLatentWarnings)
{
	VOXEL_TOOL_LATENT_HELPER_WITH_VALUE(Result, Read, DoNotUpdateRender, FINDCLOSESTNONEMPTYVOXEL_PREFIX, InResult = FindClosestNonEmptyVoxelImpl(Data, Position, bReadMaterial));
}


text:
class Configuration
{
    public:
        Configuration();
        virtual ~Configuration();
        void load(const std::string& path);
        void addLoader(std::string name, chimera::runtime::IModulePathProvider* item);
        void setLogLevel(const unsigned int& loglevel);

        std::vector<std::pair<std::string, chimera::runtime::IModulePathProvider*> >* getLoaders();
        unsigned int getLogLevel();
    protected:
    private:
        unsigned int _loglevel;
        std::vector<std::pair<std::string, chimera::runtime::IModulePathProvider*> >* _pathLookup;
};

#endif // CONFIGURATION_H


text:
package br.com.delogic.csa.repository.jpa;

public enum JpaSqlCommand {

    SELECT, DELETE;

}


text:
<?php
    if(!defined("__ZBXE__")) exit();

    /**
     * @file lyric.addon.php
     * @author Huhani (mmia268@gmail.com)
     * @brief 알송 가사 출력 애드온
     **/

	if($called_position == 'before_module_init' && $_SERVER['REQUEST_METHOD'] == 'POST' && Context::get('act') == 'getMP3FileLyric'){

		require_once('lyric.api.php');
		$document_srl = Context::get('document_srl');

		$oDocumentModel = getModel('document');
		$document_srl = Context::get('document_srl');
		$oDocument = $oDocumentModel->getDocument($document_srl);

//debugPrint(Context::getResponseMethod());
		$file = $oDocument->getUploadedFiles();
		$result = 'null';
		foreach($file as $val){
			if(substr($val->uploaded_filename, -4) === '.mp3'){
				$lyric = new Lyric($val->uploaded_filename);
				$hash = $lyric->getMD5Hash();
				$result = $lyric->getLyric($hash);
				if($result) {
					break;
				}
			}

		}

		echo $result;
		exit();

	}
	else if($called_position == 'after_module_proc' && Context::getResponseMethod()!="XMLRPC") {
		$document_srl = Context::get('document_srl');
		$act = Context::get('act');
		if($document_srl && !$act){

			$oTemplate = &TemplateHandler::getInstance();
			$output = $oTemplate->compile('./addons/lyric/tpl','lyric');
			Context::addHtmlFooter(sprintf("%s", $output));
			if(Mobile::isFromMobilePhone()) {
				Context::loadFile(array('./addons/lyric/tpl/lyric.m.js', 'body', '', null), true);
				Context::loadFile('./addons/lyric/tpl/lyric.m.css');
			} else {
				Context::loadFile(array('./addons/lyric/tpl/lyric.js', 'body', '', null), true);
				Context::loadFile(array('./addons/lyric/tpl/audio.js', 'body', '', null), true);
				Context::loadFile('./addons/lyric/tpl/lyric.css');
			}

		}
	}

?>


text:
<?php
namespace Chamilo\Core\Repository\Implementation\Office365;

use Chamilo\Core\Repository\External\Infrastructure\Service\MicrosoftGraphClientSettingsProvider;
use Chamilo\Core\User\Storage\DataClass\User;
use Chamilo\Libraries\Architecture\Application\Application;
use Chamilo\Libraries\File\Properties\FileProperties;
use Chamilo\Libraries\Platform\Session\Request;
use Chamilo\Libraries\Platform\Session\Session;
use Chamilo\Libraries\Protocol\MicrosoftClient\MicrosoftClientService;
use Chamilo\Libraries\Storage\ResultSet\ArrayResultSet;

/**
 * Data Connector Microsoft Graph API
 * @notes The Graph API has some shortcomings when querying files on Microsoft OneDrive.
 * - Cannot retrieve folders only or files only, we always receive both sorts of object.
 * - API does not support offset and count.
 * - API cannot perform full text search inside a folder.
 * The implementation resembles the OneDrive browser on office.com:
 * - Folders appear in the table on the right pane.
 * - Menu only shows the path to the current directory.
 * - Searching for items in folder is restricted to searching for items starting with given string.
 *
 * @author Andras Zolnay - edufiles
 */
class DataConnector extends \Chamilo\Core\Repository\External\DataConnector
{

    private $driveItems;

    private $folderPath;

    private $rootFolderId;

    /**
     *
     * @var MicrosoftClientService;
     */
    protected $microsoftClientService;
    const DOCUMENTS_SHARED = 'shared_with_me';
    const DOCUMENTS_RECENT = 'recent';

    /**
     * DataConnector constructor.
     *
     * @param Instance $externalRepositoryInstance
     */
    public function __construct($externalRepositoryInstance)
    {
        parent::__construct($externalRepositoryInstance);

        $user = new User();
        $user->setId(Session::get_user_id());

        $this->microsoftClientService = new MicrosoftClientService(
            new MicrosoftGraphClientSettingsProvider($externalRepositoryInstance, $user));
    }

    public function login()
    {
        $error = Request::get('error');
        if (! is_null($error))
        {
            return false;
        }

        $replyParameters = array();
        $replyParameters[Application::PARAM_CONTEXT] = Manager::context();
        $replyParameters[Manager::PARAM_ACTION] = Manager::ACTION_LOGIN;
        $replyParameters[Manager::PARAM_EXTERNAL_REPOSITORY] = $this->get_external_repository_instance_id();

        $code = Request::get('code');
        return $this->microsoftClientService->login($replyParameters, $code);
    }

    /**
     * Retrieves the given objects and converts the response to an ExternalObject instance.
     *
     * @param $id string
     * @return ExternalObject
     */
    public function retrieve_external_repository_object($id)
    {
        $request = $this->microsoftClientService->createRequest('GET', 'drive/items/' . $id);
        $result = $this->microsoftClientService->sendRequest($request);

        return $this->parseExternalRepositoryObject($result);
    }

    /*
     * (non-PHPdoc) @see
     * application/common/external_repository_manager/ExternalRepositoryConnector#count_external_repository_objects()
     */
    public function count_external_repository_objects($condition)
    {
        return count($this->getDriveItems($condition));
    }

    /**
     *
     * @param $id string
     */
    public function delete_external_repository_object($id)
    {
        $this->service->files->delete($id);
    }

    /**
     *
     * @param $content_object ContentObject
     */
    public function export_external_repository_object($content_object)
    {
    }

    /**
     *
     * @param $query mixed
     *
     * @return mixed
     */
    public static function translate_search_query($query)
    {
        return $query;
    }

    /*
     * (non-PHPdoc) @see
     * application/common/external_repository_manager/ExternalRepositoryConnector#retrieve_external_repository_objects()
     */
    public function retrieve_external_repository_objects($condition, $orderProperty, $offset, $count)
    {
        $driveItems = $this->getDriveItems($condition, $orderProperty);

        $objects = array();
        $end = min(count($driveItems), $offset + $count);
        for ($i = $offset; $i < $end; ++ $i)
        {
            $objects[] = $this->parseExternalRepositoryObject($driveItems[$i]);
        }

        return new ArrayResultSet($objects);
    }

    public function retrieveChildFolder($parent_id)
    {
        $folderPath = $this->getFolderPath();
        return new ArrayResultSet($folderPath[$parent_id]);
    }

    public function import_external_repository_object($id)
    {
        $request = $this->microsoftClientService->createRequest('GET', 'drive/items/' . $id . '/content');
        return $this->microsoftClientService->sendRequest($request, false);
    }

    public function getFolderPath()
    {
        if (! isset($this->folderPath))
        {
            $this->folderPath = array();

            $folderId = Request::get(Manager::PARAM_FOLDER);
            if (! empty($folderId))
            {
                $this->folderPath[$folderId] = array(); // Children of current folder are in table.

                while (true)
                {
                    $folder = $this->retrieveFolder($folderId);
                    if (empty($folder->getParent()))
                    {
                        break;
                    }

                    $this->folderPath[$folder->getParent()] = array($folder);
                    $folderId = $folder->getParent();
                }
            }
        }

        return $this->folderPath;
    }

    public function getRootFolderId()
    {
        if (! isset($this->rootFolderId))
        {
            $this->rootFolderId = $this->retrieveFolder('root')->getId();
        }

        return $this->rootFolderId;
    }

    public function retrieveFolder($id)
    {
        $folder = new Folder();

        if ($id == self::DOCUMENTS_SHARED || $id == self::DOCUMENTS_RECENT)
        {
            $folder->setId($id);
            $folder->setTitle($id);
            $folder->setParent(null);
        }
        else
        {
            $request = $this->microsoftClientService->createRequest('GET', 'drive/items/' . $id);
            $result = $this->microsoftClientService->sendRequest($request);

            $folder->setId($result->id);
            $folder->setTitle($result->name);
            $folder->setParent($result->parentReference->id);
        }

        return $folder;
    }

    /**
     * \brief Creates an external repository object from the result of GET request.
     *
     * @param \stdClass $response
     * @return ExternalObject
     */
    private function parseExternalRepositoryObject($response)
    {
        $object = new ExternalObject();
        $object->set_id($response->id);
        $object->set_external_repository_id($this->get_external_repository_instance_id());
        $object->set_created(strtotime($response->createdDateTime));
        $object->set_modified(strtotime($response->lastModifiedDateTime));

        if (is_null($response->remoteItem))
        {
            $object->set_title($response->name);
            $object->set_type($this->parseType($response));
            $object->set_rights($this->parseRights($response));
            $object->set_owner_id($response->createdBy->user->id);
            $object->set_owner_name($response->createdBy->user->displayName);
            $object->setModifierId($response->lastModifiedBy->user->displayName);
            $object->setUrl($response->webUrl);
        }
        else
        {
            $object->set_title($response->remoteItem->name);
            $object->set_type($this->parseType($response->remoteItem));
            $object->set_rights($this->parseRights($response->remoteItem));
        }

        return $object;
    }

    /**
     * Determines the type of the external object
     * Type is partially based on facets folder and image and partially based on the the extension of the file.
     */
    private function parseType($response)
    {
        if (! is_null($response->folder))
        {
            return ExternalObject::TYPE_FOLDER;
        }

        if (! is_null($response->image))
        {
            return ExternalObject::TYPE_IMAGE;
        }

        $file_properties = FileProperties::from_path($response->name);
        if (! empty($file_properties->get_extension()))
        {
            return $file_properties->get_extension();
        }

        return ExternalObject::TYPE_FILE;
    }

    /**
     * Returns rights dependent on type.
     */
    private function parseRights($response)
    {
        $rights = array();
        $rights[ExternalObject::RIGHT_USE] = is_null($response->folder);
        $rights[ExternalObject::RIGHT_EDIT] = false;
        $rights[ExternalObject::RIGHT_DELETE] = false;
        $rights[ExternalObject::RIGHT_DOWNLOAD] = is_null($response->folder);
        return $rights;
    }

    /**
     * \brief Retrieves all driveitems in current folder for given $searchString.
     * All driveitems are retrieved by looping over all resulting pages.
     */
    private function getDriveItems($searchString = null, $orderProperty = null)
    {
        if (! isset($this->driveItems))
        {
            $this->driveItems = array();

            $link = $this->getDriveItemsRequest($searchString);
            while (true)
            {
                $request = $this->microsoftClientService->createRequest('GET', $link);
                $result = get_object_vars($this->microsoftClientService->sendRequest($request));

                $this->driveItems = array_merge($this->driveItems, $result['value']);

                if (array_key_exists('@odata.nextLink', $result))
                {
                    $link = $result['@odata.nextLink'];
                }
                else
                {
                    break;
                }
            }
        }

        $this->sortDriveItems($this->driveItems, $orderProperty);

        // die(var_dump($this->driveItems));
        return $this->driveItems;
    }

    /**
     * Return search request for given condition and ordering.
     *
     * @return Examples: - Condition is NULL and PARAM_FOLDER is null: drive/root/children
     */
    private function getDriveItemsRequest($searchString = null)
    {
        $request = 'drive/';

        $folder = Request::get(Manager::PARAM_FOLDER);
        if (is_null($folder))
        {
            $request .= 'root/children';
        }
        else
            if ($folder == self::DOCUMENTS_SHARED)
            {
                $request .= 'sharedWithMe';
            }
            else
                if ($folder == self::DOCUMENTS_RECENT)
                {
                    $request .= 'recent';
                }
                else
                {
                    $request .= 'items/' . $folder . '/children';
                }

        $queryParameters = array();

        // Retrieve only used properties
        // $queryParameters[] = '$select=id,name,folder,file,parentReference,createdDateTime';

        if (! is_null($searchString))
        {
            // substringof does not seem to be implemented although part of OData Filters.
            // $queryParameters[] = '$filter=substringof(\'' . $searchString . '\', name)';
            // $search is accepted, however does not have any effect.
            // $queryParameters[] = '$search=' . $searchString;
            // Funtion endswith does not ssem to be implemented either.
            // $queryParameters[] = '$filter=startswith(name, \'' . $searchString . '\') Or endswith(name, \'' .
            // $searchString . '\')';
            $queryParameters[] = '$filter=startswith(name, \'' . $searchString . '\')';
        }

        if (! empty($queryParameters))
        {
            $request .= '?' . implode('&', $queryParameters);
        }

        return $request;
    }

    private function sortDriveItems(&$driveItems, $orderProperty)
    {
        if (! empty($orderProperty))
        {
            switch ($orderProperty[0]->get_property()->get_property())
            {
                case ExternalObject::PROPERTY_TITLE :
                    $compareFunctionName = 'compareDriveItemNames';

                    $folderId = Request::get(Manager::PARAM_FOLDER);
                    if ($folderId == self::DOCUMENTS_SHARED || $folderId == self::DOCUMENTS_RECENT)
                    {
                        $compareFunctionName .= 'RemoteItem';
                    }

                    break;

                case ExternalObject::PROPERTY_CREATED :
                    $compareFunctionName = 'compareDriveItemCreationDates';
                    break;

                default :
                    $compareFunctionName = null;
                    break;
            }

            $direction = 'Desc';
            if ($orderProperty[0]->get_direction() == SORT_ASC)
            {
                $direction = 'Asc';
            }

            if (! is_null($compareFunctionName))
            {
                usort($driveItems, array(self, $compareFunctionName . $direction));
            }
        }
    }

    public static function compareDriveItemNamesAsc($a, $b)
    {
        return strcmp($a->name, $b->name);
    }

    public static function compareDriveItemNamesDesc($a, $b)
    {
        return strcmp($b->name, $a->name);
    }

    public static function compareDriveItemNamesRemoteItemAsc($a, $b)
    {
        return strcmp($a->remoteItem->name, $b->remoteItem->name);
    }

    public static function compareDriveItemNamesRemoteItemDesc($a, $b)
    {
        return strcmp($b->remoteItem->name, $a->remoteItem->name);
    }

    public static function compareDriveItemCreationDatesAsc($a, $b)
    {
        return strtotime($a->createdDateTime) > strtotime($b->createdDateTime);
    }

    public static function compareDriveItemCreationDatesDesc($a, $b)
    {
        return strtotime($b->createdDateTime) > strtotime($a->createdDateTime);
    }
}


text:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
    <corners
        android:radius="4dp"
        />
    <solid
        android:color="@color/color_nebula"
        />
    <size
        android:width="128dp"
        android:height="48dp"
        />
</shape>