text:
// flRcvrStatus still necessary???
#define INCL_DEV
#define INCL_OS2MM
#define INCL_WININPUT
#define INCL_WINFRAMEMGR
#define INCL_WINTRACKRECT
#define INCL_WINMENUS
#define INCL_WINSYS
#define INCL_WINMESSAGEMGR
#define INCL_WINSHELLDATA
#define INCL_WINWINDOWMGR
#define INCL_WINHELP
#define INCL_WINPOINTERS
#define INCL_GPICONTROL
#define INCL_GPIPRIMITIVES
#define INCL_GPILOGCOLORTABLE
#define INCL_GPIBITMAPS
#define INCL_GPITRANSFORMS
#define INCL_GPIREGIONS
#define INCL_DOSFILEMGR
#define INCL_DOSSEMAPHORES
#define INCL_DOSDATETIME
#define INCL_GPILCIDS

#include <os2.h>
#include <os2me.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cutil.h>

#include "dcfioctl.h"

#pragma info(noeff)         // suppress SOM compiler informationals

#include "wpdcf77.ih"
#include "wpdcf.h"

#include "play.h"
#include "clock.h"
#include "res.h"
#include "clkdata.h"
#include "dcf77.h"
#include "paint.h"
#include "alarmthd.h"
#include "udtime.h"
#include "wndproc.h"
#include "debug.h"

/*--------------------------------------------------------------*\
 *  Globale definitions and variables for this module           *
\*--------------------------------------------------------------*/
#define CCHMAXFONTSIZENAME      32

#define TESTSIZE                12  // test size for font

#define IDX_WINDOWPTR           4   // index of WindowPtrs (QWL_USER + 4)

const SIZEL sizl = {200, 200};      // presentation space size for analog clock

const MATRIXLF vmatlfTrans =
         {
         MAKEFIXED (1, 0), MAKEFIXED (0, 0), 0L,
         MAKEFIXED (0, 0), MAKEFIXED (1, 0), 0L,
         0L,               0L,               1L
         };
const MATRIXLF vmatlfScale =
         {
         MAKEFIXED (1, 0), MAKEFIXED (0, 0), 0L,
         MAKEFIXED (0, 0), MAKEFIXED (1, 0), 0L,
         0L ,              0L,               1L
         };

/*******************************************************************\
    ClkWndProc: window procedure for the clock
    Input:   hwnd: window handle
             msg:  message type
             mp1:  parameter 1
             mp2:  parameter 2
\*******************************************************************/
MRESULT EXPENTRY ClkWndProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
    {
    WPDCF77     *somSelf;
    WPDCF77Data *somThis;
    PWINDOWDATA pWindowData;
    POINTL      ptl;
    SWP         swp;
    CHAR        szSubst[CCHMAXDATETIME];

    switch (msg)
        {
        case WM_CREATE:
            pWindowData = (PWINDOWDATA) mp1;
            ClkCreate (hwnd, pWindowData);
            return FALSE;

        case WM_1STIMER:
            ClkTimer (hwnd);
            return 0;

        case WM_BUTTON2CLICK:
            pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
            somThis = pWindowData->somThis;
            somSelf = pWindowData->somSelf;
            WinQueryPointerPos (HWND_DESKTOP, &ptl);
            WinMapWindowPoints (HWND_DESKTOP, hwnd, &ptl, 1);
            _wpDisplayMenu (somSelf, _hwndFrame, _hwndFrame, &ptl, MENU_OPENVIEWPOPUP, 0);
            break;

        case WM_PAINT:
            ClkPaint (hwnd, (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER));
            return 0;

        /* WM_MINMAXFRAME is used for controlling the icon position.                  */
        /* On default OS/2 controls the icon positions separately from window         */
        /* positions.                                                                 */
        /* The following messages will be handled: WM_MINMAXFRAME - WM_MOVE - WM_SIZE */
        /* (some receive multiple times)                                              */
        /* If in _ulPresence DISPLAY_ICONPOS is set, the following happens:           */
        /* - WM_MINMAXFRAME: On change Icon <-> Normal in ulMinMaxStat                */
        /*                   is set to MINMAX_CHANGED                                 */
        /* - WM_MOVE:        ulMinMaxStat == MINMAX_NORMAL: save position             */
        /*                   otherwise: ulMinMaxStat = MINMAX_WAIT4SIZE               */
        /* - WM_SIZE:        ulMinMaxStat == MINMAX_WAIT4SIZE: re-set position,       */
        /*                   ulMinMaxStat = MINMAX_NORMAL                             */
        case WM_MINMAXFRAME:
            pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
            somThis = pWindowData->somThis;
            if (_ulPresence & PRESENCE_MINMAXPOS)
                {
                _ulMinMaxStat = MINMAX_CHANGED;
                DebugE (D_MINMAX, "ClkWndProc", "WM_MINMAXFRAME: MINMAX_CHANGED");
                }
            break;

        case WM_PLAY_MMFILE:
            pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
            somThis = pWindowData->somThis;
            DebugE (D_ALARM, "ClkWndProc", "play multimedia file");

            if (_szAlarmSoundFile[0] != '\0' && bIsAudio)
                {
                BOOL bRC;
                bRC = ClkMciPlayFile (_hwndClient, _szAlarmSoundFile);
                DebugULx (D_ALARM, "ClkWndProc", "return for mciPlayFile: ", (bRC ? "TRUE" : "FALSE"));
                }
            return 0;

        case WM_SIZE:
            ClkSize (hwnd);
            return 0;

        case WM_MOVE:
            pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
            somThis = pWindowData->somThis;

            WinQueryWindowPos (_hwndFrame, &swp);
            if (!(swp.fl & SWP_MINIMIZE))
                {
                _lcxClock = swp.cx;
                _lcyClock = swp.cy;
                }

            /* Change Icon<->Normal? -> special handling; see WM_MINMAXFRAME */
            if (_ulMinMaxStat == MINMAX_NORMAL)
                {
                if (!(swp.fl & SWP_MINIMIZE))
                    {
                    _lxPos = swp.x;
                    _lyPos = swp.y;
                    DebugE (D_MINMAX, "ClkWndProc", "WM_MOVE: Position saved");
                    }
                else if (_ulPresence & PRESENCE_MINMAXPOS)
                    {
                    _lxIconPos = swp.x;
                    _lyIconPos = swp.y;
                    DebugE (D_MINMAX, "ClkWndProc", "WM_MOVE: Icon-Position saved");
                    }
                }
            else
                _ulMinMaxStat = MINMAX_WAIT4SIZE;

            _wpSaveDeferred (pWindowData->somSelf);
            return 0;

        case WM_BUTTON1DOWN:
            pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
            somThis = pWindowData->somThis;
            if (WinIsChild (_hwndTitleBar, HWND_OBJECT))
                return WinSendMsg (_hwndFrame, WM_TRACKFRAME,
                                   MPFROMSHORT((USHORT)mp2 | TF_MOVE), MPVOID);
            else
                break;

        case WM_MESSAGE:
            pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
            somThis = pWindowData->somThis;
            MessageBox (hwnd, (ULONG)mp1, IDMSG_ALARMTITLE, (ULONG)mp2, 0, *_szAlarmMsg == '\0' ? NULL : _szAlarmMsg);
            return 0;

        case WM_SUBSTITUTESTRING:
            pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
            somThis = pWindowData->somThis;
            switch (SHORT1FROMMP (mp1))
                {
                case 0:                     // parameter %t: time
                    GetDateTime (&_dt, MODE_PM | MODE_YEAR_2D, szSubst, NULL);
                    return szSubst;

                case 1:                     // parameter %d: date
                    GetDateTime (&_dt, MODE_PM | MODE_YEAR_2D, NULL, szSubst);
                    return szSubst;

                case 2:                     // parameter %z: time zone
                    return _szTimezone;
                }
            return 0;

        case WM_PRESPARAMCHANGED:
            ClkPresparam (hwnd, (ULONG)LONGFROMMP (mp1));
            return 0;

        /* WM_USER_STARTPLAY is used for initialization of audio output      */
        /* mp1: SHORT1: number of play actions                               */
        /*      SHORT2: reserved                                             */
        /* mp2: reserved                                                     */
        case WM_USER_STARTPLAY:
            pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
            ClkStartAudioPlay (hwnd, pWindowData, LONGFROMMP (mp1));
            return 0;

        /* MM_MCIPASSDEVICE informs the system about a change in ownership   */
        /* of a commonly used multimedia device                              */
        /* mp1: USHORT1: usDeviceID                                          */
        /*      USHORT2: reserved                                            */
        /* mp2: USHORT1: usEvent                                             */
        /*      USHORT2: reserved                                            */
        case MM_MCIPASSDEVICE:
            ClkMciPassDevice (hwnd, IDX_WINDOWPTR, SHORT1FROMMP (mp2));
            break;

        /* WM_ACTIVATE informs the system about a change of the window focus */
        /* This is used to acquire the ownership of the multimedia system    */
        /* via MM_ACQUIREDEVICE .                                            */
        /* mp1: USHORT1: usactive                                            */
        /*      USHORT2: reserved                                            */
        /* mp2: hwnd                                                         */
        case WM_ACTIVATE:
            ClkMciActivate (hwnd, IDX_WINDOWPTR, (BOOL)mp1);
            break;

        /* WM_PLAY_FINISHED informs the system about a finished play of an   */
        /* audio file.                                                       */
        case WM_PLAY_FINISHED:
            ClkMciCheckRedo (hwnd, IDX_WINDOWPTR);
            return 0;

        case WM_DESTROY:
            ClkDestroy ((PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER));
            return 0;

        case WM_CLOSE:
            pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
            somThis = pWindowData->somThis;

            if (pWindowData == NULL)
                {
                DebugE (D_WND | D_DIAG, "ClkWndProc", "WM_CLOSE: couldn't get window words");
                return FALSE;
                }

            /* Alarm anhalten */
            DebugE (D_ALARM, "ClkWndProc", "Alarm STOPPED");
            AlarmStart (somThis, stop);
            _wpDeleteFromObjUseList (pWindowData->somSelf, &pWindowData->UseItem);
            _wpRemove1sTimer (pWindowData->somSelf, hwnd);

            ClkMciClose (hwnd, IDX_WINDOWPTR);

            DebugULx (D_WND, "WM_CLOSE", "hwndFrame", _hwndFrame);
            WinDestroyWindow (_hwndFrame);
            _wpFreeMem (pWindowData->somSelf, (PBYTE)pWindowData);
            return 0;
        }

    return WinDefWindowProc (hwnd, msg, mp1, mp2);
    }

