text:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

<item>
    <shape android:shape="rectangle"  >
         <corners android:radius="5dip" />
         <stroke android:width="3dip" android:color="#80e0e0e0" />
         <solid android:color="#80e0e0e0" />
     </shape>
 </item>

<item android:bottom="3px">
    <shape android:shape="rectangle"  >
         <corners android:radius="5dip" />
         <stroke android:width="1dip" android:color="#e0e0e0" />
         <solid android:color="#ffffff" />
     </shape>
 </item>

</layer-list>


text:
namespace NelitaBeautyStudio.Data.Repositories
{
    using System.Linq;

    public interface IRepository<T> where T : class
    {
        IQueryable<T> All();

        T GetById(object id);

        void Add(T entity);

        void Update(T entity);

        void Delete(T entity);

        void Delete(object id);

        void Detach(T entity);
    }
}

redpajama_set_name: RedPajamaGithub


text:
package com.jcwhatever.nucleus.managed.resourcepacks;

import com.jcwhatever.nucleus.mixins.IPlayerReference;
import com.jcwhatever.nucleus.utils.observer.future.IFutureResult;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;

/**
 * Interface for a players resource pack view.
 */
public interface IPlayerResourcePacks extends IPlayerReference {

    /**
     * Get the resource pack the player is currently viewing.
     *
     *
If there is no default pack and the player is not viewing any pack, the
     * most recent pack is returned to show client behaviour.

     */
    @Nullable
    IResourcePack getCurrent();

    /**
     * Use the previous resource pack.
     *
     * @return  True if there is a previous resource pack, otherwise false.
     */
    boolean prev();

    /**
     * Use the specified resource pack.
     *
     * @param resourcePack  The resource pack.
     *
     * @return  True if the resource pack is set, False if a pending operation on the previous
     * resource pack is preventing the resource pack from being set.
     */
    boolean next(IResourcePack resourcePack);

    /**
     * Use the specified resource pack.
     *
     * @param resourcePack  The resource pack.
     * @param remove        Resource packs to remove from the players stack before setting
     *                      new pack.
     *
     * @return  True if the resource pack is set, False if a pending operation on the previous
     * resource pack is preventing the resource pack from being set.
     */
    boolean next(IResourcePack resourcePack, IResourcePack... remove);

    /**
     * Remove a resource pack from the players stack.
     *
     *
If the player is currently viewing the specified resource pack, this method is
     * effectively the same as invoking {@link #prev()}

     *
     * @param resourcePack  The resource pack to remove.
     *
     * @return  True if found and removed, otherwise false.
     */
    boolean remove(IResourcePack resourcePack);

    /**
     * Get the status of the current resource pack.
     */
    ResourcePackStatus getStatus();

    /**
     * Get the next change in status when it occurs.
     */
    IFutureResult<IPlayerResourcePacks> getNextStatus();

    /**
     * Get the final status when it occurs.
     *
     *
If the current status is already a final status, the future is immediately called.

     */
    IFutureResult<IPlayerResourcePacks> getFinalStatus();

    /**
     * Get the players stack of resource packs.
     *
     *
The current resource pack is at the end of the list.

     */
    List<IResourcePack> getStack();

    /**
     * Copy the players stack of resource packs to the specified
     * output collection.
     *
     * @param output  The output collection.
     *
     * @return  The output collection.
     */
    <T extends Collection<IResourcePack>> T getStack(T output);
}


text:
package aula13.e2;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

public class BigramScanner
{
	public static Map<String, TreeMap<String, Integer>> readFile(String file)
			throws IOException
	{
		// file reader
		Path fix = Paths.get(file);
		List<String> lines = Files.readAllLines(fix);

		// word list
		List<String> words = new ArrayList<>();

		// maps to return and auxiliar
		// treemap is easier so we don't have to order it afterwards
		Map<String , TreeMap<String, Integer>> all = new TreeMap<>();
		TreeMap<String, Integer> aux;

		// splits all words and puts them in the list
		for (String linha : lines)
			Arrays.stream(linha.split("\\W+")).forEach(words::add);

		// put all pairs
		String last_word = "";
		for (String word: words)
		{
			word = word.toLowerCase();
			if (word.length() >= 3)
			{
				if (last_word.equals(""))
					last_word = word;
				else
				{
					if (all.containsKey(last_word))
					{
						aux = all.get(last_word);
						if (aux.containsKey(word))
							aux.replace(word, aux.get(word)+1);
						else
							aux.put(word, 1);
					}
					else
					{
						aux = new TreeMap<>();
						aux.put(word, 1);
						all.put(last_word, aux);
					}
					last_word = word;
				}
			}
		}

		return all;
	}
}


text:
<?php

	/**
	 * @author Alexey Kulikov aka Clops <me@clops.at>
	 */
	namespace Clops\Controller;

	use Silex\Application;
	use Symfony\Component\Config\Definition\Exception\Exception;
	use Symfony\Component\HttpFoundation\File\UploadedFile;
	use Symfony\Component\HttpFoundation\JsonResponse;
	use Symfony\Component\HttpFoundation\Request;
	use Imagine\Image\Box;
	use Imagine\Image\Point;

	/**
	 * Class PageController
	 *
	 * @package Clops\Controller
	 */
	class CommitController
	{

		/**
		 * Splash Page
		 *
		 * @param Request     $request
		 * @param Application $app
		 *
		 * @return mixed
		 */
		public function addAction(Request $request, Application $app)
		{
			//check if the request has all the desired data
			if (!$request->files->has('file')) {
				return $this->error('No file set');
			}

			if (!$request->request->get('repo')) {
				return $this->error('No repo set');
			}

			if (isset($app['config']['main']['key']) && !empty($app['config']['main']['key'])) {
				if (!$request->request->get('key')) {
					return $this->error('No key set');
				}

				//the first check for a string "false" is actually a bug in the lolcommits plugin, take care!
				// @see https://github.com/mroth/lolcommits/issues/223
				if ($request->request->get('key') != 'false' && $app['config']['main']['key'] != $request->request->get('key')) {
					return $this->error('Incorrect key provided, ciao!');
				}
			}

			//init vars
			$directory  = null;
			$fileName   = null;
			$repository = ($request->request->get('repo') == '/' ? '_unknown_' : $request->request->get('repo'));
			$sha        = ($request->request->get('sha')? $request->request->get('sha') : uniqid());
			$message    = ($request->request->get('message')? $request->request->get('message') : uniqid());

			//save image to local-storage
			try {
				$path      = ROOT_PATH . "/web/commits/";
				$directory = $repository . '/' . date('Y') . '/' . date('m') . '/';
				if (!file_exists($path . $directory)) {
					mkdir($path . $directory, 0755, true);
				}

				/** @var UploadedFile $file */
				$file     = $request->files->get('file');
				$fileName = $file->getClientOriginalName();
				$file->move($path . $directory, $fileName);

				//simple changes
				$pathToFile  = $directory . $fileName;
				$pathToThumb = $directory . 'thumb_' . $fileName;

				//now also create a thumbnail from the image
				$app['imagine']
					->open($path . $pathToFile)
					->resize(new Box(268, 200))
					->crop(new Point(34, 0), new Box(200, 200))
					->save($path . $pathToThumb);

				//last but not least --> create database entry
				if(!$record = $app['db']->fetchAssoc("SELECT * FROM commits WHERE sha = ?", array( (string)$sha ))){
			        $app['db']->insert('commits', array(
				        'sha'     => $sha, //this is the primary key, sending the same commit over WILL result in an exception :)
				        'message' => $message,
				        'image'   => $pathToFile,
				        'thumb'   => $pathToThumb,
				        'repo'    => $repository
			        ));
				}
	        } catch (Exception $e) {
				$this->error($e->getMessage());
			}

			//send OK reply
			return new JsonResponse(
				array(
					'status' => 'ok',
					'file'   => 'commits/' . $directory . $fileName
				)
			);
		}

		/**
		 * @param $message
		 *
		 * @return JsonResponse
		 */
		private function error($message)
		{
			//I am not returning an error header on purpose, as lolcommits does not like it :(
			return new JsonResponse(
				array(
					'status'  => 'error',
					'message' => $message
				)
			);
		}

	}


text:
		Redirect In Progress

		Please Wait...


text:
from fabric.api import *

@task
def firewall():
    """
    Setup a firewall
    """

    from fabtools import require
    import fabtools

    require.shorewall.firewall(
        rules=[
            fabtools.shorewall.Ping(),
            fabtools.shorewall.SSH(),
            fabtools.shorewall.HTTP(),
            fabtools.shorewall.HTTPS(),
            fabtools.shorewall.SMTP(),
            fabtools.shorewall.rule(port=1234,
                source=fabtools.shorewall.hosts(['example.com'])),
        ]
    )

    require.shorewall.started()
    assert fabtools.shorewall.is_started()

    require.shorewall.stopped()
    assert fabtools.shorewall.is_stopped()


text:
"""
This module implements Compatibility corrections for mixing runs of different
functionals.
"""

from __future__ import annotations

import abc
import os
import warnings
from collections import defaultdict
from typing import Sequence, Union

import numpy as np
from monty.design_patterns import cached_class
from monty.json import MSONable
from monty.serialization import loadfn
from tqdm import tqdm
from uncertainties import ufloat

from pymatgen.analysis.structure_analyzer import oxide_type, sulfide_type
from pymatgen.core.periodic_table import Element
from pymatgen.entries.computed_entries import (
    CompositionEnergyAdjustment,
    ComputedEntry,
    ComputedStructureEntry,
    ConstantEnergyAdjustment,
    EnergyAdjustment,
    TemperatureEnergyAdjustment,
)
from pymatgen.io.vasp.sets import MITRelaxSet, MPRelaxSet

__author__ = "Amanda Wang, Ryan Kingsbury, Shyue Ping Ong, Anubhav Jain, Stephen Dacek, Sai Jayaraman"
__copyright__ = "Copyright 2012-2020, The Materials Project"
__version__ = "1.0"
__maintainer__ = "Shyue Ping Ong"
__email__ = "shyuep@gmail.com"
__date__ = "April 2020"

MODULE_DIR = os.path.dirname(os.path.abspath(__file__))
MU_H2O = -2.4583  # Free energy of formation of water, eV/H2O, used by MaterialsProjectAqueousCompatibility

AnyCompEntry = Union[ComputedEntry, ComputedStructureEntry]

class CompatibilityError(Exception):
    """
    Exception class for Compatibility. Raised by attempting correction
    on incompatible calculation
    """

