text:
/**************************************************************************/
/*!
    @file     PN532.cpp
    @author   Adafruit Industries & Seeed Studio
    @license  BSD
*/
/**************************************************************************/

#include "Arduino.h"
#include "PN532.h"
#include "PN532_debug.h"
#include <string.h>

#define HAL(func)   (_interface->func)

PN532::PN532(PN532Interface &interface)
{
    _interface = &interface;
}

/**************************************************************************/
/*!
    @brief  Setups the HW
*/
/**************************************************************************/
void PN532::begin()
{
    HAL(begin)();
    HAL(wakeup)();
}

/**************************************************************************/
/*!
    @brief  Prints a hexadecimal value in plain characters

    @param  data      Pointer to the uint8_t data
    @param  numBytes  Data length in bytes
*/
/**************************************************************************/
void PN532::PrintHex(const uint8_t *data, const uint32_t numBytes)
{
#ifdef ARDUINO
    for (uint8_t i = 0; i < numBytes; i++) {
        if (data[i] < 0x10) {
            Serial.print(" 0");
        } else {
            Serial.print(' ');
        }
        Serial.print(data[i], HEX);
    }
    Serial.println("");
#else
    for (uint8_t i = 0; i < numBytes; i++) {
        printf(" %2X", data[i]);
    }
    printf("\n");
#endif
}

/**************************************************************************/
/*!
    @brief  Prints a hexadecimal value in plain characters, along with
            the char equivalents in the following format

            00 00 00 00 00 00  ......

    @param  data      Pointer to the data
    @param  numBytes  Data length in bytes
*/
/**************************************************************************/
void PN532::PrintHexChar(const uint8_t *data, const uint32_t numBytes)
{
#ifdef ARDUINO
    for (uint8_t i = 0; i < numBytes; i++) {
        if (data[i] < 0x10) {
            Serial.print(" 0");
        } else {
            Serial.print(' ');
        }
        Serial.print(data[i], HEX);
    }
    Serial.print("    ");
    for (uint8_t i = 0; i < numBytes; i++) {
        char c = data[i];
        if (c <= 0x1f || c > 0x7f) {
            Serial.print('.');
        } else {
            Serial.print(c);
        }
    }
    Serial.println("");
#else
    for (uint8_t i = 0; i < numBytes; i++) {
        printf(" %2X", data[i]);
    }
    printf("    ");
    for (uint8_t i = 0; i < numBytes; i++) {
        char c = data[i];
        if (c <= 0x1f || c > 0x7f) {
            printf(".");
        } else {
            printf("%c", c);
        }
        printf("\n");
    }
#endif
}

/**************************************************************************/
/*!
    @brief  Checks the firmware version of the PN5xx chip

    @returns  The chip's firmware version and ID
*/
/**************************************************************************/
uint32_t PN532::getFirmwareVersion(void)
{
    uint32_t response;

    pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;

    if (HAL(writeCommand)(pn532_packetbuffer, 1)) {
        return 0;
    }

    // read data packet
    int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
    if (0 > status) {
        return 0;
    }

    response = pn532_packetbuffer[0];
    response <<= 8;
    response |= pn532_packetbuffer[1];
    response <<= 8;
    response |= pn532_packetbuffer[2];
    response <<= 8;
    response |= pn532_packetbuffer[3];

    return response;
}

/**************************************************************************/
/*!
    @brief  Read a PN532 register.

    @param  reg  the 16-bit register address.

    @returns  The register value.
*/
/**************************************************************************/
uint32_t PN532::readRegister(uint16_t reg)
{
    uint32_t response;

    pn532_packetbuffer[0] = PN532_COMMAND_READREGISTER;
    pn532_packetbuffer[1] = (reg >> 8) & 0xFF;
    pn532_packetbuffer[2] = reg & 0xFF;

    if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
        return 0;
    }

    // read data packet
    int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
    if (0 > status) {
        return 0;
    }

    response = pn532_packetbuffer[0];

    return response;
}

/**************************************************************************/
/*!
    @brief  Write to a PN532 register.

    @param  reg  the 16-bit register address.
    @param  val  the 8-bit value to write.

    @returns  0 for failure, 1 for success.
*/
/**************************************************************************/
uint32_t PN532::writeRegister(uint16_t reg, uint8_t val)
{
    uint32_t response;

    pn532_packetbuffer[0] = PN532_COMMAND_WRITEREGISTER;
    pn532_packetbuffer[1] = (reg >> 8) & 0xFF;
    pn532_packetbuffer[2] = reg & 0xFF;
    pn532_packetbuffer[3] = val;

    if (HAL(writeCommand)(pn532_packetbuffer, 4)) {
        return 0;
    }

    // read data packet
    int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
    if (0 > status) {
        return 0;
    }

    return 1;
}

/**************************************************************************/
/*!
    Writes an 8-bit value that sets the state of the PN532's GPIO pins

    @warning This function is provided exclusively for board testing and
             is dangerous since it will throw an error if any pin other
             than the ones marked "Can be used as GPIO" are modified!  All
             pins that can not be used as GPIO should ALWAYS be left high
             (value = 1) or the system will become unstable and a HW reset
             will be required to recover the PN532.

             pinState[0]  = P30     Can be used as GPIO
             pinState[1]  = P31     Can be used as GPIO
             pinState[2]  = P32     *** RESERVED (Must be 1!) ***
             pinState[3]  = P33     Can be used as GPIO
             pinState[4]  = P34     *** RESERVED (Must be 1!) ***
             pinState[5]  = P35     Can be used as GPIO

    @returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
bool PN532::writeGPIO(uint8_t pinstate)
{
    // Make sure pinstate does not try to toggle P32 or P34
    pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34);

    // Fill command buffer
    pn532_packetbuffer[0] = PN532_COMMAND_WRITEGPIO;
    pn532_packetbuffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate;  // P3 Pins
    pn532_packetbuffer[2] = 0x00;    // P7 GPIO Pins (not used ... taken by I2C)

    DMSG("Writing P3 GPIO: ");
    DMSG_HEX(pn532_packetbuffer[1]);
    DMSG("\n");

    // Send the WRITEGPIO command (0x0E)
    if (HAL(writeCommand)(pn532_packetbuffer, 3))
        return 0;

    return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
}

/**************************************************************************/
/*!
    Reads the state of the PN532's GPIO pins

    @returns An 8-bit value containing the pin state where:

             pinState[0]  = P30
             pinState[1]  = P31
             pinState[2]  = P32
             pinState[3]  = P33
             pinState[4]  = P34
             pinState[5]  = P35
*/
/**************************************************************************/
uint8_t PN532::readGPIO(void)
{
    pn532_packetbuffer[0] = PN532_COMMAND_READGPIO;

    // Send the READGPIO command (0x0C)
    if (HAL(writeCommand)(pn532_packetbuffer, 1))
        return 0x0;

    HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));

    /* READGPIO response without prefix and suffix should be in the following format:

      byte            Description
      -------------   ------------------------------------------
      b0              P3 GPIO Pins
      b1              P7 GPIO Pins (not used ... taken by I2C)
      b2              Interface Mode Pins (not used ... bus select pins)
    */

    DMSG("P3 GPIO: "); DMSG_HEX(pn532_packetbuffer[7]);
    DMSG("P7 GPIO: "); DMSG_HEX(pn532_packetbuffer[8]);
    DMSG("I0I1 GPIO: "); DMSG_HEX(pn532_packetbuffer[9]);
    DMSG("\n");

    return pn532_packetbuffer[0];
}

/**************************************************************************/
/*!
    @brief  Configures the SAM (Secure Access Module)
*/
/**************************************************************************/
bool PN532::SAMConfig(void)
{
    pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
    pn532_packetbuffer[1] = 0x01; // normal mode;
    pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second
    pn532_packetbuffer[3] = 0x01; // use IRQ pin!

    DMSG("SAMConfig\n");

    if (HAL(writeCommand)(pn532_packetbuffer, 4))
        return false;

    return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
}

/**************************************************************************/
/*!
    Sets the MxRtyPassiveActivation uint8_t of the RFConfiguration register

    @param  maxRetries    0xFF to wait forever, 0x00..0xFE to timeout
                          after mxRetries

    @returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
bool PN532::setPassiveActivationRetries(uint8_t maxRetries)
{
    pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION;
    pn532_packetbuffer[1] = 5;    // Config item 5 (MaxRetries)
    pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF)
    pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01)
    pn532_packetbuffer[4] = maxRetries;

    if (HAL(writeCommand)(pn532_packetbuffer, 5))
        return 0x0;  // no ACK

    return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
}

/***** ISO14443A Commands ******/

/**************************************************************************/
/*!
    Waits for an ISO14443A target to enter the field

    @param  cardBaudRate  Baud rate of the card
    @param  uid           Pointer to the array that will be populated
                          with the card's UID (up to 7 bytes)
    @param  uidLength     Pointer to the variable that will hold the
                          length of the card's UID.

    @returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
bool PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout)
{
    pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
    pn532_packetbuffer[1] = 1;  // max 1 cards at once (we can set this to 2 later)
    pn532_packetbuffer[2] = cardbaudrate;

    if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
        return 0x0;  // command failed
    }

    // read data packet
    if (HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) {
        return 0x0;
    }

    // check some basic stuff
    /* ISO14443A card response should be in the following format:

      byte            Description
      -------------   ------------------------------------------
      b0              Tags Found
      b1              Tag Number (only one used in this example)
      b2..3           SENS_RES
      b4              SEL_RES
      b5              NFCID Length
      b6..NFCIDLen    NFCID
    */

    if (pn532_packetbuffer[0] != 1)
        return 0;

    uint16_t sens_res = pn532_packetbuffer[2];
    sens_res <<= 8;
    sens_res |= pn532_packetbuffer[3];

    DMSG("ATQA: 0x");  DMSG_HEX(sens_res);
    DMSG("SAK: 0x");  DMSG_HEX(pn532_packetbuffer[4]);
    DMSG("\n");

    /* Card appears to be Mifare Classic */
    *uidLength = pn532_packetbuffer[5];

    for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) {
        uid[i] = pn532_packetbuffer[6 + i];
    }

    return 1;
}