/*******************************************************************\
    ClkCreate: Handle WM_CREATE message: create presentation spaces,
               initialize variable
    Input:   hwnd:        window handle
             pWindowData: pointer to window data
\*******************************************************************/
VOID ClkCreate (HWND hwnd, PWINDOWDATA pWindowData)
    {
    LONG lxTemp, lyTemp;
    WPDCF77Data *somThis;

    /* initialize access to instance data */
    somThis = pWindowData->somThis;

    /* Class view/usage details and window specific data */
    pWindowData->UseItem.type    = USAGE_OPENVIEW;
    pWindowData->ViewItem.view   = (_ulPresence & PRESENCE_DISP_DIGITAL) ? OPEN_DIGITAL : OPEN_ANALOG;
    pWindowData->ViewItem.handle = _hwndFrame;

    /* fill Window-Ptr with pWindowData and register view */
    WinSetWindowPtr (hwnd, QWL_USER, pWindowData);
    _wpAddToObjUseList (pWindowData->somSelf, &pWindowData->UseItem);
    _wpRegisterView (pWindowData->somSelf, _hwndFrame,
                     _ulPresence & PRESENCE_DISP_DIGITAL ? "Digital" : "Analog");
    WinSetFocus (HWND_DESKTOP, _hwndFrame);

    /* initialize audio */
    WinSetWindowPtr (hwnd, QWL_USER + IDX_WINDOWPTR, NULL);
    bIsAudio = ClkMciIsMultimedia () ? TRUE : FALSE;
    DebugE (D_WND, "ClkCreate => bIsAudio", (bIsAudio ? "TRUE" : "FALSE"));

    /* delete icon to paint a "living" icon */
    WinSendMsg (_hwndFrame, WM_SETICON, MPVOID, MPVOID);

    _vmatlfDateTrans = vmatlfTrans;
    _vmatlfDateScale = vmatlfScale;

    _hwndTitleBar = WinWindowFromID (_hwndFrame, FID_TITLEBAR);
    _hwndSysMenu  = WinWindowFromID (_hwndFrame, FID_SYSMENU);
    _hwndMinMax   = WinWindowFromID (_hwndFrame, FID_MINMAX);

    if (pWindowData->ViewItem.view == OPEN_ANALOG)
        {
        /* determine screen size; open device context */
        /* create presentation space                  */
        _hdc = WinOpenWindowDC (hwnd);
        _hps = GpiCreatePS (hab, _hdc, (PSIZEL)&sizl,
                            PU_ARBITRARY | GPIT_MICRO | GPIA_ASSOC);

        /* create own off-screen 'buffer' */
        _hdcBuffer = DevOpenDC ((HAB)0L, OD_MEMORY, "*", 0L, NULL, _hdc);
        _hpsBuffer = GpiCreatePS (hab, _hdcBuffer, (PSIZEL)&sizl,
                                  PU_ARBITRARY | GPIT_MICRO | GPIA_ASSOC);

        /* switch system to RGB mode */
        GpiCreateLogColorTable (_hpsBuffer, 0, LCOLF_RGB, 0, 0, NULL);

        /* determine resolution, to draw a round clock face */
        DevQueryCaps (_hdc, CAPS_HORIZONTAL_RESOLUTION, 1, (PLONG)&pWindowData->cxRes);
        DevQueryCaps (_hdc, CAPS_VERTICAL_RESOLUTION,   1, (PLONG)&pWindowData->cyRes);
        DevQueryCaps (_hdc, CAPS_COLOR_PLANES,          1, (PLONG)&pWindowData->cColorPlanes);
        DevQueryCaps (_hdc, CAPS_COLOR_BITCOUNT,        1, (PLONG)&pWindowData->cColorBitcount);
        }
    else
        {
        _hdc = WinOpenWindowDC (hwnd);
        _hps = GpiCreatePS (hab, _hdc, (PSIZEL)&sizl,
                            PU_PELS | GPIT_MICRO | GPIA_ASSOC);
        }

    ClkSetRGBColors (somThis);
    ClkSetFonts (somThis);

    /* get date and time */
    GetDateTimeOffs (_lLOffset, &_dt);
    _flRcvrStatus     = GetDCFStatus ();
    _flRcvrStatusMask = StatDCF.flMaskST & (MASK_ST_TZONE1 | MASK_ST_BATT);

    /* position window and make visible */
    if (_ulPresence & PRESENCE_DISP_MINIMIZE)
        {
        lxTemp = _lxIconPos;
        lyTemp = _lyIconPos;
        }
    else
        {
        lxTemp = _lxPos;
        lyTemp = _lyPos;
        }

    WinSetWindowPos (_hwndFrame, NULLHANDLE,
        lxTemp, lyTemp, _lcxClock, _lcyClock,
        SWP_ACTIVATE | SWP_SIZE | SWP_MOVE | (_ulPresence & PRESENCE_DISP_MINIMIZE ? SWP_MINIMIZE : 0));

    if (_ulPresence & (PRESENCE_MINMAXPOS | PRESENCE_DISP_MINIMIZE))
        WinSetWindowPos (_hwndFrame, NULLHANDLE,
                         lxTemp, lyTemp, _lcxClock, _lcyClock,
                         SWP_MOVE);

    /* show title bar? */
    if (!(_ulPresence & PRESENCE_TITLEBAR))
        ClkShowFrameControls (_hwndFrame, FALSE);

    WinShowWindow (_hwndFrame, TRUE);

    /* start timer */
    _wpAdd1sTimer (pWindowData->somSelf, hwnd);

    return;
    }

/*******************************************************************\
    ClkDestroy: Handle WM_DESTROY message:
                free presentation spaces
    Input: pWindowData: pointer to window data
\*******************************************************************/
VOID ClkDestroy (PWINDOWDATA pWindowData)
    {
    WPDCF77Data *somThis;
    HBITMAP     hbm;

    /* initialize access to instance data */
    somThis = pWindowData->somThis;

    if (pWindowData->ViewItem.view == OPEN_ANALOG)
        {
        hbm = GpiSetBitmap (_hpsBuffer, NULLHANDLE);

        if (hbm != NULLHANDLE)
            GpiDeleteBitmap (hbm);
        }

    GpiDestroyPS (_hpsBuffer);
    DevCloseDC   (_hdcBuffer);
    _hpsBuffer = NULLHANDLE;
    _hdcBuffer = NULLHANDLE;

    GpiDestroyPS (_hps);
    DevCloseDC   (_hdc);
    _hps = NULLHANDLE;
    _hdc = NULLHANDLE;

    return;
    }

/*******************************************************************\
    ClkSize: Handle WM_SIZE message:
             Calculate page viewports, determine position of
             date field
    Input: hwnd: window handle
\*******************************************************************/
VOID ClkSize (HWND hwnd)
    {
    LONG             cxSquare, cySquare, cxEdge, cyEdge, cxWindow, cyWindow;
    RECTL            rclWindow;
    RECTL            rclPage;               // size of page viewports
    SWP              swp;
    HBITMAP          hbm;
    BITMAPINFOHEADER bmp;
    PWINDOWDATA      pWindowData;
    WPDCF77Data      *somThis;

    /* initialize access to instance data */
    pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
    somThis = pWindowData->somThis;

    /* is clock iconized? */
    WinQueryWindowPos (_hwndFrame, &swp);
    if (swp.fl & SWP_MINIMIZE)
        _ulPresence |= PRESENCE_DISP_MINIMIZE;
    else
        {
        _ulPresence &= ~PRESENCE_DISP_MINIMIZE;
        _lcxClock = swp.cx;
        _lcyClock = swp.cy;
        }

    /* change Icon<->Normal? -> special handling; see WM_MINMAXFRAME */
    if (_ulMinMaxStat == MINMAX_WAIT4SIZE)
        {
        if (_ulPresence & PRESENCE_DISP_MINIMIZE)
            {
            swp.x = _lxIconPos;
            swp.y = _lyIconPos;
            }
        else
            {
            swp.x = _lxPos;
            swp.y = _lyPos;
            }
        WinSetWindowPos (_hwndFrame, NULLHANDLE,
            swp.x, swp.y, _lcxClock, _lcyClock,
            SWP_MOVE);
        _ulMinMaxStat = MINMAX_NORMAL;
        DebugE (D_MINMAX, "ClkWndProc", "WM_SIZE: Position set");
        }
    else
        {
        if (swp.fl & SWP_MINIMIZE)
            {
            _lxIconPos = swp.x;
            _lyIconPos = swp.y;
            DebugE (D_MINMAX, "ClkWndProc", "WM_SIZE: Icon-Position saved");
            }
        else
            {
            _lxPos    = swp.x;
            _lyPos    = swp.y;
            DebugE (D_MINMAX, "ClkWndProc", "WM_SIZE: Position saved");
            }
        }

    if (pWindowData->ViewItem.view == OPEN_ANALOG)
        {
        /* delete present bitmaps in buffer, if any */
        hbm = GpiSetBitmap (_hpsBuffer, NULLHANDLE);
        if (hbm != NULLHANDLE)
            GpiDeleteBitmap (hbm);

        /* determine size of client window */
        WinQueryWindowRect (hwnd, &rclWindow);
        cxWindow = rclWindow.xRight - rclWindow.xLeft;
        cyWindow = rclWindow.yTop - rclWindow.yBottom;

        /* create bitmap in window size */
        bmp.cbFix     = sizeof(BITMAPINFOHEADER);
        bmp.cx        = (SHORT)cxWindow;
        bmp.cy        = (SHORT)cyWindow;
        bmp.cPlanes   = (SHORT)pWindowData->cColorPlanes;
        bmp.cBitCount = (SHORT)pWindowData->cColorBitcount;
        hbm = GpiCreateBitmap(_hpsBuffer, (PBITMAPINFOHEADER2)&bmp, 0, NULL, NULL);
        GpiSetBitmap (_hpsBuffer, hbm);

        /* Assumption: Rectangle is limited by y-direction */
        /* -> calculate cx to achieve square rectangle     */
        /* if wrong assumption: converse action            */
        cySquare = cyWindow - 4;
        cxSquare = (cyWindow * pWindowData->cxRes) / pWindowData->cyRes;
        if (cxWindow < cxSquare)
            {
            cxSquare = cxWindow - 4;
            cySquare = (cxWindow * pWindowData->cyRes) / pWindowData->cxRes;
            }

        /* determine remaining area and set page viewport */
        cxEdge = (cxWindow - cxSquare) / 2;
        cyEdge = (cyWindow - cySquare) / 2;
        rclPage.xLeft   = cxEdge;
        rclPage.xRight  = cxWindow - cxEdge;
        rclPage.yBottom = cyEdge;
        rclPage.yTop    = cyWindow - cyEdge;

        /* determine position of date; priority sequence: */
        /* 1. Below clock                                 */
        /* 2. Left of clock                               */
        /* 3. Inside clock                                */
        if (cyWindow > (cySquare*6/5))          /* Below clock */
            {
            /* Matrix:  2.5    0      0  */
            /*          0      2.5    0  */
            /*         15    -17      1  */
            _vmatlfDateTrans.lM31  = 15;        /* horizontal */
            _vmatlfDateTrans.lM32  = -17;       /* vertical   */
            _vmatlfDateScale.fxM11 = MAKEFIXED (2, 0x8000);
            _vmatlfDateScale.fxM22 = MAKEFIXED (2, 0x8000);
            rclPage.yTop    += cyEdge;
            rclPage.yBottom += cyEdge;
            }
        else if (cxWindow > (cxSquare * 31/10))
            {
            /* Matrix:  7.875  0      0  */
            /*          0      7.875  0  */
            /*        -53      4      1  */
            _vmatlfDateTrans.lM31  = -53 ;      /* horizontal */
            _vmatlfDateTrans.lM32  = 4;         /* vertical   */
            _vmatlfDateScale.fxM11 = MAKEFIXED (7, 0xE000);
            _vmatlfDateScale.fxM22 = MAKEFIXED (7, 0xE000);
            rclPage.xRight += cxEdge;
            rclPage.xLeft  += cxEdge;
            }
        else if (cxWindow > (cxSquare * 2))     /* Left */
            {
            /* Matrix:  3.8125 0      0  */
            /*          0      7.8725 0  */
            /*        -52      2      1  */
            _vmatlfDateTrans.lM31  = -52;       /* horizontal */
            _vmatlfDateTrans.lM32  = 2;         /* vertical   */
            _vmatlfDateScale.fxM11 = MAKEFIXED (3, 0xD000);
            _vmatlfDateScale.fxM22 = MAKEFIXED (3, 0xD000);
            rclPage.xRight += cxEdge;
            rclPage.xLeft  += cxEdge;
            }
        else                                    /* Inside */
            {
            _vmatlfDateTrans.lM31  = 24;        /* horizontal */
            _vmatlfDateTrans.lM32  = 23;        /* vertical   */
            _vmatlfDateScale.fxM11 = MAKEFIXED (2, 0);
            _vmatlfDateScale.fxM22 = MAKEFIXED (2, 0);
            }

        GpiSetPageViewport (_hps,       &rclPage);
        GpiSetPageViewport (_hpsBuffer, &rclPage);
        }

    _bBufferDirty = TRUE;

    _wpSaveDeferred (pWindowData->somSelf);

    return;
    }

