text:
/**************************************************************************//**
 * @file     nu_lcd.h
 * @version  V3.00
 * @brief    Liquid-Crystal Display(LCD) driver header file
 *
 * @copyright SPDX-License-Identifier: Apache-2.0
 * @copyright Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
 *****************************************************************************/
#ifndef __NU_LCD_H__
#define __NU_LCD_H__

#ifdef __cplusplus
extern "C"
{
#endif

/** @addtogroup Standard_Driver Standard Driver
  @{
*/

/** @addtogroup LCD_Driver LCD Driver
  @{
*/

/** @addtogroup LCD_EXPORTED_CONSTANTS LCD Exported Constants
  @{
*/
/*---------------------------------------------------------------------------------------------------------*/
/*  LCD Bias Voltage Level Selection Constant Definitions                                                  */
/*---------------------------------------------------------------------------------------------------------*/
#define LCD_BIAS_LV_1_2                 (1ul << LCD_PCTL_BIAS_Pos) /*!< LCD bias voltage level selection - 1/2 Bias \hideinitializer */
#define LCD_BIAS_LV_1_3                 (2ul << LCD_PCTL_BIAS_Pos) /*!< LCD bias voltage level selection - 1/3 Bias \hideinitializer */
#define LCD_BIAS_LV_1_4                 (3ul << LCD_PCTL_BIAS_Pos) /*!< LCD bias voltage level selection - 1/4 Bias \hideinitializer */

/*---------------------------------------------------------------------------------------------------------*/
/*  LCD COM Duty Ratio Selection Constant Definitions                                                      */
/*---------------------------------------------------------------------------------------------------------*/
#define LCD_COM_DUTY_1_1                (0ul << LCD_PCTL_DUTY_Pos) /*!< LCD com duty ratio selection - 1/1 Duty \hideinitializer */
#define LCD_COM_DUTY_1_2                (1ul << LCD_PCTL_DUTY_Pos) /*!< LCD com duty ratio selection - 1/2 Duty \hideinitializer */
#define LCD_COM_DUTY_1_3                (2ul << LCD_PCTL_DUTY_Pos) /*!< LCD com duty ratio selection - 1/3 Duty \hideinitializer */
#define LCD_COM_DUTY_1_4                (3ul << LCD_PCTL_DUTY_Pos) /*!< LCD com duty ratio selection - 1/4 Duty \hideinitializer */
#define LCD_COM_DUTY_1_5                (4ul << LCD_PCTL_DUTY_Pos) /*!< LCD com duty ratio selection - 1/5 Duty \hideinitializer */
#define LCD_COM_DUTY_1_6                (5ul << LCD_PCTL_DUTY_Pos) /*!< LCD com duty ratio selection - 1/6 Duty \hideinitializer */
#define LCD_COM_DUTY_1_7                (6ul << LCD_PCTL_DUTY_Pos) /*!< LCD com duty ratio selection - 1/7 Duty \hideinitializer */
#define LCD_COM_DUTY_1_8                (7ul << LCD_PCTL_DUTY_Pos) /*!< LCD com duty ratio selection - 1/8 Duty \hideinitializer */

/*---------------------------------------------------------------------------------------------------------*/
/*  LCD Waveform Attribute Selection Constant Definitions                                                  */
/*---------------------------------------------------------------------------------------------------------*/
#define LCD_WAVEFORM_TYPE_A_NORMAL      (0ul << LCD_PCTL_TYPE_Pos) /*!< LCD waveform Type-A, no inverse \hideinitializer */
#define LCD_WAVEFORM_TYPE_B_NORMAL      (1ul << LCD_PCTL_TYPE_Pos) /*!< LCD waveform Type-B, no inverse \hideinitializer */
#define LCD_WAVEFORM_TYPE_A_INVERSE     (2ul << LCD_PCTL_TYPE_Pos) /*!< LCD waveform Type-A and inverse \hideinitializer */
#define LCD_WAVEFORM_TYPE_B_INVERSE     (3ul << LCD_PCTL_TYPE_Pos) /*!< LCD waveform Type-B and inverse \hideinitializer */

/*---------------------------------------------------------------------------------------------------------*/
/*  LCD Charge Pump Voltage Selection Constant Definitions                                                 */
/*---------------------------------------------------------------------------------------------------------*/
#define LCD_CP_VOLTAGE_LV_0             (0ul << LCD_PCTL_CPVSEL_Pos) /*!< Select LCD charge pump voltage 2.6 V \hideinitializer */
#define LCD_CP_VOLTAGE_LV_1             (1ul << LCD_PCTL_CPVSEL_Pos) /*!< Select LCD charge pump voltage 2.8 V \hideinitializer */
#define LCD_CP_VOLTAGE_LV_2             (2ul << LCD_PCTL_CPVSEL_Pos) /*!< Select LCD charge pump voltage 3.0 V \hideinitializer */
#define LCD_CP_VOLTAGE_LV_3             (3ul << LCD_PCTL_CPVSEL_Pos) /*!< Select LCD charge pump voltage 3.2 V \hideinitializer */
#define LCD_CP_VOLTAGE_LV_4             (4ul << LCD_PCTL_CPVSEL_Pos) /*!< Select LCD charge pump voltage 3.4 V \hideinitializer */
#define LCD_CP_VOLTAGE_LV_5             (5ul << LCD_PCTL_CPVSEL_Pos) /*!< Select LCD charge pump voltage 3.6 V \hideinitializer */

/*---------------------------------------------------------------------------------------------------------*/
/*  LCD Interrupt Source Constant Definitions                                                              */
/*---------------------------------------------------------------------------------------------------------*/
#define LCD_DISABLE_ALL_INT             (0ul << LCD_INTEN_FCEIEN_Pos)   /*!< Disable all LCD interrupt sources \hideinitializer */
#define LCD_FRAME_COUNTING_END_INT      (1ul << LCD_INTEN_FCEIEN_Pos)   /*!< Indicate frame count end interrupt \hideinitializer */
#define LCD_FRAME_END_INT               (1ul << LCD_INTEN_FEIEN_Pos)    /*!< Indicate frame end interrupt \hideinitializer */
#define LCD_CPTOUT_INT                  (1ul << LCD_INTEN_CTOIEN_Pos)   /*!< Indicate charge pump charging timeout interrupt \hideinitializer */
#define LCD_ENABLE_ALL_INT              (7ul << LCD_INTEN_FCEIEN_Pos)   /*!< Enable all LCD interrupt sources \hideinitializer */

/*---------------------------------------------------------------------------------------------------------*/
/*  LCD Operation Voltage Source Constant Definitions                                                      */
/*---------------------------------------------------------------------------------------------------------*/
#define LCD_VOLTAGE_SOURCE_VLCD         (0ul << LCD_DCTL_VSRC_Pos) /*!< LCD voltage source from external VLCD power \hideinitializer */
#define LCD_VOLTAGE_SOURCE_AVDD         (1ul << LCD_DCTL_VSRC_Pos) /*!< LCD voltage source from internal VDD \hideinitializer */
#define LCD_VOLTAGE_SOURCE_CP           (2ul << LCD_DCTL_VSRC_Pos) /*!< LCD voltage source from built-in charge pump \hideinitializer */

/*---------------------------------------------------------------------------------------------------------*/
/*  LCD Driving Mode Selection Constant Definitions                                                        */
/*---------------------------------------------------------------------------------------------------------*/
#define LCD_LOW_DRIVING_AND_BUF_OFF                     (0ul << LCD_DCTL_RESMODE_Pos) /*!< LCD operates with low-drive and voltage buffer disabled \hideinitializer */
#define LCD_HIGH_DRIVING_AND_BUF_OFF                    (1ul << LCD_DCTL_RESMODE_Pos) /*!< LCD operates with high-drive and voltage buffer disabled \hideinitializer */
#define LCD_LOW_DRIVING_AND_BUF_ON                      (2ul << LCD_DCTL_RESMODE_Pos) /*!< LCD operates with low-drive and voltage buffer enabled \hideinitializer */
#define LCD_HIGH_DRIVING_AND_BUF_OFF_AND_PWR_SAVING     (5ul << LCD_DCTL_RESMODE_Pos) /*!< LCD operates with high-drive, voltage buffer disabled and power saving \hideinitializer */
#define LCD_LOW_DRIVING_AND_BUF_ON_AND_PWR_SAVING       (6ul << LCD_DCTL_RESMODE_Pos) /*!< LCD operates with low-drive, voltage buffer enabled and power saving \hideinitializer */

/*---------------------------------------------------------------------------------------------------------*/
/*  LCD Power Saving Mode Constant Definitions                                                             */
/*---------------------------------------------------------------------------------------------------------*/
#define LCD_PWR_SAVING_NORMAL_MODE              (0ul << LCD_DCTL_PSVREV_Pos) /*!< The timing of LCD power saving is normal \hideinitializer */
#define LCD_PWR_SAVING_REVERSE_MODE             (1ul << LCD_DCTL_PSVREV_Pos) /*!< The timing of LCD power saving is reverse \hideinitializer */

/**@}*/ /* end of group LCD_EXPORTED_CONSTANTS */

/** @addtogroup LCD_EXPORTED_STRUCTS LCD Exported Structs
  @{
*/
/**
  * @details    LCD Configuration Data Struct
  */
typedef struct
{
    uint32_t u32SrcFreq;        /*!< LCD clock source frequency */
    uint32_t u32ComDuty;        /*!< COM duty */
    uint32_t u32BiasLevel;      /*!< Bias level */
    uint32_t u32Framerate;      /*!< Operation frame rate */
    uint32_t u32WaveformType;   /*!< Waveform type */
    uint32_t u32IntSrc;         /*!< Interrupt source */
    uint32_t u32DrivingMode;    /*!< Driving mode */
    uint32_t u32VSrc;           /*!< Voltage source */
} S_LCD_CFG_T;

/**@}*/ /* end of group LCD_EXPORTED_STRUCTS */

/** @addtogroup LCD_EXPORTED_FUNCTIONS LCD Exported Functions
  @{
*/

/**
  * @brief      Enable LCD Display
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro is used to enable LCD display.
  */
#define LCD_ENABLE_DISPLAY()        do{ LCD->CTL |= LCD_CTL_EN_Msk; while(LCD->CTL & LCD_CTL_SYNC_Msk) {} }while(0)

/**
  * @brief      Disable LCD Display
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro is used to disable LCD display.
  */
#define LCD_DISABLE_DISPLAY()       do{ LCD->CTL &= ~LCD_CTL_EN_Msk; while(LCD->CTL & LCD_CTL_SYNC_Msk) {} }while(0)

/**
  * @brief      Set LCD Waveform Type
  *
  * @param[in]  type       The LCD waveform type. It could be one of the following type
  *                             - \ref LCD_WAVEFORM_TYPE_A_NORMAL
  *                             - \ref LCD_WAVEFORM_TYPE_B_NORMAL
  *                             - \ref LCD_WAVEFORM_TYPE_A_INVERSE
  *                             - \ref LCD_WAVEFORM_TYPE_B_INVERSE
  *
  * @return     None
  *
  * @details    This macro is used to set the attribute of LCD output waveform.
  */
#define LCD_WAVEFORM_TYPE(type)     (LCD->PCTL = (LCD->PCTL & ~LCD_PCTL_TYPE_Msk) | (type))

/**
  * @brief      Set LCD Source Clock Divider
  *
  * @param[in]  div         The frequency divider, valid value is between 1 to 1024.
  *
  * @return     None
  *
  * @details    This macro is used to set the LCD operarion frequency is (LCD source frequency / div).
  */
#define LCD_SET_FREQDIV(div)        (LCD->PCTL = (LCD->PCTL & ~LCD_PCTL_FREQDIV_Msk) | (((div)-1) << LCD_PCTL_FREQDIV_Pos))

/**
  * @brief      Set Charge Pump Voltage
  *
  * @param[in]  voltage     The target charge pump voltage. It could be one of the following voltage level
  *                             - \ref LCD_CP_VOLTAGE_LV_0, 2.6 V
  *                             - \ref LCD_CP_VOLTAGE_LV_1, 2.8 V
  *                             - \ref LCD_CP_VOLTAGE_LV_2, 3.0 V
  *                             - \ref LCD_CP_VOLTAGE_LV_3, 3.2 V
  *                             - \ref LCD_CP_VOLTAGE_LV_4, 3.4 V
  *                             - \ref LCD_CP_VOLTAGE_LV_5, 3.6 V
  *
  * @return     None
  *
  * @details    This macro is used to set charge pump voltage for VLCD.
  */
#define LCD_SET_CP_VOLTAGE(voltage) (LCD->PCTL = (LCD->PCTL & ~LCD_PCTL_CPVSEL_Msk) | (voltage))

/**
  * @brief      Decrease Charge Pump Voltage
  *
  * @param[in]  unit        The tuning units, valid value is between 0 to 7.
  *                         One unit of voltage is about 0.03V, and the charge pump voltage is decreased (unit * 0.03)V.
  *
  * @return     None
  *
  * @details    This macro is used to decrease charge pump voltage by specific units.
  */
#define LCD_CP_VOLTAGE_DECREASE(unit)   (LCD->PCTL = (LCD->PCTL & ~LCD_PCTL_CPVTUNE_Msk) | ((unit) << LCD_PCTL_CPVTUNE_Pos))

/**
  * @brief      Increase Charge Pump Voltage
  *
  * @param[in]  unit        The tuning units, valid value is between 1 to 8.
  *                         One unit of voltage is about 0.03V, and the charge pump voltage is increased (unit * 0.03)V.
  *
  * @return     None
  *
  * @details    This macro is used to increase charge pump voltage by specific units.
  */
#define LCD_CP_VOLTAGE_INCREASE(unit)   (LCD->PCTL = (LCD->PCTL & ~LCD_PCTL_CPVTUNE_Msk) | ((16-(unit)) << LCD_PCTL_CPVTUNE_Pos))

/**
  * @brief      Set LCD Blinking ON
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro is used to enable LCD blinking.
  */
#define LCD_BLINKING_ON()       (LCD->FCTL |= LCD_FCTL_BLINK_Msk)

/**
  * @brief      Set LCD Blinking OFF
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro is used to disable LCD blinking.
  */
#define LCD_BLINKING_OFF()      (LCD->FCTL &= ~LCD_FCTL_BLINK_Msk)

/**
  * @brief      Set LCD Frame Counting Value
  *
  * @param[in]  value       Frame counting value. Valid value is between 1 to 1024.
  *
  * @return     None
  *
  * @details    This macro is used to set the LCD frame counting value to configure the blink interval.
  * @note       For type-B waveform, the frame counter increases at the end of odd frames, not even frames.
  */
#define LCD_SET_FRAME_COUNTING_VALUE(value)     (LCD->FCTL = (LCD->FCTL & ~LCD_FCTL_FCV_Msk) | (((value)-1) << LCD_FCTL_FCV_Pos))

/**
  * @brief      Set Null Frame Time
  *
  * @param[in]  unit        The unit parameter is used to determine the null frame time, valid value is between 0 to 15.
  *                         And one unit time is one LCD operation clock period.
  *
  * @return     None
  *
  * @details    This macro is used to set the one null frame time.
  * @note       All COM and SEG output voltages will keep at 0V during a null frame.
  */
#define LCD_SET_NULL_FRAME_TIME(unit)       (LCD->FCTL = (LCD->FCTL & ~LCD_FCTL_NFTIME_Msk) | ((unit) << LCD_FCTL_NFTIME_Pos))

/**
  * @brief      Set Continuous Frames
  *
  * @param[in]  frame       The continuous frames, valid setting is between 1 to 16 frames.
  *
  * @return     None
  *
  * @details    This macro is used to specify the number of continuous frames reached to insert one null frame.
  */
#define LCD_SET_CONTINUOUS_FRAME(frame)     (LCD->FCTL = (LCD->FCTL & ~LCD_FCTL_NFNUM_Msk) | (((frame)-1) << LCD_FCTL_NFNUM_Pos))

/**
  * @brief      Select LCD Voltage Source
  *
  * @param[in]  mode        The LCD operation voltage source. It could be one of the following source
  *                             - \ref LCD_VOLTAGE_SOURCE_VLCD
  *                             - \ref LCD_VOLTAGE_SOURCE_AVDD
  *                             - \ref LCD_VOLTAGE_SOURCE_CP
  *
  * @return     None
  *
  * @details    This macro is used to select LCD operation voltage source.
  */
#define LCD_VOLTAGE_SOURCE(source)  (LCD->DCTL = (LCD->DCTL & ~LCD_DCTL_VSRC_Msk) | (source))

/**
  * @brief      Set LCD Driving Mode
  *
  * @param[in]  mode        The LCD operation driving mode. It could be one of the following mode
  *                             - \ref LCD_LOW_DRIVING_AND_BUF_OFF
  *                             - \ref LCD_HIGH_DRIVING_AND_BUF_OFF
  *                             - \ref LCD_LOW_DRIVING_AND_BUF_ON
  *                             - \ref LCD_HIGH_DRIVING_AND_BUF_OFF_AND_PWR_SAVING
  *                             - \ref LCD_LOW_DRIVING_AND_BUF_ON_AND_PWR_SAVING
  *
  * @return     None
  *
  * @details    This macro is used to set LCD operation drivig mode.
  */
#define LCD_DRIVING_MODE(mode)      (LCD->DCTL = (LCD->DCTL & ~(LCD_DCTL_RESMODE_Msk | LCD_DCTL_BUFEN_Msk | LCD_DCTL_PSVEN_Msk)) | (mode))

/**
  * @brief      Select Power Saving Mode
  *
  * @param[in]  mode        The LCD power saving mode selection. It could be one of the following constant definition
  *                             - \ref LCD_PWR_SAVING_NORMAL_MODE
  *                             - \ref LCD_PWR_SAVING_REVERSE_MODE
  *
  * @return     None
  *
  * @details    This macro is used to set the LCD power saving mode.
  *             When the timing of power saving mode is reversed, the original power saving period becomes no power saving,
  *             and the original no power saving period becomes power saving.
  */
#define LCD_PWR_SAVING_MODE(mode)   (LCD->DCTL = (LCD->DCTL & ~LCD_DCTL_PSVREV_Msk) | (mode))

/**
  * @brief      Set Power Saving T1 Period
  *
  * @param[in]  t1      The number of t1 to determine T1 period, valid value is between 1 to 16.
  *                     And one unit of t1 period is half of LCD operation clock period.
  *
  * @return     None
  *
  * @details    This macro is used to configure the T1 (Enable Time) period of power saving.
  */
#define LCD_PWR_SAVING_T1_PERIOD(t1)    (LCD->DCTL = (LCD->DCTL & ~LCD_DCTL_PSVT1_Msk) | (((t1)-1) << LCD_DCTL_PSVT1_Pos))

/**
  * @brief      Set Power Saving T2 Period
  *
  * @param[in]  t2      The number of t2 to determine T2 period, valid value is between 1 to 16.
  *                     And one unit of t1 period is half of LCD operation clock period.
  *
  * @return     None
  *
  * @details    This macro is used to configure the T2 (On Time) period of power saving.
  */
#define LCD_PWR_SAVING_T2_PERIOD(t2)    (LCD->DCTL = (LCD->DCTL & ~LCD_DCTL_PSVT2_Msk) | (((t2)-1) << LCD_DCTL_PSVT2_Pos))

/**
  * @brief      Set Charging Timeout Time
  *
  * @param[in]  value   The maximum timeout value, valid value is between 1 to 8192.
  *                     And one unit of timeout value is one LCD operation clock period.
  *
  * @return     None
  *
  * @details    This macro is used to set maximum timeout time of charge pump charging timer.
  */
#define LCD_SET_CHARGE_TIMEOUT_TIME(value)  (LCD->DCTL = (LCD->DCTL & ~LCD_DCTL_CTOTIME_Msk) | (((value)-1) << LCD_DCTL_CTOTIME_Pos))

/**
  * @brief      Select Device Package Type
  *
  * @param[in]  pak     Select device package type.
  *                     0 for 128-pin package, and 1 for 64-pin package.
  *
  * @return     None
  *
  * @details    This macro is used to select device output pins for LCD controller with different package type.
  */
#define LCD_SELECT_PACKAGE_TYPE(pkg)    (LCD->PKGSEL = (LCD->PKGSEL & ~LCD_PKGSEL_PKG_Msk) | ((pkg) << LCD_PKGSEL_PKG_Pos))

/**
  * @brief      Enable LCD Frame Counting End Interrupt
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro is used to enable frame count end interrupt function.
  */
#define LCD_ENABLE_FRAME_COUNTING_END_INT()     (LCD->INTEN |= LCD_INTEN_FCEIEN_Msk)

/**
  * @brief      Disable LCD Frame Counting End Interrupt
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro is used to disable frame count end interrupt function.
  */
#define LCD_DISABLE_FRAME_COUNTING_END_INT()    (LCD->INTEN &= ~LCD_INTEN_FCEIEN_Msk)

/**
  * @brief      Enable LCD Frame End Interrupt
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro is used to enable frame end interrupt function.
  */
#define LCD_ENABLE_FRAME_END_INT()      (LCD->INTEN |= LCD_INTEN_FEIEN_Msk)

/**
  * @brief      Disable LCD Frame End Interrupt
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro is used to disable frame end interrupt function.
  */
#define LCD_DISABLE_FRAME_END_INT()     (LCD->INTEN &= ~LCD_INTEN_FEIEN_Msk)

/**
  * @brief      Enable Charging Timeout Interrupt
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro is used to enable charge pump charging timeout interrupt function.
  */
#define LCD_ENABLE_CHARGE_TIMEOUT_INT()     (LCD->INTEN |= LCD_INTEN_CTOIEN_Msk)

/**
  * @brief      Disable Charging Timeout Interrupt
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro is used to disable charge pump charging timeout interrupt function.
  */
#define LCD_DISABLE_CHARGE_TIMEOUT_INT()    (LCD->INTEN &= ~LCD_INTEN_CTOIEN_Msk)

/**
  * @brief      Get LCD Frame Counting End Flag
  *
  * @param      None
  *
  * @retval     0   Frame count end flag did not occur
  * @retval     1   Frame count end flag occurred
  *
  * @details    This macro gets frame count end flag.
  */
#define LCD_GET_FRAME_COUNTING_END_FLAG()   ((LCD->STS & LCD_STS_FCEF_Msk)? 1UL : 0UL)

/**
  * @brief      Clear LCD Frame Counting End Flag
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro clears frame count end flag.
  */
#define LCD_CLEAR_FRAME_COUNTING_END_FLAG() (LCD->STS = LCD_STS_FCEF_Msk)

/**
  * @brief      Get LCD Frame End Flag
  *
  * @param      None
  *
  * @retval     0   Frame end flag did not occur
  * @retval     1   Frame end flag occurred
  *
  * @details    This macro gets frame end flag.
  */
#define LCD_GET_FRAME_END_FLAG()            ((LCD->STS & LCD_STS_FEF_Msk)? 1UL : 0UL)

/**
  * @brief      Clear LCD Frame End Flag
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro clears frame end flag.
  */
#define LCD_CLEAR_FRAME_END_FLAG()          (LCD->STS = LCD_STS_FEF_Msk)

/**
  * @brief      Get Charging Timeout Flag
  *
  * @param      None
  *
  * @retval     0   Charge pump timer timeout flag did not occur
  * @retval     1   Charge pump timer timeout flag occurred
  *
  * @details    This macro gets charge pump charging timeout flag.
  */
#define LCD_GET_CHARGE_TIMEOUT_FLAG()       ((LCD->STS & LCD_STS_CTOF_Msk)? 1UL : 0UL)

/**
  * @brief      Clear Charging Timeout Flag
  *
  * @param      None
  *
  * @return     None
  *
  * @details    This macro clears charge pump charging timeout flag.
  */
#define LCD_CLEAR_CHARGE_TIMEOUT_FLAG()     (LCD->STS = LCD_STS_CTOF_Msk)

/**
  * @brief      Get Charging Time
  *
  * @param      None
  *
  * @return     Current 13-bit charging timer value
  *
  * @details    This macro gets charging timer value while stops charge pump charging.
  */
#define LCD_GET_CHARGE_TIME()              ((LCD->STS & LCD_STS_CTIME_Msk) >> 16)

uint32_t LCD_Open(S_LCD_CFG_T *pLCDCfg);
void LCD_Close(void);
void LCD_SetPixel(uint32_t u32Com, uint32_t u32Seg, uint32_t u32OnFlag);
void LCD_SetAllPixels(uint32_t u32OnOff);
uint32_t LCD_EnableBlink(uint32_t u32ms);
void LCD_DisableBlink(void);
void LCD_EnableInt(uint32_t u32IntSrc);
void LCD_DisableInt(uint32_t u32IntSrc);

/**@}*/ /* end of group LCD_EXPORTED_FUNCTIONS */

/**@}*/ /* end of group LCD_Driver */

/**@}*/ /* end of group Standard_Driver */

#ifdef __cplusplus
}
#endif