/***** Mifare Classic Functions ******/

/**************************************************************************/
/*!
      Indicates whether the specified block number is the first block
      in the sector (block 0 relative to the current sector)
*/
/**************************************************************************/
bool PN532::mifareclassic_IsFirstBlock (uint32_t uiBlock)
{
    // Test if we are in the small or big sectors
    if (uiBlock < 128)
        return ((uiBlock) % 4 == 0);
    else
        return ((uiBlock) % 16 == 0);
}

/**************************************************************************/
/*!
      Indicates whether the specified block number is the sector trailer
*/
/**************************************************************************/
bool PN532::mifareclassic_IsTrailerBlock (uint32_t uiBlock)
{
    // Test if we are in the small or big sectors
    if (uiBlock < 128)
        return ((uiBlock + 1) % 4 == 0);
    else
        return ((uiBlock + 1) % 16 == 0);
}

/**************************************************************************/
/*!
    Tries to authenticate a block of memory on a MIFARE card using the
    INDATAEXCHANGE command.  See section 7.3.8 of the PN532 User Manual
    for more information on sending MIFARE and other commands.

    @param  uid           Pointer to a byte array containing the card UID
    @param  uidLen        The length (in bytes) of the card's UID (Should
                          be 4 for MIFARE Classic)
    @param  blockNumber   The block number to authenticate.  (0..63 for
                          1KB cards, and 0..255 for 4KB cards).
    @param  keyNumber     Which key type to use during authentication
                          (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
    @param  keyData       Pointer to a byte array containing the 6 bytes
                          key value

    @returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532::mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData)
{
    uint8_t i;

    // Hang on to the key and uid data
    memcpy (_key, keyData, 6);
    memcpy (_uid, uid, uidLen);
    _uidLen = uidLen;

    // Prepare the authentication command //
    pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;   /* Data Exchange Header */
    pn532_packetbuffer[1] = 1;                              /* Max card numbers */
    pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A;
    pn532_packetbuffer[3] = blockNumber;                    /* Block Number (1K = 0..63, 4K = 0..255 */
    memcpy (pn532_packetbuffer + 4, _key, 6);
    for (i = 0; i < _uidLen; i++) {
        pn532_packetbuffer[10 + i] = _uid[i];              /* 4 bytes card ID */
    }

    if (HAL(writeCommand)(pn532_packetbuffer, 10 + _uidLen))
        return 0;

    // Read the response packet
    HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));

    // Check if the response is valid and we are authenticated???
    // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00
    // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good
    if (pn532_packetbuffer[0] != 0x00) {
        DMSG("Authentification failed\n");
        return 0;
    }

    return 1;
}

/**************************************************************************/
/*!
    Tries to read an entire 16-bytes data block at the specified block
    address.

    @param  blockNumber   The block number to authenticate.  (0..63 for
                          1KB cards, and 0..255 for 4KB cards).
    @param  data          Pointer to the byte array that will hold the
                          retrieved data (if any)

    @returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532::mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data)
{
    DMSG("Trying to read 16 bytes from block ");
    DMSG_INT(blockNumber);

    /* Prepare the command */
    pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
    pn532_packetbuffer[1] = 1;                      /* Card number */
    pn532_packetbuffer[2] = MIFARE_CMD_READ;        /* Mifare Read command = 0x30 */
    pn532_packetbuffer[3] = blockNumber;            /* Block Number (0..63 for 1K, 0..255 for 4K) */

    /* Send the command */
    if (HAL(writeCommand)(pn532_packetbuffer, 4)) {
        return 0;
    }

    /* Read the response packet */
    HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));

    /* If byte 8 isn't 0x00 we probably have an error */
    if (pn532_packetbuffer[0] != 0x00) {
        return 0;
    }

    /* Copy the 16 data bytes to the output buffer        */
    /* Block content starts at byte 9 of a valid response */
    memcpy (data, pn532_packetbuffer + 1, 16);

    return 1;
}

/**************************************************************************/
/*!
    Tries to write an entire 16-bytes data block at the specified block
    address.

    @param  blockNumber   The block number to authenticate.  (0..63 for
                          1KB cards, and 0..255 for 4KB cards).
    @param  data          The byte array that contains the data to write.

    @returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532::mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data)
{
    /* Prepare the first command */
    pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
    pn532_packetbuffer[1] = 1;                      /* Card number */
    pn532_packetbuffer[2] = MIFARE_CMD_WRITE;       /* Mifare Write command = 0xA0 */
    pn532_packetbuffer[3] = blockNumber;            /* Block Number (0..63 for 1K, 0..255 for 4K) */
    memcpy (pn532_packetbuffer + 4, data, 16);        /* Data Payload */

    /* Send the command */
    if (HAL(writeCommand)(pn532_packetbuffer, 20)) {
        return 0;
    }

    /* Read the response packet */
    return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
}

/**************************************************************************/
/*!
    Formats a Mifare Classic card to store NDEF Records

    @returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532::mifareclassic_FormatNDEF (void)
{
    uint8_t sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
    uint8_t sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
    uint8_t sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

    // Note 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 must be used for key A
    // for the MAD sector in NDEF records (sector 0)

    // Write block 1 and 2 to the card
    if (!(mifareclassic_WriteDataBlock (1, sectorbuffer1)))
        return 0;
    if (!(mifareclassic_WriteDataBlock (2, sectorbuffer2)))
        return 0;
    // Write key A and access rights card
    if (!(mifareclassic_WriteDataBlock (3, sectorbuffer3)))
        return 0;

    // Seems that everything was OK (?!)
    return 1;
}

/**************************************************************************/
/*!
    Writes an NDEF URI Record to the specified sector (1..15)

    Note that this function assumes that the Mifare Classic card is
    already formatted to work as an "NFC Forum Tag" and uses a MAD1
    file system.  You can use the NXP TagWriter app on Android to
    properly format cards for this.

    @param  sectorNumber  The sector that the URI record should be written
                          to (can be 1..15 for a 1K card)
    @param  uriIdentifier The uri identifier code (0 = none, 0x01 =
                          "http://www.", etc.)
    @param  url           The uri text to write (max 38 characters).

    @returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532::mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char *url)
{
    // Figure out how long the string is
    uint8_t len = strlen(url);

    // Make sure we're within a 1K limit for the sector number
    if ((sectorNumber < 1) || (sectorNumber > 15))
        return 0;

    // Make sure the URI payload is between 1 and 38 chars
    if ((len < 1) || (len > 38))
        return 0;

    // Note 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 must be used for key A
    // in NDEF records

    // Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message)
    uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, len + 5, 0xD1, 0x01, len + 1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    if (len <= 6) {
        // Unlikely we'll get a url this short, but why not ...
        memcpy (sectorbuffer1 + 9, url, len);
        sectorbuffer1[len + 9] = 0xFE;
    } else if (len == 7) {
        // 0xFE needs to be wrapped around to next block
        memcpy (sectorbuffer1 + 9, url, len);
        sectorbuffer2[0] = 0xFE;
    } else if ((len > 7) || (len <= 22)) {
        // Url fits in two blocks
        memcpy (sectorbuffer1 + 9, url, 7);
        memcpy (sectorbuffer2, url + 7, len - 7);
        sectorbuffer2[len - 7] = 0xFE;
    } else if (len == 23) {
        // 0xFE needs to be wrapped around to final block
        memcpy (sectorbuffer1 + 9, url, 7);
        memcpy (sectorbuffer2, url + 7, len - 7);
        sectorbuffer3[0] = 0xFE;
    } else {
        // Url fits in three blocks
        memcpy (sectorbuffer1 + 9, url, 7);
        memcpy (sectorbuffer2, url + 7, 16);
        memcpy (sectorbuffer3, url + 23, len - 24);
        sectorbuffer3[len - 22] = 0xFE;
    }

    // Now write all three blocks back to the card
    if (!(mifareclassic_WriteDataBlock (sectorNumber * 4, sectorbuffer1)))
        return 0;
    if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 1, sectorbuffer2)))
        return 0;
    if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 2, sectorbuffer3)))
        return 0;
    if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 3, sectorbuffer4)))
        return 0;

    // Seems that everything was OK (?!)
    return 1;
}

/***** Mifare Ultralight Functions ******/

/**************************************************************************/
/*!
    Tries to read an entire 4-bytes page at the specified address.

    @param  page        The page number (0..63 in most cases)
    @param  buffer      Pointer to the byte array that will hold the
                        retrieved data (if any)
*/
/**************************************************************************/
uint8_t PN532::mifareultralight_ReadPage (uint8_t page, uint8_t *buffer)
{
    if (page >= 64) {
        DMSG("Page value out of range\n");
        return 0;
    }

    /* Prepare the command */
    pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
    pn532_packetbuffer[1] = 1;                   /* Card number */
    pn532_packetbuffer[2] = MIFARE_CMD_READ;     /* Mifare Read command = 0x30 */
    pn532_packetbuffer[3] = page;                /* Page Number (0..63 in most cases) */

    /* Send the command */
    if (HAL(writeCommand)(pn532_packetbuffer, 4)) {
        return 0;
    }

    /* Read the response packet */
    HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));

    /* If byte 8 isn't 0x00 we probably have an error */
    if (pn532_packetbuffer[0] == 0x00) {
        /* Copy the 4 data bytes to the output buffer         */
        /* Block content starts at byte 9 of a valid response */
        /* Note that the command actually reads 16 bytes or 4  */
        /* pages at a time ... we simply discard the last 12  */
        /* bytes                                              */
        memcpy (buffer, pn532_packetbuffer + 1, 4);
    } else {
        return 0;
    }

    // Return OK signal
    return 1;
}