/*******************************************************************\
    ClkTimer: Handle WM_1STIMER message:
    Input: hwnd: window handle
\*******************************************************************/
VOID ClkTimer (HWND hwnd)
    {
    PWINDOWDATA  pWindowData;
    WPDCF77      *somSelf;
    WPDCF77Data  *somThis;
    DATETIME     dtNew;
    USHORT       flRcvrStatusNew;
    USHORT       flRcvrStatusMaskNew;
    ULONG        ulTime;
    BOOL         bUpdate = FALSE;

    /* initialize access to instance data */
    pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
    somSelf     = pWindowData->somSelf;
    somThis     = pWindowData->somThis;

    /* get new time */
    GetDateTimeOffs (_lLOffset, &dtNew);

    if (pWindowData->ViewItem.view == OPEN_ANALOG)
        {
        /* get new DCF state */
        flRcvrStatusNew     = GetDCFStatus ();
        flRcvrStatusMaskNew = StatDCF.flMaskST & (MASK_ST_TZONE1 | MASK_ST_BATT);

        if ((_dt.minutes ^ dtNew.minutes) + (_dt.hours ^ dtNew.hours) +
            (_dt.day     ^ dtNew.day)     + (_dt.month ^ dtNew.month) +
            (_dt.year    ^ dtNew.year))
            {
            /* Redraw, as minute has been changed */
            ClkDrawClock (_hpsBuffer, DCLK_HANDS, somThis, &dtNew, flRcvrStatusNew);
            ClkUpdateScreen (_hps, somThis, NULL);
            bUpdate = TRUE;

            if (_ulPresence & PRESENCE_DISP_SEC_HAND && !(_ulPresence & PRESENCE_DISP_MINIMIZE))
                {
                GpiSetMix (_hps, FM_INVERT);
                ClkDrawHand (_hps, somThis, HT_SECOND, dtNew.seconds);
                }
            }

        /* start audio output, if installed and activated */
        if (dtNew.minutes == 0 && dtNew.seconds == 0 && bIsAudio)
            WinPostMsg (hwnd, WM_USER_STARTPLAY, MPFROMSHORT (dtNew.hours), 0);

        // ??? clock is drawn twice on minute change????
        if (flRcvrStatusNew != _flRcvrStatus || flRcvrStatusMaskNew != _flRcvrStatusMask)
            {
            if ((flRcvrStatusNew ^ _flRcvrStatus) &
                (STATUS_TZONE1 | STATUS_TZONE2    | STATUS_CARRIER |
                 STATUS_BATT   | STATUS_TIMEVALID | STATUS_ISDRIVER) ||
                flRcvrStatusMaskNew != _flRcvrStatusMask)
                {
                /* draw status display */
                ClkDrawClock (_hpsBuffer, DCLK_ALL, somThis, &dtNew, flRcvrStatusNew);
                ClkUpdateScreen (_hps, somThis, NULL);
                bUpdate = TRUE;
                _flRcvrStatus     = flRcvrStatusNew;
                _flRcvrStatusMask = flRcvrStatusMaskNew;

                if (_ulPresence & PRESENCE_DISP_SEC_HAND && !(_ulPresence & PRESENCE_DISP_MINIMIZE))
                    {
                    GpiSetMix (_hps, FM_INVERT);
                    ClkDrawHand (_hps, somThis, HT_SECOND, dtNew.seconds);
                    }
                }
            }

        if (_ulPresence & PRESENCE_DISP_SEC_HAND && !(_ulPresence & PRESENCE_DISP_MINIMIZE) && !bUpdate)
            {
            /* otherwise just delete and redraw second hand */
            GpiSetMix (_hps, FM_INVERT);
            ClkDrawHand (_hps, somThis, HT_SECOND, _dt.seconds);
            ClkDrawHand (_hps, somThis, HT_SECOND, dtNew.seconds);
            }

        }
    else
        {
        ClkDrawDigitalTime (hwnd, &dtNew,
            (_dt.minutes ^ dtNew.minutes) + (_dt.hours ^ dtNew.hours) +
            (_dt.day     ^ dtNew.day)     + (_dt.month ^ dtNew.month) +
            (_dt.year    ^ dtNew.year) ?
            DCLK_ALL : DCLK_HANDS);
        }

    _dt = dtNew;

    if (!_ulTimeChangeCheck)
        /* initialize on first pass */
        _ulTimeChangeCheck = (ULONG)GetTimeLowOffs (_lLOffset);
    else
        {
        /* Quick check, if another session has change the time */
        ulTime = (ULONG)GetTimeLowOffs (_lLOffset);
        if (ulTime > (_ulTimeChangeCheck + 60) ||
            _ulTimeChangeCheck > (ulTime + 60))
            {
            /* time has been changed for more than 60 seconds */
            DebugE (D_ALARM, "ClkTimer", "TimeChange");
            if (!AlarmSetTimer (somThis, &dtNew))
                _wpSaveDeferred (somSelf);
            _wpRefreshClockView (somSelf);          // face only is sufficient! ???
            }
        _ulTimeChangeCheck = ulTime;
        }

    return;
    }

/*******************************************************************\
    ClkStartAudioPlay: Calculates number of gongs depending on
                       time and plays the corresponding WAV file,
                       if possible and necessary
    Input: hwnd:    window handle
           ulHours: hours of time
\*******************************************************************/
VOID ClkStartAudioPlay (HWND hwnd, PWINDOWDATA pWindowData, ULONG ulHours)
    {
    WPDCF77     *somSelf;
    HOBJECT      hObject;

    somSelf = pWindowData->somSelf;
    hObject = _wpQueryHandle (somSelf);

    if ((hObject == hClsRingingObject) && (szClsGongFile[0] != '\0'))
        {
        if (bClsIs1PerHour)
            ulHours = 1;
        else
            {
            ulHours = ulHours % 12;
            ulHours = ulHours ? ulHours : 12;
            }

        if (ClkMciLoadFile (hwnd, IDX_WINDOWPTR, szClsGongFile, ulHours))
            ClkMciStartPlayBack (hwnd, IDX_WINDOWPTR, WM_PLAY_FINISHED);
        }

    return;
    }

/*******************************************************************\
    ClkPresparam: Handles changes of presentation parameters
                  PP_BACKGROUNDCOLOR and PP_FONTNAMESIZE
    Input: hwnd:   window handle
           ulType: PresParam type: PP_*
\*******************************************************************/
VOID ClkPresparam (HWND hwnd, ULONG ulType)
    {
    PWINDOWDATA pWindowData;
    WPDCF77     *somSelf;
    WPDCF77Data *somThis;
    RGB         rgb;
    LONG        lCount;
    PBYTE       pBuffer;

    /* Initialize access to instance data */
    pWindowData = (PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER);
    somSelf     = pWindowData->somSelf;
    somThis     = pWindowData->somThis;

    switch (ulType)
        {
        case PP_BACKGROUNDCOLOR:
            WinQueryPresParam (hwnd, ulType, 0, NULL, sizeof (RGB), (PVOID)&rgb,
                QPF_PURERGBCOLOR);

            _clrFace    = (rgb.bRed<<16) + (rgb.bGreen<<8) + rgb.bBlue;
            _clrBackgnd = _clrDateOnAnalog = _clrFace;
            DebugULx (D_DRAG, "ClkWndProc", "RGB-value", _clrFace);
            break;

        case PP_FONTNAMESIZE:
            if (!DosAllocMem ((PPVOID)&pBuffer, CCHMAXFONTSIZENAME + sizeof (FONTMETRICS),
                             PAG_COMMIT | PAG_READ | PAG_WRITE))
                {
                WinQueryPresParam (hwnd, ulType, 0, NULL, CCHMAXFONTSIZENAME, (PVOID)pBuffer, 0);

                lCount = 1;
                GpiQueryFonts (_hpsBuffer, QF_PUBLIC, strchr (pBuffer, '.')+1, &lCount,
                    sizeof (FONTMETRICS), (PFONTMETRICS)&pBuffer[CCHMAXFONTSIZENAME]);

                DebugE (D_DRAG, "ClkWndProc => szFacename",   ((PFONTMETRICS)(pBuffer+CCHMAXFONTSIZENAME))->szFacename);
                DebugE (D_DRAG, "ClkWndProc => szFamilyname", ((PFONTMETRICS)(pBuffer+CCHMAXFONTSIZENAME))->szFamilyname);

                if (lCount == 1 && ((PFONTMETRICS)(pBuffer+CCHMAXFONTSIZENAME))->fsDefn & FM_DEFN_OUTLINE)
                    {
                    memset (&_fAttrD, 0, sizeof (FATTRS));
                    memset (&_fAttrT, 0, sizeof (FATTRS));
                    _fAttrD.usRecordLength = _fAttrT.usRecordLength = sizeof (FATTRS);
                    _fAttrD.fsFontUse      = _fAttrT.fsFontUse      = 0;
                    _fAttrD.fsType         = _fAttrT.fsType         = FATTR_FONTUSE_OUTLINE;
                    strcpy (_fAttrD.szFacename, ((PFONTMETRICS)(pBuffer+CCHMAXFONTSIZENAME))->szFacename);
                    strcpy (_fAttrT.szFacename, ((PFONTMETRICS)(pBuffer+CCHMAXFONTSIZENAME))->szFacename);
                    strcpy (_szFontFamilyD,     ((PFONTMETRICS)(pBuffer+CCHMAXFONTSIZENAME))->szFamilyname);
                    strcpy (_szFontFamilyT,     ((PFONTMETRICS)(pBuffer+CCHMAXFONTSIZENAME))->szFamilyname);
                    }
                else
                    {
                    WinAlarm (HWND_DESKTOP, WA_ERROR);
                    return;
                    }

                DosFreeMem (pBuffer);
                }
            break;
        }

    _wpRefreshClockView (somSelf);
    _wpSaveDeferred (somSelf);
    return;
    }