class Correction(metaclass=abc.ABCMeta):
    """
    A Correction class is a pre-defined scheme for correction a computed
    entry based on the type and chemistry of the structure and the
    calculation parameters. All Correction classes must implement a
    correct_entry method.
    """

    @abc.abstractmethod
    def get_correction(self, entry):
        """
        Returns correction and uncertainty for a single entry.

        Args:
            entry: A ComputedEntry object.

        Returns:
            The energy correction to be applied and the uncertainty of the correction.

        Raises:
            CompatibilityError if entry is not compatible.
        """
        return

    def correct_entry(self, entry):
        """
        Corrects a single entry.

        Args:
            entry: A ComputedEntry object.

        Returns:
            An processed entry.

        Raises:
            CompatibilityError if entry is not compatible.
        """
        new_corr = self.get_correction(entry)
        old_std_dev = entry.correction_uncertainty
        if np.isnan(old_std_dev):
            old_std_dev = 0
        old_corr = ufloat(entry.correction, old_std_dev)
        updated_corr = new_corr + old_corr

        if updated_corr.nominal_value != 0 and updated_corr.std_dev == 0:
            # if there are no error values available for the corrections applied,
            # set correction uncertainty to not a number
            uncertainty = np.nan
        else:
            uncertainty = updated_corr.std_dev

        entry.energy_adjustments.append(ConstantEnergyAdjustment(updated_corr.nominal_value, uncertainty))

        return entry

class PotcarCorrection(Correction):
    """
    Checks that POTCARs are valid within a pre-defined input set. This
    ensures that calculations performed using different InputSets are not
    compared against each other.

    Entry.parameters must contain a "potcar_symbols" key that is a list of
    all POTCARs used in the run. Again, using the example of an Fe2O3 run
    using Materials Project parameters, this would look like
    entry.parameters["potcar_symbols"] = ['PAW_PBE Fe_pv 06Sep2000',
    'PAW_PBE O 08Apr2002'].
    """

    def __init__(self, input_set, check_hash=False):
        """
        Args:
            input_set: InputSet object used to generate the runs (used to check
                for correct potcar symbols)

            check_hash (bool): If true, uses the potcar hash to check for valid
                potcars. If false, uses the potcar symbol (Less reliable).
                Defaults to True

        Raises:
            ValueError if entry do not contain "potcar_symbols" key.
            CombatibilityError if wrong potcar symbols
        """
        potcar_settings = input_set.CONFIG["POTCAR"]
        if isinstance(list(potcar_settings.values())[-1], dict):
            if check_hash:
                self.valid_potcars = {k: d["hash"] for k, d in potcar_settings.items()}
            else:
                self.valid_potcars = {k: d["symbol"] for k, d in potcar_settings.items()}
        else:
            if check_hash:
                raise ValueError("Cannot check hashes of potcars, since hashes are not included in the entry.")
            self.valid_potcars = potcar_settings

        self.input_set = input_set
        self.check_hash = check_hash

    def get_correction(self, entry) -> ufloat:
        """
        :param entry: A ComputedEntry/ComputedStructureEntry
        :return: Correction, Uncertainty.
        """
        if self.check_hash:
            if entry.parameters.get("potcar_spec"):
                psp_settings = {d.get("hash") for d in entry.parameters["potcar_spec"] if d}
            else:
                raise ValueError("Cannot check hash without potcar_spec field")
        else:
            if entry.parameters.get("potcar_spec"):
                psp_settings = {d.get("titel").split()[1] for d in entry.parameters["potcar_spec"] if d}
            else:
                psp_settings = {sym.split()[1] for sym in entry.parameters["potcar_symbols"] if sym}

        if {self.valid_potcars.get(str(el)) for el in entry.composition.elements} != psp_settings:
            raise CompatibilityError("Incompatible potcar")
        return ufloat(0.0, 0.0)

    def __str__(self):
        return f"{self.input_set.__name__} Potcar Correction"

@cached_class
class GasCorrection(Correction):
    """
    Correct gas energies to obtain the right formation energies. Note that
    this depends on calculations being run within the same input set.
    Used by legacy MaterialsProjectCompatibility and MITCompatibility.
    """

    def __init__(self, config_file):
        """
        Args:
            config_file: Path to the selected compatibility.yaml config file.
        """
        c = loadfn(config_file)
        self.name = c["Name"]
        self.cpd_energies = c["Advanced"]["CompoundEnergies"]

    def get_correction(self, entry) -> ufloat:
        """
        :param entry: A ComputedEntry/ComputedStructureEntry
        :return: Correction.
        """
        comp = entry.composition

        correction = ufloat(0.0, 0.0)

        # set error to 0 because old MPCompatibility doesn't have errors

        # only correct GGA or GGA+U entries
        if entry.parameters.get("run_type", None) not in ["GGA", "GGA+U"]:
            return ufloat(0.0, 0.0)

        rform = entry.composition.reduced_formula
        if rform in self.cpd_energies:
            correction += self.cpd_energies[rform] * comp.num_atoms - entry.uncorrected_energy

        return correction

    def __str__(self):
        return f"{self.name} Gas Correction"

@cached_class
class AnionCorrection(Correction):
    """
    Correct anion energies to obtain the right formation energies. Note that
    this depends on calculations being run within the same input set.

    Used by legacy MaterialsProjectCompatibility and MITCompatibility.
    """

    def __init__(self, config_file, correct_peroxide=True):
        """
        Args:
            config_file: Path to the selected compatibility.yaml config file.
            correct_peroxide: Specify whether peroxide/superoxide/ozonide
                corrections are to be applied or not.
        """
        c = loadfn(config_file)
        self.oxide_correction = c["OxideCorrections"]
        self.sulfide_correction = c.get("SulfideCorrections", defaultdict(float))
        self.name = c["Name"]
        self.correct_peroxide = correct_peroxide

    def get_correction(self, entry) -> ufloat:
        """
        :param entry: A ComputedEntry/ComputedStructureEntry
        :return: Correction.
        """
        comp = entry.composition
        if len(comp) == 1:  # Skip element entry
            return ufloat(0.0, 0.0)

        correction = ufloat(0.0, 0.0)

        # only correct GGA or GGA+U entries
        if entry.parameters.get("run_type", None) not in ["GGA", "GGA+U"]:
            return ufloat(0.0, 0.0)

        # Check for sulfide corrections
        if Element("S") in comp:
            sf_type = "sulfide"

            if entry.data.get("sulfide_type"):
                sf_type = entry.data["sulfide_type"]
            elif hasattr(entry, "structure"):
                warnings.warn(sf_type)
                sf_type = sulfide_type(entry.structure)

            # use the same correction for polysulfides and sulfides
            if sf_type == "polysulfide":
                sf_type = "sulfide"

            if sf_type in self.sulfide_correction:
                correction += self.sulfide_correction[sf_type] * comp["S"]

        # Check for oxide, peroxide, superoxide, and ozonide corrections.
        if Element("O") in comp:
            if self.correct_peroxide:
                if entry.data.get("oxide_type"):
                    if entry.data["oxide_type"] in self.oxide_correction:
                        ox_corr = self.oxide_correction[entry.data["oxide_type"]]
                        correction += ox_corr * comp["O"]
                    if entry.data["oxide_type"] == "hydroxide":
                        ox_corr = self.oxide_correction["oxide"]
                        correction += ox_corr * comp["O"]

                elif hasattr(entry, "structure"):
                    ox_type, nbonds = oxide_type(entry.structure, 1.05, return_nbonds=True)
                    if ox_type in self.oxide_correction:
                        correction += self.oxide_correction[ox_type] * nbonds
                    elif ox_type == "hydroxide":
                        correction += self.oxide_correction["oxide"] * comp["O"]
                else:
                    warnings.warn(
                        "No structure or oxide_type parameter present. Note "
                        "that peroxide/superoxide corrections are not as "
                        "reliable and relies only on detection of special"
                        "formulas, e.g., Li2O2."
                    )
                    rform = entry.composition.reduced_formula
                    if rform in UCorrection.common_peroxides:
                        correction += self.oxide_correction["peroxide"] * comp["O"]
                    elif rform in UCorrection.common_superoxides:
                        correction += self.oxide_correction["superoxide"] * comp["O"]
                    elif rform in UCorrection.ozonides:
                        correction += self.oxide_correction["ozonide"] * comp["O"]
                    elif Element("O") in comp.elements and len(comp.elements) > 1:
                        correction += self.oxide_correction["oxide"] * comp["O"]
            else:
                correction += self.oxide_correction["oxide"] * comp["O"]

        return correction

    def __str__(self):
        return f"{self.name} Anion Correction"

@cached_class
class AqueousCorrection(Correction):
    """
    This class implements aqueous phase compound corrections for elements
    and H2O.

    Used only by MITAqueousCompatibility.
    """

    def __init__(self, config_file, error_file=None):
        """
        Args:
            config_file: Path to the selected compatibility.yaml config file.
            error_file: Path to the selected compatibilityErrors.yaml config file.
        """
        c = loadfn(config_file)
        self.cpd_energies = c["AqueousCompoundEnergies"]
        # there will either be a CompositionCorrections OR an OxideCorrections key,
        # but not both, depending on the compatibility scheme we are using.
        # MITCompatibility only uses OxideCorrections, and hence self.comp_correction is none.
        self.comp_correction = c.get("CompositionCorrections", defaultdict(float))
        self.oxide_correction = c.get("OxideCorrections", defaultdict(float))
        self.name = c["Name"]
        if error_file:
            e = loadfn(error_file)
            self.cpd_errors = e.get("AqueousCompoundEnergies", defaultdict(float))
        else:
            self.cpd_errors = defaultdict(float)

    def get_correction(self, entry) -> ufloat:
        """
        :param entry: A ComputedEntry/ComputedStructureEntry
        :return: Correction, Uncertainty.
        """
        from pymatgen.analysis.pourbaix_diagram import MU_H2O

        comp = entry.composition
        rform = comp.reduced_formula
        cpdenergies = self.cpd_energies

        # only correct GGA or GGA+U entries
        if entry.parameters.get("run_type", None) not in ["GGA", "GGA+U"]:
            return ufloat(0.0, 0.0)

        correction = ufloat(0.0, 0.0)

        if rform in cpdenergies:
            if rform in ["H2", "H2O"]:
                corr = cpdenergies[rform] * comp.num_atoms - entry.uncorrected_energy - entry.correction
                err = self.cpd_errors[rform] * comp.num_atoms

                correction += ufloat(corr, err)
            else:
                corr = cpdenergies[rform] * comp.num_atoms
                err = self.cpd_errors[rform] * comp.num_atoms

                correction += ufloat(corr, err)
        if not rform == "H2O":
            # if the composition contains water molecules (e.g. FeO.nH2O),
            # correct the gibbs free energy such that the waters are assigned energy=MU_H2O
            # in other words, we assume that the DFT energy of such a compound is really
            # a superposition of the "real" solid DFT energy (FeO in this case) and the free
            # energy of some water molecules
            # e.g. that E_FeO.nH2O = E_FeO + n * g_H2O
            # so, to get the most accurate gibbs free energy, we want to replace
            # g_FeO.nH2O = E_FeO.nH2O + dE_Fe + (n+1) * dE_O + 2n dE_H
            # with
            # g_FeO = E_FeO.nH2O + dE_Fe + dE_O + n g_H2O
            # where E is DFT energy, dE is an energy correction, and g is gibbs free energy
            # This means we have to 1) remove energy corrections associated with H and O in water
            # and then 2) remove the free energy of the water molecules

            nH2O = int(min(comp["H"] / 2.0, comp["O"]))  # only count whole water molecules
            if nH2O > 0:
                # first, remove any H or O corrections already applied to H2O in the
                # formation energy so that we don't double count them
                # No. of H atoms not in a water
                correction -= ufloat((comp["H"] - nH2O / 2) * self.comp_correction["H"], 0.0)
                # No. of O atoms not in a water
                correction -= ufloat(
                    (comp["O"] - nH2O) * (self.comp_correction["oxide"] + self.oxide_correction["oxide"]),
                    0.0,
                )
                # next, add MU_H2O for each water molecule present
                correction += ufloat(-1 * MU_H2O * nH2O, 0.0)
                # correction += 0.5 * 2.46 * nH2O  # this is the old way this correction was calculated

        return correction

    def __str__(self):
        return f"{self.name} Aqueous Correction"