/**************************************************************************/
/*!
    Tries to write an entire 4-bytes data buffer at the specified page
    address.

    @param  page     The page number to write into.  (0..63).
    @param  buffer   The byte array that contains the data to write.

    @returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532::mifareultralight_WritePage (uint8_t page, uint8_t *buffer)
{
    /* Prepare the first command */
    pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
    pn532_packetbuffer[1] = 1;                           /* Card number */
    pn532_packetbuffer[2] = MIFARE_CMD_WRITE_ULTRALIGHT; /* Mifare UL Write cmd = 0xA2 */
    pn532_packetbuffer[3] = page;                        /* page Number (0..63) */
    memcpy (pn532_packetbuffer + 4, buffer, 4);          /* Data Payload */

    /* Send the command */
    if (HAL(writeCommand)(pn532_packetbuffer, 8)) {
        return 0;
    }

    /* Read the response packet */
    return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
}

/**************************************************************************/
/*!
    @brief  Exchanges an APDU with the currently inlisted peer

    @param  send            Pointer to data to send
    @param  sendLength      Length of the data to send
    @param  response        Pointer to response data
    @param  responseLength  Pointer to the response data length
*/
/**************************************************************************/
bool PN532::inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength)
{
    uint8_t i;

    pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
    pn532_packetbuffer[1] = inListedTag;

    if (HAL(writeCommand)(pn532_packetbuffer, 2, send, sendLength)) {
        return false;
    }

    int16_t status = HAL(readResponse)(response, *responseLength, 1000);
    if (status < 0) {
        return false;
    }

    if ((response[0] & 0x3f) != 0) {
        DMSG("Status code indicates an error\n");
        return false;
    }

    uint8_t length = status;
    length -= 1;

    if (length > *responseLength) {
        length = *responseLength; // silent truncation...
    }

    for (uint8_t i = 0; i < length; i++) {
        response[i] = response[i + 1];
    }
    *responseLength = length;

    return true;
}

/**************************************************************************/
/*!
    @brief  'InLists' a passive target. PN532 acting as reader/initiator,
            peer acting as card/responder.
*/
/**************************************************************************/
bool PN532::inListPassiveTarget()
{
    pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
    pn532_packetbuffer[1] = 1;
    pn532_packetbuffer[2] = 0;

    DMSG("inList passive target\n");

    if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
        return false;
    }

    int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 30000);
    if (status < 0) {
        return false;
    }

    if (pn532_packetbuffer[0] != 1) {
        return false;
    }

    inListedTag = pn532_packetbuffer[1];

    return true;
}

int8_t PN532::tgInitAsTarget(const uint8_t* command, const uint8_t len, const uint16_t timeout){

  int8_t status = HAL(writeCommand)(command, len);
    if (status < 0) {
        return -1;
    }

    status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout);
    if (status > 0) {
        return 1;
    } else if (PN532_TIMEOUT == status) {
        return 0;
    } else {
        return -2;
    }
}

/**
 * Peer to Peer
 */
int8_t PN532::tgInitAsTarget(uint16_t timeout)
{
    const uint8_t command[] = {
        PN532_COMMAND_TGINITASTARGET,
        0,
        0x00, 0x00,         //SENS_RES
        0x00, 0x00, 0x00,   //NFCID1
        0x40,               //SEL_RES

        0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, // POL_RES
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xFF, 0xFF,

        0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, 0x00, 0x00, //NFCID3t: Change this to desired value

        0x06, 0x46,  0x66, 0x6D, 0x01, 0x01, 0x10, 0x00// LLCP magic number and version parameter
    };
    return tgInitAsTarget(command, sizeof(command), timeout);
}

int16_t PN532::tgGetData(uint8_t *buf, uint8_t len)
{
    buf[0] = PN532_COMMAND_TGGETDATA;

    if (HAL(writeCommand)(buf, 1)) {
        return -1;
    }

    int16_t status = HAL(readResponse)(buf, len, 3000);
    if (0 >= status) {
        return status;
    }

    uint16_t length = status - 1;

    if (buf[0] != 0) {
        DMSG("status is not ok\n");
        return -5;
    }

    for (uint8_t i = 0; i < length; i++) {
        buf[i] = buf[i + 1];
    }

    return length;
}

bool PN532::tgSetData(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
{
    if (hlen > (sizeof(pn532_packetbuffer) - 1)) {
        if ((body != 0) || (header == pn532_packetbuffer)) {
            DMSG("tgSetData:buffer too small\n");
            return false;
        }

        pn532_packetbuffer[0] = PN532_COMMAND_TGSETDATA;
        if (HAL(writeCommand)(pn532_packetbuffer, 1, header, hlen)) {
            return false;
        }
    } else {
        for (int8_t i = hlen - 1; i >= 0; i--){
            pn532_packetbuffer[i + 1] = header[i];
        }
        pn532_packetbuffer[0] = PN532_COMMAND_TGSETDATA;

        if (HAL(writeCommand)(pn532_packetbuffer, hlen + 1, body, blen)) {
            return false;
        }
    }

    if (0 > HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 3000)) {
        return false;
    }

    if (0 != pn532_packetbuffer[0]) {
        return false;
    }

    return true;
}

int16_t PN532::inRelease(const uint8_t relevantTarget){

    pn532_packetbuffer[0] = PN532_COMMAND_INRELEASE;
    pn532_packetbuffer[1] = relevantTarget;

    if (HAL(writeCommand)(pn532_packetbuffer, 2)) {
        return 0;
    }

    // read data packet
    return HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
}

/***** FeliCa Functions ******/
/**************************************************************************/
/*!
    @brief  Poll FeliCa card. PN532 acting as reader/initiator,
            peer acting as card/responder.
    @param[in]  systemCode             Designation of System Code. When sending FFFFh as System Code,
                                       all FeliCa cards can return response.
    @param[in]  requestCode            Designation of Request Data as follows:
                                         00h: No Request
                                         01h: System Code request (to acquire System Code of the card)
                                         02h: Communication perfomance request
    @param[out] idm                    IDm of the card (8 bytes)
    @param[out] pmm                    PMm of the card (8 bytes)
    @param[out] systemCodeResponse     System Code of the card (Optional, 2bytes)
    @return                            = 1: A FeliCa card has detected
                                       = 0: No card has detected
                                       < 0: error
*/
/**************************************************************************/
int8_t PN532::felica_Polling(uint16_t systemCode, uint8_t requestCode, uint8_t * idm, uint8_t * pmm, uint16_t *systemCodeResponse, uint16_t timeout)
{
  pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
  pn532_packetbuffer[1] = 1;
  pn532_packetbuffer[2] = 1;
  pn532_packetbuffer[3] = FELICA_CMD_POLLING;
  pn532_packetbuffer[4] = (systemCode >> 8) & 0xFF;
  pn532_packetbuffer[5] = systemCode & 0xFF;
  pn532_packetbuffer[6] = requestCode;
  pn532_packetbuffer[7] = 0;

  if (HAL(writeCommand)(pn532_packetbuffer, 8)) {
    DMSG("Could not send Polling command\n");
    return -1;
  }

  int16_t status = HAL(readResponse)(pn532_packetbuffer, 22, timeout);
  if (status < 0) {
    DMSG("Could not receive response\n");
    return -2;
  }

  // Check NbTg (pn532_packetbuffer[7])
  if (pn532_packetbuffer[0] == 0) {
    DMSG("No card had detected\n");
    return 0;
  } else if (pn532_packetbuffer[0] != 1) {
    DMSG("Unhandled number of targets inlisted. NbTg: ");
    DMSG_HEX(pn532_packetbuffer[7]);
    DMSG("\n");
    return -3;
  }

  inListedTag = pn532_packetbuffer[1];
  DMSG("Tag number: ");
  DMSG_HEX(pn532_packetbuffer[1]);
  DMSG("\n");

  // length check
  uint8_t responseLength = pn532_packetbuffer[2];
  if (responseLength != 18 && responseLength != 20) {
    DMSG("Wrong response length\n");
    return -4;
  }

  uint8_t i;
  for (i=0; i<8; ++i) {
    idm[i] = pn532_packetbuffer[4+i];
    _felicaIDm[i] = pn532_packetbuffer[4+i];
    pmm[i] = pn532_packetbuffer[12+i];
    _felicaPMm[i] = pn532_packetbuffer[12+i];
  }

  if ( responseLength == 20 ) {
    *systemCodeResponse = (uint16_t)((pn532_packetbuffer[20] << 8) + pn532_packetbuffer[21]);
  }

  return 1;
}

/**************************************************************************/
/*!
    @brief  Sends FeliCa command to the currently inlisted peer

    @param[in]  command         FeliCa command packet. (e.g. 00 FF FF 00 00  for Polling command)
    @param[in]  commandlength   Length of the FeliCa command packet. (e.g. 0x05 for above Polling command )
    @param[out] response        FeliCa response packet. (e.g. 01 NFCID2(8 bytes) PAD(8 bytes)  for Polling response)
    @param[out] responselength  Length of the FeliCa response packet. (e.g. 0x11 for above Polling command )
    @return                          = 1: Success
                                     < 0: error
*/
/**************************************************************************/
int8_t PN532::felica_SendCommand (const uint8_t *command, uint8_t commandlength, uint8_t *response, uint8_t *responseLength)
{
  if (commandlength > 0xFE) {
    DMSG("Command length too long\n");
    return -1;
  }

  pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
  pn532_packetbuffer[1] = inListedTag;
  pn532_packetbuffer[2] = commandlength + 1;

  if (HAL(writeCommand)(pn532_packetbuffer, 3, command, commandlength)) {
    DMSG("Could not send FeliCa command\n");
    return -2;
  }

  // Wait card response
  int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 200);
  if (status < 0) {
    DMSG("Could not receive response\n");
    return -3;
  }

  // Check status (pn532_packetbuffer[0])
  if ((pn532_packetbuffer[0] & 0x3F)!=0) {
    DMSG("Status code indicates an error: ");
    DMSG_HEX(pn532_packetbuffer[0]);
    DMSG("\n");
    return -4;
  }

  // length check
  *responseLength = pn532_packetbuffer[1] - 1;
  if ( (status - 2) != *responseLength) {
    DMSG("Wrong response length\n");
    return -5;
  }

  memcpy(response, &pn532_packetbuffer[2], *responseLength);

  return 1;
}