/*******************************************************************\
    ClkDrawString: Output of a string into the rectable prcl.
                   The characters are transformed in a way to fit
                   the complete string into the rectangle.
    Input: hps:       presentation space
           ulFGColor: foreground color
           pszString: string
           prcl:      pointer to RECTL structure
\*******************************************************************/
VOID ClkDrawString (HPS hps, ULONG ulFGColor, PCHAR pszString, PRECTL prcl)
    {
    USHORT      cx, cy;
    ULONG       ulc;
    SIZEF       sizef;
    POINTL      ptl;
    POINTL      aptlCharPos[12];                    // buffer for draw positions
    FONTMETRICS fm;

    /* set color and text mode */
    GpiSetColor (hps, ulFGColor);
    GpiSetCharMode (hps, CM_MODE3);

    /* Preliminary size of character box */
    sizef.cx = sizef.cy = MAKEFIXED (TESTSIZE, 0);  // set drawing aspect to nominal value 1:1, set size to 12
    GpiSetCharBox (hps, &sizef);

    /* CALCULATION OF CHARACTER WIDTH:                                              */
    /* Thereto the width of the complete string in calculated based on a            */
    /* character cx x cy (180/Pi = 57.3):                                           */
    /*                   l = Xende - Xanfang + tan(sl)*dy                           */
    /*    Approximation: l = Xende - Xanfang + sl*lMaxAscender/57.3                 */
    /* New character size is then x = TESTSIZE * cx/l                               */
    /* Abbreviations: sl:  character angle for italic                               */
    /*                cx:  target string length                                     */
    /*                dy:  empirically determined hight (about lMaxAscender * 1.4)  */
    /* CALCULATION OF CHARACTER HEIGHT:                                             */
    /* The height of a character box is determined via lMaxAscender and an          */
    /* empirical constant (14): cy = cy*14/lMaxAscender                             */
    cx = LOUSHORT (prcl->xRight - prcl->xLeft);
    cy = LOUSHORT (prcl->yTop   - prcl->yBottom);

    ptl.x = prcl->xLeft;
    ptl.y = prcl->yBottom;

    ulc = strlen (pszString);
    GpiQueryCharStringPosAt (hps, &ptl, 0, strlen (pszString), pszString, NULL, aptlCharPos);
    GpiQueryFontMetrics (hps, sizeof (FONTMETRICS), &fm);

    sizef.cy = (FIXED)(65536. * ((double)(cy * 14)/(double)fm.lMaxAscender));
    sizef.cx = (FIXED)(65536 * (double)TESTSIZE * (double)cx /
        ((double)(aptlCharPos[ulc].x - aptlCharPos[0].x) +
        (double)fm.lMaxAscender * (double)(fm.sCharSlope&0x1FF) / 81.86));

    /* draw string */
    GpiSetCharBox (hps, &sizef);
    GpiCharStringAt (hps, &ptl, strlen (pszString), pszString);

    return;
    }

/*******************************************************************\
    ClkDrawDigitalTime: draw digital clock
    Input: hwnd:       window handle
           pdt:        DATETIME structure
           ulPresence: presentation flags
           ulMode:     mode: DCLK_ALL or DCLK_HANDS
\*******************************************************************/
VOID ClkDrawDigitalTime (HWND hwnd, PDATETIME pdt, ULONG ulMode)
    {
    RECTL  rcl;
    RECTL  rclTime;
    RECTL  rclDate;
    CHAR   achTime[10];
    CHAR   achFinalDate[12];
    WPDCF77Data *somThis;

    somThis = ((PWINDOWDATA)WinQueryWindowPtr (hwnd, QWL_USER))->somThis;

    GetDateTime (pdt, MODE_PM | MODE_YEAR_2D, achTime, achFinalDate);

    WinQueryWindowRect (hwnd, &rcl);
    if (!(_ulPresence & PRESENCE_DISP_MINIMIZE) || (ulMode == DCLK_ALL))
        WinFillRect (_hps, &rcl, _sclrBG.ulSurface);

    rcl.yBottom += (rcl.yTop - rcl.yBottom)/10;
    rcl.yTop    -= (rcl.yTop - rcl.yBottom)/20;
    rcl.xLeft   += (rcl.xRight - rcl.xLeft)/20;
    rcl.xRight  -= (rcl.xRight - rcl.xLeft)/20;

    switch (_ulPresence & (PRESENCE_DISP_TIME | PRESENCE_DISP_DATE))
        {
        case PRESENCE_DISP_DATE:
            rclDate = rcl;
            break;

        case PRESENCE_DISP_TIME | PRESENCE_DISP_DATE:
            if (!(_ulPresence & PRESENCE_DISP_MINIMIZE))
                {
                rclTime = rclDate = rcl;
                rclTime.yBottom = rclDate.yTop = (rcl.yTop + rcl.yBottom) / 2;
                rclTime.yBottom += (rclTime.yTop - rclTime.yBottom)/10;
                rclDate.yTop    -= (rclTime.yTop - rclTime.yBottom)/10;
                break;
                } /* else: continue to next case statement */

        case PRESENCE_DISP_TIME:
            rclTime = rcl;
            break;
        }

    if (_ulPresence & PRESENCE_DISP_MINIMIZE)
        {
        /* Iconized: Refresh on new minute */
        if (ulMode == DCLK_ALL)
            {
            GpiSetCharSet (_hps, LCID_TIME);
            achTime[5] = '\0';
            ClkDrawString (_hps, _ulclrTimeText, achTime, &rcl);
            }
        }
    else
        {
        if (_ulPresence & PRESENCE_DISP_TIME)
            {
            GpiSetCharSet (_hps, LCID_TIME);
            ClkDrawString (_hps, _ulclrTimeText, achTime, &rclTime);
            }
        }

    if (_ulPresence & PRESENCE_DISP_DATE && !(_ulPresence & PRESENCE_DISP_MINIMIZE))
        {
        GpiSetCharSet (_hps, LCID_DATE);
        ClkDrawString (_hps, _ulclrDateText, achFinalDate, &rclDate);
        }

    return;
    }

/*******************************************************************\
    ClkRefresh: Initiates a redraw of the clock
    Input: somThis: pointer to instance data
\*******************************************************************/
VOID ClkRefresh (WPDCF77Data *somThis)
    {
    _bBufferDirty = TRUE;
    ClkSetRGBColors (somThis);
    ClkSetFonts (somThis);
    WinInvalidateRect (_hwndClient, NULL, TRUE);
    return;
    }

/*******************************************************************\
    ClkShowFrameControls: hide/show switch title bar
    Input: hwndFrame: window handle of frame window
           bShow:     TRUE:  show title bar
                      FALSE: hide title bar
\*******************************************************************/
VOID ClkShowFrameControls (HWND hwndFrame, BOOL bShow)
    {
    WPDCF77     *somSelf;
    WPDCF77Data *somThis;
    HWND        hwnd;

    somSelf = (WPDCF77 *)WinQueryWindowPtr (hwndFrame, QWL_USER);
    somThis = WPDCF77GetData (somSelf);

    if (bShow)
        hwnd = hwndFrame;
    else
        hwnd = HWND_OBJECT;

    WinSetParent (_hwndTitleBar, hwnd, bShow);
    WinSetParent (_hwndSysMenu,  hwnd, bShow);
    WinSetParent (_hwndMinMax,   hwnd, bShow);

    WinSendMsg (hwndFrame, WM_UPDATEFRAME,
                MPFROMLONG (FCF_TITLEBAR | FCF_SYSMENU | FCF_MINMAX | FCF_MENU),
                MPVOID);

    if (bShow)
        WinInvalidateRect (hwndFrame, NULL, TRUE);
    return;
    }

/*******************************************************************\
    ClkSetFonts: copy FATTR structure for the fonts out of
    			 instance data
    Input: somThis: pointer to instance data
\*******************************************************************/
VOID ClkSetFonts (WPDCF77Data *somThis)
    {
    /* query font out of instance data */
    memcpy (&_fAttrDate, &_fAttrD, sizeof (FATTRS));
    memcpy (&_fAttrTime, &_fAttrT, sizeof (FATTRS));
    strcpy (_szFontFamilyDate, _szFontFamilyD);
    strcpy (_szFontFamilyTime, _szFontFamilyT);

    return;
    }

/*******************************************************************\
    ClkSetRGBColors: calculate shading of RGB colors
    Input: somThis: pointer to instance data
\*******************************************************************/
VOID ClkSetRGBColors (WPDCF77Data *somThis)
    {

    /* copy color values */
    _sclrFace.ulSurface       = _clrFace;
    _sclrBG.ulSurface         = _clrBackgnd;
    _sclrHHand.ulSurface      = _clrHHand;
    _sclrMHand.ulSurface      = _clrMHand;
    _sclrMajorTicks.ulSurface = _clrTick;
    _sclrMinorTicks.ulSurface = _clrFace;
    _sclrRing.ulSurface       = _clrFace;
    _sclrDate.ulSurface       = _clrDateOnAnalog;
    _ulclrTransparent         = _clrTransparent;
    _ulclrDateText            = _clrDateText;
    _ulclrTimeText            = _clrTimeText;

    /* fill color tables */
    ClkShadeLight (&_sclrMajorTicks);
    ClkShadeLight (&_sclrMinorTicks);
    ClkShadeLight (&_sclrFace);
    ClkShadeLight (&_sclrRing);
    ClkShadeLight (&_sclrHHand);
    ClkShadeLight (&_sclrMHand);
    ClkShadeLight (&_sclrBG);
    ClkShadeLight (&_sclrDate);

    _sclrHHand.ulShade = RGB_BLACK;
    _sclrMHand.ulShade = RGB_BLACK;

    return;
    }

/*******************************************************************\
    ClkShadeLight: determine shading of a color and fill
                COLORS structure
    Input: psColors: pointer to COLORS structure
\*******************************************************************/
VOID ClkShadeLight (PCOLORS psColors)
    {
    typedef union _RGBLONG
        {
        RGB     rgb;
        LONG    lng;
        } RGBLONG;
    RGBLONG  rgbSurface, rgbShade, rgbLight;

    /* delete all colors */
    rgbSurface.lng = rgbShade.lng = rgbLight.lng = 0L;

    /* load surface color */
    rgbSurface.lng = psColors->ulSurface;

    /* calculate shade */
    rgbShade.rgb.bBlue  = ClkShadeRGBByte (rgbSurface.rgb.bBlue);
    rgbShade.rgb.bRed   = ClkShadeRGBByte (rgbSurface.rgb.bRed);
    rgbShade.rgb.bGreen = ClkShadeRGBByte (rgbSurface.rgb.bGreen);

    /* calculate bright color */
    rgbLight.rgb.bBlue  = ClkLightRGBByte (rgbSurface.rgb.bBlue);
    rgbLight.rgb.bRed   = ClkLightRGBByte (rgbSurface.rgb.bRed);
    rgbLight.rgb.bGreen = ClkLightRGBByte (rgbSurface.rgb.bGreen);

    /* copy colors to output buffer */
    psColors->ulShade = rgbShade.lng;
    psColors->ulLight = rgbLight.lng;

    return;
    }