#endif /* __NU_LCD_H__ */


text:
<?xml version="1.0" encoding="utf-8"?>
<StructureMap Id="Generics">
  <Assembly Name="StructureMap.Testing.GenericWidgets" />
  <PluginFamily Assembly="StructureMap.Testing.GenericWidgets" Type="StructureMap.Testing.GenericWidgets.IThing`2" DefaultKey="Red">
    <Plugin Assembly="StructureMap.Testing.GenericWidgets" Type="StructureMap.Testing.GenericWidgets.ColorThing`2" ConcreteKey="Color" />
    <Plugin Assembly="StructureMap.Testing.GenericWidgets" Type="StructureMap.Testing.GenericWidgets.ComplexThing`2" ConcreteKey="Complex" />
    <Instance Key="Red" Type="Color">
      <Property Name="color" Value="Red" />
    </Instance>
    <Instance Key="Complicated" Type="Complex">
      <Property Name="name" Value="Jeremy" />
      <Property Name="age" Value="32" />
      <Property Name="ready" Value="true" />
    </Instance>
  </PluginFamily>
  <PluginFamily Assembly="StructureMap.Testing.GenericWidgets" Type="StructureMap.Testing.GenericWidgets.ISimpleThing`1" DefaultKey="Simple">
    <Plugin Assembly="StructureMap.Testing.GenericWidgets" Type="StructureMap.Testing.GenericWidgets.SimpleThing`1" ConcreteKey="Simple" />
  </PluginFamily>