@cached_class
class UCorrection(Correction):
    """
    This class implements the GGA/GGA+U mixing scheme, which allows mixing of
    entries. Entry.parameters must contain a "hubbards" key which is a dict
    of all non-zero Hubbard U values used in the calculation. For example,
    if you ran a Fe2O3 calculation with Materials Project parameters,
    this would look like entry.parameters["hubbards"] = {"Fe": 5.3}
    If the "hubbards" key is missing, a GGA run is assumed.

    It should be noted that ComputedEntries assimilated using the
    pymatgen.apps.borg package and obtained via the MaterialsProject REST
    interface using the pymatgen.matproj.rest package will automatically have
    these fields populated.
    """

    common_peroxides = [
        "Li2O2",
        "Na2O2",
        "K2O2",
        "Cs2O2",
        "Rb2O2",
        "BeO2",
        "MgO2",
        "CaO2",
        "SrO2",
        "BaO2",
    ]
    common_superoxides = ["LiO2", "NaO2", "KO2", "RbO2", "CsO2"]
    ozonides = ["LiO3", "NaO3", "KO3", "NaO5"]

    def __init__(self, config_file, input_set, compat_type, error_file=None):
        """
        Args:
            config_file: Path to the selected compatibility.yaml config file.
            input_set: InputSet object (to check for the +U settings)
            compat_type: Two options, GGA or Advanced.  GGA means all GGA+U
                entries are excluded.  Advanced means mixing scheme is
                implemented to make entries compatible with each other,
                but entries which are supposed to be done in GGA+U will have the
                equivalent GGA entries excluded. For example, Fe oxides should
                have a U value under the Advanced scheme. A GGA Fe oxide run
                will therefore be excluded under the scheme.
            error_file: Path to the selected compatibilityErrors.yaml config file.
        """
        if compat_type not in ["GGA", "Advanced"]:
            raise CompatibilityError(f"Invalid compat_type {compat_type}")

        c = loadfn(config_file)

        self.input_set = input_set
        if compat_type == "Advanced":
            self.u_settings = self.input_set.CONFIG["INCAR"]["LDAUU"]
            self.u_corrections = c["Advanced"]["UCorrections"]
        else:
            self.u_settings = {}
            self.u_corrections = {}

        self.name = c["Name"]
        self.compat_type = compat_type

        if error_file:
            e = loadfn(error_file)
            self.u_errors = e["Advanced"]["UCorrections"]
        else:
            self.u_errors = {}

    def get_correction(self, entry) -> ufloat:
        """
        :param entry: A ComputedEntry/ComputedStructureEntry
        :return: Correction, Uncertainty.
        """
        if entry.parameters.get("run_type") not in ["GGA", "GGA+U"]:
            raise CompatibilityError(
                f"Entry {entry.entry_id} has invalid run type {entry.parameters.get('run_type')}. Discarding."
            )

        calc_u = entry.parameters.get("hubbards", None)
        calc_u = defaultdict(int) if calc_u is None else calc_u
        comp = entry.composition

        elements = sorted((el for el in comp.elements if comp[el] > 0), key=lambda el: el.X)
        most_electroneg = elements[-1].symbol
        correction = ufloat(0.0, 0.0)

        # only correct GGA or GGA+U entries
        if entry.parameters.get("run_type", None) not in ["GGA", "GGA+U"]:
            return ufloat(0.0, 0.0)

        ucorr = self.u_corrections.get(most_electroneg, {})
        usettings = self.u_settings.get(most_electroneg, {})
        uerrors = self.u_errors.get(most_electroneg, defaultdict(float))

        for el in comp.elements:
            sym = el.symbol
            # Check for bad U values
            if calc_u.get(sym, 0) != usettings.get(sym, 0):
                raise CompatibilityError(f"Invalid U value of {calc_u.get(sym, 0)} on {sym}")
            if sym in ucorr:
                correction += ufloat(ucorr[sym], uerrors[sym]) * comp[el]

        return correction

    def __str__(self):
        return f"{self.name} {self.compat_type} Correction"

class Compatibility(MSONable, metaclass=abc.ABCMeta):
    """
    Abstract Compatibility class, not intended for direct use.
    Compatibility classes are used to correct the energies of an entry or a set
    of entries. All Compatibility classes must implement .get_adjustments method.
    """

    @abc.abstractmethod
    def get_adjustments(self, entry: AnyCompEntry) -> list[EnergyAdjustment]:
        """
        Get the energy adjustments for a ComputedEntry.

        This method must generate a list of EnergyAdjustment objects
        of the appropriate type (constant, composition-based, or temperature-based)
        to be applied to the ComputedEntry, and must raise a CompatibilityError
        if the entry is not compatible.

        Args:
            entry: A ComputedEntry object.

        Returns:
            [EnergyAdjustment]: A list of EnergyAdjustment to be applied to the
                Entry.

        Raises:
            CompatibilityError if the entry is not compatible
        """

    def process_entry(self, entry: ComputedEntry) -> ComputedEntry | None:
        """
        Process a single entry with the chosen Corrections. Note
        that this method will change the data of the original entry.

        Args:
            entry: A ComputedEntry object.
        Returns:
            An adjusted entry if entry is compatible, otherwise None is
            returned.
        """
        try:
            return self.process_entries(entry)[0]
        except IndexError:
            return None

    def process_entries(
        self, entries: AnyCompEntry | list[AnyCompEntry], clean: bool = True, verbose: bool = False
    ) -> list[ComputedEntry]:
        """
        Process a sequence of entries with the chosen Compatibility scheme. Note
        that this method will change the data of the original entries.

        Args:
            entries: ComputedEntry or [ComputedEntry]
            clean: bool, whether to remove any previously-applied energy adjustments.
                If True, all EnergyAdjustment are removed prior to processing the Entry.
                Default is True.
            verbose: bool, whether to display progress bar for processing multiple entries.
                Default is False.

        Returns:
            A list of adjusted entries.  Entries in the original list which
            are not compatible are excluded.
        """
        # convert input arg to a list if not already
        if isinstance(entries, ComputedEntry):
            entries = [entries]

        processed_entry_list = []

        for entry in tqdm(entries, disable=(not verbose)):
            ignore_entry = False
            # if clean is True, remove all previous adjustments from the entry
            if clean:
                entry.energy_adjustments = []

            # get the energy adjustments
            try:
                adjustments = self.get_adjustments(entry)
            except CompatibilityError:
                ignore_entry = True
                continue

            for ea in adjustments:
                # Has this correction already been applied?
                if (ea.name, ea.cls, ea.value) in [(ea.name, ea.cls, ea.value) for ea in entry.energy_adjustments]:
                    # we already applied this exact correction. Do nothing.
                    pass
                elif (ea.name, ea.cls) in [(ea.name, ea.cls) for ea in entry.energy_adjustments]:
                    # we already applied a correction with the same name
                    # but a different value. Something is wrong.
                    ignore_entry = True
                    warnings.warn(
                        "Entry {} already has an energy adjustment called {}, but its "
                        "value differs from the value of {:.3f} calculated here. This "
                        "Entry will be discarded.".format(entry.entry_id, ea.name, ea.value)
                    )
                else:
                    # Add the correction to the energy_adjustments list
                    entry.energy_adjustments.append(ea)

            if not ignore_entry:
                processed_entry_list.append(entry)

        return processed_entry_list

    @staticmethod
    def explain(entry):
        """
        Prints an explanation of the energy adjustments applied by the
        Compatibility class. Inspired by the "explain" methods in many database
        methodologies.

        Args:
            entry: A ComputedEntry.
        """
        print(
            "The uncorrected energy of {} is {:.3f} eV ({:.3f} eV/atom).".format(
                entry.composition,
                entry.uncorrected_energy,
                entry.uncorrected_energy / entry.composition.num_atoms,
            )
        )

        if len(entry.energy_adjustments) > 0:
            print("The following energy adjustments have been applied to this entry:")
            for e in entry.energy_adjustments:
                print(f"\t\t{e.name}: {e.value:.3f} eV ({e.value / entry.composition.num_atoms:.3f} eV/atom)")
        elif entry.correction == 0:
            print("No energy adjustments have been applied to this entry.")

        print(
            "The final energy after adjustments is {:.3f} eV ({:.3f} eV/atom).".format(
                entry.energy, entry.energy_per_atom
            )
        )