/**************************************************************************/
/*!
    @brief  Sends FeliCa Request Service command

    @param[in]  numNode           length of the nodeCodeList
    @param[in]  nodeCodeList      Node codes(Big Endian)
    @param[out] keyVersions       Key Version of each Node (Big Endian)
    @return                          = 1: Success
                                     < 0: error
*/
/**************************************************************************/
int8_t PN532::felica_RequestService(uint8_t numNode, uint16_t *nodeCodeList, uint16_t *keyVersions)
{
  if (numNode > FELICA_REQ_SERVICE_MAX_NODE_NUM) {
    DMSG("numNode is too large\n");
    return -1;
  }

  uint8_t i, j=0;
  uint8_t cmdLen = 1 + 8 + 1 + 2*numNode;
  uint8_t cmd[cmdLen];
  cmd[j++] = FELICA_CMD_REQUEST_SERVICE;
  for (i=0; i<8; ++i) {
    cmd[j++] = _felicaIDm[i];
  }
  cmd[j++] = numNode;
  for (i=0; i<numNode; ++i) {
    cmd[j++] = nodeCodeList[i] & 0xFF;
    cmd[j++] = (nodeCodeList[i] >> 8) & 0xff;
  }

  uint8_t response[10+2*numNode];
  uint8_t responseLength;

  if (felica_SendCommand(cmd, cmdLen, response, &responseLength) != 1) {
    DMSG("Request Service command failed\n");
    return -2;
  }

  // length check
  if ( responseLength != 10+2*numNode ) {
    DMSG("Request Service command failed (wrong response length)\n");
    return -3;
  }

  for(i=0; i<numNode; i++) {
    keyVersions[i] = (uint16_t)(response[10+i*2] + (response[10+i*2+1] << 8));
  }
  return 1;
}

/**************************************************************************/
/*!
    @brief  Sends FeliCa Request Service command

    @param[out]  mode         Current Mode of the card
    @return                   = 1: Success
                              < 0: error
*/
/**************************************************************************/
int8_t PN532::felica_RequestResponse(uint8_t * mode)
{
  uint8_t cmd[9];
  cmd[0] = FELICA_CMD_REQUEST_RESPONSE;
  memcpy(&cmd[1], _felicaIDm, 8);

  uint8_t response[10];
  uint8_t responseLength;
  if (felica_SendCommand(cmd, 9, response, &responseLength) != 1) {
    DMSG("Request Response command failed\n");
    return -1;
  }

  // length check
  if ( responseLength != 10) {
    DMSG("Request Response command failed (wrong response length)\n");
    return -2;
  }

  *mode = response[9];
  return 1;
}

/**************************************************************************/
/*!
    @brief  Sends FeliCa Read Without Encryption command

    @param[in]  numService         Length of the serviceCodeList
    @param[in]  serviceCodeList    Service Code List (Big Endian)
    @param[in]  numBlock           Length of the blockList
    @param[in]  blockList          Block List (Big Endian, This API only accepts 2-byte block list element)
    @param[out] blockData          Block Data
    @return                        = 1: Success
                                   < 0: error
*/
/**************************************************************************/
int8_t PN532::felica_ReadWithoutEncryption (uint8_t numService, const uint16_t *serviceCodeList, uint8_t numBlock, const uint16_t *blockList, uint8_t blockData[][16])
{
  if (numService > FELICA_READ_MAX_SERVICE_NUM) {
    DMSG("numService is too large\n");
    return -1;
  }
  if (numBlock > FELICA_READ_MAX_BLOCK_NUM) {
    DMSG("numBlock is too large\n");
    return -2;
  }

  uint8_t i, j=0, k;
  uint8_t cmdLen = 1 + 8 + 1 + 2*numService + 1 + 2*numBlock;
  uint8_t cmd[cmdLen];
  cmd[j++] = FELICA_CMD_READ_WITHOUT_ENCRYPTION;
  for (i=0; i<8; ++i) {
    cmd[j++] = _felicaIDm[i];
  }
  cmd[j++] = numService;
  for (i=0; i<numService; ++i) {
    cmd[j++] = serviceCodeList[i] & 0xFF;
    cmd[j++] = (serviceCodeList[i] >> 8) & 0xff;
  }
  cmd[j++] = numBlock;
  for (i=0; i<numBlock; ++i) {
    cmd[j++] = (blockList[i] >> 8) & 0xFF;
    cmd[j++] = blockList[i] & 0xff;
  }

  uint8_t response[12+16*numBlock];
  uint8_t responseLength;
  if (felica_SendCommand(cmd, cmdLen, response, &responseLength) != 1) {
    DMSG("Read Without Encryption command failed\n");
    return -3;
  }

  // length check
  if ( responseLength != 12+16*numBlock ) {
    DMSG("Read Without Encryption command failed (wrong response length)\n");
    return -4;
  }

  // status flag check
  if ( response[9] != 0 || response[10] != 0 ) {
    DMSG("Read Without Encryption command failed (Status Flag: ");
    DMSG_HEX(pn532_packetbuffer[9]);
    DMSG_HEX(pn532_packetbuffer[10]);
    DMSG(")\n");
    return -5;
  }

  k = 12;
  for(i=0; i<numBlock; i++ ) {
    for(j=0; j<16; j++ ) {
      blockData[i][j] = response[k++];
    }
  }

  return 1;
}

/**************************************************************************/
/*!
    @brief  Sends FeliCa Write Without Encryption command

    @param[in]  numService         Length of the serviceCodeList
    @param[in]  serviceCodeList    Service Code List (Big Endian)
    @param[in]  numBlock           Length of the blockList
    @param[in]  blockList          Block List (Big Endian, This API only accepts 2-byte block list element)
    @param[in]  blockData          Block Data (each Block has 16 bytes)
    @return                        = 1: Success
                                   < 0: error
*/
/**************************************************************************/
int8_t PN532::felica_WriteWithoutEncryption (uint8_t numService, const uint16_t *serviceCodeList, uint8_t numBlock, const uint16_t *blockList, uint8_t blockData[][16])
{
  if (numService > FELICA_WRITE_MAX_SERVICE_NUM) {
    DMSG("numService is too large\n");
    return -1;
  }
  if (numBlock > FELICA_WRITE_MAX_BLOCK_NUM) {
    DMSG("numBlock is too large\n");
    return -2;
  }

  uint8_t i, j=0, k;
  uint8_t cmdLen = 1 + 8 + 1 + 2*numService + 1 + 2*numBlock + 16 * numBlock;
  uint8_t cmd[cmdLen];
  cmd[j++] = FELICA_CMD_WRITE_WITHOUT_ENCRYPTION;
  for (i=0; i<8; ++i) {
    cmd[j++] = _felicaIDm[i];
  }
  cmd[j++] = numService;
  for (i=0; i<numService; ++i) {
    cmd[j++] = serviceCodeList[i] & 0xFF;
    cmd[j++] = (serviceCodeList[i] >> 8) & 0xff;
  }
  cmd[j++] = numBlock;
  for (i=0; i<numBlock; ++i) {
    cmd[j++] = (blockList[i] >> 8) & 0xFF;
    cmd[j++] = blockList[i] & 0xff;
  }
  for (i=0; i<numBlock; ++i) {
    for(k=0; k<16; k++) {
      cmd[j++] = blockData[i][k];
    }
  }

  uint8_t response[11];
  uint8_t responseLength;
  if (felica_SendCommand(cmd, cmdLen, response, &responseLength) != 1) {
    DMSG("Write Without Encryption command failed\n");
    return -3;
  }

  // length check
  if ( responseLength != 11 ) {
    DMSG("Write Without Encryption command failed (wrong response length)\n");
    return -4;
  }

  // status flag check
  if ( response[9] != 0 || response[10] != 0 ) {
    DMSG("Write Without Encryption command failed (Status Flag: ");
    DMSG_HEX(pn532_packetbuffer[9]);
    DMSG_HEX(pn532_packetbuffer[10]);
    DMSG(")\n");
    return -5;
  }

  return 1;
}

/**************************************************************************/
/*!
    @brief  Sends FeliCa Request System Code command

    @param[out] numSystemCode        Length of the systemCodeList
    @param[out] systemCodeList       System Code list (Array length should longer than 16)
    @return                          = 1: Success
                                     < 0: error
*/
/**************************************************************************/
int8_t PN532::felica_RequestSystemCode(uint8_t * numSystemCode, uint16_t *systemCodeList)
{
  uint8_t cmd[9];
  cmd[0] = FELICA_CMD_REQUEST_SYSTEM_CODE;
  memcpy(&cmd[1], _felicaIDm, 8);

  uint8_t response[10 + 2 * 16];
  uint8_t responseLength;
  if (felica_SendCommand(cmd, 9, response, &responseLength) != 1) {
    DMSG("Request System Code command failed\n");
    return -1;
  }
  *numSystemCode = response[9];

  // length check
  if ( responseLength < 10 + 2 * *numSystemCode ) {
    DMSG("Request System Code command failed (wrong response length)\n");
    return -2;
  }

  uint8_t i;
  for(i=0; i<*numSystemCode; i++) {
    systemCodeList[i] = (uint16_t)((response[10+i*2]<< 8) + response[10+i*2+1]);
  }

  return 1;
}