</StructureMap>

redpajama_set_name: RedPajamaGithub


text:
package game.actor;

import java.awt.Point;
import java.awt.geom.Point2D;
/**
 * the class to represent the user controlled hero of the game
 *
 */
public class Pacman extends Actor {

	private Item item;

	/**returns the item that this pacman holds*/
	public Item getItem(){
		return item;
	}
	/**sets the item that this pacman holds*/
	public void setItem(String name,int xLoc,int yLoc){
		item=new Item(name,new Point( xLoc, yLoc));
	}

	/**removes an item that this pacman holds*/
	public void removeItem(){
		item=null;
	}
	/**constructs a new pacman for playing*/
   public Pacman(double speed, Point2D initialLocation, String[][] imagePaths) {
      super("pacman", speed, initialLocation, imagePaths);
   }

   /**
    * use this method to register directional commands. Each time the arrow key
    * is pressed, this method should be called to store the new direction. This
    * method deals with the logic needed to determine what currentDirection and
    * nextDirection should be.
    *
    * @param newDirection
    */
   public void addDirection(MovementDirection newDirection) {
      // if we are not moving now, set both directions to be newDirection
      if (currentDirection == MovementDirection.NONE ||
    		  MovementDirection.isOpposite(currentDirection, newDirection))
         currentDirection = newDirection;
      nextDirection = newDirection;
   }
}


text:
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Diagnostics.Contracts;
using System;

// Disable the "this variable is not used" warning as every field would imply it.
#pragma warning disable 0414
// Disable the "this variable is never assigned to".
#pragma warning disable 0067
// Disable the "this event is never assigned to".
#pragma warning disable 0649
// Disable the "this variable is never used".
#pragma warning disable 0169
// Disable the "new keyword not required" warning.
#pragma warning disable 0109
// Disable the "extern without DllImport" warning.
#pragma warning disable 0626
// Disable the "could hide other member" warning, can happen on certain properties.
#pragma warning disable 0108

namespace System.Web.SessionState
{
  public partial class SessionIDManager : ISessionIDManager
  {
    #region Methods and constructors
    public virtual new string CreateSessionID(System.Web.HttpContext context)
    {
      return default(string);
    }

    public virtual new string Decode(string id)
    {
      return default(string);
    }

    public virtual new string Encode(string id)
    {
      return default(string);
    }

    public string GetSessionID(System.Web.HttpContext context)
    {
      return default(string);
    }

    public void Initialize()
    {
    }

    public bool InitializeRequest(System.Web.HttpContext context, bool suppressAutoDetectRedirect, out bool supportSessionIDReissue)
    {
      supportSessionIDReissue = default(bool);

      return default(bool);
    }

    public void RemoveSessionID(System.Web.HttpContext context)
    {
    }

    public void SaveSessionID(System.Web.HttpContext context, string id, out bool redirected, out bool cookieAdded)
    {
      redirected = default(bool);
      cookieAdded = default(bool);
    }

    public SessionIDManager()
    {
    }

    public virtual new bool Validate(string id)
    {
      return default(bool);
    }
    #endregion

    #region Properties and indexers
    public static int SessionIDMaxLength
    {
      get
      {
        return default(int);
      }
    }
    #endregion
  }
}


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

   	<title>Light mouse navigation</title>

		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<link rel="stylesheet" type="text/css" href="../../../codebase/dhtmlx.css"/>

Light mouse navigation

      You can enable/disable "light mouse navigation" mode

      The keyboard navigation can be disabled/enabled as well

            enable light mouse navigation

            disabel light mouse navigation

             enable hot keys

            disable hot keys


text:
#ifndef QSSLERROR_H
#define QSSLERROR_H

#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/qvariant.h>
#include <QtNetwork/qsslcertificate.h>

QT_BEGIN_NAMESPACE

#ifndef QT_NO_SSL

class QSslErrorPrivate;
class Q_NETWORK_EXPORT QSslError
{
public:
    enum SslError {
        NoError,
        UnableToGetIssuerCertificate,
        UnableToDecryptCertificateSignature,
        UnableToDecodeIssuerPublicKey,
        CertificateSignatureFailed,
        CertificateNotYetValid,
        CertificateExpired,
        InvalidNotBeforeField,
        InvalidNotAfterField,
        SelfSignedCertificate,
        SelfSignedCertificateInChain,
        UnableToGetLocalIssuerCertificate,
        UnableToVerifyFirstCertificate,
        CertificateRevoked,
        InvalidCaCertificate,
        PathLengthExceeded,
        InvalidPurpose,
        CertificateUntrusted,
        CertificateRejected,
        SubjectIssuerMismatch, // hostname mismatch?
        AuthorityIssuerSerialNumberMismatch,
        NoPeerCertificate,
        HostNameMismatch,
        NoSslSupport,
        CertificateBlacklisted,
        UnspecifiedError = -1
    };

    // RVCT compiler in debug build does not like about default values in const-
    // So as an workaround we define all constructor overloads here explicitly
    QSslError();
    QSslError(SslError error);
    QSslError(SslError error, const QSslCertificate &certificate);

    QSslError(const QSslError &other);

    void swap(QSslError &other) Q_DECL_NOTHROW
    { qSwap(d, other.d); }

    ~QSslError();
#ifdef Q_COMPILER_RVALUE_REFS
    QSslError &operator=(QSslError &&other) Q_DECL_NOTHROW { swap(other); return *this; }
#endif
    QSslError &operator=(const QSslError &other);
    bool operator==(const QSslError &other) const;
    inline bool operator!=(const QSslError &other) const
    { return !(*this == other); }

    SslError error() const;
    QString errorString() const;
    QSslCertificate certificate() const;

private:
    QScopedPointer<QSslErrorPrivate> d;
};
Q_DECLARE_SHARED(QSslError)

Q_NETWORK_EXPORT uint qHash(const QSslError &key, uint seed = 0) Q_DECL_NOTHROW;

#ifndef QT_NO_DEBUG_STREAM
class QDebug;
Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslError &error);
Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslError::SslError &error);
#endif

#endif // QT_NO_SSL

QT_END_NAMESPACE

#ifndef QT_NO_SSL
Q_DECLARE_METATYPE(QList<QSslError>)
#endif

#endif


text:
class TranslatedSortStyle < ActiveRecord::Base
  belongs_to :language
  belongs_to :sort_style

  attr_accessible :sort_style, :name, :language, :sort_style_id, :language_id
end


text:
struct cfunc_closure_data {
    CFUNC_TYPE_HEADER

	mrb_state *mrb;

    ffi_closure *closure;
    ffi_cif *cif;

    int argc;
    mrb_value *arg_types;
    ffi_type **arg_ffi_types;
    mrb_value return_type;

    void *closure_pointer;
};

#define cfunc_closure_data_pointer(mrb, val) \
    cfunc_pointer_ptr(val)

void init_cfunc_closure(mrb_state *mrb, struct RClass* module);

mrb_value cfunc_closure_new(mrb_state *mrb, mrb_value self);
mrb_value cfunc_closure_to_pointer(mrb_state *mrb, mrb_value self);

void cfunc_closure_call_binding(ffi_cif *cif, void *ret, void **args, void *self_);

#endif


text:
<?php

namespace Sistema\Bundle\FrontendBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Sistema\Bundle\FrontendBundle\Form\DataTransformer\ClienteToNumberTransformer;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class ClienteSelectorType extends AbstractType
{
    /**
     * @var ObjectManager
     */
    private $om;

    /**
     * @param ObjectManager $om
     */
    public function __construct(ObjectManager $om)
    {
        $this->om = $om;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $transformer = new ClienteToNumberTransformer($this->om);
        $builder->addModelTransformer($transformer);
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'invalid_message' => 'El Cliente no existe',
        ));
    }

    public function getParent()
    {
        return 'text';
    }

    public function getName()
    {
        return 'cliente_selector';
    }
}
?>


text:
name              "nominatim"
maintainer        "OpenStreetMap Administrators"
maintainer_email  "admins@openstreetmap.org"
license           "Apache-2.0"
description       "Installs and configures nominatim servers"

version           "1.0.0"
supports          "ubuntu"
depends           "accounts"
depends           "fail2ban"
depends           "git"
depends           "munin"
depends           "nginx"
depends           "php"
depends           "postgresql"
depends           "prometheus"
depends           "python"
depends           "systemd"


text:
package com.madeye.notify;