class CorrectionsList(Compatibility):
    """
    The CorrectionsList class combines a list of corrections to be applied to
    an entry or a set of entries. Note that some of the Corrections have
    interdependencies. For example, PotcarCorrection must always be used
    before any other compatibility. Also, AnionCorrection("MP") must be used
    with PotcarCorrection("MP") (similarly with "MIT"). Typically,
    you should use the specific MaterialsProjectCompatibility and
    MITCompatibility subclasses instead.
    """

    def __init__(self, corrections: Sequence):
        """
        Args:
            corrections: List of corrections to apply.
        """
        self.corrections = corrections
        super().__init__()

    def get_adjustments(self, entry):
        """
        Get the list of energy adjustments to be applied to an entry.
        """
        adjustment_list = []
        corrections, uncertainties = self.get_corrections_dict(entry)

        for k, v in corrections.items():
            if v != 0 and uncertainties[k] == 0:
                uncertainty = np.nan
            else:
                uncertainty = uncertainties[k]
            adjustment_list.append(
                ConstantEnergyAdjustment(
                    v,
                    uncertainty=uncertainty,
                    name=k,
                    cls=self.as_dict(),
                )
            )

        return adjustment_list

    def get_corrections_dict(self, entry):
        """
        Returns the corrections applied to a particular entry.

        Args:
            entry: A ComputedEntry object.

        Returns:
            ({correction_name: value})
        """
        corrections = {}
        uncertainties = {}
        for c in self.corrections:
            val = c.get_correction(entry)
            if val != 0:
                corrections[str(c)] = val.nominal_value
                uncertainties[str(c)] = val.std_dev
        return corrections, uncertainties

    def get_explanation_dict(self, entry):
        """
        Provides an explanation dict of the corrections that are being applied
        for a given compatibility scheme. Inspired by the "explain" methods
        in many database methodologies.

        Args:
            entry: A ComputedEntry.

        Returns:
            (dict) of the form
            {"Compatibility": "string",
            "Uncorrected_energy": float,
            "Corrected_energy": float,
            "correction_uncertainty:" float,
            "Corrections": [{"Name of Correction": {
            "Value": float, "Explanation": "string", "Uncertainty": float}]}
        """
        centry = self.process_entry(entry)
        if centry is None:
            uncorrected_energy = entry.uncorrected_energy
            corrected_energy = None
            correction_uncertainty = None
        else:
            uncorrected_energy = centry.uncorrected_energy
            corrected_energy = centry.energy
            correction_uncertainty = centry.correction_uncertainty
        d = {
            "compatibility": self.__class__.__name__,
            "uncorrected_energy": uncorrected_energy,
            "corrected_energy": corrected_energy,
            "correction_uncertainty": correction_uncertainty,
        }
        corrections = []
        corr_dict, uncer_dict = self.get_corrections_dict(entry)
        for c in self.corrections:
            if corr_dict.get(str(c), 0) != 0 and uncer_dict.get(str(c), 0) == 0:
                uncer = np.nan
            else:
                uncer = uncer_dict.get(str(c), 0)
            cd = {
                "name": str(c),
                "description": c.__doc__.split("Args")[0].strip(),
                "value": corr_dict.get(str(c), 0),
                "uncertainty": uncer,
            }
            corrections.append(cd)
        d["corrections"] = corrections
        return d

    def explain(self, entry):
        """
        Prints an explanation of the corrections that are being applied for a
        given compatibility scheme. Inspired by the "explain" methods in many
        database methodologies.

        Args:
            entry: A ComputedEntry.
        """
        d = self.get_explanation_dict(entry)
        print(f"The uncorrected value of the energy of {entry.composition} is {d['uncorrected_energy']:f} eV")
        print(f"The following corrections / screening are applied for {d['compatibility']}:\n")
        for c in d["corrections"]:
            print(f"{c['name']} correction: {c['description']}\n")
            print(f"For the entry, this correction has the value {c['value']:f} eV.")
            if c["uncertainty"] != 0 or c["value"] == 0:
                print(f"This correction has an uncertainty value of {c['uncertainty']:f} eV.")
            else:
                print("This correction does not have uncertainty data available")
            print("-" * 30)

        print(f"The final energy after corrections is {d['corrected_energy']:f}")

class MaterialsProjectCompatibility(CorrectionsList):
    """
    This class implements the GGA/GGA+U mixing scheme, which allows mixing of
    entries. Note that this should only be used for VASP calculations using the
    MaterialsProject parameters (see pymatgen.io.vaspio_set.MPVaspInputSet).
    Using this compatibility scheme on runs with different parameters is not
    valid.
    """

    def __init__(self, compat_type="Advanced", correct_peroxide=True, check_potcar_hash=False):
        """
        Args:
            compat_type: Two options, GGA or Advanced.  GGA means all GGA+U
                entries are excluded.  Advanced means mixing scheme is
                implemented to make entries compatible with each other,
                but entries which are supposed to be done in GGA+U will have the
                equivalent GGA entries excluded. For example, Fe oxides should
                have a U value under the Advanced scheme. A GGA Fe oxide run
                will therefore be excluded under the scheme.
            correct_peroxide: Specify whether peroxide/superoxide/ozonide
                corrections are to be applied or not.
            check_potcar_hash (bool): Use potcar hash to verify potcars are correct.
        """
        self.compat_type = compat_type
        self.correct_peroxide = correct_peroxide
        self.check_potcar_hash = check_potcar_hash
        fp = os.path.join(MODULE_DIR, "MPCompatibility.yaml")
        super().__init__(
            [
                PotcarCorrection(MPRelaxSet, check_hash=check_potcar_hash),
                GasCorrection(fp),
                AnionCorrection(fp, correct_peroxide=correct_peroxide),
                UCorrection(fp, MPRelaxSet, compat_type),
            ]
        )

@cached_class
class MaterialsProject2020Compatibility(Compatibility):
    """
    This class implements the Materials Project 2020 energy correction scheme,
    which incorporates uncertainty quantification and allows for mixing of GGA
    and GGA+U entries (see References).

    Note that this scheme should only be applied to VASP calculations that use the
    Materials Project input set parameters (see pymatgen.io.vasp.sets.MPRelaxSet).
    Using this compatibility scheme on calculations with different parameters is not
    valid.
    """

    def __init__(
        self,
        compat_type="Advanced",
        correct_peroxide=True,
        check_potcar_hash=False,
        config_file=None,
    ):
        """
        Args:
            compat_type: Two options, GGA or Advanced.  GGA means all GGA+U
                entries are excluded. Advanced means the GGA/GGA+U mixing scheme
                of Jain et al. (see References) is implemented. In this case,
                entries which are supposed to be calculated in GGA+U (i.e.,
                transition metal oxides and fluorides) will have the corresponding
                GGA entries excluded. For example, Fe oxides should
                have a U value under the Advanced scheme. An Fe oxide run in GGA
                will therefore be excluded.

                To use the "Advanced" type, Entry.parameters must contain a "hubbards"
                key which is a dict of all non-zero Hubbard U values used in the
                calculation. For example, if you ran a Fe2O3 calculation with
                Materials Project parameters, this would look like
                entry.parameters["hubbards"] = {"Fe": 5.3}. If the "hubbards" key
                is missing, a GGA run is assumed. Entries obtained from the
                MaterialsProject database will automatically have these fields
                populated.

                (Default: "Advanced")
            correct_peroxide: Specify whether peroxide/superoxide/ozonide
                corrections are to be applied or not. If false, all oxygen-containing
                compounds are assigned the 'oxide' correction. (Default: True)
            check_potcar_hash (bool): Use potcar hash to verify POTCAR settings are
                consistent with MPRelaxSet. If False, only the POTCAR symbols will
                be used. (Default: False)
            config_file (Path): Path to the selected compatibility.yaml config file.
                If None, defaults to `MP2020Compatibility.yaml` distributed with
                pymatgen.

        References:
            Wang, A., Kingsbury, R., McDermott, M., Horton, M., Jain. A., Ong, S.P.,
                Dwaraknath, S., Persson, K. A framework for quantifying uncertainty
                in DFT energy corrections. Scientific Reports 11: 15496, 2021.
                https://doi.org/10.1038/s41598-021-94550-5

            Jain, A. et al. Formation enthalpies by mixing GGA and GGA + U calculations.
                Phys. Rev. B - Condens. Matter Mater. Phys. 84, 1–10 (2011).
        """
        if compat_type not in ["GGA", "Advanced"]:
            raise CompatibilityError(f"Invalid compat_type {compat_type}")

        self.compat_type = compat_type
        self.correct_peroxide = correct_peroxide
        self.check_potcar_hash = check_potcar_hash

        # load corrections and uncertainties
        if config_file:
            if os.path.isfile(config_file):
                self.config_file = config_file
                c = loadfn(self.config_file)
            else:
                raise ValueError(
                    f"Custom MaterialsProject2020Compatibility config_file ({config_file}) does not exist."
                )
        else:
            self.config_file = None
            c = loadfn(os.path.join(MODULE_DIR, "MP2020Compatibility.yaml"))

        self.name = c["Name"]
        self.comp_correction = c["Corrections"].get("CompositionCorrections", defaultdict(float))
        self.comp_errors = c["Uncertainties"].get("CompositionCorrections", defaultdict(float))

        if self.compat_type == "Advanced":
            self.u_settings = MPRelaxSet.CONFIG["INCAR"]["LDAUU"]
            self.u_corrections = c["Corrections"].get("GGAUMixingCorrections", defaultdict(float))
            self.u_errors = c["Uncertainties"].get("GGAUMixingCorrections", defaultdict(float))
        else:
            self.u_settings = {}
            self.u_corrections = {}
            self.u_errors = {}

    def get_adjustments(self, entry: AnyCompEntry):
        """
        Get the energy adjustments for a ComputedEntry or ComputedStructureEntry.

        Energy corrections are implemented directly in this method instead of in
        separate AnionCorrection, GasCorrection, or UCorrection classes which
        were used in the legacy correction scheme.

        Args:
            entry: A ComputedEntry or ComputedStructureEntry object.

        Returns:
            [EnergyAdjustment]: A list of EnergyAdjustment to be applied to the
                Entry.

        Raises:
            CompatibilityError if the entry is not compatible
        """
        if entry.parameters.get("run_type") not in ["GGA", "GGA+U"]:
            raise CompatibilityError(
                "Entry {} has invalid run type {}. Must be GGA or GGA+U. Discarding.".format(
                    entry.entry_id, entry.parameters.get("run_type")
                )
            )

        # check the POTCAR symbols
        # this should return ufloat(0, 0) or raise a CompatibilityError or ValueError
        pc = PotcarCorrection(MPRelaxSet, check_hash=self.check_potcar_hash)
        pc.get_correction(entry)

        # apply energy adjustments
        adjustments: list[CompositionEnergyAdjustment] = []

        comp = entry.composition
        rform = comp.reduced_formula
        # sorted list of elements, ordered by electronegativity
        elements = sorted((el for el in comp.elements if comp[el] > 0), key=lambda el: el.X)

        # Skip single elements
        if len(comp) == 1:
            return adjustments

        # Check for sulfide corrections
        if Element("S") in comp:
            sf_type = "sulfide"
            if entry.data.get("sulfide_type"):
                sf_type = entry.data["sulfide_type"]
            elif hasattr(entry, "structure"):
                sf_type = sulfide_type(entry.structure)

            # use the same correction for polysulfides and sulfides
            if sf_type == "polysulfide":
                sf_type = "sulfide"

            if sf_type == "sulfide":
                adjustments.append(
                    CompositionEnergyAdjustment(
                        self.comp_correction["S"],
                        comp["S"],
                        uncertainty_per_atom=self.comp_errors["S"],
                        name="MP2020 anion correction (S)",
                        cls=self.as_dict(),
                    )
                )

        # Check for oxide, peroxide, superoxide, and ozonide corrections.
        if Element("O") in comp:
            if self.correct_peroxide:
                # determine the oxide_type
                if entry.data.get("oxide_type"):
                    ox_type = entry.data["oxide_type"]
                elif hasattr(entry, "structure"):
                    ox_type, nbonds = oxide_type(entry.structure, 1.05, return_nbonds=True)
                else:
                    warnings.warn(
                        "No structure or oxide_type parameter present. Note "
                        "that peroxide/superoxide corrections are not as "
                        "reliable and relies only on detection of special"
                        "formulas, e.g., Li2O2."
                    )

                    common_peroxides = [
                        "Li2O2",
                        "Na2O2",
                        "K2O2",
                        "Cs2O2",
                        "Rb2O2",
                        "BeO2",
                        "MgO2",
                        "CaO2",
                        "SrO2",
                        "BaO2",
                    ]
                    common_superoxides = ["LiO2", "NaO2", "KO2", "RbO2", "CsO2"]
                    ozonides = ["LiO3", "NaO3", "KO3", "NaO5"]

                    if rform in common_peroxides:
                        ox_type = "peroxide"
                    elif rform in common_superoxides:
                        ox_type = "superoxide"
                    elif rform in ozonides:
                        ox_type = "ozonide"
                    else:
                        ox_type = "oxide"
            else:
                ox_type = "oxide"

            if ox_type == "hydroxide":
                ox_type = "oxide"

            adjustments.append(
                CompositionEnergyAdjustment(
                    self.comp_correction[ox_type],
                    comp["O"],
                    uncertainty_per_atom=self.comp_errors[ox_type],
                    name=f"MP2020 anion correction ({ox_type})",
                    cls=self.as_dict(),
                )
            )

        # Check for anion corrections
        # only apply anion corrections if the element is an anion
        # first check for a pre-populated oxidation states key
        # the key is expected to comprise a dict corresponding to the first element output by
        # Composition.oxi_state_guesses(), e.g. {'Al': 3.0, 'S': 2.0, 'O': -2.0} for 'Al2SO4'
        if "oxidation_states" not in entry.data.keys():
            # try to guess the oxidation states from composition
            # for performance reasons, fail if the composition is too large
            try:
                oxi_states = entry.composition.oxi_state_guesses(max_sites=-20)
            except ValueError:
                oxi_states = []

            if oxi_states == []:
                entry.data["oxidation_states"] = {}
            else:
                entry.data["oxidation_states"] = oxi_states[0]

        if entry.data["oxidation_states"] == {}:
            warnings.warn(
                f"Failed to guess oxidation states for Entry {entry.entry_id} "
                f"({entry.composition.reduced_formula}). Assigning anion correction to "
                "only the most electronegative atom."
            )

        for anion in ["Br", "I", "Se", "Si", "Sb", "Te", "H", "N", "F", "Cl"]:
            if Element(anion) in comp and anion in self.comp_correction:
                apply_correction = False
                # if the oxidation_states key is not populated, only apply the correction if the anion
                # is the most electronegative element
                if entry.data["oxidation_states"].get(anion, 0) < 0:
                    apply_correction = True
                else:
                    most_electroneg = elements[-1].symbol
                    if anion == most_electroneg:
                        apply_correction = True

                if apply_correction:
                    adjustments.append(
                        CompositionEnergyAdjustment(
                            self.comp_correction[anion],
                            comp[anion],
                            uncertainty_per_atom=self.comp_errors[anion],
                            name=f"MP2020 anion correction ({anion})",
                            cls=self.as_dict(),
                        )
                    )

        # GGA / GGA+U mixing scheme corrections
        calc_u = entry.parameters.get("hubbards", None)
        calc_u = defaultdict(int) if calc_u is None else calc_u
        most_electroneg = elements[-1].symbol
        ucorr = self.u_corrections.get(most_electroneg, defaultdict(float))
        usettings = self.u_settings.get(most_electroneg, defaultdict(float))
        uerrors = self.u_errors.get(most_electroneg, defaultdict(float))

        for el in comp.elements:
            sym = el.symbol
            # Check for bad U values
            if calc_u.get(sym, 0) != usettings.get(sym, 0):
                raise CompatibilityError(f"Invalid U value of {calc_u.get(sym, 0):.1f} on {sym}")
            if sym in ucorr:
                adjustments.append(
                    CompositionEnergyAdjustment(
                        ucorr[sym],
                        comp[el],
                        uncertainty_per_atom=uerrors[sym],
                        name=f"MP2020 GGA/GGA+U mixing correction ({sym})",
                        cls=self.as_dict(),
                    )
                )

        return adjustments