/**************************************************************************/
/*!
    @brief  Release FeliCa card
    @return                          = 1: Success
                                     < 0: error
*/
/**************************************************************************/
int8_t PN532::felica_Release()
{
  // InRelease
  pn532_packetbuffer[0] = PN532_COMMAND_INRELEASE;
  pn532_packetbuffer[1] = 0x00;   // All target
  DMSG("Release all FeliCa target\n");

  if (HAL(writeCommand)(pn532_packetbuffer, 2)) {
    DMSG("No ACK\n");
    return -1;  // no ACK
  }

  // Wait card response
  int16_t frameLength = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 1000);
  if (frameLength < 0) {
    DMSG("Could not receive response\n");
    return -2;
  }

  // Check status (pn532_packetbuffer[0])
  if ((pn532_packetbuffer[0] & 0x3F)!=0) {
    DMSG("Status code indicates an error: ");
    DMSG_HEX(pn532_packetbuffer[7]);
    DMSG("\n");
    return -3;
  }

  return 1;
}


text:
New AFMC supervisor course aims to develop stronger leaders
Brett Carbo, 75th Force Support Squadron course facilitator, welcomes civilian and military members attending a new supervisory development course Oct. 27, 2020, at Hill Air Force Base, Utah. Air Force Materiel Command launched the new in-person/virtual course this week with the first iteration taking place at Hill. (U.S. Air Force photo by Todd Cromar)
Barbara Hanlin, Air Force Sustainment Center site senior functional for personnel, was the first presenter of the day and provided the course introduction to civilian and military members attending a new supervisory development course Oct. 27, 2020 at Hill Air Force Base, Utah. Air Force Materiel Command launched the new in-person/virtual course this week with the first iteration taking place at Hill. (U.S. Air Force photo by Todd Cromar)
Published Nov. 2, 2020
By Marisa Alia-Novobilski
WRIGHT-PATTERSON AIR FORCE BASE, Ohio --
The Air Force Materiel Command beta-tested a new Supervisor Development Course Oct. 27-29 in an effort to better equip first-line supervisors with the tools, knowledge and expertise to successfully lead command teams.
The course is a complement to the mandatory supervisor training provided by the Air Force and offers supervisors in-depth knowledge of personnel and workplace policies as well as the opportunity for practical application of concepts through case studies and collaborative learning.
"Feedback from multiple command-wide surveys such as the AFMC We Need, DEOCS (Defense Organizational Climate Survey) and FEVS (Federal Employee Viewpoint Survey) indicates that our civilian first-line supervisors aren't receiving the training they need," said Patricia M. Young, AFMC Executive Director. "The AFMC Supervisor Development Course is not intended to replace or impede existing leader development efforts which address the myriad of human domain competencies successful leaders must possess and continuously refine. Rather, it was developed to expand on current developmental efforts and serve as an investment in our first-line supervisor's growth as we posture them for success."
Nearly a dozen supervisors attended the in-person beta course held at Hill Air Force Base, Utah, and future instructional leaders logged in virtually to observe their content areas. Topics covered included: human resource policy and guidance; employee attendance and leave administration; equal employment opportunity programs; discipline and adverse action; administrative grievance procedures; performance plans and appraisals; workforce incentives and awards; and more.
Each day ended with practical application of skills through case study application under the guidance of an experienced mentor, offering a peer-supported, active-learning experience in a guided environment.
"The AFMC course is taught in a manner to provide deeper comprehension of human resources concepts with a student handbook designed to sustain what was learned in the classroom while providing quick reference on the job," said Gregory Diehl, AFMC Employee Development Manager and course lead. "Additionally, class mentors help the supervisors understand the importance of the material and relate their experiences concerning the challenges and rewards of being a supervisor."
Gregory Buck, a Contract Depot Maintenance Section Chief at the 420th Supply Chain Maintenance Squadron at Hill AFB said that he found the course to be extremely helpful, particularly given the opportunities for practical application of policies that can seem complex and confusing.
"This course is a perfect stepping stone a new supervisor needs to successfully lead their team and manage their employees," said Buck. "Real life examples and case studies make it easy to stay focused by giving a glimpse of the challenges a supervisor may face while providing the resources and knowledge on how to handle them."
Shannon Schaefer, a section chief at the Air Force Life Cycle Management Center, found the course to be a great way to reinforce the computer-based supervisor training while also providing networking opportunities with other supervisors who they could turn to during times of need.
"The main highlight was realizing supervising is a team effort, and we have a touch point with specialists to assist us with admin efforts so we are able to stay focused on mission goals. This course will be essential for new supervisors as well as an excellent refresher for those that are more seasoned," she said.
The long-term plan is for the course to be a one-time, in-person requirement for AFMC supervisors, with the final course to roll out to AFMC centers and installations starting in January 2021. Course leaders are currently looking at alternative learning options that take into account the current COVID-19 environment while still providing for an on-target official launch date for the course.
AFMC supervisors of civilian employees at non-AFMC installations will be reached through virtual methods after the course content has been fielded and properly validated.
"This is a developmental opportunity unlike anything else that is being offered through other venues," said Young. "It's just one way we're working to help build the supervisors and leaders that the AFMC needs to continue to be successful into the future."
AFMC We Need supervisor training AFMC Air Force Materiel Command Air Force We Need AFWN

redpajama_set_name: RedPajamaCommonCrawl


text:
Q: http redirect to specific https link I have a webpage that I would like to redirect to a specific link if the user is coming from http://
<script language="JavaScript">
  var loc = window.location.href+'';
    if (loc.indexOf('http://')==0){
      window.location.href = loc.replace('http://','https://secure.example.com/app');
    }
</script>

If the user comes from http://example.com/app or any http:// I would like to redirect it to that exact link.
When I run this JavaScript it is taking https://secure.example.com/app and adding domain.com/app like below

https://secure.example.com/appexample.com/app

Any help with this would be greatly appreciated.
I also tried the meta tag thing
<meta http-equiv="refresh" content="2;url=https://secure.example.com/app" />
But its just keeps refreshing and doesnt feel right with the hesitation page change.

A: <script language="JavaScript">
  var loc = window.location.href+'';
    if (loc.indexOf('http://www.')==0){
         window.location.href = loc.replace('http://www.','https://secure.');
    }
    else if (loc.indexOf('http://')==0) {
        window.location.href = loc.replace('http://','https://secure.');
    }
</script>

It was doing what you describe because you were replacing http:// with https://secure.example.com/app so of course everything that was after http:// will still be there afterwards.

A: I would recommend simply replacing http:// with https://secure. when there's no www.
To additionally cover cases where there is a www, you can simply replace www. with nothing:

//var loc = window.location.href;
var loc = 'http://www.example.com/app';
console.log(loc);
loc = loc.replace('www.', '');
loc = loc.replace('http://', 'https://secure.');
console.log(loc);

A: Add this to your server configuration file instead of doing it in html
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

301 REDIRECT should be the better way to do it
for an javascript approach(es6). not the recommended way because browser redirect is not always reliable
 return location.protocol != 'https:' ? location.protocol = "https:"
: {do nothing logic}

redpajama_set_name: RedPajamaStackExchange


Today a new inspiration for Maja Design. Two pages for a new minialbum with my favourite theme Summer by the Sea. We have a very hot and especially dry summer here and every thought of a cool fresh sea breeze is more than welcome.
were a wonderful addition and very practical to attach my flip flop images.
I wish you a wonderful summertime!


text:
Pulpit pals: Christians, Jews, Muslims plan shared worship
By Adelle M. Banks Religion News Service
· May 18, 2011 5:14 pm
Religious and human rights activists are asking U.S. churches to invite Jewish and Muslim clergy to their sanctuaries to read from sacred texts next month in an initiative designed to counter anti-Muslim bigotry.
The June 26 initiative, called "Faith Shared: Uniting in Prayer and Understanding," is co-sponsored by the Interfaith Alliance and Human Rights First. Leaders of the two Washington-based groups said the event hopes to demonstrate respect for Islam in the wake of Quran burnings in recent months.
"As a Christian minister who is a pastor in a local congregation, it is important to me for our nation and our world to know that not all Christians promote hate, attack religions different from their own and seek to desecrate the scripture of others," the Rev. Welton Gaddy, president of the Interfaith Alliance, said Tuesday.
More than 50 churches in 26 states already have committed to the initiative, including the Washington National Cathedral.
Tad Stahnke, director of policy and programs for Human Rights First, said he hopes the initiative will draw attention to religious freedom and counter negative stereotypes of Christian leaders making anti-Muslim statements.
"We want to send a message to the world," he said, "that Americans do respect religious differences and reject religious bigotry and the demonization of Islam or any other religion."
Utah's Right