import com.skype.*;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class SkypeNotifyMyAndroid {

    private enum NotificationType { Status, Message }

//    private static final Logger LOG = Logger.getLogger(SkypeNotifyMyAndroid.class.getName());

    private static final Logger LOG = LoggerFactory.getLogger(SkypeNotifyMyAndroid.class);

    private static final String PROP_APIKEY = "nma.apikey";
    private static final String PROP_APPLICATION = "nma.application_name";
    private static final String PROP_BASE_URL = "nma.base_url";
    private static final String PROP_PRIORITY_BASE = "nma.priority.";
    private static final String PROP_USER_BASE = "nma.users.";

    private static final int DEFAULT_PRIORITY = -100;

    private String apiKey;
    private String application;
    private URI baseUri;

    private Map<NotificationType, Integer> priorityMap = new HashMap<NotificationType, Integer>();
    private Map<String, Integer> userPriorityBoost = new HashMap<String, Integer>();

    private Properties configuration;

    static {
    }

    private class UserStatusListener extends UserListenerAdapter {
        @Override
        public void statusMonitor(User.Status status, User user) throws SkypeException {
            String userId = user.toString();
            String displayName = user.getFullName();

            displayName = StringUtils.isBlank(displayName) ? userId : displayName;

            String statusStr = status.toString();

            try {
                LOG.info(displayName + ": " + statusStr);

                sendNmaNotification(NotificationType.Status, userId, displayName, "Status: " + statusStr);
            } catch (NotificationFailedException e) {
                LOG.warn("Failed to Notify My Android", e);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        final SkypeNotifyMyAndroid nma;

        LOG.info("Skype Notify My Android running");

        if (args.length > 0){
            nma = new SkypeNotifyMyAndroid(args[0]);
        } else {
            nma = new SkypeNotifyMyAndroid();
        }

        Skype.setDaemon(false); // to prevent exiting from this program
        Skype.addChatMessageListener(new ChatMessageAdapter() {
            public void chatMessageReceived(ChatMessage received) throws SkypeException {
                String content = received.getContent();
                String sender = received.getSenderDisplayName();
                String userId = received.getId();
                ChatMessage.Status status = received.getStatus();

                LOG.info("From " + sender + ": " + content + " (" + status.name() + ", " + received.getTime() + ", " + received.getType().name() + ")");
                if (status == ChatMessage.Status.RECEIVED){
                    try {
                        nma.sendNmaNotification(NotificationType.Message, userId, sender, content);
                    } catch (NotificationFailedException e) {
                        LOG.warn("Failed to Notify My Android", e);
                    }
                }
            }
        });
        Skype.addUserListener(nma.createUserStatusListener());
    }

    public SkypeNotifyMyAndroid() throws NotificationException {
        this(null);
    }

    public SkypeNotifyMyAndroid(String configFile) throws NotificationException {

        try {
            this.configuration = loadProperties(configFile);

            this.apiKey = getProperty(PROP_APIKEY);
            String baseUrl = getProperty(PROP_BASE_URL);
            this.application = getProperty(PROP_APPLICATION);

            if (StringUtils.isBlank(this.apiKey)){
                throw new NotificationException("No API key supplied");
            }

            for (NotificationType ntype : NotificationType.values()){
                String propName = PROP_PRIORITY_BASE + ntype.name();
                String propValueStr = getProperty(propName);
                int propValue;

                propValue = StringUtils.isBlank(propValueStr) ? DEFAULT_PRIORITY : Integer.parseInt(propValueStr);

                this.priorityMap.put(ntype, propValue);
            }

            this.userPriorityBoost = getUserPriorityBoost(this.configuration);

            this.baseUri = new URI(baseUrl);
        } catch (IOException e) {
            throw new RuntimeException("Failed to load configuration properties");
        } catch (URISyntaxException e) {
            throw new RuntimeException("Failed to parse URI for SkypeNotifyMyAndroid");
        }
    }

    private Map<String, Integer> getUserPriorityBoost(Properties config) throws IOException {
        Map<String, Integer> boostMap = new HashMap<String, Integer>();

        for (String propertyName : config.stringPropertyNames()){
            if (propertyName.startsWith(PROP_USER_BASE)){
                String name = propertyName.substring(PROP_USER_BASE.length());
                String valueStr = config.getProperty(propertyName);

                if (StringUtils.isBlank(valueStr) == false){
                    int value = Integer.parseInt(valueStr);

                    boostMap.put(name, value);
                }
            }
        }

        return boostMap;
    }

    private UserStatusListener createUserStatusListener(){
        return new UserStatusListener();
    }

    private int getPriority(NotificationType type, String userId){
        Integer priority = this.priorityMap.get(type);

        if (priority == null){
            priority = DEFAULT_PRIORITY;
        }

        Integer userBoost = this.userPriorityBoost.get(userId);

        if (userBoost != null){
            priority += userBoost;
        }

        return priority;
    }

    private Properties loadProperties(String externalFile) throws IOException {
        Properties props = new Properties();
        InputStream is =  SkypeNotifyMyAndroid.class.getResourceAsStream("/notifymyandroid.properties");
        props.load(is);
        is.close();

        BufferedReader reader = new BufferedReader(new FileReader(externalFile));
        props.load(reader);
        reader.close();

        return props;
    }

    private String getProperty(String propertyName){
        String prop = System.getProperty(propertyName);

        if (this.configuration != null && StringUtils.isBlank(prop)){
            prop = this.configuration.getProperty(propertyName);
        }

        return prop;
    }

    private void sendNmaNotification(NotificationType type, String userId, String name, String content) throws NotificationFailedException {
        URIBuilder builder = new URIBuilder(this.baseUri);

        int priority = getPriority(type, userId);

        if (priority >= -2){
            if (priority > 2){
                priority = 2;
            }

            builder.addParameter("apikey", this.apiKey);
            builder.addParameter("application", this.application);
            builder.addParameter("event", name);
            builder.addParameter("description", content);
            builder.addParameter("priority", Integer.toString(priority));

            CloseableHttpResponse response = null;

            try {
                CloseableHttpClient httpclient = HttpClients.createDefault();

                URI uri = builder.build();

                LOG.debug("URI: " + uri);

                HttpGet get = new HttpGet(uri);

                response = httpclient.execute(get);

                StatusLine status = response.getStatusLine();

                int statusCode = status.getStatusCode();

                HttpEntity entity1 = response.getEntity();
                EntityUtils.consume(entity1);

                if (statusCode != 200){
                    throw new NotificationFailedException("Failed to call SkypeNotifyMyAndroid REST API - status code: " + statusCode);
                }
            } catch (IOException e) {
                throw new NotificationFailedException("Failed to call SkypeNotifyMyAndroid REST API", e);
            } catch (URISyntaxException e) {
                throw new NotificationFailedException("Failed to build URI for SkypeNotifyMyAndroid", e);
            } finally {
                if (response != null){
                    try {
                        response.close();
                    } catch (IOException e) {
                        LOG.error("Failed to close HTTP connection to SkypeNotifyMyAndroid", e);
                    }
                }
            }
        }
    }
}


text:
/**
 * File SolverRunner.java
 *
 * This file is part of the jCoCoA project 2014.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.anon.cocoa.solvers;

import org.anon.cocoa.agents.Agent;
import org.anon.cocoa.messages.HashMessage;
import org.anon.cocoa.messages.Message;
import org.anon.cocoa.variables.Variable;

/**
 * SolverRunner
 *
 * Wrapper for around a solver to make it run asynchronously
 *
 * @author Anomymous
 * @version 0.1
 * @since 4 apr. 2014
 *
 */
public class RootedIterativeSolverWrapper<T extends Variable<V>, V> extends AbstractSolver<T, V>
        implements IterativeSolver {

    private static final String INIT_NEXT = "ROOTED_ITER_SOLVER:INIT_NEXT";
    private static final String TICK_NEXT = "ROOTED_ITER_SOLVER:TICK_NEXT";
    private static final String COUNTFIELD = "currentCount";

    private final IterativeSolver wrappedSolver;
    private int counter;

    /**
     *
     */
    public RootedIterativeSolverWrapper(final Agent<T, V> agent, final IterativeSolver solver) {
        super(agent);
        this.wrappedSolver = solver;
        this.counter = 0;
    }

    @Override
    public void init() {
        if (this.isRoot()) {
            this.wrappedSolver.init();

            this.counter++;
            final Message initMessage = new HashMessage(this.myVariable.getID(),
                    RootedIterativeSolverWrapper.INIT_NEXT);
            initMessage.put(RootedIterativeSolverWrapper.COUNTFIELD, this.counter);
            super.sendToNeighbors(initMessage);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.anon.cocoa.solvers.Solver#push(org.anon.cocoa.messages.Message)
     */
    @Override
    public synchronized void push(final Message m) {
        if (m.containsKey(RootedIterativeSolverWrapper.COUNTFIELD)) {
            final int mcount = (int) m.get(RootedIterativeSolverWrapper.COUNTFIELD);
            if (mcount > this.counter) {
                this.counter = mcount;
            } else {
                return; // Ignore the entire message
            }
        }

        if (m.getType().equals(RootedIterativeSolverWrapper.INIT_NEXT)) {
            this.wrappedSolver.init();
            super.sendToNeighbors(m); // Forward the message (the source will not be correct, but whatever...)
        } else if (m.getType().equals(RootedIterativeSolverWrapper.TICK_NEXT)) {
            this.wrappedSolver.tick();
            super.sendToNeighbors(m);
        } else {
            // Act as if we were not here...
            this.wrappedSolver.push(m);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.anon.cocoa.solvers.IterativeSolver#tick()
     */
    @Override
    public void tick() {
        if (this.isRoot()) {
            this.wrappedSolver.tick();

            this.counter++;
            final Message tickMessage = new HashMessage(this.myVariable.getID(),
                    RootedIterativeSolverWrapper.TICK_NEXT);
            tickMessage.put(RootedIterativeSolverWrapper.COUNTFIELD, this.counter);
            super.sendToNeighbors(tickMessage);
        }
    }

    protected boolean isRoot() {
        return this.parent.has(CoCoSolver.ROOTNAME_PROPERTY) && (Boolean) this.parent.get(CoCoSolver.ROOTNAME_PROPERTY);
    }

    @Override
    public void reset() {
        super.reset();
        this.wrappedSolver.reset();
        this.counter = 0;
    }

}


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

package com.google.gwtjsonrpc.client.impl.ser;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsonUtils;
import com.google.gwtjsonrpc.client.impl.JsonSerializer;

public class PrimitiveArraySerializer {
  public static final PrimitiveArraySerializer INSTANCE = new PrimitiveArraySerializer();

  private void printJsonWithToString(final StringBuilder sb, final Object[] o) {
    sb.append('[');
    for (int i = 0, n = o.length; i < n; i++) {
      if (i > 0) {
        sb.append(',');
      }
      sb.append(o[i] != null ? o[i].toString() : JsonSerializer.JS_NULL);
    }
    sb.append(']');
  }

  // Serialisation of Boxed Primitives
  public void printJson(final StringBuilder sb, final Boolean[] o) {
    printJsonWithToString(sb, o);
  }

  public void printJson(final StringBuilder sb, final Byte[] o) {
    printJsonWithToString(sb, o);
  }

  public void printJson(final StringBuilder sb, final Character[] o) {
    sb.append('[');
    for (int i = 0, n = o.length; i < n; i++) {
      if (i > 0) {
        sb.append(',');
      }
      if (o[i] != null) {
        sb.append(JsonUtils.escapeValue(String.valueOf(o[i])));
      } else sb.append(JsonSerializer.JS_NULL);
    }
    sb.append(']');
  }

  public void printJson(final StringBuilder sb, final Double[] o) {
    printJsonWithToString(sb, o);
  }

  public void printJson(final StringBuilder sb, final Float[] o) {
    printJsonWithToString(sb, o);
  }

  public void printJson(final StringBuilder sb, final Integer[] o) {
    printJsonWithToString(sb, o);
  }

  public void printJson(final StringBuilder sb, final Short[] o) {
    printJsonWithToString(sb, o);
  }

  // Serialisation of Primitives
  public void printJson(final StringBuilder sb, final boolean[] o) {
    sb.append('[');
    for (int i = 0, n = o.length; i < n; i++) {
      if (i > 0) {
        sb.append(',');
      }
      sb.append(o[i]);
    }
    sb.append(']');
  }

  public void printJson(final StringBuilder sb, final byte[] o) {
    sb.append('[');
    for (int i = 0, n = o.length; i < n; i++) {
      if (i > 0) {
        sb.append(',');
      }
      sb.append(o[i]);
    }
    sb.append(']');
  }

  public void printJson(final StringBuilder sb, final char[] o) {
    sb.append('[');
    for (int i = 0, n = o.length; i < n; i++) {
      if (i > 0) {
        sb.append(',');
      }
      sb.append(o[i]);
    }
    sb.append(']');
  }

  public void printJson(final StringBuilder sb, final double[] o) {
    sb.append('[');
    for (int i = 0, n = o.length; i < n; i++) {
      if (i > 0) {
        sb.append(',');
      }
      sb.append(o[i]);
    }
    sb.append(']');
  }

  public void printJson(final StringBuilder sb, final float[] o) {
    sb.append('[');
    for (int i = 0, n = o.length; i < n; i++) {
      if (i > 0) {
        sb.append(',');
      }
      sb.append(o[i]);
    }
    sb.append(']');
  }

  public void printJson(final StringBuilder sb, final int[] o) {
    sb.append('[');
    for (int i = 0, n = o.length; i < n; i++) {
      if (i > 0) {
        sb.append(',');
      }
      sb.append(o[i]);
    }
    sb.append(']');
  }

  public void printJson(final StringBuilder sb, final short[] o) {
    sb.append('[');
    for (int i = 0, n = o.length; i < n; i++) {
      if (i > 0) {
        sb.append(',');
      }
      sb.append(o[i]);
    }
    sb.append(']');
  }

  // DeSerialisation native getters
  private static final native boolean getBoolean(JavaScriptObject jso, int pos)
      /*-{ return jso[pos]; }-*/ ;

  private static final native byte getByte(JavaScriptObject jso, int pos)
      /*-{ return jso[pos]; }-*/ ;

  private static final native String getString(JavaScriptObject jso, int pos)
      /*-{ return jso[pos]; }-*/ ;

  private static final native double getDouble(JavaScriptObject jso, int pos)
      /*-{ return jso[pos]; }-*/ ;

  private static final native float getFloat(JavaScriptObject jso, int pos)
      /*-{ return jso[pos]; }-*/ ;

  private static final native int getInteger(JavaScriptObject jso, int pos)
      /*-{ return jso[pos]; }-*/ ;

  private static final native short getShort(JavaScriptObject jso, int pos)
      /*-{ return jso[pos]; }-*/ ;

  // DeSerialisation of boxed primitive arrays
  public void fromJson(final JavaScriptObject jso, final Boolean[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getBoolean(jso, i);
    }
  }

  public void fromJson(final JavaScriptObject jso, final Byte[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getByte(jso, i);
    }
  }

  public void fromJson(final JavaScriptObject jso, final Character[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = JsonSerializer.toChar(getString(jso, i));
    }
  }

  public void fromJson(final JavaScriptObject jso, final Double[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getDouble(jso, i);
    }
  }

  public void fromJson(final JavaScriptObject jso, final Float[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getFloat(jso, i);
    }
  }

  public void fromJson(final JavaScriptObject jso, final Integer[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getInteger(jso, i);
    }
  }

  public void fromJson(final JavaScriptObject jso, final Short[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getShort(jso, i);
    }
  }

  // DeSerialisation of primitive arrays
  public void fromJson(final JavaScriptObject jso, final boolean[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getBoolean(jso, i);
    }
  }

  public void fromJson(final JavaScriptObject jso, final byte[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getByte(jso, i);
    }
  }

  public void fromJson(final JavaScriptObject jso, final char[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = JsonSerializer.toChar(getString(jso, i));
    }
  }

  public void fromJson(final JavaScriptObject jso, final double[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getDouble(jso, i);
    }
  }

  public void fromJson(final JavaScriptObject jso, final float[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getFloat(jso, i);
    }
  }

  public void fromJson(final JavaScriptObject jso, final int[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getInteger(jso, i);
    }
  }

  public void fromJson(final JavaScriptObject jso, final short[] r) {
    for (int i = 0; i < r.length; i++) {
      r[i] = getShort(jso, i);
    }
  }
}


text:
#ifndef TENSORFLOW_LITE_DELEGATES_GPU_COMMON_GPU_INFO_H_
#define TENSORFLOW_LITE_DELEGATES_GPU_COMMON_GPU_INFO_H_

#include <string>
#include <vector>

#include "tensorflow/lite/delegates/gpu/common/data_type.h"

namespace tflite {
namespace gpu {

// The VendorID returned by the GPU driver.
enum class GpuVendor {
  kApple,
  kQualcomm,
  kMali,
  kPowerVR,
  kNvidia,
  kAMD,
  kIntel,
  kUnknown
};

enum class GpuApi {
  kUnknown,
  kOpenCl,
  kMetal,
  kVulkan,
  kOpenGl,
};

enum class AdrenoGpu {
  // Adreno 6xx series
  kAdreno685,
  kAdreno680,
  kAdreno675,
  kAdreno650,
  kAdreno640,
  kAdreno630,
  kAdreno620,
  kAdreno618,
  kAdreno616,
  kAdreno615,
  kAdreno612,
  kAdreno610,
  kAdreno605,
  // Adreno 5xx series
  kAdreno540,
  kAdreno530,
  kAdreno512,
  kAdreno510,
  kAdreno509,
  kAdreno508,
  kAdreno506,
  kAdreno505,
  kAdreno504,
  // Adreno 4xx series
  kAdreno430,
  kAdreno420,
  kAdreno418,
  kAdreno405,
  // Adreno 3xx series
  kAdreno330,
  kAdreno320,
  kAdreno308,
  kAdreno306,
  kAdreno305,
  kAdreno304,
  // Adreno 2xx series
  kAdreno225,
  kAdreno220,
  kAdreno205,
  kAdreno203,
  kAdreno200,
  // Adreno 1xx series
  kAdreno130,
  kAdreno120,
  kUnknown
};

struct AdrenoInfo {
  AdrenoInfo() = default;
  explicit AdrenoInfo(const std::string& device_version);

  AdrenoGpu adreno_gpu;

  bool IsAdreno1xx() const;
  bool IsAdreno2xx() const;
  bool IsAdreno3xx() const;
  bool IsAdreno4xx() const;
  bool IsAdreno5xx() const;
  bool IsAdreno6xx() const;
  bool IsAdreno6xxOrHigher() const;

  // This function returns some not very documented physical parameter of
  // Adreno6xx GPU.
  // We obtained it using Snapdragon Profiler.
  int GetMaximumWavesCount() const;

  // returns amount of register memory per CU(Compute Unit) in bytes.
  int GetRegisterMemorySizePerComputeUnit() const;

  // returns maximum possible amount of waves based on register usage.
  int GetMaximumWavesCount(int register_footprint_per_tread,
                           bool full_wave = true) const;

  int GetWaveSize(bool full_wave) const;

  // Not supported on some Adreno devices with specific driver version.
  // b/131099086
  bool support_one_layer_texture_array = true;
};

enum class AppleGpu {
  kUnknown,
  kA7,
  kA8,
  kA8X,
  kA9,
  kA9X,
  kA10,
  kA10X,
  kA11,
  kA12,
  kA12X,
  kA12Z,
  kA13,
  kA14,
};

struct AppleInfo {
  AppleInfo() = default;
  explicit AppleInfo(const std::string& gpu_description);
  AppleGpu gpu_type;

  bool IsLocalMemoryPreferredOverGlobal() const;

  bool IsBionic() const;

  // floating point rounding mode
  bool IsRoundToNearestSupported() const;

  int GetComputeUnitsCount() const;
};

enum class MaliGpu {
  kUnknown,
  kT604,
  kT622,
  kT624,
  kT628,
  kT658,
  kT678,
  kT720,
  kT760,
  kT820,
  kT830,
  kT860,
  kT880,
  kG31,
  kG51,
  kG71,
  kG52,
  kG72,
  kG76,
  kG57,
  kG77,
  kG68,
  kG78,
};

struct MaliInfo {
  MaliInfo() = default;
  explicit MaliInfo(const std::string& gpu_description);
  MaliGpu gpu_version;

  bool IsMaliT6xx() const;
  bool IsMaliT7xx() const;
  bool IsMaliT8xx() const;
  bool IsMidgard() const;
  bool IsBifrostGen1() const;
  bool IsBifrostGen2() const;
  bool IsBifrostGen3() const;
  bool IsBifrost() const;
  bool IsValhall() const;
};

struct OpenGlInfo {
  std::string renderer_name;
  std::string vendor_name;
  std::string version;
  int major_version = -1;
  int minor_version = -1;

  int max_image_units = 0;
  int max_ssbo_bindings = 0;
  int max_image_bindings = 0;
  int max_work_group_invocations = 0;
  int max_texture_size = 0;
  int max_array_texture_layers = 0;

  std::vector<std::string> extensions;
  int max_compute_work_group_size_x;
  int max_compute_work_group_size_y;
  int max_compute_work_group_size_z;
};

struct VulkanInfo {
  std::string vendor_name;
  uint32_t api_version = -1;
  uint32_t api_version_major = -1;
  uint32_t api_version_minor = -1;
  uint32_t api_version_patch = -1;

  uint32_t max_per_stage_descriptor_sampled_images = 0;
  uint32_t max_compute_work_group_invocations;
  uint32_t max_image_dimension_2d;
  uint32_t max_image_array_layers;

  std::vector<std::string> extensions;
  int max_compute_work_group_size_x;
  int max_compute_work_group_size_y;
  int max_compute_work_group_size_z;
};

enum class OpenClVersion {
  kCl1_0,
  kCl1_1,
  kCl1_2,
  kCl2_0,
  kCl2_1,
  kCl2_2,
  kCl3_0,
  kUnknown,
};
std::string OpenClVersionToString(OpenClVersion version);

struct OpenClInfo {
  OpenClVersion cl_version;

  std::vector<std::string> extensions;
  bool supports_fp16;
  bool supports_image3d_writes;
  int compute_units_count;
  uint64_t buffer_max_size;
  uint64_t image2d_max_width;
  uint64_t image2d_max_height;
  uint64_t image_buffer_max_size;
  uint64_t image_array_max_layers;
  uint64_t image3d_max_width;
  uint64_t image3d_max_height;
  uint64_t image3d_max_depth;
  int max_work_group_size_x;
  int max_work_group_size_y;
  int max_work_group_size_z;
  int max_work_group_total_size;

  // rtn is ROUND_TO_NEAREST
  // with rtn precision is much better then with rtz (ROUND_TO_ZERO)
  // Adreno 3xx supports only rtz, Adreno 4xx and more support rtn
  // Mali from T6xx supports rtn
  // PowerVR supports only rtz
  bool supports_fp32_rtn;
  bool supports_fp16_rtn;

  bool supports_r_f16_tex2d = false;
  bool supports_rg_f16_tex2d = false;
  bool supports_rgb_f16_tex2d = false;
  bool supports_rgba_f16_tex2d = false;

  bool supports_r_f32_tex2d = false;
  bool supports_rg_f32_tex2d = false;
  bool supports_rgb_f32_tex2d = false;
  bool supports_rgba_f32_tex2d = false;
};

struct GpuInfo {
  bool IsAdreno() const;
  bool IsApple() const;
  bool IsMali() const;
  bool IsPowerVR() const;
  bool IsNvidia() const;
  bool IsAMD() const;
  bool IsIntel() const;

  // floating point rounding mode
  bool IsRoundToNearestSupported() const;

  bool SupportsFP16() const;

  bool SupportsTextureArray() const;
  bool SupportsImageBuffer() const;
  bool SupportsImage3D() const;

  // returns true if device have fixed wave size equal to 32
  bool IsWaveSizeEqualTo32() const;
  bool SupportsSubGroupWithSize(int sub_group_size) const;

  bool SupportsFloatImage2D(DataType data_type, int channels) const;
  bool SupportsExtension(const std::string& extension) const;

  int GetComputeUnitsCount() const;

  int GetMaxImageArguments() const;

  int GetMaxWorkGroupSizeForX() const;
  int GetMaxWorkGroupSizeForY() const;
  int GetMaxWorkGroupSizeForZ() const;
  int GetMaxWorkGroupTotalSize() const;

  uint64_t GetMaxImage2DWidth() const;
  uint64_t GetMaxImage2DHeight() const;
  uint64_t GetMaxImage2DArrayLayers() const;
  uint64_t GetMaxImage3DWidth() const;
  uint64_t GetMaxImage3DHeight() const;
  uint64_t GetMaxImage3DDepth() const;
  uint64_t GetMaxBufferSize() const;
  uint64_t GetMaxImageBufferWidth() const;

  GpuVendor vendor = GpuVendor::kUnknown;
  GpuApi gpu_api = GpuApi::kUnknown;

  std::vector<int> supported_subgroup_sizes;

  AdrenoInfo adreno_info;
  AppleInfo apple_info;
  MaliInfo mali_info;

  // OpenGL specific, gpu_api should be kOpenGl
  OpenGlInfo opengl_info;
  bool IsApiOpenGl() const;
  bool IsApiOpenGl31OrAbove() const;

  // Vulkan specific, gpu_api should be kVulkan
  VulkanInfo vulkan_info;
  bool IsApiVulkan() const;

  bool IsApiMetal() const;

  OpenClInfo opencl_info;
  bool IsApiOpenCl() const;
  bool IsCL20OrHigher() const;
  bool IsCL30OrHigher() const;
};

// Currently it initializes:
// vendor
// AdrenoInfo if vendor is kQualcomm
// AppleInfo if vendor is kApple
// MaliInfo if vendor is kMali
void GetGpuInfoFromDeviceDescription(const std::string& gpu_description,
                                     GpuApi gpu_api, GpuInfo* gpu_info);

}  // namespace gpu
}  // namespace tflite

#endif  // TENSORFLOW_LITE_DELEGATES_GPU_COMMON_GPU_INFO_H_


text:
'''Script to import/export all the skeleton related objects.'''

# ***** BEGIN LICENSE BLOCK *****
#
# Copyright © 2005-2015, NIF File Format Library and Tools contributors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#
#    * Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials provided
#      with the distribution.
#
#    * Neither the name of the NIF File Format Library and Tools
#      project nor the names of its contributors may be used to endorse
#      or promote products derived from this software without specific
#      prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# ***** END LICENSE BLOCK *****

import bpy
import mathutils
from io_scene_nif.utility import nif_utils
from io_scene_nif.utility.nif_logging import NifLog

from pyffi.formats.nif import NifFormat

class Armature():

    def __init__(self, parent):
        self.nif_export = parent

    def rebuild_bones_extra_matrices(self):
        """Recover bone extra matrices."""

        try:
            bonetxt = bpy.data.texts["BoneExMat"]
        except KeyError:
            return
        # Blender bone names are unique so we can use them as keys.
        for b_textline in bonetxt.lines:
            line = b_textline.body
            if len(line) > 0:
                # reconstruct matrix from text
                b, m = line.split('/')
                try:
                    matrix = mathutils.Matrix(
                        [[float(f) for f in row.split(',')]
                         for row in m.split(';')])
                except:
                    raise nif_utils.NifError('Syntax error in BoneExMat buffer.')
                # Check if matrices are clean, and if necessary fix them.
                quat = matrix.to_3x3().to_quaternion()
                if sum(sum(abs(x) for x in vec)
                       for vec in matrix.to_3x3() - quat.to_matrix()) > 0.01:
                    NifLog.warn("Bad bone extra matrix for bone {0}.\n"
                                   "Attempting to fix... but bone transform may be incompatible with existing animations.".format(b))
                    NifLog.debug("Old invalid matrix:\n{0}".format(str(matrix)))
                    trans = matrix.to_translation()
                    matrix = quat.to_matrix().resize_4x4()
                    matrix[0][3] = trans[0]
                    matrix[1][3] = trans[1]
                    matrix[2][3] = trans[2]
                    NifLog.debug("New valid matrix:\n{0}".format(matrix))
                # Matrices are stored inverted for easier math later on.
                matrix.invert()
                self.set_bone_extra_matrix_inv(b, matrix)

    def set_bone_extra_matrix_inv(self, bone_name, matrix):
        """Set bone extra matrix, inverted. The bone_name is first converted
        to blender style (to ensure compatibility with older imports).
        """
        self.nif_export.dict_bones_extra_matrix_inv[self.nif_export.get_bone_name_for_blender(bone_name)] = matrix

    def get_bone_extra_matrix_inv(self, bone_name):
        """Get bone extra matrix, inverted. The bone_name is first converted
        to blender style (to ensure compatibility with older imports).
        """
        return self.nif_export.dict_bones_extra_matrix_inv[self.nif_export.get_bone_name_for_blender(bone_name)]

    def export_bones(self, arm, parent_block):
        """Export the bones of an armature."""
        # the armature was already exported as a NiNode
        # now we must export the armature's bones
        assert( arm.type == 'ARMATURE' )

        # find the root bones
        # dictionary of bones (name -> bone)
        bones = dict(list(arm.data.bones.items()))
        root_bones = []
        for root_bone in list(bones.values()):
            while root_bone.parent in list(bones.values()):
                root_bone = root_bone.parent
            if root_bones.count(root_bone) == 0:
                root_bones.append(root_bone)

        if bpy.types.Action(arm):
            bones_ipo = bpy.types.ActionGroups(arm) # dictionary of Bone Ipos (name -> ipo)
        else:
            bones_ipo = {} # no ipos

        bones_node = {} # maps bone names to NiNode blocks

        # here all the bones are added
        # first create all bones with their keyframes
        # and then fix the links in a second run

        # ok, let's create the bone NiNode blocks
        for bone in list(bones.values()):
            # create a new block for this bone
            node = self.nif_export.objecthelper.create_ninode(bone)
            # doing bone map now makes linkage very easy in second run
            bones_node[bone.name] = node

            # add the node and the keyframe for this bone
            node.name = self.nif_export.objecthelper.get_full_name(bone.name)

            if (bone.niftools_bone.boneflags != 0):
                node.flags = bone.niftools_bone.boneflags
            else:
                if NifOp.props.game in ('OBLIVION', 'FALLOUT_3', 'SKYRIM'):
                    # default for Oblivion bones
                    # note: bodies have 0x000E, clothing has 0x000F
                    node.flags = 0x000E
                elif NifOp.props.game in ('CIVILIZATION_IV', 'EMPIRE_EARTH_II'):
                    if bone.children:
                        # default for Civ IV/EE II bones with children
                        node.flags = 0x0006
                    else:
                        # default for Civ IV/EE II final bones
                        node.flags = 0x0016
                elif NifOp.props.game in ('DIVINITY_2',):
                    if bone.children:
                        # default for Div 2 bones with children
                        node.flags = 0x0186
                    elif bone.name.lower()[-9:] == 'footsteps':
                        node.flags = 0x0116
                    else:
                        # default for Div 2 final bones
                        node.flags = 0x0196
                else:
                    node.flags = 0x0002 # default for Morrowind bones

            self.nif_export.objecthelper.set_object_matrix(bone, 'localspace', node) # rest pose

            # bone rotations are stored in the IPO relative to the rest position
            # so we must take the rest position into account
            # (need original one, without extra transforms, so extra = False)
            bone_rest_matrix = self.get_bone_rest_matrix(bone, 'BONESPACE',
                                                    extra = False)
            try:
                bonexmat_inv = mathutils.Matrix(
                    self.get_bone_extra_matrix_inv(bone.name))
            except KeyError:
                bonexmat_inv = mathutils.Matrix()
                bonexmat_inv.identity()
            if bone.name in bones_ipo:
                self.nif_export.animationhelper.export_keyframes(
                    bones_ipo[bone.name], 'localspace', node,
                    bind_matrix = bone_rest_matrix, extra_mat_inv = bonexmat_inv)

            # does bone have priority value in NULL constraint?
            for constr in arm.pose.bones[bone.name].constraints:
                # yes! store it for reference when creating the kf file
                if constr.name[:9].lower() == "priority:":
                    self.nif_export.dict_bone_priorities[
                        self.get_bone_name_for_nif(bone.name)
                        ] = int(constr.name[9:])

        # now fix the linkage between the blocks
        for bone in list(bones.values()):
            # link the bone's children to the bone
            if bone.children:
                NifLog.debug("Linking children of bone {0}".format(bone.name))
                for child in bone.children:
                    # bone.children returns also grandchildren etc.
                    # we only want immediate children, so do a parent check
                    if child.parent.name == bone.name:
                        bones_node[bone.name].add_child(bones_node[child.name])
            # if it is a root bone, link it to the armature
            if not bone.parent:
                parent_block.add_child(bones_node[bone.name])

    def export_children(self, b_obj, parent_block):
        """Export all children of blender object b_obj as children of
        parent_block."""
        # loop over all obj's children
        for b_obj_child in b_obj.children:
            # is it a regular node?
            if b_obj_child.type in ['MESH', 'EMPTY', 'ARMATURE']:
                if (b_obj.type != 'ARMATURE'):
                    # not parented to an armature
                    self.nif_export.objecthelper.export_node(b_obj_child, 'localspace',
                                     parent_block, b_obj_child.name)
                else:
                    # this object is parented to an armature
                    # we should check whether it is really parented to the
                    # armature using vertex weights
                    # or whether it is parented to some bone of the armature
                    parent_bone_name = b_obj_child.parent_bone
                    if parent_bone_name == "":
                        self.nif_export.objecthelper.export_node(b_obj_child, 'localspace',
                                         parent_block, b_obj_child.name)
                    else:
                        # we should parent the object to the bone instead of
                        # to the armature
                        # so let's find that bone!
                        nif_bone_name = self.nif_export.objecthelper.get_full_name(parent_bone_name)
                        for bone_block in self.nif_export.dict_blocks:
                            if isinstance(bone_block, NifFormat.NiNode) and \
                                bone_block.name.decode() == nif_bone_name:
                                # ok, we should parent to block
                                # instead of to parent_block
                                # two problems to resolve:
                                #   - blender bone matrix is not the exported
                                #     bone matrix!
                                #   - blender objects parented to bone have
                                #     extra translation along the Y axis
                                #     with length of the bone ("tail")
                                # this is handled in the get_object_srt function
                                self.nif_export.objecthelper.export_node(b_obj_child, 'localspace',
                                                 bone_block, b_obj_child.name)
                                break
                        else:
                            assert(False) # BUG!

    def get_bone_rest_matrix(self, bone, space, extra = True, tail = False):
        """Get bone matrix in rest position ("bind pose"). Space can be
        ARMATURESPACE or BONESPACE. This returns also a 4x4 matrix if space
        is BONESPACE (translation is bone head plus tail from parent bone).
        If tail is True then the matrix translation includes the bone tail."""
        # Retrieves the offset from the original NIF matrix, if existing
        correction_matrix = mathutils.Matrix()
        if extra:
            try:
                correction_matrix = mathutils.Matrix(
                    self.get_bone_extra_matrix_inv(bone.name))
            except KeyError:
                correction_matrix.identity()
        else:
            correction_matrix.identity()
        if (space == 'ARMATURESPACE'):
            matrix = mathutils.Matrix(bone.matrix_local)
            if tail:
                tail_pos = bone.tail_local
                matrix[0][3] = tail_pos[0]
                matrix[1][3] = tail_pos[1]
                matrix[2][3] = tail_pos[2]
            return correction_matrix * matrix
        elif (space == 'BONESPACE'):
            if bone.parent:
                # not sure why extra = True is required here
                # but if extra = extra then transforms are messed up, so keep
                # for now
                parinv = self.get_bone_rest_matrix(bone.parent, 'ARMATURESPACE',
                                                   extra = True, tail = False)
                parinv.invert()
                return self.get_bone_rest_matrix(bone,
                                                 'ARMATURESPACE',
                                                 extra = extra,
                                                 tail = tail) * parinv
            else:
                return self.get_bone_rest_matrix(bone, 'ARMATURESPACE',
                                                 extra = extra, tail = tail)
        else:
            assert(False) # bug!


text:
const float D3D12PipelineStateCache::IntermediateClearColor[4] = { 0.0f, 0.2f, 0.3f, 1.0f };

D3D12PipelineStateCache::D3D12PipelineStateCache(UINT width, UINT height, std::wstring name) :
	DXSample(width, height, name),
	m_psoLibrary(FrameCount, RootParameterUberShaderCB),
	m_frameIndex(0),
	m_swapChainEvent(0),
	m_drawIndex(0),
	m_maxDrawsPerFrame(256),
	m_dynamicCB(sizeof(DrawConstantBuffer), m_maxDrawsPerFrame, FrameCount),
	m_viewport(),
	m_scissorRect(),
	m_rtvDescriptorSize(0),
	m_srvDescriptorSize(0)
{
	ZeroMemory(m_fenceValues, sizeof(m_fenceValues));
	memset(m_enabledEffects, true, sizeof(m_enabledEffects));

	m_viewport.Width = static_cast<float>(width);
	m_viewport.Height = static_cast<float>(height);
	m_viewport.MaxDepth = 1.0f;

	m_scissorRect.right = static_cast<LONG>(width);
	m_scissorRect.bottom = static_cast<LONG>(height);
}

void D3D12PipelineStateCache::OnInit()
{
	UpdateWindowTextPso();
	m_camera.Init({ 0.0f, 0.0f, 5.0f });
	m_camera.SetMoveSpeed(1.0f);

	m_projectionMatrix = m_camera.GetProjectionMatrix(0.8f, m_aspectRatio);

	LoadPipeline();
	LoadAssets();
}

// Load the rendering pipeline dependencies.
void D3D12PipelineStateCache::LoadPipeline()
{
#ifdef _DEBUG
	// Enable the D3D12 debug layer.
	{
		ComPtr<ID3D12Debug> debugController;
		if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
		{
			debugController->EnableDebugLayer();
		}
	}
#endif

	ComPtr<IDXGIFactory4> factory;
	ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&factory)));

	if (m_useWarpDevice)
	{
		ComPtr<IDXGIAdapter> warpAdapter;
		ThrowIfFailed(factory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter)));

		ThrowIfFailed(D3D12CreateDevice(
			warpAdapter.Get(),
			D3D_FEATURE_LEVEL_11_0,
			IID_PPV_ARGS(&m_device)
			));
	}
	else
	{
		ThrowIfFailed(D3D12CreateDevice(
			nullptr,
			D3D_FEATURE_LEVEL_11_0,
			IID_PPV_ARGS(&m_device)
			));
	}

	// Describe and create the command queue.
	D3D12_COMMAND_QUEUE_DESC queueDesc = {};
	queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
	queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;

	ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue)));

	// Describe and create the swap chain.
	DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
	swapChainDesc.BufferCount = FrameCount;
	swapChainDesc.BufferDesc.Width = m_width;
	swapChainDesc.BufferDesc.Height = m_height;
	swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
	swapChainDesc.OutputWindow = m_hwnd;
	swapChainDesc.SampleDesc.Count = 1;
	swapChainDesc.Windowed = TRUE;
	swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;

	ComPtr<IDXGISwapChain> swapChain;
	ThrowIfFailed(factory->CreateSwapChain(
		m_commandQueue.Get(),		// Swap chain needs the queue so that it can force a flush on it.
		&swapChainDesc,
		&swapChain
		));

	ThrowIfFailed(swapChain.As(&m_swapChain));

	m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
	m_swapChainEvent = m_swapChain->GetFrameLatencyWaitableObject();

	// Create descriptor heaps.
	{
		// Describe and create a render target view (RTV) descriptor heap.
		D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
		rtvHeapDesc.NumDescriptors = FrameCount + 1;	// A descriptor for each frame + 1 intermediate render target.
		rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
		rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
		ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap)));

		// Describe and create a shader resource view (SRV) descriptor heap.
		D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
		srvHeapDesc.NumDescriptors = 1;
		srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
		srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
		ThrowIfFailed(m_device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvHeap)));

		m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
		m_srvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
	}

	// Create frame resources.
	{
		CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());

		// Create RTVs and a command allocator for each frame.
		for (UINT n = 0; n < FrameCount; n++)
		{
			ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n])));

			// Create a RTV of the swap chain's back buffer.
			m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle);
			rtvHandle.Offset(1, m_rtvDescriptorSize);

			ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocators[n])));
		}

		D3D12_RESOURCE_DESC renderTargetDesc = m_renderTargets[0]->GetDesc();

		D3D12_CLEAR_VALUE clearValue = {};
		memcpy(clearValue.Color, IntermediateClearColor, sizeof(IntermediateClearColor));
		clearValue.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

		// Create an intermediate render target that is the same dimensions as the swap chain.
		ThrowIfFailed(m_device->CreateCommittedResource(
			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
			D3D12_HEAP_FLAG_NONE,
			&renderTargetDesc,
			D3D12_RESOURCE_STATE_RENDER_TARGET,
			&clearValue,
			IID_PPV_ARGS(&m_intermediateRenderTarget)));

		m_device->CreateRenderTargetView(m_intermediateRenderTarget.Get(), nullptr, rtvHandle);
		rtvHandle.Offset(1, m_rtvDescriptorSize);

		// Create a SRV of the intermediate render target.
		D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
		srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
		srvDesc.Format = renderTargetDesc.Format;
		srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
		srvDesc.Texture2D.MipLevels = 1;

		CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(m_srvHeap->GetCPUDescriptorHandleForHeapStart());
		m_device->CreateShaderResourceView(m_intermediateRenderTarget.Get(), &srvDesc, srvHandle);
	}
}