/*******************************************************************\
    ClkShadeRGBByte: determine RGB value of the shadow of a
    				 base color
    Input: brgb: base color: normal brightness
    return:      base color: shaded brightness
\*******************************************************************/
BYTE ClkShadeRGBByte (BYTE brgb)
    {
    #define SHADER   ( (BYTE) 0x50)

    return (brgb > SHADER) ? (brgb - SHADER) : 0;
    }

/*******************************************************************\
    ClkLightRGBByte: determine RGB value of an illuminated
    			     base color
    Input: brgb: base color: normal brightness
    return:      base color: illuminated brightness
\*******************************************************************/
BYTE ClkLightRGBByte (BYTE brgb)
    {

    #define LIGHTER  ( (BYTE) 0x40)

    return (brgb < (0xFF - LIGHTER)) ? (brgb + LIGHTER) : 0xFF;
    }


Most people start off at some point during their college lives at composing and compiling their first résumés. From here on, the race begins for landing the best jobs and earning the highest salaries. While different people view résumés with varying interests, there's one thing beyond a shadow of a doubt— your résumé is your first impression.
Of course the traditional résumé has been partially replaced by online sources, social networks and other platforms, but the same rules apply to all these forms of media, regardless of all other factors.
1. How should we format?
There is a general understanding that your résumé should start with your personal details, education, and experience, but nothing is really set in stone. I've seen lots of people spending days and even weeks dividing their résumés into columns, adding colors, and pictures. For me, a résumé is a business document that is best kept simple.
People who review your résumés will be interested in the details you provide, such as job experience and companies you have worked, for rather than the colors you used. So, keep it to the point and give out only relevant details.
The worst things I've seen in résumés are common errors that I personally consider careless mistakes, and with that attitude I don't think you deserve any further consideration. Case closed.
While many jobs may require only your technical expertise, employers and recruiters also look for other qualities in candidates and basic writing and editing skills are at the top-of-the-list. If you don't have basic skills, you need to acquire those today. As a substitute, you could pay a professional résumé writer to do it for you, but that's a last resort, not career advice.
Don't just generalize about what you've done, give precise details in brief. For instance, instead of saying you taught English, say you taught English to French-speaking hospitality management students in Ivory Coast. Make sure you also list your hard and soft skills. Many recruiters and HR professionals will be keen to know about those.
You should understand the needs of your next prospective employer. Make sure your education and experiences are listed up-front. That does not always imply that the recruiter should see it without scrolling, but he or she should certainly not have to rummage through to find this information. So if you're an engineer who has worked on certain machines that industry-insiders may be interested in, specify the particular machines and anything similar that might catch their eye.
Be sure to post your résumé on as many website as possible. Most employers and recruiters around the world are using the myriad online sources to dig up their next recruit. To be noticed, you must reach out through as many sources as possible while being relentless with the traditional form of sending out your CV via post and email to as many local recruiters as possible.
Keeping adding to your accolades and your chances of landing your dream job will inflate significantly.


text:
Searching for Precedent
Design by Rebecca Goldberg
Meera Rothman·
We've been through this before.
Unprecedented times. Unprecedented deaths. An unprecedented president. In less than a year, unprecedented disruption. I am fucking sick of the word unprecedented, but I can't escape it. It's on every channel, email, and news alert. True, sometimes the unprecedented can be wonderful and liberating—the train is finally off the tracks. But the unprecedented can also be singularly terrifying. There is no reference point, no first or second draft to look back on. It's just us––people––free-falling through 2020 and making things up as we go. If you sit and think too hard about it (as I have been doing all of June), everything seems too strange to believe. Like we have detached from the natural string of time.
It reminds me of a line from a story by Yalitza Ferreras. This geologist, who has a lifelong obsession with rocks, loses part of her hand trying to touch and feel molten lava. In the months following the accident, she's lying in bed, unable to move, and her boyfriend comes to comfort her: This can't go on forever, he would say, as she felt the layers of forever crushing her down.
This is often how it feels. A global disease is killing hundreds of thousands of people, and all around us there is loss. Hospitals overflow with people who can't breathe, workers lose their jobs, children can't go to school, and everyone is being shepherded quickly and urgently into buildings and rooms, so that in the end we lose the ability to move. It feels like our lives have been unbuttoned one by one and flipped inside out. The school and city that I've spent the last three years digging fingernails and roots into is shut down, and we're all staring at screens around the world trying to reach out to each other.
But I'm also reaching desperately for an explanation. I don't understand how an event so extreme can fit into the narrative of my life, or even the narrative of history. I feel that there must be a precedent––there has to be one. This can't be the first time that universities shut down, or that the world spun into freefall.
It made sense to start my search for a precedent with the last global pandemic. The influenza pandemic of 1918 is largely overlooked in U.S. history; I had never even heard of it until this year. Scientists initially thought the virus was just a common cold, until it started destroying people's lungs, filling them with fluid and causing tissue inflammation. The virus infected about 500 million people, a third of the world population, and killed 50 million, far higher than the death rate of World War I. I wonder how people back then comprehended this degree of death and destruction. I wonder if they looked for precedents, too. Just like today, people in 1918 wore masks and avoided large groups. Just like today, Yale was completely shut down. There's little writing about what it was like in New Haven back then––it's almost like people have forgotten.
But Julia Irwin has not. In 2008, the then-doctoral student at Yale's History of Science and Medicine program wrote a deep dive historical paper about influenza's impact on the city. Irwin's paper is a goldmine. She studied how the pandemic affected group relations in New Haven, specifically the relationships between the city's largely 'Anglo' majority and a newer group of working-class Italian immigrants. Irwin is now an associate professor of history at the University of South Florida, and she has been working from home during the pandemic. Through the Zoom screen, I can see that she has thick, layered brown hair and a warm smile.
Irwin spent the bulk of her early career researching pandemics. Even though today her research focuses on international history, her voice picks up speed and inflates with energy when our conversation pivots to public health.
"In epidemics, but also disasters more broadly, those sorts of moments reveal issues that are already in societies that are sometimes below the surface," she explains. "Health disparities, for example, or economic disparities that are existing but people have become complacent about. An epidemic can bring those to life."
The influenza epidemic of 1918 was a prime example, precipitating a harsh nativist stance against the Italian immigrant community. According to Irwin, Italians died at a rate twice as high as Anglo residents in Connecticut. Public health officials used this data to confirm the theory that Italians as a 'race' had succumbed more to the disease. Yet despite the fact that this prejudice became visible during the pandemic, Irwin found that Italian and Anglo residents unexpectedly suppressed the unrest.
"Contrary to historiographic expectations, the New Haven story is one narrated by piercing silences and a distinct lack of hostility towards the immigrant community. These silences must be understood as a product of the period's political and social context," Irwin says.
World War I was coming to a close when the influenza pandemic occurred, and Americans were calling for unity and cooperation, Irwin explained. Anglo-Americans used the need for Americanism to explain why all citizens had a patriotic duty to follow public health guidelines. Meanwhile, Italian-Americans acquiesced to these guidelines and started to construct a public image of themselves as responsible citizens. Instead of clashing, leaders of both Italian and Anglo groups supported a new end-of-war unity. The shift in New Haveners' mentalities towards one another was a direct result of the time period.
Today, the same sorts of pervasive health disparities are manifesting in New Haven, but between Black and white Americans. Due to centuries of systemic violence, Black people in New Haven are the racial group most likely to be hospitalized and to die from coronavirus, according to statistics from New Haven Mayor Elicker in April. However, unlike in 1918, we are not approaching the end of a war but rather the end of an openly racist president's term. Police officers are murdering Black Americans in cold blood, and the Black Lives Matter movement has taken flight. While the influenza pandemic may have smoothed over community fissures in New Haven, the coronavirus pandemic has certainly not.
There are few mentions of Yale in Irwin's paper, but midway through she writes, "During the epidemic, Yale University, a centre of significant power and influence in New Haven, quarantined itself and 'refused to let any of the students speak to any citizen unless he had a special pass.'"
Irwin details how Yale prided itself on the number of nurses it had to care for sick students, and celebrated the fact that just three Yale students died. Meanwhile, New Haven suffered from a severe shortage in nurses, and the New Haven Register reports that the total Connecticut death toll was over fifty-five hundred.
Yale's actions today will speak to whether or not it has learned from the apathy of its past. A couple months ago, President Salovey declined Mayor Elicker's request to open up some of Yale's empty dorm rooms for public safety officers at risk of contracting coronavirus.
Elicker criticized Yale, asking, "If your house is burning down and you asked a neighbor if your kids could stay at your house and your neighbor said 'no,' but here is a check so you could stay at the Econo Lodge across town, what would that tell you about your neighbor?"
The next day, Salovey announced that he would make three hundred beds available. But on a city budget call in mid-May, dozens of New Haveners demanded that Yale do more with its $30 billion endowment. So far during the pandemic, Yale has offered New Haven just $1 million.
"I'm fucking sick of the word unprecedented"
On the first of July at nine in the morning, President Salovey sends an email entitled 'Fall 2020,' announcing that we'll be returning to campus. It seems impossible. I can't remember a time when my heart didn't race when I left the house, or when I lived without the background noise of the hot, screaming TV. I think there's something about staying inside that makes time feel completely stagnant, like you could wake up every morning for the rest of eternity and you'd still be stuck in the pandemic's layers of forever. Going outside for runs and trips to the grocery store are my only reprieve.
If anyone could tell me whether people felt like this before, it would be Judith Schiff. She prefers to talk on the phone, so I call her from the landline in my basement. Schiff is the chief research archivist of Yale Library's Manuscripts and Archives and the city historian of New Haven. She grew up in New Haven, went to Hillhouse High School, and has been working at Yale for over forty years.
Our conversation meanders. I ask one question, and Schiff slides seamlessly down tangents of history, often losing me in the enormous network of knowledge she holds. We talk about how Yale was founded, the origin of Skull and Bones, and what Yale school dances were like a hundred years ago. But eventually we make our way to World War II.
World War II was one of the most recent instances when Yale's campus was severely disrupted. Charles Seymour, the president at the time, supported the war, while many students opposed it, causing tension on campus. But when the U.S. finally entered the war, all students, regardless of their beliefs, were subject to the draft.
"Yale became a sort of ghost town," Schiff says. "They only had enough students to fill two residential colleges, who were ineligible for the draft either because they were too young or they had disabilities."
Many formerly enrolled students went elsewhere. People picked fruit on farms to keep up the food supply, some became firefighters, and others assumed civic positions. And, with students gone, Seymour offered up Yale's campus as a military base. Over the course of the war, twenty thousand people came to Yale's campus for training. Old Campus was rented to the Air Force, which trained at Tweed Airport in New Haven during the day and slept on campus at night.
"It was a constantly changing student body," she explains.
When students finally returned in 1946, they called it "reconversion." Seymour welcomed anyone who had survived the war and wanted to finish their degree back to campus. Overnight, Yale was transformed from a student body of thirty-five hundred to eight thousand students.
"They called any house in New Haven—do you have an extra bedroom? Can someone sleep in your basement?"
Schiff tells me there were hundreds of cots in the gym and single rooms were turned into triples. Some of the students returning back to campus were married and had babies by this point.
"I remember meeting a woman who was married to a Yale physician," Schiff recalls. "She had two babies in diapers in one half of a quonset hut on Science Hill."
I have to look up what a quonset hut is—it's essentially a steel dome that looks like a can sliced in half. I'm trying to imagine hundreds of these semi-circles lined up on Science Hill and housing families with babies.
"Of course, there were no disposable diapers in those days," Schiff laughs.
To my surprise, the layers of forever ease up and I return to campus. The day I arrive, my friend and I go for a socially distanced walk up Prospect Street and Science Hill (I am relieved to see that there are no quonset huts). We pass fewer than twenty people. It's strange to see Yale so quiet, to walk without weaving around people or having the usual litany of semi awkward run-ins. I miss the frenzy.
But it's also fascinating to see campus like this. It's as if Yale has been dropped and cracked open, like a fruit or a large glass jar. The shroud of isolation that usually encircles these eight blocks has been stripped away, and the pandemic has allowed reality to seep in. This is a quieter way of going to college, but in many ways it is a more grounded one, free of pretenses. My friend tells me that it's been like this all summer, and that nearly everyone is seriously social distancing.
My last interview takes place six feet apart on the chairs outside the Yale Art Gallery. I am late and he is early. My interviewee wears a green shirt and hat, and he looks strangely comfortable on one of the sidewalk's stiff metal chairs, watching the cars pass on Chapel Street. He is eighty-five years old.
Sam Chauncey became a Yale administrator when he was just twenty-one. He started as an assistant dean, served as Yale's chief of staff for twenty years, and then founded the Yale Health Management Program, the first health/business program of its kind at a major university. Now retired, he advises students as a Davenport Fellow.
"For the first two and a half months, everything was shut down," he recalls. "I could stand at my building and see all the way to Broadway and not see a single human being on the street."
Chauncey's voice is strong and clear, and if he hadn't told me otherwise, I would have thought he was much younger. He smiles often, revealing two slightly crossed front teeth.
"It was great for everyone because you could walk without worrying that you'd run into anybody… I try to do six miles a day."
The coronavirus pandemic is not the first pivotal moment Chauncey has witnessed at Yale. As chief of staff, he helped lead Yale during the radical movements of the nineteen-sixties and seventies, and he contributed to both the admission of minority students and women into Yale. Chauncey is best known for his leadership during the May Day rally in 1970, during which twenty thousand to thirty thousand protestors arrived on the New Haven Green to denounce the arrest of Bobby Seale, a Black Panther leader who was put on trial for allegedly murdering a fellow Panther member. This is the only time since 1950 when Chauncey recalls Yale shutting down.
"Every single store on Broadway was boarded up," he says. "There were national guard troops on York Street. So that was a very eerie feeling."
Unlike other universities, which closed their campuses and took issue with the protests, Chauncey invited the protesters in. While other campuses erupted into deadly violence, Chauncey tactfully juggled the needs of protesters, police, students, and faculty, enabling the protests to take place peacefully.
"If you look in the sixties, there was a woman named Rachel Carson who wrote Silent Spring––she was said to be a nut. Everyone said she was crazy. The gay and lesbian movement was beginning and they were nuts. The antiwar people were nuts. It turned out that all those things they were preaching were today's gospel. I think that having society upset and your individual life upset is a good thing," he says. "I'm in favor of revolution, quite frankly."
Chauncey acknowledges that today's pandemic poses unique challenges that the upheavals of the sixties did not. While May Day was a disruption caused by people, the pandemic is an invisible enemy. The 'radicals' who arrived on campus were driven by issues they passionately believed in, whereas the coronavirus has no ideology. Still, Chauncey hopes that Yale students and faculty will find some meaning in the pandemic and in society being "shaken up."
"Every Yale student should ask him or herself––do I want to go back and be a Yale student just the way I was a year ago? Have I got some new values about things? Maybe my view of human life is a little different."
As I ponder this, he tells me what he himself has learned.
"Before the pandemic, I usually had two appointments in the morning. I was having lunch with somebody, I had two appointments in the afternoon. I might be going to a dinner at night with somebody in New Haven. Now, you spend more time by yourself and I have come to believe that I don't want to go back to normal. I want a new normal."
In the spirit of Chauncey, I am working on casting my gaze forward. In the two weeks we've been in New Haven so far, my friends and I have barely left our house. We cook dinners and sit in circles with our computers and we put our faith in change.
Nothing has the privilege of lasting forever.
New Haven's streets feel empty but in the outlines surrounding their silence, I can see a loud and resounding respect for this city. Yale, with its sky-high gothic towers, has closed and shut down, and the city has swelled and sighed with students coming and going. But New Haven remains, with a population that outnumbers students approximately 10:1, even when campus is at its fullest. There are trees that were rooted here when campus closed in 1918, when students left for war in 1945, when protestors came in 1970. There are people who remember.
The best part of my new room is that there is a skylight in the ceiling. Over the course of each day, I can watch light flood different parts of the room. I considered putting a shade on it so I could sleep better, but decided against it. If I stand on the right side of my room, I can see the Payne Whitney Gym, but if I stand on the left side by my bed, I just see open sky. When I feel crushed with claustrophobia, I look up.
—Meera Rothman is a senior in Benjamin Franklin College and an Associate Editor.
September 2020 | Volume 53 Number 1
Meera Rothman
Somebody help! I have COVID and I'm standing alone outside Maison Mathis
Previous Stuck in the Middle
Next Art in Crisis
The Race for Ward 1