text:
Home/Entertainment/Celebrities/Top 10 Most Handsome Field Hockey Players in The World (2021)
Top 10 Most Handsome Field Hockey Players in The World (2021)
KirtiLast Updated: August 25, 2021
Field Hockey is slowly becoming a famous sport, especially in India after the Indian men and Women hockey team qualified for the Field Hockey semi-finals in the Tokyo 2020 Olympics. There are many wonderful players who are really good in Field hockey because of their marvellous skills. They also have a huge female fan following because of their awesome looks. Let's take a look at their personality and unique style. Today we have compiled a list of the most handsome hockey players from all around the world. Be sure to check the full list and tell us in the comments down below who's your favourite or if you would like to suggest a name for the most handsome hockey player.
Top 10 most handsome field hockey players in the world
Krishan Bahadur Pathak
Krishan Bahadur Pathak is a young and handsome Indian field hockey player. Krishan Pathak plays as a goalkeeper for the National Team of India. He is very cute and charming. He has a muscular body and he is 1.70 m tall. He is just 24 years old and achieved a lot of fame in just this age.
Related: Top 10 most beautiful woman tennis players in the world
Surender Kumar
Surender Kumar is a brilliant Indian field Hockey player. He plays as a defender in the Indian National hockey team. He is 1.79 m tall and has a bold personality. He looks very smart with a beard. He is a 27 years old smart and charming player who is very good at hockey.
Fergus Kavanagh
Fergus Kavanagh is an amazing Australian field hockey player. He is very handsome and has a dashing personality. He has a huge number of female fan following. He is 1.83 m tall and a big bodybuilder. He is a very popular hockey player. In 2008, he won a bronze medal with his team at the Summer Olympics.
Eddie Ockenden
Edward "Eddie" Clyve Ockenden is a very smart and charming field hockey player from Australia. He is 1.8 m tall and looks very handsome with a beard. His hazel eyes being the centre of attraction all the time. He has an amazing personality and body.
Blake Govers
Blake Govers is a professional field hockey player from Australia who has a large fan following because of his amazing style and good looks. He is tall, smart and charming. He is very famous at the age of 25 years only. He is also very nice in his skills.
Related: Top 10 Most Popular Indian YouTubers in 2021
Jacob Thomas Whetton
Jacob Thomas Whetton is one of the cutest field hockey players in the world. He is very sweet and charming. He has a nice face cut with a beautiful smile. He has a cute smiling face and golden hair. He is 30 years old and he is the player who plays as a forward for the National team of Australia.
David Ames
David Vincent Leslie Ames is a handsome Irish Player. He is a professional field hockey player, he plays the role of Midfielder and defender in the Britain National team. He is very smart and has a unique style. He is very popular and very handsome, not least than any star.
Samuel Ward
Samuel Ward is a person of amazing good looks. He has his own style and personality which is very attractive. He is very famous for his haircuts. He is an amazing player and an awesome looking guy. He is very cool and has billions of fans of his style and good looking personality.
George Pinner
George Pinner is a very good looking person. Nobody believes that he is not a model but a great sportsman. He plays as a goalkeeper. He is very handsome and his features are very sharp and beautiful. He is very tall and has an amazing body. He broke many hearts of his female fans when he got married.
Related: Top 10 most handsome WWE Male Wrestlers
Henry Weir
William Henry Weir is an amazing English field Hockey Player. He plays as a defender in the National Hockey team of Britain. He is very smart and strong. He is very known for his serious killing looks. He is a very handsome sportsperson. He is 1.76 m tall and has a large body shape which gives a macho look.


text:
Dr. Strangelove Redux
By Bexis on July 20, 2009
Remember "Dr. Strangelove"?
"Ripper: Have you ever heard of a thing called fluoridation. Fluoridation of water?
Mandrake: Uh? Yes, I-I have heard of that, Jack, yes. Yes.
Ripper: Well, do you know what it is?
Mandrake: No, no I don't know what it is, no.
Ripper: Do you realize that fluoridation is the most monstrously conceived and dangerous Communist plot we have ever had to face?"
We have a rule here at the Drug and Device Law Blog: We don't write about unpublished Tenth Circuit opinions unless they remind us of "Dr Strangelove."
In Ronwin v. Bayer Corp., No. 08-8089, slip op. (10th Cir. June 17, 2009) (link here), Ronwin, age 77, ingested the statin Baycol for seven months. Two years later, Rowin was diagnosed with a torn rotator cuff, which he had surgically repaired. Naturally, he sued Bayer, claiming the statin caused the torn rotator cuff.
Ronwin proffered his own expert testimony and that of Dr. Raul Reyes in support of his claim. Reyes was a surgeon with over 50 years experience, but "he admitted in his deposition that he had never prescribed statin drugs and that he was unaware of any published medical literature linking statins, or Baycol in particular, to rotator cuff injuries." Slip op. at 6-7.
Ixnay on the expertsay.
Now Ronwin himself was a different story. He'd been a chemist and biochemist for nearly 20 years before going to law school and then practicing law for 20 years. And here was his theory — and our "Dr. Strangelove" moment!
Ronwin said that Baycol's chemical structure "can give rise to flouride ion which can, in turn, cause injury to numerous body components . . . . In support of this theory, he cited a book and a number of scientific papers addressing the effects of flouridated drinking water on various parts of the human body." Id. at 8.
The Tenth Circuit gave Ronwin's contention more dignity than we have here — what with our snitty comments about Dr. Strangelove and all that — holding only that "Dr. Ronwin's relevant practical experience in biochemistry was too stale to qualify him to give an expert causation opinion in this case." Id. at 9.
The appellate court also trotted through a few other familiar issues to wrap things up. A plaintiff is required to offer existing scientific proof of causation and cannot rely on a hope that future studies will link the plaintiff's injury to the defendant's drug. Id. at 9-10. A treating physician must rule out all other possible causes of an injury if a differential diagnosis is to be trusted. Id. at 11. And, in addition to ruling out other causes, a physician must also "rule in" the defendant's drug as a possible cause of injury. Id.
So we're generally happy with this opinion, although we wouldn't have minded if the Tenth Circuit had chosen to publish it.
In fact, there's really only one other issue that's eating at us:
"We must be . . . increasingly on the alert to prevent them from taking over other mineshaft space, in order to breed more prodigiously than we do, thus, knocking us out in superior numbers when we emerge! Mr. President, we must not allow . . . a mine shaft gap!"
Tags: Expert Witnesses


text:
Q: Open link in new tab, maintaining window.opener The link should open a new tab, WITH reference to window.opener of the original tab. Currently window.opener is set to null.
This has special effect in iOS 12.2 where the window.opener is actually set to null, as opposed to older versions where it's not.
I think that what we need is to keep the new tab in the same browsing-context, but I don't know how.

A: I found the answer: add rel='opener' to the  tag


text:
Juno Diagnostics™ To Present At The January 2023 Biotech Showcase In San Francisco
SAN DIEGO--(BUSINESS WIRE), December 12, 2022 --Juno Diagnostics™ (JunoDx™), a company focused on bringing vital health information to patients by improving access, affordability, and transparency, today announced that JunoDx's Founder and Chief Executive Officer, Dirk van den Boom, will present a corporate overview at the Biotech Showcase 2023 meeting on Monday, January 9, 2023, at 2:00 PM. The Biotech Showcase Conference is taking place in San Francisco in parallel to the J.P. Morgan (JPM) 41st Annual HealthCare Conference.
The Company will be available to meet potential partners, collaborators, and investors. One-to-one appointments may be requested as follows:
The Biotech Showcase partnering platform: https://informaconnect.com/biotech-showcase/
Biotechnology Innovation Organization (BIO) partnering platform: https://www.bio.org/events/bio-partnering-jpm
About Juno Diagnostics™
Juno Diagnostics™ is a category-defining health company bringing vital prenatal health information to patients by combining accessibility, affordability, and transparency. The Company has developed a proprietary Sample Collection Kit and Device to facilitate capillary blood-based testing. Its lead product, the Juno Hazel™ test, is a non-invasive prenatal screening (NIPS) test that utilizes Juno's proprietary Sample Collection Kit and improves access to high-quality testing results without the high cost, long lead times, and phlebotomy requirements of traditional NIPS.
For more information, visit www.junodx.com and engage with us on LinkedIn.
Investor and Media Contact:
Amy Conrad
Juniper Point
amy@juniper-point.com
Left Older Post Back to In the press Newer Post Right


Micromax has started teasing its upcoming FHD display bearing smartphone, called Canvas Turbo featuring Hollywood hunk X-men star Hugh Jackman, who has been appointed as its brand ambassador. Hugh Jackman is the 2nd star after Khiladi Akshay Kumar to be appointed as the brand ambassador for promoting Micromax's smartphones around the globe. According to the company, people will see Hugh jackman endorsing the company's Canvas smartphones starting with Canvas Turbo.
Announcing Hugh Jackman as the Brand ambassador, Shubhodip Pal, Chief Marketing Officer, Micromax has noted that the company is very excited to welcome Hugh Jackman in the Micromax family as he truly embodies the aspirational, reinventing and fearless persona of the brand Micromax. As we look to expand our footprint across the globe in various international markets, the association with the Hugh Jackman is an ideal partnership for us to connect with audiences as he is the leading name in the entertainment industry in the world.
"I am extremely thrilled and honored to be part of the Micromax family. I am a huge lover of India as it is one of the most exciting countries in the world and we also share our love for cricket. Phones are genuinely time saving devices that can help you live a better life while juggling around with different situations," Hugh Jackman noted in statement.
There is no indication regarding the expected launch schedule of Canvas Turbo yet, but we wouldn't be surprised if Micromax releases the phone before Diwali to capitalise on the festival shopping.
According to the report, the Micromax Canvas Turbo will come with FHD display, Android 4.3 Jelly Bean and Quad-core processor. The remaining specification of the phone is still unclear at the moment.


text:
Olympics Connection: Charlie Gerard and Red Gerard
Charlie Gerard's cousin, Red Gerard, has a pair of Top 5 finishes in snowboarding at the 2022 Beijing Olympics. Red set a record when he won Gold in the 2018 Olympics in Korea at only 17 years old.
The Gerard cousins grew up near each other in Rocky River, Ohio.
"Growing up, they had a big house on the lake," Gerard said. "We'd do all the extreme sports in the winter – water ski, dirt bike, snowboarding. He might've played hockey when he was younger, but obviously he chose a different route. He's doing great out there."
Red participated in the Slopestyle event this year and earned fourth place after boarding down the course slope that was built to replicate the Great Wall of China.
"Seeing him on TV in the Olympics is mind blowing, it doesn't seem real. It's pretty impressive. He won the gold medal as the youngest Olympian ever. I'm just really proud of him and excited for him and his family."
Red keeps up with Charlie's hockey games on the internet and was able to attend the USA hockey games in Beijing in between his own events. Charlie says they keep in touch and text frequently as they root for each other.
← PSECU Player of the Week: Matt Strome
Phantoms Power Play Presented by Provident Bank →