class MITCompatibility(CorrectionsList):
    """
    This class implements the GGA/GGA+U mixing scheme, which allows mixing of
    entries. Note that this should only be used for VASP calculations using the
    MIT parameters (see pymatgen.io.vaspio_set MITVaspInputSet). Using
    this compatibility scheme on runs with different parameters is not valid.
    """

    def __init__(self, compat_type="Advanced", correct_peroxide=True, check_potcar_hash=False):
        """
        Args:
            compat_type: Two options, GGA or Advanced.  GGA means all GGA+U
                entries are excluded.  Advanced means mixing scheme is
                implemented to make entries compatible with each other,
                but entries which are supposed to be done in GGA+U will have the
                equivalent GGA entries excluded. For example, Fe oxides should
                have a U value under the Advanced scheme. A GGA Fe oxide run
                will therefore be excluded under the scheme.
            correct_peroxide: Specify whether peroxide/superoxide/ozonide
                corrections are to be applied or not.
            check_potcar_hash (bool): Use potcar hash to verify potcars are correct.
        """
        self.compat_type = compat_type
        self.correct_peroxide = correct_peroxide
        self.check_potcar_hash = check_potcar_hash
        fp = os.path.join(MODULE_DIR, "MITCompatibility.yaml")
        super().__init__(
            [
                PotcarCorrection(MITRelaxSet, check_hash=check_potcar_hash),
                GasCorrection(fp),
                AnionCorrection(fp, correct_peroxide=correct_peroxide),
                UCorrection(fp, MITRelaxSet, compat_type),
            ]
        )

class MITAqueousCompatibility(CorrectionsList):
    """
    This class implements the GGA/GGA+U mixing scheme, which allows mixing of
    entries. Note that this should only be used for VASP calculations using the
    MIT parameters (see pymatgen.io.vaspio_set MITVaspInputSet). Using
    this compatibility scheme on runs with different parameters is not valid.
    """

    def __init__(self, compat_type="Advanced", correct_peroxide=True, check_potcar_hash=False):
        """
        Args:
            compat_type: Two options, GGA or Advanced.  GGA means all GGA+U
                entries are excluded.  Advanced means mixing scheme is
                implemented to make entries compatible with each other,
                but entries which are supposed to be done in GGA+U will have the
                equivalent GGA entries excluded. For example, Fe oxides should
                have a U value under the Advanced scheme. A GGA Fe oxide run
                will therefore be excluded under the scheme.
            correct_peroxide: Specify whether peroxide/superoxide/ozonide
                corrections are to be applied or not.
            check_potcar_hash (bool): Use potcar hash to verify potcars are correct.
        """
        self.compat_type = compat_type
        self.correct_peroxide = correct_peroxide
        self.check_potcar_hash = check_potcar_hash
        fp = os.path.join(MODULE_DIR, "MITCompatibility.yaml")
        super().__init__(
            [
                PotcarCorrection(MITRelaxSet, check_hash=check_potcar_hash),
                GasCorrection(fp),
                AnionCorrection(fp, correct_peroxide=correct_peroxide),
                UCorrection(fp, MITRelaxSet, compat_type),
                AqueousCorrection(fp),
            ]
        )