redpajama_set_name: RedPajamaCommonCrawl


Kollege of Knowledge of Toastmasters International Division F & A. Dr. Jose G. Lepervanche, President of Top O' The Rock Toastmasters was presenter in the Treasurer's Officer Training 2009. Top O' The Rock Toastmasters meet every Wednesday from 12 noon to 1 pm. Guests are welcome. Visit our website at http://www.toporock.com.


Need the status of your shipment, find a package, or get proof of delivery? Package tracking and shipment location services made easy with Tracking Locator. Track your shipments and get updates all from one location. Free tracking tools for both US and international shipments from FedEx®, UPS®, USPS®, DHL® and more.


Jenny has over 20 years of experience in international procurement. Having started her career as a supply manager with Owens Corning, she went on to work with FreeMarkets (Ariba) managing the sourcing projects of global enterprises. While there, Jenny first encountered colleague Jason Busch, who later co-founded Azul Partners and Spend Matters. After several years at FreeMarkets, working in Europe and Asia, Jenny co-founded e-Three in the UK. It specialized in procurement consultancy facilitated by strategic procurement technology. e-Three became a global partner of Oracle and was one of the first organizations to configure and host Oracle technology in the cloud. e-Three successfully merged and subsequently sold to a global Oracle partner based in North America. Now part of the Spend Matters team, Jenny brings her knowledge as a practitioner, business owner and source-to-pay technology advocate to the team and wider Spend Matters audience.
Rewind 12 years, the procurement tech landscape travelled in the slipstream of global Financial platforms, typically in larger on premise ERP implementations, cloud for the few.
Today we're seeing a different picture of procurement technology consumerism. What we're buying, from whom and how it's being managed has changed – significantly.


text:
package org.jbpm.runtime.manager.impl.lock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

import org.jbpm.runtime.manager.spi.RuntimeManagerLock;

public class DebugRuntimeManagerLock implements RuntimeManagerLock {

    private ReentrantLock lock = new ReentrantLock(true);
    private List<StackTraceElement[]> traces;
    private long currentThreadId;

    public DebugRuntimeManagerLock() {
        traces = new ArrayList<>();
        currentThreadId = -1;
    }

    @Override
    public void lock() {
        lock.lock();
        addTraces();
    }

    @Override
    public boolean tryLock(long units, TimeUnit timeUnit) throws InterruptedException {
        boolean outcome = lock.tryLock(units, timeUnit);
        if(outcome) {
            addTraces();
        }
        return outcome;
    }

    @Override
    public void lockInterruptible() throws InterruptedException {
        lock.lockInterruptibly();
        addTraces();
    }

    private void addTraces() {
        long newThreadId = Thread.currentThread().getId();
        if(currentThreadId < 0 || currentThreadId != newThreadId) {
            currentThreadId = newThreadId;
            traces.clear();
        }
        // we add all stack traces during reentrant lock
        traces.add(Thread.currentThread().getStackTrace());
    }
    @Override
    public void unlock() {
        // only we clear up when count is 0
        if(currentThreadId == Thread.currentThread().getId() && lock.getHoldCount() == 1) {
            traces.clear(); // clean up
        }
        lock.unlock();
    }

    @Override
    public boolean isHeldByCurrentThread() {
        return lock.isHeldByCurrentThread();
    }

    @Override
    public boolean hasQueuedThreads() {
        return lock.hasQueuedThreads();
    }

    @Override
    public int getQueueLength() {
        return lock.getQueueLength();
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("DebugRuntimeManagerLock [");
        builder.append(lock);
        builder.append("]\n");

        builder.append("--------CURRENT REENTRANT STACKTRACE-----------------------\n");

        for (int i = 0; i < traces.size(); i++) {
            builder.append("\tSTACKTRACE " + i + "\n");
            StackTraceElement[] trace = traces.get(i);
            for(int j = 0; j < trace.length; j++) {
                builder.append("\t\t\t" + trace[j] + "\n");
            }
        }
        builder.append("--------END CURRENT REENTRANT STACKTRACE-------------------\n");
        return builder.toString();
    }

}

redpajama_set_name: RedPajamaGithub