text:
Sport / Dundee FC
Former Dundee man Dave McKay backs McCann and Gartland to get it right
by Tom Duthie
Dundee manager Neil McCann and his assistant Graham Gartland have both left the club
Sign up to our Sport newsletter
He'll have his own business to take care of from three o'clock on Saturday — but it's a safe bet once that's out of the way, one of the first things Dave Mackay will do is check the score from Dens Park where two of his former employers will have been battling it out.
Now boss of Ladbrokes League Two table-toppers Stirling Albion, Dave started his career with Dundee before going on to become a legendary Scottish Cup-winning captain for St Johnstone.
His interest in both camps is further strengthened by the fact his former McDiarmid Park team-mate Graham Gartland is now No 2 at the Dark Blues.
Graham Gartland (left) and Dave Mackay (right) crowd out Aberdeen striker Nick Blackman when both played for St Johnstone
And last, but certainly not least, for him this weekend's Tayside derby is a dress rehearsal for his Saints testimonial game in Perth next month.
As he looks to this weekend's action, unsurprisingly "Cup-tie" shares the view that a contrasting start to the season for the pair makes St Johnstone clear favourites.
While they've started the campaign unbeaten, Dundee are at the other end of the table still seeking a victory.
Well as the Perth men have been going, he doesn't rule out a home win and, whether or not it comes, has backed Gartland and boss Neil McCann to turn things round.
Having himself only been in management for 10 months, Dave probably has as good an understanding of what they're going through right now.
"It doesn't matter how long you've played, going into management is a huge change," he said.
"I went straight from being a player at St Johnstone and suddenly, instead of being responsible for yourself, you're in charge of a dressing-room.
"Neil did his TV work after he stopped playing but, for him, it will be the same kind of situation. It takes time to get used to it but you do.
"Sooner or later you will have a sticky spell like Dundee are going through just now. I did around the turn of the year when we went bottom and you start to question yourself.
"What you have to do is stick to your beliefs and I know Neil and Graham will do that because they are strong people who have good ideas about the game."
That's a phrase he repeats about his old boss at Saints, Tommy Wright, a man he admits he learned a lot from and some of whose methods he's put into effect at Stirling.
"Tommy's a great manager and I'm not surprised Saints have started the season so well. He knows exactly how to put out a team that wins game.
"He was great to work with and one big thing I've taken into management that he does is to make sure I get the right types when I'm signing players.
"You always want ability but it's important you get people who are going to work hard and won't be divisive figures in the dressing-room.
"Tommy's very good when it comes to that and it means he's always building from a very sound base.
"This season he's done that and added flair in the shape of Michael O'Halloran and Stefan Scougall — and they've got off to a brilliant start."
Another Wright strength is never underestimating the opposition and Dave knows that will be the case on Saturday.
"I've watched quite a bit of Dundee on the TV so far and they look to have been playing better football than the results suggest.
"They've been creating a lot of chances and, if they start going in, they can do well against anyone. Saints will be well aware of that."
Graham Gartland
neil mccann


Convert keywords to various annotations, include: Text, Link, FreeText, Line, Square.
2018-10-14 00:00:00 2.0 Convert keywords in PDF pages to Highlight Annotations.
Convert keywords in PDF pages to hyperlinks.
Fast and powerful hit highlighting for PDF files.
Annotate PDF using predefined keywords and phrases.
Multicolor hit highlighting for different keywords.
VeryPDF Image to PDF OCR SDK for .NET 2.1 - VeryPDF Image to PDF OCR SDK for .NET is a powerful .NET conversion tool that allows third-party developers to quickly integrate Image to PDF OCR Converter into their own standalone applications. Image to PDF OCR can convert scanned JPEG to PDF.
JPG to Vector Converter 2.1 - JPG to Vector Converter can be used to convert JPG to Vector such as JPG to EPS format in a short time.
GIF to Word OCR Converter 2.0 - GIF to Word OCR Converter can help you get the useful text messages saved in a GIF image.
PDF to XLSX Converter 2.1 - VeryPDF PDF to XLSX Converter is designed for those office users who need to convert PDF file to Excel in batch.
VeryPDF PDF to Text OCR SDK for .NET 2.0 - VeryPDF PDF to Text OCR SDK for .NET can recognize text from scanned documents with Optical Character Recognition technology. It can extract text from scanned PDF and even images. As a command line tool, users can implement batch process with batch.
The Antiplagiarism software detects a possibility of commiting plagiarism with the highest efficiency among solutions available on the market.
5 downloads VeryUtils PDF to PDF/A Converter Command Line - Create a PDF/A from a normal PDF file. VeryUtils PDF to PDF/A Converter Command Line is a Command Line application for converting PDF documents into the PDF/A format for long-term archiving.
9 downloads PDF merge is a command line tool for merging pdf files and pictures.


text:
George Wyner
Follow George Wyner
George Wyner Quick Links Pictures Video Film RSS
George Wyner Quick Links
Pictures Video Film RSS
Trouble With The Curve - Trailer Trailer
Gus Lobel is one of the most formidable baseball talent scouts around, however his age starts to fail him in his career as his eyesight deteriorates and he is unable to focus properly on the Atlanta Braves games he goes to watch. Worried about his health and career, his long-time boss and good friend enlists Lobel's daughter to accompany her father on what is to be the last talent scouting trip of his career. Mickey Lobel has never had a strong relationship with her father, since he was unable to look after her alone following the death of her mother. Nonetheless, she compromises her high status lawyer job and agrees to keep an eye on Gus, despite his protests. On the way, Mickey meets Gus's friend Johnny Flanagan; a former baseball player and aspiring talent scout who looks up to Gus and takes an interest in the beautiful Mickey. Much is to be discovered for everyone on this journey as it becomes less about baseball and more about truth, love and family.
'Trouble with the Curve' serves as the first film that Clint Eastwood has starred in without being the director since 1993 when he appeared in 'In the Line of Fire'. It is directed by Robert Lorenz in his directorial debut (though he has previously worked as an assistant director on various blockbusters) and written by Randy Brown. It is set for release on November 30th 2012.
Starring: Clint Eastwood, Justin Timberlake, John Goodman, Matthew Lillard, Chelcie Ross, Raymond Anthony Thomas, Ed Lauter, Clifton Guterman, George Wyner, Bob Gunton, Jack Gilpin, Scott Eastwood & Tom Dreesen.
George Wyner Monday 10th January 2011 TV Land's Hot In Cleveland / Retired At 35 Premiere Party held at the Sunset Tower Hotel West Hollywood, California
A Serious Man Review
The Coen brothers take another sharp turn, catching us off-guard with this offbeat suburban drama that's not only a witty window into America's Jewish subculture, but also a potent exploration of the pressures of modern life.
In 1967 Minnesota, physics professor Larry Gopnik (Stuhlbarg) is struggling as squeezes in on him. His loser uncle (Kind) has taken up residence on the sofa, his wife (Lennick) has decided to run off with a local widower (Melamed), and his teen kids (Wolff and McManus) are constantly pestering him about trivialities. Meanwhile, he's waiting to hear if he'll be given tenure at work and facing some medical tests. To make sense of it all, he consults his lawyer (Arkin) and a series of rabbis (Helberg, Wyner and Mandell).
Continue reading: A Serious Man Review
George Wyner Movies
Gus Lobel is one of the most formidable baseball talent scouts around, however his age...
A Serious Man Movie Review
The Coen brothers take another sharp turn, catching us off-guard with this offbeat suburban drama...


text:
Celebrating the Women of PAC
March is Women's History Month: a time to reflect on the contributions of women throughout history and in modern society. It's officially recognized in the US, UK, and Australia, culminating in celebrations on International Women's Day, which is held on March 8th.
What better opportunity could there be to celebrate the contributions of women in our own team?
Pacific Aerospace Consulting is here today -in very large part- because of the women who have been a part of our team throughout the years. PAC is a family company, founded in 2004 by husband-and-wife team Eric and Keren Rambow. Together, Keren and Eric built the company from the ground up-establishing the foundations for success, and the values that we adhere to today.
It's easy to say that we value and honour the unique contribution of women in our workplace, but what does this actually look like in practice? For starters, PAC's Executive Leadership Team is led equally by women. There is a whole team of women in Business Planning, Marketing & Communications, HR and Finance that provide the company's framework for success. Additionally, some of PAC's most technical and dynamic roles are held by women, in fields such as Systems Administration, Logistics, Project Management, and Engineering. Notably, of those skillsets in Australia, 3-out-of-4 women are also Veterans.
In a male-dominated industry, women not only contribute to the STEM environment in which we work, but they often bring a much needed human-element to the workplace—leading through empathy, compassion, inclusion. The women in PAC's history have brought a critical balance to our engineering/technical workforce and enabled the company to continue growing and forming a positive and productive culture while maintaining exceptional technical expertise.
Diversity and Inclusion (D&I) is encouraged at the highest levels of our company. When we have highly diverse teams, we all contribute our unique experiences and perspectives to the "special PAC sauce". D&I is more than a policy, it's how you act. We demonstrate this every day by how we treat people, support them and their families and recruit new talent into our business.
With all of this in mind, today, we're celebrating the women that have been a part of PAC's past, present, and future. This March, we encourage you to reach out to your female colleagues and let them know how much they're appreciated!
If you'd like to join our team, visit the Careers page to see all open opportunities.
« PAC Announces Partnership with Biomedtech Australia
PAC Attends Aerospace Experience Day at Aviation High School »