void D3D12PipelineStateCache::LoadAssets()
{
	// Create the root signature.
	{
		CD3DX12_DESCRIPTOR_RANGE ranges[RootParametersCount];
		ranges[RootParameterSRV].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);

		CD3DX12_ROOT_PARAMETER rootParameters[RootParametersCount];
		rootParameters[RootParameterUberShaderCB].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);
		rootParameters[RootParameterCB].InitAsConstantBufferView(1, 0, D3D12_SHADER_VISIBILITY_ALL);
		rootParameters[RootParameterSRV].InitAsDescriptorTable(1, &ranges[RootParameterSRV]);

		D3D12_STATIC_SAMPLER_DESC sampler = {};
		sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
		sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
		sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
		sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
		sampler.MipLODBias = 0;
		sampler.MaxAnisotropy = 0;
		sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
		sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
		sampler.MinLOD = 0.0f;
		sampler.MaxLOD = 9999.0f;
		sampler.ShaderRegister = 0;
		sampler.RegisterSpace = 0;
		sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;

		CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;
		rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

		ComPtr<ID3DBlob> signature;
		ComPtr<ID3DBlob> error;
		ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));
		ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));
	}

	// Create the command list.
	ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), nullptr, IID_PPV_ARGS(&m_commandList)));

	ComPtr<ID3D12Resource> vertexIndexBufferUpload;

	// Vertex and Index Buffer.
	{
		const VertexPositionColor cubeVertices[] = {
			{ { -1.0f, 1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } },	// Back Top Left
			{ { 1.0f, 1.0f, -1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } },	// Back Top Right
			{ { 1.0f, 1.0f, 1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } },	// Front Top Right
			{ { -1.0f, 1.0f, 1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } },	// Front Top Left

			{ { -1.0f, -1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } },	// Back Bottom Left
			{ { 1.0f, -1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } },	// Back Bottom Right
			{ { 1.0f, -1.0f, 1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } },	// Front Bottom Right
			{ { -1.0f, -1.0f, 1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } },	// Front Bottom Left
		};

		const UINT cubeIndices[] =
		{
			0, 1, 3,
			1, 2, 3,

			3, 2, 7,
			6, 7, 2,

			2, 1, 6,
			5, 6, 1,

			1, 0, 5,
			4, 5, 0,

			0, 3, 4,
			7, 4, 3,

			7, 6, 4,
			5, 4, 6,
		};

		static const VertexPositionUV quadVertices[] =
		{
			{ { -1.0f, -1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f } },	// Bottom Left
			{ { -1.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f } },	// Top Left
			{ { 1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f } },	// Bottom Right
			{ { 1.0f, 1.0f, 0.0f, 1.0f }, { 1.0f, 0.0f } },		// Top Right
		};

		const UINT vertexIndexBufferSize = sizeof(cubeIndices) + sizeof(cubeVertices) + sizeof(quadVertices);

		ThrowIfFailed(m_device->CreateCommittedResource(
			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
			D3D12_HEAP_FLAG_NONE,
			&CD3DX12_RESOURCE_DESC::Buffer(vertexIndexBufferSize),
			D3D12_RESOURCE_STATE_COPY_DEST,
			nullptr,
			IID_PPV_ARGS(&m_vertexIndexBuffer)));

		ThrowIfFailed(m_device->CreateCommittedResource(
			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
			D3D12_HEAP_FLAG_NONE,
			&CD3DX12_RESOURCE_DESC::Buffer(vertexIndexBufferSize),
			D3D12_RESOURCE_STATE_GENERIC_READ,
			nullptr,
			IID_PPV_ARGS(&vertexIndexBufferUpload)));

		UINT8* mappedUploadHeap = nullptr;
		ThrowIfFailed(vertexIndexBufferUpload->Map(0, nullptr, reinterpret_cast<void**>(&mappedUploadHeap)));

		// Fill in part of the upload heap with our index and vertex data.
		UINT8* heapLocation = static_cast<UINT8*>(mappedUploadHeap);
		memcpy(heapLocation, cubeVertices, sizeof(cubeVertices));
		heapLocation += sizeof(cubeVertices);
		memcpy(heapLocation, cubeIndices, sizeof(cubeIndices));
		heapLocation += sizeof(cubeIndices);
		memcpy(heapLocation, quadVertices, sizeof(quadVertices));

		// Pack the vertices and indices into their destination by copying from the upload heap.
		m_commandList->CopyBufferRegion(m_vertexIndexBuffer.Get(), 0, vertexIndexBufferUpload.Get(), 0, vertexIndexBufferSize);
		m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexIndexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER | D3D12_RESOURCE_STATE_INDEX_BUFFER));

		// Create the index and vertex buffer views.
		m_cubeVbv.BufferLocation = m_vertexIndexBuffer.Get()->GetGPUVirtualAddress();
		m_cubeVbv.SizeInBytes = sizeof(cubeVertices);
		m_cubeVbv.StrideInBytes = sizeof(VertexPositionColor);

		m_cubeIbv.BufferLocation = m_cubeVbv.BufferLocation + sizeof(cubeVertices);
		m_cubeIbv.SizeInBytes = sizeof(cubeIndices);
		m_cubeIbv.Format = DXGI_FORMAT_R32_UINT;

		m_quadVbv.BufferLocation = m_cubeIbv.BufferLocation + sizeof(cubeIndices);
		m_quadVbv.SizeInBytes = sizeof(quadVertices);
		m_quadVbv.StrideInBytes = sizeof(VertexPositionUV);
	}

	// Create the constant buffer.
	m_dynamicCB.Init(m_device.Get());

	// Close the command list and execute it to begin the vertex/index buffer copy
	// into the default heap.
	ThrowIfFailed(m_commandList->Close());
	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

	// Create synchronization objects and wait until assets have been uploaded to the GPU.
	{
		ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));
		m_fenceValues[m_frameIndex]++;

		// Create an event handle to use for frame synchronization.
		m_fenceEvent = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
		if (m_fenceEvent == nullptr)
		{
			ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
		}

		// Wait for the command list to execute; we are reusing the same command
		// list in our main loop but for now, we just want to wait for setup to
		// complete before continuing.
		WaitForGpu();
	}

	m_psoLibrary.Build(m_device.Get(), m_rootSignature.Get());
}