text:
Edge City Brewery opens in the midst of a pandemic, selling growlers to go
By Brianna Crane | April 16, 2020
Edge City, a taproom and brewery on Monroe Road, is now open, offering growlers to go Tuesday through Sunday.
With the stay at home order still in effect, you won't be able to experience the brewery in its full capacity just yet. Mandii Green, partner and head of marketing and advertising for the brewery, said the idea is to give people a taste of Edge City until they can throw an official grand opening.
"It hasn't been ideal, but we are taking it day by day and staying positive," she said. "During times like these you have to just stay the course, be upbeat and optimistic."
You can also buy a $25 gift card now and redeem it for $35 once it opens. They've got plenty of merch, too.
Growlers to go: Growlers are $10 for 32 ounces, and you can purchase them from 1 to 6 p.m. on Tuesday through Sunday (closed Monday). There are 11 options, including four IPAs and two beers created in collaboration with Traust Brewing and One World Brewing. You can find the whole menu here.
Team: Brothers Jared Thomas (brewmaster) and John Thomas (operations) are the founders of Edge City. Jared was head brewer at Ass Clown in Cornelius, and before that he was the head brewer at a start-up brewery in Colorado. And Green of Belles Creative is a partner and heading up marketing and advertising.
What they're excited about: "We are most excited about joining the thriving Charlotte beer scene and being creative with our beer recipes," the team told the Agenda. "We want to establish more of a collaborative approach to our brewery by partnering with other brewers, entrepreneurs, and local vendors."
Beer: The idea is to keep beers rotating and include a good mix of traditional beers as well as some more experimental flavors.
Design: The team told us they bring the outdoors in, so expect lots of greenery and an organic feel. In terms of special designs and decor, they plan to bring in "creative installations and features."
Layout: It's two stories, with the second story being the brewhouse "where guests will be able to come check out the brewing action," Green said. There will also be a spacious dog-friendly patio and tons of outdoor green space.
Why it matters: The area is seeing a lot of growth, and this is the first brewery in that immediate Monroe Road area. The exact address is 6209 Old Post Road.
Agenda related guide: Complete list and map of Charlotte's 30 local breweries, plus the most popular beer at each
Edge City brewery founders John and Jared Thomas (yes, they're brothers)
Axios Charlotte receives investment from Knight Foundation to hire investigative reporter
by Ted Williams and Michael Graff


text:
Q: How can I get a dynamic modal to also map out with my card list? Whenever my program runs; the cards are displayed on the screen with the correct information. But when I click on the button to open the modal; it displays incorrect information, like the wrong event title or multiple statuses.
My guess is that the cards are actual objects that are being mapped to the screen; but the modal is one entity so it shows whatever is at that point in time. How do I correctly map a modal with my card mapping so I can dynamically show information on the modal about that particular card?
class Events extends Component {

state = {
    creating: false
};

startCreateEventHandler = () =>
    this.setState({ creating: true });

modalCancelHandler = () => {
    this.setState({ creating: false });
}

componentDidMount() {
    this.ensureDataFetched();
}

ensureDataFetched() {
    this.props.requestEvents();
}

render() {
    return (

        {this.props.events.map(event =>
        <React.Fragment>
            {this.state.creating &&
                <Modal title="Add Event" canCancel onCancel=
                   {this.modalCancelHandler}>

{event.title}

{event.start}

{event.ticketRequests.map(request =>
                        request.status)}

heyyy

                </Modal>
            }

            <Card color="blue" className="card" style={{ width: '18red'
}}>
                <CardBody className="card-body">
                    <CardTitle>{event.title}</CardTitle>
                    <CardText>Event Info</CardText>
                    <button className="requestButton"
                    color="yellow">Request Tickets</button>
                    <button className="claimButton" onClick=
                    {this.startCreateEventHandler}>Tickets Claimed:
                    </button>
                </CardBody>
                </Card>
        </React.Fragment>

        )}

    );
}
}

Modal File
import React from 'react';
import './modal.css';

const modal = props => (

{props.title}

{props.children}

        {props.canCancel && (
            <button className="btn" onClick={props.onCancel}>
                Cancel
            </button>
        )}

);

export default modal;

A: What is happening here is that you are opening all modals at once.
What you could do is keep in the state the index (or unique id) of each event and only render the modal if the index/unique id matches.
class Events extends Component {

  state = {
    creatingId: -1
  };

  startCreateEventHandler = creatingId =>
    this.setState({ creatingId });

  modalCancelHandler = () => {
    this.setState({ creatingId: -1 });
  }

  componentDidMount() {
    this.ensureDataFetched();
  }

  ensureDataFetched() {
    this.props.requestEvents();
  }

  render() {
    return (

        {this.props.events.map((event, i) =>
        <React.Fragment>
            // the best way of doing it is with unique id property, but it also works with index
            // {this.state.creatingId == event.id &&
               {this.state.creatingId == i &&
                <Modal title="Add Event" canCancel onCancel=
                   {this.modalCancelHandler}>

{event.title}

{event.start}

{event.ticketRequests.map(request =>
                        request.status)}

heyyy

                </Modal>
            }

            <Card color="blue" className="card" style={{ width: '18red' }}>
                <CardBody className="card-body">
                    <CardTitle>{event.title}</CardTitle>
                    <CardText>Event Info</CardText>
                    <button className="requestButton"
                    color="yellow">Request Tickets</button>
                    <button className="claimButton" onClick=
                    {() => this.startCreateEventHandler(i)}>Tickets Claimed:
                    </button>
                </CardBody>
                </Card>
        </React.Fragment>

        )}

    );
  }
}

redpajama_set_name: RedPajamaStackExchange


Mark Goodfellow, Alcoa union leader, speaks during the governor's announcement Thursday of a new state deal for the company.
MASSENA – Gov. Andrew M. Cuomo visited Massena today to announce that an agreement has been reached with Alcoa that would preserve 450 jobs at the aluminum company's smelting plant.
The new seven-year agreement is subject to approval by the New York Power Authority Board of Trustees, and Governor Cuomo is recommending the board vote in support of the proposed deal at its meeting on March 26, said a press release from the governor's office.
The new contract provides Alcoa with a 240-megawatt low-cost hydropower allocation from NYPA's St. Lawrence-Franklin D. Roosevelt Power Project through 2026. The power rate is indexed to the price of aluminum and will increase or decrease depending on the market price of aluminum.
The new agreement, between Alcoa and the New York Power Authority, extends the previous contract, which expires at the end of the month, through 2026.
That contract had included the protection of 145 jobs that are now supported by Arconic, which separated from Alcoa in 2016 but maintained operations at the same site.
Mark Goodfellow, Alcoa union leader, also spoke during the announcement and credited the governor's leadership in securing the contract. Goodfellow said the state had once again delivered for the region.
"We are pleased that this deal could be reached and are grateful to the many hardworking and dedicated employees and their families who make the company what it is and the community a special place to live," said State Sen. Joseph Griffo, 47th district which includes Massena.
State Sen. Patty Ritchie who represents Ogdensburg and other towns in St. Lawrence County said, "I want to applaud the New York Power Authority and Alcoa for coming together to reach this agreement—which is a victory for the local workforce and the regional economy. Alcoa has a great history in the North Country and protecting its future in Massena is a win-win for our entire region."
"I'm thrilled with the leadership shown by NYPA, the Governor and Alcoa in coming to an agreement that will be a critical investment for the future of Massena," said Assembly Member Mark Walczyk who represents the River District.
Alcoa signed its original contract with NYPA in July 1955, more than three years before the St. Lawrence-FDR project—the Power Authority's first generating plant—began producing electricity.
In December 2018, the governor announced that Arconic would maintain its workforce through 2028, ensuring a commitment of roughly 600 jobs total at the smelting facility.
"This agreement announced today secures hundreds of jobs at Alcoa, continues the upward momentum of the North Country and builds on New York's thriving economy," Governor Cuomo said. "Alcoa has once again committed itself to Massena for the long-term through this hallmark agreement, which will protect its workers and the state investments made to the region and the facility for years to come."
He acknowledged that the state had turned a "blind eye" towards the North Country in the past and that the economy has suffered as a result.
"Alcoa is pleased to have reached an agreement with NYPA that provides the Massena smelter with competitively priced energy for the next seven years," said Tim Reyes, president of Alcoa Aluminum. "While the global aluminum industry faces numerous challenges, securing competitive and reliable power is essential for supporting the facility's future. We thank Governor Andrew Cuomo and U.S. Senator Chuck Schumer for their support during this process and NYPA for its continued cooperation."
This is the latest in a long line of state bailout deals for the aluminum giant.
The Alcoa deal announced Nov. 24, 2015 granted the Alcoa $30 million from the New York Power Authority in power discounts and $43.6 million from the state.
Alcoa had said on Nov. 2, 2015 it would curtail operations at the smelter at its Massena West plant, which would have eliminated at least 487 jobs, leaving about 217 positions for other functions at the plant. Under the Nov. 24 agreement, Alcoa was required to employ a total of at least 600 full-time equivalent employees – those working at least 35 hours a week – throughout Massena West. The company offered a voluntary retirement package to eligible employees, according to a November 2015 statement from Cuomo's office.
Alcoa's bailout includes a hefty NYPA electricity discount, in addition to millions of dollars in discounts and incentives Alcoa has already received from the agency.
The 2015 deal is the latest in a long series of incentives offered to the company in exchange for maintaining jobs at the facility.
On multiple occasions, Alcoa has failed to live up to promises made in previous agreements.
According to a March 2014 news release from the governor's office, the company promised to maintain 750 jobs at the west plant and provide training for the east plant's future workforce, once a promised $600 million modernization of the Alcoa East plant was underway. That plan was dropped.
In summer 2013, Gov. Cuomo was quoted as saying 1,000 jobs would be guaranteed under a deal that had been struck with Alcoa.
However, the 2015 deal includes up to $40 million in financial penalties should the company breach its commitment to maintain at least 600 jobs, or close the plant before the contract expires March 31, 2019.
The 2015 coporate welfare package was announced after Alcoa made public plans to layoff 487 employees.


text:
Maine groups say state rule change capping cash prizes hurts fundraising efforts
Sen. Roger Katz, R-Augusta, has sponsored emergency legislation to reverse the rule change made last year and tucked into the state budget.
Jan Michaud takes part on Sept. 19, 2017, in a celebration of the Calumet Educational & Literary Foundation in Augusta. Staff file photo by Joe Phelan
Civic organizations that use raffles with substantial cash prizes to raise money say a state rule change hidden in the last state budget bill, capping cash raffle prizes at $1,000, hampers their ability to bring in money to support their efforts to help in their communities.
"It impacts us directly. The Elks, in Maine, raise over $5 million a year, some of that through raffles," said Mike Michaud, exalted ruler of the Augusta Elks Lodge. "Not being able to do this cripples our ability to keep raising money, that's what we do with these raffles. We're going to have to find other means to raise these monies for our charities, which is climbing up an even steeper hill."
Sen. Roger Katz, R-Augusta, is sponsoring legislation aimed at reversing a new state rule capping cash raffle prizes at $1,000. Staff file photo by Joe Phelan
Larry Guimond and Rachel Boucher Ellis lead the singing of Le Club Calumet's anthem July 8, 2016, during the opening night of Le Festival de La Bastille in Augusta. Staff file photo by Joe Phelan
People dance in the main tent on July 8, 2016, during the opening night of Le Festival de La Bastille in Augusta. Staff file photo by Joe Phelan
Sen. Roger Katz, R-Augusta, has sponsored emergency legislation to reverse the rule change made last year, which Katz said was tucked into what he described as the 900-page budget bill of Gov. Paul LePage's administration. The change apparently escaped the attention of many people, including Katz, and Michaud, who didn't learn about the change until a meeting this winter with other Maine Elks leaders.
"No one, including myself, picked up on it. We collectively dropped the ball," Katz said of the rule change getting through largely unnoticed. "It's law. It came to my attention from a couple of representatives of the Calumet Club."
Dan Doiron, a member of the Le Club Calumet involved in organizing the club's popular Franco-America festival, Le Festival de la Bastille, which takes place every other year, said a raffle, with $20,000 in total prize money and a $10,000 cash prize, is part of the festival and helps raise funds that go into the club's general fund.
"Those funds help support our contributions to the community throughout the year," Doiron said. "It's a real shock to the organization. It looks like it slipped in as part of a bigger bill. That's not a great way to do things."
Every other year the Augusta Elks Lodge holds a raffle with $10,000 in total prizes, with a $3,000 top prize. Proceeds from that raffle fund the local fraternal organization's summer festival, which raised about $15,000 last summer for the Maine Children's Cancer Program and K9s on the Front Line, a Maine-based nonprofit that provides trained service dogs to military veterans with post-traumatic stress disorder.
Michaud and the leaders of other local organizations that raise funds with such raffles said while they could give away prizes other than cash, or smaller cash prizes, those don't seem to generate nearly as much interest from the raffle-ticket-buying public.
"I think the opportunity or excitement of winning that much money helps sell those tickets," said Tom Warren, chief executive officer of the Kennebec Valley YMCA, which annually splits the proceeds of a raffle it does in a partnership with the Friends of Lithgow Library, which has a $10,000 cash prize and generates $12,000 to $15,000 each for the library and the YMCA. "If we did a raffle and the payout would be a lot less, I think it'd be much more difficult. I'm sure we'll figure something out, but it certainly makes it more difficult and very well may result in us raising less money and having less money to give back."
Warren said the YMCA uses its share of the raffle proceeds to fund its Strong Kids Campaign, which provides scholarships so children who wouldn't be able to afford to join the Y can become members.
Katz said he hopes the emergency legislation will pass as an emergency measure so organizations across the state that use cash raffles to raise money still may have such events this summer.
The bill, L.D. 1837, "An Act to Allow Cash Prizes for Certain Raffles Conducted by Charitable Organization," has been referred to the Veterans and Legal Affairs Committee, which Katz anticipates will hold a hearing on the bill within the next couple of weeks. Katz noted it's an issue across the state, not just in Augusta.
Such fundraisers, he said, "have enabled community groups to do a great deal of good, and the same thing is replicated in communities throughout Maine. I'm unaware of any problems that have come up with this culture of nonprofit raffles."
Asked for information about why the law change was included in the state budget bill, Julie Rabinowitz, press secretary in the governor's office, said Friday that questions about that issue were passed along to the state's Gambling Control Board, where officials could not be reached for comment immediately.
The current law does allow charitable organizations that register with the state's Gambling Control Unit to give away noncash prizes up to a value of $75,000.
However, Michaud said people don't seem as interested in winning items as they are in cash.
"We've raffled off boats and motors, vacation trips and things like that, and they garner some interest; but the cash raffle is really, really one of the stronger means of raising money for our charitable organizations," Michaud said. "I don't think whoever drafted that bill had any idea at all the impact it'd have on fraternal organizations, the Y, the hospitals and others that run these raffles to raise money for their communities."
Organizations holding raffles are limited, both in the current and proposed legislation, to one raffle a year.
augusta maine


text:
Featured • Humanosity • In Depth • Politics • World
African Debt: The Hidden Story of How the World Bank and the IMF Destroyed Africa
exc-5c0029174d7a9c5ae8687922
The World Bank and the IMF were originally set up after the Second World War. The World Bank was tasked with rebuilding Europe whilst the IMF was given the job of ensuring trade flowed smoothly and give short term loans to countries that had a balance of payment problems. They are made up of member countries and the power each member has is based on their contributions to each institution.
As Western countries are the biggest contributors, they have the lion's share of the power to determine policies. Over time they have taken on the role of setting the economic policy for many of the countries around the world, especially developing countries. They have the power to decide if a country is creditworthy or not and, in order to receive the seal of approval, countries have to follow the economic prescription the two institutions offer.
Structural Adjustment Programmes
Ever since the 1980s this prescription has been in the form of Structural Adjustment Programmes (SAPs) which were sold to the developing world as the magic bullet that would free them from rising debt and set them on the path to economic development. Yet it was all a lie and Africa paid a terrible price.
The African debt crisis has its roots in the oil crisis of the 1970s when OPEC dramatically increased the price of oil, crashing Western economies and garnering a windfall in the process. That massive windfall was largely invested in Western banks who in turn looked to loan the money back out.
The prevailing economic wisdom was that the path to economic development lay in taking out loans to accelerate economic development so borrowing was heavily encouraged and Africa borrowed heavily, especially as the loans on offer came with low-interest rates. It didn't matter to the lenders that the money was going to political elites who promptly wasted the money on luxuries, white elephant projects and, in many cases, the money was simply stolen and then reinvested in those same western banks.
Whilst interest rates remained low in the 70s, no-one paid much attention to the orgy of corruption that swept through Africa but as the 80s arrived everything changed. Facing rising inflation the US raised interest rates dramatically and European banks followed suit. Those loans given to African countries now saw the interest rates rise significantly. In 1980 the total debt of developing countries was $567 billion.
From 1980 to 1992 these countries paid back $1662 billion but the craziness of the situation was that to repay their initial debts, developing countries had been encouraged to take more loans. As a result, their debt in 1992 had grown to $1419 billion, despite the huge amount of repayments they had made over the decade.
As their debt ballooned the IMF insisted that further loans would only be offered if African countries accepted SAPs. These involved the deregulation of trade protections, the ending of price controls and subsidies, export-led economic policies, privatisations and the ending of free health care and education. Basically, countries had to export their raw materials, end any welfare programmes and accept higher prices for food. The theory was economic growth would ultimately trickle down, leading to poverty reduction. The results were disastrous.
Image by Simon Allen from Pixabay
The Export Trap
On the economic front, it may seem that the development of export goods such as minerals, coffee, cotton and other crops would bring benefits by increasing revenue to the exporting countries but it is an unequal exchange.
A country may get revenue for exporting unprocessed goods but they would lose that revenue (and more) by importing processed goods. Instant coffee costs more than exported coffee beans and all the extra value created in processing the beans goes to the country that does the processing. So countries became economically dependent on the price of raw materials, over which they had little control, leaving them at the mercy of big industrial conglomerates whose interest lay in driving down the prices. Unemployment soared and wages declined.
On the social front, the results were equally disastrous. Government healthcare programmes collapsed and were replaced by western NGOs. Few families could afford to educate their children and illiteracy rates, which had been falling, began to rise again. Diseases like malaria and cholera began to increase again.
All the while political elites, who had grown wealthy on the corrupt appropriation of the loans on offer, continued to thrive and invest their ill-gotten gains back into the west. As always the effects were mainly felt by the poor and women in particular as the burden of caring for the sick fell on them and an increase in divorce rates meant women were stuck with all the costs of supporting the children.
In West Africa, the effects were particularly devastating. The lack of education, health and jobs led to the growth of a disenfranchised population of young men with no prospects. They were easily recruited by a new generation of politicians like Charles Taylor in Liberia who saw civil war and conflict as the most profitable way to advance their ambitions.
The shocking fact about SAPs was not that the economic theory underpinning them was bankrupt but that their main aim was to ensure debt repayment and in this, they were hugely successful. The world continues to live with the consequences.
Acquiring Knowledge. How Did We Learn to Cook Poisonous Plants?
How to Temper Chocolate and Make Filled Chocolates


text:
Researchers' Zone
About ScienceNordic
Allergies to e.g. milk may be caused by airborne proteins that penetrate the skin, new study finds. (Photo: Colourbox)
Food allergy may arise through our skin
People with dry and fragile skin often suffer from food allergies, new study suggests.
Lise Hornung
wednesday 29. May 2013 - 06:57
Studies have shown that some people may get milk allergy from airborne milk proteins that penetrate through their skin. The same may also apply to those who are allergic to eggs, wheat or fish.
In any case, people deficient in filaggrin – a protein that affects the skin's permeability – are more likely than others to report food allergies.
So concludes an international study with 3,471 participants, headed by Allan Linneberg, MD, associate professor and the head of research at the Research Centre for Prevention and Health (RCPH) at Glostrup University Hospital, Denmark.
"We know that filaggrin affects how permeable a person's skin is to external factors at the molecular level," he says.
Our theory is that people with this skin barrier defect are at an increased risk of getting food allergies because microscopic amounts of e.g. wheat flour can penetrate through the skin.
Allan Linneberg
Filaggrin deficiency has previously been linked with asthma, eczema and allergies in a comprehensive Danish study from 2010.
Allergies and eczema – a common cause?
Filaggrin deficiency is caused by a genetic mutation that is present in 8-10 percent of the population.
These people's skin does not retain water well, which leads to dryness and problems with eczema. When the skin lacks this protein, its ability to shield against external dirt and substances is reduced.
Scientists have known for some time that food allergies are more common in people with atopic dermatitis.
"We have also identified a common genetic predisposition to atopic dermatitis and food allergies, which we will continue to examine," says Linneberg, adding that there is still some uncertainty regarding the explanation for this correlation.
He believes it is possible that the timing and the amount – for instance when cow's milk is introduced for the first time – may affect the risk of developing allergies.
"If the body's first introduction to a certain protein comes in large amounts through eating it, the immune system might not find it appropriate to start fighting it. Conversely, however, the immune system might respond if the protein is introduced in a small amount through the skin."
This does not mean that parents should worry about baking with their kids, but further studies may help determine the ideal time and method for introducing certain foods to infants. But according to Linneberg, there is still a long way to go before we have any concrete recommendations.
He and his colleagues are currently studying whether filaggrin deficiency can be linked to peanut allergies.
Upcoming animal studies will also be taking a closer look at the link between the gene mutation and food allergies.
Read the Danish version of this article at videnskab.dk
Scientific links
Association between Loss-of-Function Mutations in the Filaggrin Gene and Self-Reported Food Allergy and Alcohol Sensitivity, International Archives of Allergy and Immunology 2013;161:234-242, DOI: 10.1159/000345
Allan Linneberg's profile (in Danish only)
The Research Centre for Prevention and Health
prevention diseases denmark allergies videnskab.dk health
Mild long-term effects of Covid last longer among the youngest children
What is the rose from the Selbu mitten doing in the remains of a medieval cathedral in Sudan?
Researchers' Zone:
Extreme variation in snake venom: no two bites are the same
Snake venom is affected by many factors and therefore varies to a degree that makes it almost impossible to find broadly effective treatments.
Living human brain in petri dishes provides unique insight into old mysteries
For the first time in Denmark, researchers are examining living pieces of human brain in a laboratory.
ABOUT SCIENCE NORDIC
© ScienceNordic.com
SCIENCE NORDIC OFFICES:
Oslo: c/o forskning.no, Postbox 5 Torshov, 0412 Oslo, Norway. Phone +47 22 80 98 90
Copenhagen: c/o Videnskab.dk, Carl Jacobsens Vej 16, Entr. 16, 2500 Valby, Denmark. Phone +45 707 01 788