@cached_class
class MaterialsProjectAqueousCompatibility(Compatibility):
    """
    This class implements the Aqueous energy referencing scheme for constructing
    Pourbaix diagrams from DFT energies, as described in Persson et al.

    This scheme applies various energy adjustments to convert DFT energies into
    Gibbs free energies of formation at 298 K and to guarantee that the experimental
    formation free energy of H2O is reproduced. Briefly, the steps are:

        1. Beginning with the DFT energy of O2, adjust the energy of H2 so that
           the experimental reaction energy of -2.458 eV/H2O is reproduced.
        2. Add entropy to the DFT energy of any compounds that are liquid or
           gaseous at room temperature
        3. Adjust the DFT energies of solid hydrate compounds (compounds that
           contain water, e.g. FeO.nH2O) such that the energies of the embedded
           H2O molecules are equal to the experimental free energy

    The above energy adjustments are computed dynamically based on the input
    Entries.

    References:
        K.A. Persson, B. Waldwick, P. Lazic, G. Ceder, Prediction of solid-aqueous
        equilibria: Scheme to combine first-principles calculations of solids with
        experimental aqueous states, Phys. Rev. B - Condens. Matter Mater. Phys.
        85 (2012) 1–12. doi:10.1103/PhysRevB.85.235438.
    """

    def __init__(
        self,
        solid_compat: Compatibility | type[Compatibility] | None = MaterialsProject2020Compatibility,
        o2_energy: float | None = None,
        h2o_energy: float | None = None,
        h2o_adjustments: float | None = None,
    ):
        """
        Initialize the MaterialsProjectAqueousCompatibility class.

        Note that this class requires as inputs the ground-state DFT energies of O2 and H2O, plus the value of any
        energy adjustments applied to an H2O molecule. If these parameters are not provided in __init__, they can
        be automatically populated by including ComputedEntry for the ground state of O2 and H2O in a list of
        entries passed to process_entries. process_entries will fail if one or the other is not provided.

        Args:
            solid_compat: Compatibility scheme used to pre-process solid DFT energies prior to applying aqueous
                energy adjustments. May be passed as a class (e.g. MaterialsProject2020Compatibility) or an instance
                (e.g., MaterialsProject2020Compatibility()). If None, solid DFT energies are used as-is.
                Default: MaterialsProject2020Compatibility
            o2_energy: The ground-state DFT energy of oxygen gas, including any adjustments or corrections, in eV/atom.
                If not set, this value will be determined from any O2 entries passed to process_entries.
                Default: None
            h2o_energy: The ground-state DFT energy of water, including any adjstments or corrections, in eV/atom.
                If not set, this value will be determined from any H2O entries passed to process_entries.
                Default: None
            h2o_adjustments: Total energy adjustments applied to one water molecule, in eV/atom.
                If not set, this value will be determined from any H2O entries passed to process_entries.
                Default: None
        """
        self.solid_compat = None
        # check whether solid_compat has been instantiated
        if solid_compat is None:
            self.solid_compat = None
        elif isinstance(solid_compat, type) and issubclass(solid_compat, Compatibility):
            self.solid_compat = solid_compat()
        elif issubclass(type(solid_compat), Compatibility):
            self.solid_compat = solid_compat
        else:
            raise ValueError("Expected a Compatibility class, instance of a Compatibility or None")

        self.o2_energy = o2_energy
        self.h2o_energy = h2o_energy
        self.h2_energy = None
        self.h2o_adjustments = h2o_adjustments

        if not all([self.o2_energy, self.h2o_energy, self.h2o_adjustments]):
            warnings.warn(
                "You did not provide the required O2 and H2O energies. {} "
                "needs these energies in order to compute the appropriate energy adjustments. It will try "
                "to determine the values from ComputedEntry for O2 and H2O passed to process_entries, but "
                "will fail if these entries are not provided.".format(type(self).__name__)
            )

        # Standard state entropy of molecular-like compounds at 298K (-T delta S)
        # from Kubaschewski Tables (eV/atom)
        self.cpd_entropies = {
            "O2": 0.316731,
            "N2": 0.295729,
            "F2": 0.313025,
            "Cl2": 0.344373,
            "Br": 0.235039,
            "Hg": 0.234421,
            "H2O": 0.071963,  # 0.215891 eV/H2O
        }
        self.name = "MP Aqueous free energy adjustment"
        super().__init__()

    def get_adjustments(self, entry):
        """
        Returns the corrections applied to a particular entry.

        Args:
            entry: A ComputedEntry object.

        Returns:
            [EnergyAdjustment]: Energy adjustments to be applied to entry.

        Raises:
            CompatibilityError if the required O2 and H2O energies have not been provided to
            MaterialsProjectAqueousCompatibility during init or in the list of entries passed to process_entries.
        """
        adjustments = []
        if self.o2_energy is None or self.h2o_energy is None or self.h2o_adjustments is None:
            raise CompatibilityError(
                "You did not provide the required O2 and H2O energies. "
                "{} needs these energies in order to compute "
                "the appropriate energy adjustments. Either specify the energies as arguments "
                "to {}.__init__ or run process_entries on a list that includes ComputedEntry for "
                "the ground state of O2 and H2O.".format(type(self).__name__, type(self).__name__)
            )

        # compute the free energies of H2 and H2O (eV/atom) to guarantee that the
        # formationfree energy of H2O is equal to -2.4583 eV/H2O from experiments
        # (MU_H2O from Pourbaix module)

        # Free energy of H2 in eV/atom, fitted using Eq. 40 of Persson et al. PRB 2012 85(23)
        # for this calculation ONLY, we need the (corrected) DFT energy of water
        self.fit_h2_energy = round(
            0.5
            * (
                3 * (self.h2o_energy - self.cpd_entropies["H2O"]) - (self.o2_energy - self.cpd_entropies["O2"]) - MU_H2O
            ),
            6,
        )

        comp = entry.composition
        rform = comp.reduced_formula

        # use fit_h2_energy to adjust the energy of all H2 polymorphs such that
        # the lowest energy polymorph has the correct experimental value
        # if h2o and o2 energies have been set explicitly via kwargs, then
        # all H2 polymorphs will get the same energy.
        if rform == "H2":
            adjustments.append(
                ConstantEnergyAdjustment(
                    (self.fit_h2_energy - self.h2_energy) * comp.num_atoms,
                    uncertainty=np.nan,
                    name="MP Aqueous H2 / H2O referencing",
                    cls=self.as_dict(),
                    description="Adjusts the H2 energy to reproduce the experimental "
                    "Gibbs formation free energy of H2O, based on the DFT energy "
                    "of Oxygen and H2O",
                )
            )

        # add minus T delta S to the DFT energy (enthalpy) of compounds that are
        # molecular-like at room temperature
        if rform in self.cpd_entropies:
            adjustments.append(
                TemperatureEnergyAdjustment(
                    -1 * self.cpd_entropies[rform] / 298,
                    298,
                    comp.num_atoms,
                    uncertainty_per_deg=np.nan,
                    name="Compound entropy at room temperature",
                    cls=self.as_dict(),
                    description="Adds the entropy (T delta S) to energies of compounds that "
                    "are gaseous or liquid at standard state",
                )
            )

        # TODO - detection of embedded water molecules is not very sophisticated
        # Should be replaced with some kind of actual structure detection

        # For any compound except water, check to see if it is a hydrate (contains)
        # H2O in its structure. If so, adjust the energy to remove MU_H2O ev per
        # embedded water molecule.
        # in other words, we assume that the DFT energy of such a compound is really
        # a superposition of the "real" solid DFT energy (FeO in this case) and the free
        # energy of some water molecules
        # e.g. that E_FeO.nH2O = E_FeO + n * g_H2O
        # so, to get the most accurate gibbs free energy, we want to replace
        # g_FeO.nH2O = E_FeO.nH2O + dE_Fe + (n+1) * dE_O + 2n dE_H
        # with
        # g_FeO = E_FeO.nH2O + dE_Fe + dE_O + n g_H2O
        # where E is DFT energy, dE is an energy correction, and g is gibbs free energy
        # This means we have to 1) remove energy corrections associated with H and O in water
        # and then 2) remove the free energy of the water molecules
        if not rform == "H2O":
            # count the number of whole water molecules in the composition
            nH2O = int(min(comp["H"] / 2.0, comp["O"]))
            if nH2O > 0:
                # first, remove any H or O corrections already applied to H2O in the
                # formation energy so that we don't double count them
                # next, remove MU_H2O for each water molecule present
                hydrate_adjustment = -1 * (self.h2o_adjustments * 3 + MU_H2O)

                adjustments.append(
                    CompositionEnergyAdjustment(
                        hydrate_adjustment,
                        nH2O,
                        uncertainty_per_atom=np.nan,
                        name="MP Aqueous hydrate",
                        cls=self.as_dict(),
                        description="Adjust the energy of solid hydrate compounds (compounds "
                        "containing H2O molecules in their structure) so that the "
                        "free energies of embedded H2O molecules match the experimental"
                        " value enforced by the MP Aqueous energy referencing scheme.",
                    )
                )

        return adjustments

    def process_entries(self, entries: ComputedEntry | list[ComputedEntry], clean: bool = False, verbose: bool = False):
        """
        Process a sequence of entries with the chosen Compatibility scheme.

        Args:
            entries: ComputedEntry or [ComputedEntry]
            clean: bool, whether to remove any previously-applied energy adjustments.
                If True, all EnergyAdjustment are removed prior to processing the Entry.
                Default is False.
            verbose: bool, whether to display progress bar for processing multiple entries.
                Default is False.

        Returns:
            A list of adjusted entries.  Entries in the original list which
            are not compatible are excluded.
        """
        # convert input arg to a list if not already
        if isinstance(entries, ComputedEntry):
            entries = [entries]

        # pre-process entries with the given solid compatibility class
        if self.solid_compat:
            entries = self.solid_compat.process_entries(entries, clean=True)

        # when processing single entries, all H2 polymorphs will get assigned the
        # same energy
        if len(entries) == 1 and entries[0].composition.reduced_formula == "H2":
            warnings.warn(
                "Processing single H2 entries will result in the all polymorphs "
                "being assigned the same energy. This should not cause problems "
                "with Pourbaix diagram construction, but may be confusing. "
                "Pass all entries to process_entries() at once in if you want to "
                "preserve H2 polymorph energy differences."
            )

        # extract the DFT energies of oxygen and water from the list of entries, if present
        # do not do this when processing a single entry, as it might lead to unintended
        # results
        if len(entries) > 1:
            if not self.o2_energy:
                o2_entries = [e for e in entries if e.composition.reduced_formula == "O2"]
                if o2_entries:
                    self.o2_energy = min(e.energy_per_atom for e in o2_entries)

            if not self.h2o_energy and not self.h2o_adjustments:
                h2o_entries = [e for e in entries if e.composition.reduced_formula == "H2O"]
                if h2o_entries:
                    h2o_entries = sorted(h2o_entries, key=lambda e: e.energy_per_atom)
                    self.h2o_energy = h2o_entries[0].energy_per_atom
                    self.h2o_adjustments = h2o_entries[0].correction / h2o_entries[0].composition.num_atoms

        h2_entries = [e for e in entries if e.composition.reduced_formula == "H2"]
        if h2_entries:
            h2_entries = sorted(h2_entries, key=lambda e: e.energy_per_atom)
            self.h2_energy = h2_entries[0].energy_per_atom  # type: ignore

        return super().process_entries(entries, clean=clean, verbose=verbose)


text:
import os
import shutil
import ctypes
from glob import iglob
from data.filegroups import typeGroups, typeList
from data.settings import SORTER_IGNORE_FILENAME, SORTER_FOLDER_IDENTITY_FILENAME
from pathlib import Path

def has_signore_file(path, filename=SORTER_IGNORE_FILENAME):
    """Return True is a SORTER_IGNORE_FILENAME file is found in path."""
    try:
        open(os.path.join(path, filename), 'r').close()
    except FileNotFoundError:
        return False
    else:
        return True

def write_identity_file(path, ignore_file=False):
    """Create a SORTER_FOLDER_IDENTITY_FILENAME file in path."""
    files = []
    identity_file = os.path.join(path, SORTER_FOLDER_IDENTITY_FILENAME)
    try:
        open(identity_file, 'x').close()
    except FileExistsError:
        pass
    files.append(identity_file)
    if ignore_file:
        ignore_file_path = os.path.join(path, SORTER_IGNORE_FILENAME)
        try:
            open(ignore_file_path, 'x').close()
        except FileExistsError:
            pass
        files.append(ignore_file_path)
    if os.name == 'nt':
        # Hide file - Windows
        for file_ in files:
            ctypes.windll.kernel32.SetFileAttributesW(file_, 2)

class RelativePathError(ValueError):
    """Raise when the given value is a relative path."""

class EmptyNameError(ValueError):
    """Raise when the given value is empty."""