// Update frame-based values.
void D3D12PipelineStateCache::OnUpdate()
{
	// Wait for the previous Present to complete.
	WaitForSingleObjectEx(m_swapChainEvent, 100, FALSE);

	m_timer.Tick(NULL);
	m_camera.Update(static_cast<float>(m_timer.GetElapsedSeconds()));
}

// Render the scene.
void D3D12PipelineStateCache::OnRender()
{
	// Record all the commands we need to render the scene into the command list.
	PopulateCommandList();

	// Execute the command list.
	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

	// Present the frame.
	ThrowIfFailed(m_swapChain->Present(0, 0));

	m_drawIndex = 0;
	m_psoLibrary.EndFrame();

	MoveToNextFrame();
}

void D3D12PipelineStateCache::OnDestroy()
{
	// Wait for the GPU to be done with all resources.
	WaitForGpu();

	CloseHandle(m_fenceEvent);
}

bool D3D12PipelineStateCache::OnEvent(MSG msg)
{
	switch (msg.message)
	{
	case WM_KEYDOWN:
		m_camera.OnKeyDown(msg.wParam);
		break;

	case WM_KEYUP:
		m_camera.OnKeyUp(msg.wParam);
		OnKeyUp(msg.wParam);
		break;
	}

	return false;
}

// Fill the command list with all the render commands and dependent state.
void D3D12PipelineStateCache::PopulateCommandList()
{
	// Command list allocators can only be reset when the associated
	// command lists have finished execution on the GPU; apps should use
	// fences to determine GPU execution progress.
	ThrowIfFailed(m_commandAllocators[m_frameIndex]->Reset());

	// However, when ExecuteCommandList() is called on a particular command
	// list, that command list can then be reset at any time and must be before
	// re-recording.
	ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_frameIndex].Get(), nullptr));

	// Set necessary state.
	m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());

	ID3D12DescriptorHeap* ppHeaps[] = { m_srvHeap.Get() };
	m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);

	m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	m_commandList->RSSetViewports(1, &m_viewport);
	m_commandList->RSSetScissorRects(1, &m_scissorRect);

	CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);
	CD3DX12_CPU_DESCRIPTOR_HANDLE intermediateRtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), FrameCount, m_rtvDescriptorSize);
	CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(m_srvHeap->GetGPUDescriptorHandleForHeapStart());

	m_commandList->OMSetRenderTargets(1, &intermediateRtvHandle, FALSE, nullptr);

	// Record commands.
	m_commandList->ClearRenderTargetView(intermediateRtvHandle, IntermediateClearColor, 0, nullptr);

	// Draw the scene as normal into the back buffer.
	{
		static float rot = 0.0f;
		DrawConstantBuffer* drawCB = (DrawConstantBuffer*)m_dynamicCB.GetMappedMemory(m_drawIndex, m_frameIndex);
		drawCB->worldViewProjection = XMMatrixTranspose(XMMatrixRotationY(rot) * XMMatrixRotationX(-rot) * m_camera.GetViewMatrix() * m_projectionMatrix);

		rot += 0.01f;

		m_commandList->IASetVertexBuffers(0, 1, &m_cubeVbv);
		m_commandList->IASetIndexBuffer(&m_cubeIbv);
		m_psoLibrary.SetPipelineState(m_device.Get(), m_rootSignature.Get(), m_commandList.Get(), BaseNormal3DRender, m_frameIndex);

		m_commandList->SetGraphicsRootConstantBufferView(RootParameterCB, m_dynamicCB.GetGpuVirtualAddress(m_drawIndex, m_frameIndex));
		m_commandList->DrawIndexedInstanced(36, 1, 0, 0, 0);
		m_drawIndex++;
	}

	// Set up the state for a fullscreen quad.
	m_commandList->IASetVertexBuffers(0, 1, &m_quadVbv);
	m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);

	const float black[] = { 0.0f, 0.0f, 0.0f, 0.0f };
	m_commandList->ClearRenderTargetView(rtvHandle, black, 0, nullptr);
	m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);

	// Indicate that the back buffer will be used as a render target and the
	// intermediate render target will be used as a SRV.
	D3D12_RESOURCE_BARRIER barriers[] = {
		CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET),
		CD3DX12_RESOURCE_BARRIER::Transition(m_intermediateRenderTarget.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)
	};

	m_commandList->ResourceBarrier(_countof(barriers), barriers);

	m_commandList->SetGraphicsRootDescriptorTable(RootParameterSRV, m_srvHeap->GetGPUDescriptorHandleForHeapStart());

	// Draw some quads using the rendered scene with some effect shaders.
	{
		UINT quadCount = 0;
		static const UINT quadsX = 3;
		static const UINT quadsY = 3;

		// Cycle through all of the effects.
		for (UINT i = PostBlit; i < EffectPipelineTypeCount; i++)
		{
			if (m_enabledEffects[i])
			{
				D3D12_VIEWPORT viewport = {};
				viewport.TopLeftX = (quadCount % quadsX) * (m_viewport.Width / quadsX);
				viewport.TopLeftY = (quadCount / quadsY) * (m_viewport.Height / quadsY);
				viewport.Width = m_viewport.Width / quadsX;
				viewport.Height = m_viewport.Height / quadsY;
				viewport.MinDepth = 0.0f;
				viewport.MaxDepth = 0.0f;

				m_commandList->RSSetViewports(1, &viewport);
				m_psoLibrary.SetPipelineState(m_device.Get(), m_rootSignature.Get(), m_commandList.Get(), static_cast<EffectPipelineType>(i), m_frameIndex);
				m_commandList->DrawInstanced(4, 1, 0, 0);
			}

			quadCount++;
		}
	}

	// Revert resource states back to original values.
	barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
	barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
	barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
	barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;

	m_commandList->ResourceBarrier(_countof(barriers), barriers);

	ThrowIfFailed(m_commandList->Close());
}