text:
Doing the legwork for heart patients
A NEW technique which involves removing a patient's vein for their heart bypass is being trialled at The James Cook University Hospital.
Currently around 900 coronary artery bypass grafts – a type of surgery to treat heart disease – are carried out at the Middlesbrough hospital each year.
The surgery uses a vein taken from the leg to bypass a narrowed or blocked coronary artery. This can improve blood flow to the heart and reduce the chance of a heart attack.
Traditionally, a long cut is made through the skin in the leg and the vein is identified and removed. This new procedure – known as endoscopic vein harvesting – avoids the long cut but still meticulously removes the vein.
Instead of operating through the skin, a long, thin endoscopic instrument is passed through a very small cut and along the vein under the skin, separating the vein from its branches and freeing it from surrounding tissues.
The vein is then removed intact through another second very small cut at the other end of the vein. Currently James Cook is the first hospital in the North-east to use this technique and one of only three in the country.
Consultant cardiothoracic surgeon and chief of service Simon Kendall said: "Vein grafts are often used to replace or bypass diseased arteries but patients who have had the surgery often say the cut on their leg is worse than the one on the chest. Also the leg wound can take a bit longer to heal and is more susceptible to infection.
"The main emphasis of the NHS is on patient quality and safety – endoscopic vein harvesting involves removing the vein in a very safe fashion and of course is much less invasive to patients. While we are the third heart centre in the UK to use this procedure it is common practice in the United States."
The trial at James Cook began at the end of June and already 20 patients needing by-pass surgery have had their veins harvested. A surgeon's assistant from the United States has also been working at the hospital to help the heart team learn the new technique.
Mr Kendall added: "We hope to treat 50 patients this year but the initial results suggest this is going very well. The feedback from the patients has been excellent; they are amazed and say they have much less pain."


You're going to be the most popular toy in the chest this Halloween in this Buzz Lightyear Costume for adults. Become Tim Allen's space case character who thinks toys can fly in this costume that also includes detachable wings and a hood. The body of the jumpsuit is mainly white with a black midsection and shoulder segments. The white pants feature a bright green belt that matches with the green on the accompanying boot tops. The costume's top comes with padding on the chest to give a raised look. On the chest itself are Buzz's trademark voice buttons and his blue eagle insignia. On the left side is his name in a large yellow bar. The detachable wings are made from a foam material and feature the red and white caution stripes as well as the green tips, just like the movie. A purple stretch hood goes over your head to give you the look of a helmetless Buzz.


text:
Q: PHP preg_replace: remove punctuation from beginning and end of string What regular expression can I use in PHP to remove all punctuation from the beginning and end of a string?

A: I wouldn't use a regex, probably something like...
$str = trim($str, '"\'');

Where the second argument is what you define as punctuation.
Assuming what you really meant was to strip out stuff which isn't letters, digits, etc, I'd go with...
$str = preg_replace('/^\PL+|\PL\z/', '', $str);

A: Might depend on your definition of punctuation.  If it's "anything but alphanumerics" or something like that, then a regular expression may be the way to go.  But if it's "period, question mark, and exclamation point" or some other manageable list, this will be easier to understand:
trim($string, '?!.');

A: It depends on what you call punctuation, but:
preg_replace('/^\W*(.+?)\W*$/', '$1', $source);

A: To keep only alphanumeric chars
preg_replace('/[^a-z0-9]+/i', '', $string);

for ALL ponctuations:
preg_replace('[:punct:]+', '', $string);


text:
'The Thing' Fan Theory Has a Different Take on the Monster's Idenity
filmem January 4, 2022 2 min read
Image via Universal Pictures
John Carpenter's The Thing may not have wowed critics or audiences upon its initial release in 1982 but has garnered a massive cult and mainstream following since then. Fan theories are always running rampant about the film's ending, but this fan theory posted to Reddit adds a great piece to the discussion.
Reddit user /u/No-Welcome-3707 pitched their theory to the internet on /r/FanTheories, and it adds a fascinating angle to the final film and the consequences. Mild spoilers for John Carpenter's The Thing.
We know at the start of the movie that the Thing took out the Norwegian base so this already partly confirmed. However, in the next scene, the radio operator says that he can't contact anyone. We know this refers to their commanding officers in South America and Australia, but then he goes on to say that he hasn't been able to contact anyone "on the continent" for the past two weeks. I think this indicates that the Thing didn't just wipe out the Norwegians but every other base on Antarctica.
/u/No-Welcome-3707 on /r/FanTheories
It definitely makes sense, but it does ask more questions than answers. The most popular retort to this theory in the comments comes from the explanation that losing radio contact with the outside world is much more a plot device for isolation than anything deeper for the story.
This would dismiss the popular fan theory that both Macready and Chiles are the Thing and suggest that only one is at the end of The Thing. Whether or not this would fly with hardcore fans of The Thing is uncertain, as the following for the film is very much built upon the speculation of its ending and open-endedness.
The Thing is celebrating its 40th anniversary this year and continues to amass more of a following many years after its release.
Previous AFTERLIFE, and Who He Consulted Along the Way — GeekTyrant
Next Netflix's Space Force Season 2 Premiere Date & First Look


When you invest in inbound marketing, you invest in becoming a media source. You no longer have to invest in buying spots and slots on someone else's programming. You ARE the producer and the medium.
Instead of creative being a small portion of your marketing, your budget gets flipped upside down. Creative now gets the lion's share of your marketing dollars, and the push gets a much smaller share.
In both cases, you are working to get your message out to potential customers, but by using inbound marketing, you acknowledge that paying someone else to push your content in 2017 is running your marketing spigot into a bucket with a bunch of holes in it.
Inbound marketing does not necessarily give the instant gratification of traditional media. You don't get to drive by your brand pushing into the sky every morning on your way to work like you do with a billboard. You don't get the rush of dopamine that comes when you see your your commercial interrupt the Pittsburgh Steelers on a crisp Sunday afternoon, and you won't be able to hear your commercial on the radio or in the local newspaper if that's your thing.
What you will be able to do is build assets that will continue to drive leads for you long after you've paid your invoice. You will be able to recycle your content assets and drive down creative costs in the future by reformatting creative assets for different situations. You will be able to link content to each other to drive SEO, and you will be able to track what marketing is striking a chord with your target audience and which is falling flat.
Budgets rise and fall, and there is no doubt that an integrated marketing strategy that encompasses a full spectrum of tactical branding and advertising is the best approach. All the gears move better when they are moving in the same direction and work together. But those budgets and strategies shouldn't be developed and executed according to our egos as businesspeople. They should be judged by their ability to aid in our long term growth.
Make no mistake, the path toward sustained inbound marketing lead generation is an investment in long game success. It's not for those that are impatient or are going to fold if they don't see leads pouring in at the 3-6 month mark.
Content marketing success takes on average a good 12-18 months to take root, sprout, and start to bear significant fruit, but ask those who are patient enough to taste that fruit how sweet it is and whether it was worth the wait.
Until we get to know you and your business, we can't tell you what strategy is best for your specific situation, but we do know that as more and more people recognize the power of producing and pushing out their own content, competition for attention will become more fierce, and those that begin investing in gaining the attention of a market hungry for information, guidance, and even entertainment now will be the first to reap the rewards as we continue to see more and more lead generation come from digital sources.


text:
Enfield Shaker Portraits
Sister Zelinda Smith
Carte de Visite, Sister Zelinda Smith
C. E. Lewis, Photographer, Lebanon, NH, ca. 1880
Zelinda Smith, daughter of Uriah and Susan (Peck) Smith, was born January 30, 1820 in Mount Morris, New York.
Zelinda Smith was born into a family of religious reformers and preachers. Her uncle, Elias Smith was a founder of New England's Christian Connexion movement, and the editor of what is believed to be America's first religious newspaper, The Herald of Gospel Liberty in 1808. Zelinda's father Uriah was not as charismatic or controversial a preacher as his brother, but the two shared the belief that common people should take their religious destiny into their own hands, think for themselves, base their faith only on the bible, and oppose centralized authority. Their faith called them to reject the doctrines of the Trinity and of predestination, to oppose slavery, espouse temperance, and support women preachers of the gospel. These beliefs were consistent with Shaker teaching and led Uriah to consider a Shaker life for his children.
In 1835 the family moved from Woodstock, Vermont to Enfield, NH at which time Zelinda and three of her siblings, Elias, Amanda, and Philo, were placed with the Shakers. Uriah, his wife and youngest child, Susan, settled on property at the head of Mascoma Lake and began to gather a small congregation of individuals who would ultimately identify themselves as Universalists. Zelinda's sister Amanda and brother Philo left the Shakers as young adults, but Zelinda and her older brother, Elias, remained lifelong Shakers.
Zelinda moved from the gathering order to the Church family in 1837 and entered fully into the Shaker religious revival that was underway. She was one of many instruments who conveyed messages from the spirit world to the society during "The Period of Mother's Work."
She became an Office Deaconess in 1857. Her duties included serving as cook for Trustee's office residents, and for Shaker and non-Shaker visitors travelling here for business or fellowship. Zelinda was also an accomplished tailoress.
Between 1864 and 1899 she served alternately at the Trustees Offices of the Church and North Family. In both places she is identified in the public census as a seamstress.
Zelinda's biological sister Susan married an Enfield entrepreneur, James Willis Johnson. They lived in Enfield Center. James had many business dealings with the Shakers, and Susan brought relatives to visit the community. Zelinda's niece wrote this account:
"When I was a young girl I visited an aunt every summer who lived in Enfield Center. The only way for her to entertain was to hire a horse and democrat wagon of a neighbor and go to the Shakers for either dinner or to Church…. How well I remember the face, but have forgotten the name of the lovely gracious woman who had charge of the office [Mary Fall], her cheeks were like red roses. When we came she would send word to the dining room that we would be over in a little while and after we went over our Aunt Zelinda Smith would come in and curtsy and then leave, too busy to stop.
"She certainly exemplified the saying of "straight as a ramrod." I always wondered why she didn't crack when she stooped over. After eating and going back to the office her brother, Uncle Elias, would be called and always seemed to enjoy having us come. He was as jolly as Zelinda was stiff. He played a fife, which was permitted. I suppose they both lie in the cemetery back of the church. They had brother Filo there who ran away and a sister Amanda who left and married in Minnesota."1
Zelinda's Shaker family knew her not as a stiff ramrod but as a sweet Shaker sister, who for 60 years was universally loved and respected.
Zelinda Smith died January 30, 1899 of pneumonia at the Shaker community in Enfield, New Hampshire. Her obituary was published in March 1899 issue of The Manifesto (p. 43). She is buried in the Church Family Shaker Cemetery in Enfield.
Original author: Mary Ann Haagen