class Directory(object):
    """A path object that can be a file or folder.

    data attributes:
        Path - a pathlib.Path instance of this path
        path - the absolute path to this Directory instance
        parent - the parent folder in which this Directory instance
            is contained
        name - the name of this instance including the suffix
        hidden_path - True is any of the parents, or this instance,
            is hidden
        suffix - the last part of the name, which defines the file
            type
        stem - the name without the suffix

    methods:
        in_hidden_path
    """

    def __init__(self, path):
        if not os.path.isabs(path):
            raise RelativePathError('relative paths cannot be used')
        self.Path = Path(os.path.abspath(path))
        self._path = self.Path.absolute().__str__()
        self._parent = self.Path.parent.absolute().__str__()
        self._name = self.Path.name
        self._hidden_path = self.in_hidden_path(self._path)
        self._suffix = self.Path.suffix
        self._stem = self.Path.stem

    def __str__(self):
        return self.path

    @property
    def path(self):
        return self._get_path()

    @path.setter
    def path(self, value):
        self._set_path(value)

    @property
    def parent(self):
        return self._parent

    @property
    def name(self):
        return self._name

    @property
    def hidden_path(self):
        return self._hidden_path

    @property
    def suffix(self):
        return self._suffix

    @property
    def stem(self):
        return self._stem

    def _get_path(self):
        return self._path

    def _set_path(self, value):
        self.__init__(value)

    def in_hidden_path(self, full_path):
        """Return True if any parent folder, or this instance, is hidden,
        False otherwise.
        """
        paths = full_path.split(os.sep)

        if os.name == 'nt':
            get_hidden_attribute = ctypes.windll.kernel32.GetFileAttributesW
            for i in range(len(paths) + 1):
                path = os.sep.join(paths[:i])
                try:
                    attrs = get_hidden_attribute(path)
                    result = bool(attrs & 2)
                except AttributeError:
                    result = False
                if result:
                    return True
        else:
            for i in range(len(paths) + 1):
                path = str(os.sep).join(paths[:i])
                base_name = os.path.basename(path)
                if base_name.startswith('.') or base_name.startswith('__'):
                    return True

        return False

class File(Directory):
    """An instance of a file.

    Inherits from Directory.

    class attributes:
        default_category=UNDEFINED - the default name for files whose
            categories are not defined in the filegroups module

    data attributes:
        extension - the suffix without the dot(.)
        category - the category to which this File instance belongs
            to as defined in the filegroups module
        exists - True if self.path points to an existent file in
            the system

    methods:
        touch
        get_category
        find_suitable_name
        move_to
    """

    default_category = 'UNDEFINED'

    def __init__(self, path):
        super(File, self).__init__(path)
        extension = self.Path.suffix[1:]
        self._extension = extension or self.default_category
        self._category = self.get_category(extension)
        self._exists = self.Path.is_file

    @property
    def extension(self):
        return self._extension

    @property
    def category(self):
        return self._category

    @property
    def exists(self):
        return self._exists()

    def touch(self, **kwargs):
        """Creates this file on the hard drive.

        kwargs:
            mode=438
            exist_ok=True
        """
        self.Path.touch(**kwargs)

    def get_category(self, extension):
        """Return the category of the file instance as determined by its
        extension.

        Categories are determined in the filegroups module.

        The return value is not a full path, just the base name.
        """
        if extension:
            file_extension = set([extension.upper()])
            for key in typeGroups.keys():
                common = set(typeGroups[key]) & file_extension
                if common:
                    return key
        return self.default_category

    def find_suitable_name(self, file_path):
        """Validate whether a file with the same name exists, return a name
        indicating that it is a duplicate, else return the given file name.
        """
        dirname = os.path.dirname(file_path)
        new_filename = os.path.basename(file_path)
        count = 1

        while os.path.isfile(file_path):
            new_filename = '{0} - dup ({1}){2}'.format(
                self.stem, count, self.suffix)
            file_path = os.path.join(dirname, new_filename)
            count += 1

        return new_filename

    def move_to(self, dst_root_path, group=False, by_extension=False, group_folder_name=None):
        """Move the file instance to the location relative to the
        specified dst_root_path.

        dst_root_path is the root folder from where files will be organised
        by their extension.

        If dst_root_path = '/home/User/'
        final destination may be

                '/home/User/<extension>/<this file>'
                - group=False, ignore other options

                or

                '/home/User/<category>/<this file>'
                - group=True, by_extension=False, group_folder_name=None

                or

                '/home/User/<category>/<extension>/<this file>'
                - group=True, by_extension=True, group_folder_name=None

                or

                '/home/User/<group_folder_name>/<this file>'
                - group=True,by_extension=False,group_folder_name=<some name>

                or

                '/home/User/<group_folder_name>/<extension>/<this file>'
                - group=True,by_extension=True,group_folder_name=<some name>
        """
        if group:
            if group_folder_name is None:
                final_dst, go_back, ignore_file = self._set_category_filename_dst(
                    dst_root_path, by_extension)
            elif not group_folder_name.strip():
                raise EmptyNameError('blank name not allowed')
            else:
                final_dst, go_back, ignore_file = self._set_group_folder_dst(
                    dst_root_path, by_extension, group_folder_name.strip())
        else:
            final_dst, go_back, ignore_file = self._set_extension_filename_dst(
                dst_root_path)

        final_dir = os.path.dirname(final_dst)

        if not os.path.dirname(self.path) == final_dir:
            os.makedirs(final_dir, exist_ok=True)
            try:
                shutil.move(self.path, final_dst)
            except PermissionError:
                pass
            else:
                if go_back == 2:
                    write_identity_file(os.path.dirname(
                        os.path.dirname(final_dst)), ignore_file=ignore_file)
                    write_identity_file(os.path.dirname(final_dst))
                if go_back == 1:
                    write_identity_file(os.path.dirname(final_dst), ignore_file=ignore_file)
                self.path = final_dst

    def _set_group_folder_dst(self, root_path, by_extension, group_folder_name):
        if by_extension:
            group_folder_dst = os.path.join(
                root_path, group_folder_name, self.extension.upper())
            go_back = 2
            ignore_file = True
        else:
            group_folder_dst = os.path.join(root_path, group_folder_name)
            go_back = 1
            ignore_file = True
        return self._set_final_destination(group_folder_dst), go_back, ignore_file

    def _set_category_filename_dst(self, root_path, by_extension):
        if by_extension:
            category_dst = os.path.join(
                root_path, self.category, self.extension.upper())
            go_back = 2
            ignore_file = True
        else:
            category_dst = os.path.join(root_path, self.category)
            go_back = 1
            ignore_file = True
        return self._set_final_destination(category_dst), go_back, ignore_file

    def _set_extension_filename_dst(self, root_path):
        extension_dst = os.path.join(root_path, self.extension.upper())
        go_back = 1
        ignore_file = False
        return self._set_final_destination(extension_dst), go_back, ignore_file

    def _set_final_destination(self, parent_path):
        dst = os.path.join(parent_path, self.name)
        suitable_name = self.find_suitable_name(dst)
        return os.path.join(parent_path, suitable_name)

class Folder(Directory):
    """An instance of a folder.

    Inherits from Directory.

    class attributes:
        default_category=FOLDERS - the default name for folders whose categories
            are not defined in filegroups module

    data attributes:
        exists - True if folder in self.path exists and is a folder
        for_sorter - True if folder was generated by Sorter
        category_folder - The category of this instance as defined by filegroups
            module

    methods:
        glob
        move_to
        group
    """

    default_category = 'FOLDERS'

    def __init__(self, path):
        super(Folder, self).__init__(path)
        self._exists = self.Path.is_dir
        self._for_sorter = self._is_sorter_folder()
        self._category_folder = self._get_category_folder()

    @property
    def exists(self):
        return self._exists()

    @property
    def for_sorter(self):
        return self._for_sorter

    @property
    def category_folder(self):
        return self._category_folder

    def create(self, **kwargs):
        """Create this Folder.

        Calls pathlib.Path.mkdir(**kwargs)

        kwargs:
            mode=511
            parents=False
        """
        self.Path.mkdir(**kwargs)

    def glob(self, pattern):
        """Iterate over this path and yield all content matching the
        given pattern.

        Calls pathlib.Path.glob(pattern)
        """
        return self.Path.glob(pattern)

    def _is_sorter_folder(self, path=None):
        """Return True if Folder instance was generated by Sorter, else False.

        The folder in path has to exist.
        """
        path = path or self.path
        try:
            sorter_identity = os.path.join(
                path, SORTER_FOLDER_IDENTITY_FILENAME)
            open(sorter_identity, 'r').close()
        except FileNotFoundError:
            # For compatibility
            dirname = self.name
            if dirname.isupper():
                if dirname == self.default_category or dirname in typeList:
                    return True
            else:
                if dirname in typeGroups.keys():
                    return True
        else:
            return True

        return False

    def _get_category_folder(self):
        # category folder is not full path
        if self.for_sorter:
            if self.name.upper() in typeList:
                category = [key for key in typeGroups.keys() if set(
                    typeGroups[key]) & set([self.name])][0]
                return category
            if self.name in typeGroups.keys():
                return None

        return self.default_category

    def move_to(self, dst_root_path, **kwargs):
        """Move the folder to dst_root_path and, if self.for_sorter is True,
        create a SORTER_FOLDER_IDENTITY_FILENAME file only if the folder has
        been generated by the current operation i.e. not preexistent.

        Once all files have been relocated self.path is mapped to the new
        location.

        If this folder contains a SORTER_IGNORE_FILENAME file then
        it will be skipped. Nothing will happen.

        If dst_root_path points to the current path the Folder.group is called.
        """
        if has_signore_file(self.path):
            return
        if self.path == dst_root_path:
            if kwargs.get('group', False):
                self.group(dst_root_path, **kwargs)
            else:
                return

        group_folder_name = kwargs.get('group_folder_name', None)
        if group_folder_name:
            category_dst = os.path.join(dst_root_path, group_folder_name)
            create_category_identity_file = True
        elif self.category_folder is None:
            category_dst = dst_root_path
            create_category_identity_file = False
        else:
            category_dst = os.path.join(dst_root_path, self.category_folder)
            create_category_identity_file = True

        final_dst = os.path.join(category_dst, self.name)
        self._move_contents(final_dst)
        if self.for_sorter:
            write_identity_file(final_dst)
        if create_category_identity_file:
            write_identity_file(category_dst)
        try:
            os.rmdir(self.path)
        except OSError:
            pass
        self.path = final_dst

    def _move_contents(self, dst, src=None):
        if src is None:
            path_gen = self.glob('*')
        else:
            path_gen = iglob(os.path.join(src, '*'))

        contents = (str(i) for i in path_gen if (os.path.isfile(str(i)) and os.path.basename(str(i))
                                                 != SORTER_IGNORE_FILENAME) or (os.path.isdir(str(i)) and not has_signore_file(str(i))))
        os.makedirs(dst, exist_ok=True)

        for i in contents:
            item = str(i)
            if os.path.isfile(item):
                try:
                    open(os.path.join(dst, os.path.basename(item)), 'r').close()
                except FileNotFoundError:
                    shutil.move(item, dst)
            if os.path.isdir(item):
                dir_ = os.path.join(dst, os.path.basename(item))
                try:
                    os.makedirs(dir_)
                except FileExistsError:
                    self._move_contents(dst, src=item)
                else:
                    os.rmdir(dir_)
                    try:
                        shutil.move(item, dst)
                    except shutil.Error:
                        pass

    def group(self, dst_root_path, **kwargs):
        """Relocate files in relation to dst_root_path and delete this
        folder.

        If this folder contains a SORTER_IGNORE_FILENAME file then
        it will be skipped. Nothing will happen.

        dst_root_path is the root folder from where files will be organised
        by their extension.

        If dst_root_path = /home/User/
            then relocation happens as follows:

            /home/User/<this folder>/
            -group=False,ignore the rest

            or

            /home/User/<category>/<this folder>/
            -group=True,group_folder_name=None,ignore the rest

            or

            /home/User/<group_folder_name>/<this folder>/
            -group=True,group_folder_name=<some name>,ignore the rest

        kwargs: (as defined in sdir.File)
            group=False,
            by_extension=False,
            group_folder_name=None
        """
        if has_signore_file(self.path):
            return
        if 'group' not in kwargs.keys():
            kwargs['group'] = True
        contents = (str(i) for i in self.glob('*') if os.path.isfile(str(i))
                    and os.path.basename(str(i)) != SORTER_IGNORE_FILENAME)
        for item in contents:
            file_ = File(item)
            file_.move_to(dst_root_path, **kwargs)

        try:
            os.rmdir(self.path)
        except OSError:
            pass