void D3D12PipelineStateCache::ToggleEffect(EffectPipelineType type)
{
	if (m_enabledEffects[type])
	{
		// Wait until all frames using the shader are rendered before destroying
		// the shader.
		WaitForGpu();

		m_psoLibrary.DestroyShader(type);
	}

	m_enabledEffects[type] = !m_enabledEffects[type];
}

void D3D12PipelineStateCache::OnKeyUp(WPARAM key)
{
	switch (key)
	{
	case 'C':
		WaitForGpu();
		m_psoLibrary.ClearPSOCache();
		break;

	case 'U':
		m_psoLibrary.ToggleUberShader();
		break;

	case 'L':
		m_psoLibrary.ToggleDiskLibrary();
		break;

	case '1':
		ToggleEffect(PostBlit);
		break;

	case '2':
		ToggleEffect(PostInvert);
		break;

	case '3':
		ToggleEffect(PostGrayScale);
		break;

	case '4':
		ToggleEffect(PostEdgeDetect);
		break;

	case '5':
		ToggleEffect(PostBlur);
		break;

	case '6':
		ToggleEffect(PostWarp);
		break;

	case '7':
		ToggleEffect(PostPixelate);
		break;

	case '8':
		ToggleEffect(PostDistort);
		break;

	case '9':
		ToggleEffect(PostWave);
		break;

	default:
		break;
	}

	UpdateWindowTextPso();
}