text:
#ifndef _EXTRUDESTRATEGY_H_
#define _EXTRUDESTRATEGY_H_

#include <Gdiplus.h>
#include "ITextStrategy.h"

namespace TextDesigner
{

class ExtrudeStrategy : public ITextStrategy
{
public:
	//!  default constructor
	ExtrudeStrategy(void);
	//! destructor
	virtual ~ExtrudeStrategy(void);

	ITextStrategy* Clone();

	/** Initialize the strategy

	@param[in]		clrText is the text color
	@param[in]		clrOutline is the outline color
	@param[in]		nThickness is the outline thickness
	*/
	void Init(
		Gdiplus::Color clrText,
		Gdiplus::Color clrOutline,
		int nThickness,
		int nOffsetX,
		int nOffsetY );

	/** Initialize the strategy

	@param[in]		pbrushText is the text brush(Must cleaned up by caller)
	@param[in]		clrOutline is the outline color
	@param[in]		nThickness is the outline thickness
	*/
	void Init(
		Gdiplus::Brush* pbrushText,
		Gdiplus::Color clrOutline,
		int nThickness,
		int nOffsetX,
		int nOffsetY );

	/** Draw String, using a point as the starting point

	@param[in]		pGraphics is the graphics context
	@param[in]		pFontFamily is font family which is used(Collection of similar fonts)
	@param[in]		fontStyle like Bold, Italic or Regular should be specified.
	@param[in]		nfontSize is font size
	@param[in]		pszText is the text which is displayed.
	@param[in]		ptDraw is the staring point to draw
	@param[in]		pStrFormat is the string format to be specified(can be left at default)
	@return true for success
	*/
	bool DrawString(
		Gdiplus::Graphics* pGraphics,
		Gdiplus::FontFamily* pFontFamily,
		Gdiplus::FontStyle fontStyle,
		int nfontSize,
		const wchar_t*pszText,
		Gdiplus::Point ptDraw,
		Gdiplus::StringFormat* pStrFormat);

	/** Draw String, using a rectangle

	@param[in]		pGraphics is the graphics context
	@param[in]		pFontFamily is font family which is used(Collection of similar fonts)
	@param[in]		fontStyle like Bold, Italic or Regular should be specified.
	@param[in]		nfontSize is font size
	@param[in]		pszText is the text which is displayed.
	@param[in]		rtDraw is the rectangle where the whole drawing will be centralized
	@param[in]		pStrFormat is the string format to be specified(can be left at default)
	@return true for success
	*/
	bool DrawString(
		Gdiplus::Graphics* pGraphics,
		Gdiplus::FontFamily* pFontFamily,
		Gdiplus::FontStyle fontStyle,
		int nfontSize,
		const wchar_t*pszText,
		Gdiplus::Rect rtDraw,
		Gdiplus::StringFormat* pStrFormat);

	/** Draw String using a starting point. Using GDI paths, instead of GDI+ paths

	@param[in]		pGraphics is the graphics context
	@param[in]		pLogFont is the LOGFONT from which the font will be created.
	@param[in]		pszText is the text which is displayed.
	@param[in]		ptDraw is the staring point to draw
	@return true for success
	*/
	bool GdiDrawString(
		Gdiplus::Graphics* pGraphics,
		LOGFONTW* pLogFont,
		const wchar_t*pszText,
		Gdiplus::Point ptDraw);

	/** Draw String using a rectangle. Using GDI paths, instead of GDI+ paths

	@param[in]		pGraphics is the graphics context
	@param[in]		pLogFont is the LOGFONT from which the font will be created.
	@param[in]		pszText is the text which is displayed.
	@param[in]		rtDraw is the rectangle where the whole drawing will be centralized
	@return true for success
	*/
	bool GdiDrawString(
		Gdiplus::Graphics* pGraphics,
		LOGFONTW* pLogFont,
		const wchar_t*pszText,
		Gdiplus::Rect rtDraw);

	/** Measure String, using a point as the starting point

	@param[in]		pGraphics is the graphics context
	@param[in]		pFontFamily is font family which is used(Collection of similar fonts)
	@param[in]		fontStyle like Bold, Italic or Regular should be specified.
	@param[in]		nfontSize is font size
	@param[in]		pszText is the text which is displayed.
	@param[in]		ptDraw is the staring point to draw
	@param[in]		pStrFormat is the string format to be specified(can be left at default)
	@param[out]		pfDestWidth is the destination pixels width
	@param[out]		pfDestHeight is the destination pixels height
	@return true for success
	*/
	bool MeasureString(
		Gdiplus::Graphics* pGraphics,
		Gdiplus::FontFamily* pFontFamily,
		Gdiplus::FontStyle fontStyle,
		int nfontSize,
		const wchar_t*pszText,
		Gdiplus::Point ptDraw,
		Gdiplus::StringFormat* pStrFormat,
		float* pfPixelsStartX,
		float* pfPixelsStartY,
		float* pfDestWidth,
		float* pfDestHeight );

	/** Measure String, using a rectangle

	@param[in]		pGraphics is the graphics context
	@param[in]		pFontFamily is font family which is used(Collection of similar fonts)
	@param[in]		fontStyle like Bold, Italic or Regular should be specified.
	@param[in]		nfontSize is font size
	@param[in]		pszText is the text which is displayed.
	@param[in]		rtDraw is the rectangle where the whole drawing will be centralized
	@param[in]		pStrFormat is the string format to be specified(can be left at default)
	@param[out]		pfDestWidth is the destination pixels width
	@param[out]		pfDestHeight is the destination pixels height
	@return true for success
	*/
	bool MeasureString(
		Gdiplus::Graphics* pGraphics,
		Gdiplus::FontFamily* pFontFamily,
		Gdiplus::FontStyle fontStyle,
		int nfontSize,
		const wchar_t*pszText,
		Gdiplus::Rect rtDraw,
		Gdiplus::StringFormat* pStrFormat,
		float* pfPixelsStartX,
		float* pfPixelsStartY,
		float* pfDestWidth,
		float* pfDestHeight );

	/** Measure String using a starting point. Using GDI paths, instead of GDI+ paths

	@param[in]		pGraphics is the graphics context
	@param[in]		pLogFont is the LOGFONT from which the font will becreated.
	@param[in]		pszText is the text which is displayed.
	@param[in]		ptDraw is the staring point to draw
	@param[out]		pfDestWidth is the destination pixels width
	@param[out]		pfDestHeight is the destination pixels height
	@return true for success
	*/
	bool GdiMeasureString(
		Gdiplus::Graphics* pGraphics,
		LOGFONTW* pLogFont,
		const wchar_t*pszText,
		Gdiplus::Point ptDraw,
		float* pfPixelsStartX,
		float* pfPixelsStartY,
		float* pfDestWidth,
		float* pfDestHeight );

	/** Measure String using a rectangle. Using GDI paths, instead of GDI+ paths

	@param[in]		pGraphics is the graphics context
	@param[in]		pLogFont is the LOGFONT from which the font will becreated.
	@param[in]		pszText is the text which is displayed.
	@param[in]		rtDraw is the rectangle where the whole drawing will be centralized
	@param[out]		pfDestWidth is the destination pixels width
	@param[out]		pfDestHeight is the destination pixels height
	@return true for success
	*/
	bool GdiMeasureString(
		Gdiplus::Graphics* pGraphics,
		LOGFONTW* pLogFont,
		const wchar_t*pszText,
		Gdiplus::Rect rtDraw,
		float* pfPixelsStartX,
		float* pfPixelsStartY,
		float* pfDestWidth,
		float* pfDestHeight );

	/** Measure String using a starting point. Using GDI paths, instead of GDI+ paths

	@param[in]		pGraphics is the graphics context
	@param[in]		pLogFont is the LOGFONT from which the font will becreated.
	@param[in]		pszText is the text which is displayed.
	@param[in]		ptDraw is the staring point to draw
	@param[out]		pfDestWidth is the destination pixels width
	@param[out]		pfDestHeight is the destination pixels height
	@return true for success
	*/
	bool GdiMeasureStringRealHeight(
		Gdiplus::Graphics* pGraphics,
		LOGFONTW* pLogFont,
		const wchar_t*pszText,
		Gdiplus::Point ptDraw,
		float* pfPixelsStartX,
		float* pfPixelsStartY,
		float* pfDestWidth,
		float* pfDestHeight );

	/** Measure String using a rectangle. Using GDI paths, instead of GDI+ paths

	@param[in]		pGraphics is the graphics context
	@param[in]		pLogFont is the LOGFONT from which the font will becreated.
	@param[in]		pszText is the text which is displayed.
	@param[in]		rtDraw is the rectangle where the whole drawing will be centralized
	@param[out]		pfDestWidth is the destination pixels width
	@param[out]		pfDestHeight is the destination pixels height
	@return true for success
	*/
	bool GdiMeasureStringRealHeight(
		Gdiplus::Graphics* pGraphics,
		LOGFONTW* pLogFont,
		const wchar_t*pszText,
		Gdiplus::Rect rtDraw,
		float* pfPixelsStartX,
		float* pfPixelsStartY,
		float* pfDestWidth,
		float* pfDestHeight );

protected:
	//! m_clrText is the text color
	Gdiplus::Color m_clrText;
	//! m_clrOutline is the outline color
	Gdiplus::Color m_clrOutline;
	//! m_nThickness is the outline thickness
	int m_nThickness;
	//! X Direction of Extrude
	int m_nOffsetX;
	//! Y Direction of Extrude
	int m_nOffsetY;
	//! Text Brush
	Gdiplus::Brush* m_pbrushText;
	//! Using color or brush for text
	bool m_bClrText;

};

} // namespace TextDesigner

#endif // _EXTRUDESTRATEGY_H_