void D3D12PipelineStateCache::UpdateWindowTextPso()
{
	std::wstringstream stringStream;
	stringStream << L"  [Use Uber Shader: ";
	stringStream << (m_psoLibrary.UberShadersEnabled() ? L"true]" : L"false]");
	stringStream << L"   [Use DiskCache: ";
	stringStream << (m_psoLibrary.DiskCacheEnabled() ? L"true]" : L"false]");

	SetCustomWindowText(stringStream.str().c_str());
}

// Wait for pending GPU work to complete.
void D3D12PipelineStateCache::WaitForGpu()
{
	// Schedule a Signal command in the queue.
	ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), m_fenceValues[m_frameIndex]));

	// Wait until the fence has been processed.
	ThrowIfFailed(m_fence->SetEventOnCompletion(m_fenceValues[m_frameIndex], m_fenceEvent));
	WaitForSingleObjectEx(m_fenceEvent, INFINITE, FALSE);

	// Increment the fence value for the current frame.
	m_fenceValues[m_frameIndex]++;
}

// Prepare to render the next frame.
void D3D12PipelineStateCache::MoveToNextFrame()
{
	// Schedule a Signal command in the queue.
	const UINT64 currentFenceValue = m_fenceValues[m_frameIndex];
	ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), currentFenceValue));

	// Update the frame index.
	m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();

	// If the next frame is not ready to be rendered yet, wait until it is ready.
	if (m_fence->GetCompletedValue() < m_fenceValues[m_frameIndex])
	{
		ThrowIfFailed(m_fence->SetEventOnCompletion(m_fenceValues[m_frameIndex], m_fenceEvent));
		WaitForSingleObjectEx(m_fenceEvent, INFINITE, FALSE);
	}

	// Set the fence value for the next frame.
	m_fenceValues[m_frameIndex] = currentFenceValue + 1;
}


text:
package quota

var (
	_ QuotaStorage = &MockQuotaStorage{}
	_ QuotaService = &MockQuotaService{}
)

type MockQuotaStorage struct {
	OnInc      func(string, int) error
	OnSet      func(string, int) error
	OnSetLimit func(string, int) error
	OnGet      func(string) (*Quota, error)
}

func (m *MockQuotaStorage) Inc(name string, quantity int) error {
	return m.OnInc(name, quantity)
}

func (m *MockQuotaStorage) Set(name string, limit int) error {
	return m.OnSet(name, limit)
}

func (m *MockQuotaStorage) SetLimit(name string, limit int) error {
	return m.OnSetLimit(name, limit)
}

func (m *MockQuotaStorage) Get(name string) (*Quota, error) {
	return m.OnGet(name)
}

type MockQuotaService struct {
	OnInc      func(string, int) error
	OnSet      func(string, int) error
	OnSetLimit func(string, int) error
	OnGet      func(string) (*Quota, error)
}

func (m *MockQuotaService) Inc(name string, delta int) error {
	if m.OnInc == nil {
		return nil
	}
	return m.OnInc(name, delta)
}

func (m *MockQuotaService) SetLimit(name string, limit int) error {
	if m.OnSetLimit == nil {
		return nil
	}
	return m.OnSetLimit(name, limit)
}

func (m *MockQuotaService) Set(name string, quantity int) error {
	if m.OnSet == nil {
		return nil
	}
	return m.OnSet(name, quantity)
}

func (m *MockQuotaService) Get(name string) (*Quota, error) {
	if m.OnGet == nil {
		return nil, nil
	}
	return m.OnGet(name)
}


text:
<?php

namespace Hail;

use Hail\{
    Facade\Facade,
    Container\Compiler,
    Container\Container,
    Debugger\Debugger,
    Util\Env
};

/**
 * Class Framework
 *
 * @package Hail
 */
class Framework
{
    public static function bootstrap($basePath): Container
    {
        \root_path([
            '@hail' => \dirname(__DIR__),
            '@base' => $basePath,
            '@app' => $basePath . '/app',
            '@storage' => $basePath . '/storage',
            '@runtime' => $basePath . '/storage/runtime',
        ]);

        if (PHP_VERSION_ID < 70200) {
            if ((\ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING) !== 0) {
                \ini_set('mbstring.func_overload', '0');
            }
        }

        if (\mb_internal_encoding() !== 'UTF-8') {
            \mb_internal_encoding('UTF-8');
        }

        Env::load($basePath);

        $config = new Config();

        if (!\class_exists('\Container', false)) {
            require self::compileContainer($config);
        }

        $container = new \Container();
        $container->set('config', $config);

        Facade::setContainer($container);
        $container->get('alias')->register();

        static::timezone(
            $config->get('app.timezone')
        );

        Debugger::enable(
            \env('PRODUCTION_MODE'),
            \storage_path('log')
        );

        return $container;
    }

    public static function compileContainer(Config $config): string
    {
        $file = \runtime_path('Container.php');

        if (
            !\is_file($file) ||
            \filemtime($file) < $config->getMTime('container')
        ) {
            $compiler = new Compiler(
                $config->get('container')
            );

            \file_put_contents($file, $compiler->compile());

            if (\function_exists('\opcache_invalidate')) {
                \opcache_invalidate($file, true);
            }
        }

        return $file;
    }

    public static function timezone(string $timezone)
    {
        if ($timezone !== \date_default_timezone_get()) {
            \date_default_timezone_set($timezone);
        }
    }
}