text:
#include "displayTypes.h"
#include "displayInternal.h"

#include "font_5x4.h"
#include "font_8x4.h"
#include "font_7x5.h"
#include "font_8x6.h"
#include "font_16x8.h"
#include "HT1632.h"
#include "images.h"
#include "fortunes.h"

#include "commonUtils.h"
#include "dictionary.h"
#include "stdTypes.h"
#include "motionSensor.h"
#include "lightSensor.h"
#include "inbox.h"

#include <cassert>
#include <time.h>
#include <string.h>

// Local types

class DisplayInternalInfo {
public:
  DisplayInternalInfo(HT1632Class& ht1632);
  ~DisplayInternalInfo();

  HT1632Class& ht1632;
  Dictionary& dictionary;
  MotionSensor& motionSensor;
  LightSensor& lightSensor;
  InboxRegistry& inboxRegistry;

private:
  DisplayInternalInfo() = delete;
  DisplayInternalInfo(const DisplayInternalInfo& other) = delete;
  DisplayInternalInfo& operator=(const DisplayInternalInfo& other) = delete;
};

typedef void (*modeFunctionParamPtr)(DisplayInternalInfo& info, const void* param);
typedef void (*modeFunctionPtr)(DisplayInternalInfo& info);

typedef enum {
  displayModeNothing = 0,
  displayModeBasicClock,
  displayModeMessage
} DisplayMode;

typedef struct {
  AnimationStep animationStep;
  Int8U animationStepPhase;
  Int8U animationStepPhaseValue;
} Animation;

typedef struct {
  bool enabled;
  Font font;
  DisplayColor displayColor;
  char msg[BACKGROUND_MESSAGE_MSG_SIZE];
  int x;
  int y;
  Animation animation;
} BackgroundMessage;

typedef struct {
  bool enabled;
  DisplayColor displayColor;
  ImgArt imgArt;
  int x;
  int y;
  Animation animation;
} BackgroundImg;

typedef struct {
  const char* img;
  Int8U width;
  Int8U height;
} ImgArtInfo;

#define INCREMENT_Y_SCALE 1000
#define INCREMENT_Y_VALUE 800
struct ModeMessageData {
  char msg[MESSAGE_MAX_SIZE]; // ignored if modeMsgsIndex is valid
  ModeMsgsIndex modeMsgsIndex;  // offset of modeMessageMsg (-1 => none)
  bool incrementX;  // dictate whether text will scroll
  int confetti;  // max number of confetti (0 => none)
  bool alternateFont;
  DisplayColor displayColor;
  bool blink;
  modeFunctionParamPtr completedCallback;
  const void* completedCallbackParam;

  int incrementY; // increment Y factor every fastTick (can be negative)
  int repeats;    // number of times message will be displayed, before calling 'completed'  (~0 => forever)
                  // only used when incrementX is 'true'
  Int32U timeout;   // max number of seconds before calling 'completed'  (~0 => forever)
  Font font;

  int currX;
  int currYFactor;
  bool blinkBlankInEffect;

  int wd;
};

// ----

// Forward declarations

static const char* getFontData(Font font);
static const char* getFontWidth(Font font);
static char getFontHeight(Font font);
static int getFontGlyphStep(Font font);
static int getAdjustedTextY(Font font, int wantedY);
static Font getNextFont(Font font);

static std::string lookupDictValue(DisplayInternalInfo& displayInternalInfo, const char* key);
static void updateMotionDetectedPixel(DisplayInternalInfo& displayInternalInfo, bool invokeRender = true);

// not to be confused with initModeMessage()
static void initModeMessageData(int currX = 0, int currY = 0, bool incrementX = true,
				bool incrementY = false, int confetti = 0, bool blink = false,
				Font font = font5x4, Int32U timeout = ~0);
static DisplayMode getDisplayMode();

static void changeDisplayMode(DisplayMode displayMode, DisplayInternalInfo& displayInternalInfo, const void* param = 0);
static void changeDisplayModeBasicClock(DisplayInternalInfo& displayInternalInfo, const void* param);

static void initBackgroundMessage(int offset);
static void drawBackgroundMessages(DisplayInternalInfo& displayInternalInfo);

static void initBackgroundImg(int offset);
static void drawBackgroundImgs(DisplayInternalInfo& displayInternalInfo);

static ImgArtInfo getImgArtInfo(ImgArt imgArt);

// ----

// Locals

static BackgroundMessage backgroundMessage[BACKGROUND_MESSAGE_COUNT];
static BackgroundImg backgroundImg[BACKGROUND_IMG_COUNT];

static int modeMessageDataColorEffect = 0;
static ModeMessageData modeMessageData;

static int currModeIndex = 0;

static Int8U animationStepTickerFast = 0;
static Int8U animationStepTicker100ms = 0;
static Int8U animationStepTicker250ms = 0;
static Int8U animationStepTicker500ms = 0;
static Int8U animationStepTicker1sec = 0;
static Int8U animationStepTicker5sec = 0;
static Int8U animationStepTicker10sec = 0;

struct Mode {
  DisplayMode displayMode;
  const char* const displayModeStr;
  const InboxMsgType inboxMsgType;
  modeFunctionParamPtr handlerInit;
  modeFunctionPtr handlerTickFast;
  modeFunctionPtr handlerTick100ms;
  modeFunctionPtr handlerTick250ms;
  modeFunctionPtr handlerTick500ms;
  modeFunctionPtr handlerTick1Sec;
  modeFunctionPtr handlerTick5Sec;
  modeFunctionPtr handlerTick10Sec;
  modeFunctionPtr handlerTick25Sec;
  modeFunctionPtr handlerTick1Min;
};

static const char* const msgDictPrefix = "#dict_";
static const int msgDictPrefixLen = (int) strlen(msgDictPrefix);

// ----------------------------------------

static bool willAnimate(const Animation* animation) {
  if (animation == nullptr || animation->animationStepPhase == 0) return true;
  switch (animation->animationStep) {
     case animationStepNone:
       return true;
     case animationStepFast:
       return animationStepTickerFast % animation->animationStepPhase == animation->animationStepPhaseValue;
     case animationStep100ms:
       return animationStepTicker100ms % animation->animationStepPhase == animation->animationStepPhaseValue;
     case animationStep250ms:
       return animationStepTicker250ms % animation->animationStepPhase == animation->animationStepPhaseValue;
     case animationStep500ms:
       return animationStepTicker500ms % animation->animationStepPhase == animation->animationStepPhaseValue;
     case animationStep1sec:
       return animationStepTicker1sec % animation->animationStepPhase == animation->animationStepPhaseValue;
     case animationStep5sec:
       return animationStepTicker5sec % animation->animationStepPhase == animation->animationStepPhaseValue;
     case animationStep10sec:
       return animationStepTicker10sec % animation->animationStepPhase == animation->animationStepPhaseValue;
     default:
       break;
  }
  return true;
}

static struct tm* getTimeInfo(struct tm& timeInfo) {
  time_t rawTime;
  time(&rawTime);
  return localtime_r(&rawTime, &timeInfo);
}

// ----------------------------------------
// ----------------------------------------

// modeBasicClock

const char daySun[] = "Sunday"; const char dayMon[] = "Monday"; const char dayTue[] = "Tuesday";
const char dayWed[] = "Wednesday"; const char dayThu[] = "Thursday"; const char dayFri[] = "Friday";
const char daySat[] = "Saturday";
static const char* const daysOfWeek[] = {daySun, dayMon, dayTue, dayWed, dayThu, dayFri, daySat};

const char monthJan[] = "January"; const char monthFeb[] = "February"; const char monthMar[] = "March";
const char monthApr[] = "April";   const char monthMay[] = "May";      const char monthJun[] = "June";
const char monthJul[] = "July";    const char monthAug[] = "August";   const char monthSep[] = "September";
const char monthOct[] = "October"; const char monthNov[] = "November"; const char monthDec[] = "December";
static const char* const months[] = {monthJan, monthFeb, monthMar, monthApr, monthMay, monthJun, monthJul,
				     monthAug, monthSep, monthOct, monthNov, monthDec};

static char* getDayOfMonthStr(int day, char* const bufferOut, size_t bufferOutSize) {
  if (day == 1) {
    snprintf(bufferOut, bufferOutSize, "1st");
  } else if (day == 2) {
    snprintf(bufferOut, bufferOutSize, "2nd");
  } else if (day == 3) {
    snprintf(bufferOut, bufferOutSize, "3rd");
  } else if (day == 21) {
    snprintf(bufferOut, bufferOutSize, "21st");
  } else if (day == 22) {
    snprintf(bufferOut, bufferOutSize, "22nd");
  } else if (day == 23) {
      snprintf(bufferOut, bufferOutSize, "23rd");
  } else if (day == 31) {
    snprintf(bufferOut, bufferOutSize, "31st");
  } else {
    snprintf(bufferOut, bufferOutSize, "%dth", day);
  }
  return bufferOut;
}

static void modeBasicClockShowTemperature(DisplayInternalInfo& displayInternalInfo);  // FWD

static void modeBasicClockSlow(DisplayInternalInfo& displayInternalInfo) {
  HT1632Class& HT1632 = displayInternalInfo.ht1632;
  char localDisplayBuffer[MESSAGE_MAX_SIZE];
  struct tm timeInfo;
  static const int clockBaseX = 0;

  getTimeInfo(timeInfo);

  const bool isPm = timeInfo.tm_hour > 11;
  int hour = timeInfo.tm_hour - (timeInfo.tm_hour > 12 ? 12 : 0);
  if (hour == 0) hour = 12; // midnight

  // part 1
  HT1632.drawTarget(BUFFER_BOARD(1)); HT1632.clear();

  snprintf(localDisplayBuffer, sizeof(localDisplayBuffer), "%2d:%02d", hour, timeInfo.tm_min);
  HT1632.drawText(localDisplayBuffer, clockBaseX + 0 /*x*/, 0 /*y*/, FONT_16X8, FONT_16X8_WIDTH, FONT_16X8_HEIGHT, FONT_16X8_STEP_GLYPH);

  snprintf(localDisplayBuffer, sizeof(localDisplayBuffer), "%s", isPm ? "pm":"am");
  HT1632.drawText(localDisplayBuffer, clockBaseX + 39 /*x*/, 9 /*y*/, FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH);

#if 0
  // DEBUG hack day
  timeInfo.tm_wday = 3;
  timeInfo.tm_mon = 8;
  timeInfo.tm_mday = 22;
#endif

  // part 2
  const char* const weekDayStr =
    (timeInfo.tm_wday >=0 && timeInfo.tm_wday <= 6) ? daysOfWeek[timeInfo.tm_wday] : "DDD";
  strncpy(localDisplayBuffer, weekDayStr, sizeof(localDisplayBuffer));

  HT1632.drawTarget(BUFFER_BOARD(2)); HT1632.clear();
  HT1632.drawText(localDisplayBuffer, clockBaseX + 49 /*x*/, 0 /*y*/, FONT_7X5, FONT_7X5_WIDTH, FONT_7X5_HEIGHT, FONT_7X5_STEP_GLYPH);

  // put first 3 characthers of the month, followed by the day into a string
  const char* const monthStr =
    (timeInfo.tm_mon >=0 && timeInfo.tm_mon <= 11) ? months[timeInfo.tm_mon] : "MMM";
  assert(sizeof(localDisplayBuffer) >= 6);
  strncpy(localDisplayBuffer, monthStr, 4 /*sizeof(localDisplayBuffer)*/);
  localDisplayBuffer[3] = ' ';
  getDayOfMonthStr(timeInfo.tm_mday, (char*) (localDisplayBuffer + 4), sizeof(localDisplayBuffer) - 4);
  for (int i=1; i < 3; ++i) {
    HT1632.drawTarget(BUFFER_BOARD(i));
    HT1632.drawText(localDisplayBuffer, clockBaseX + 49 /*x*/, 8 /*y*/, FONT_8X4, FONT_8X4_WIDTH, FONT_8X4_HEIGHT, FONT_8X4_STEP_GLYPH);
  }

  // part 3
  modeBasicClockShowTemperature(displayInternalInfo);

  // HT1632.renderAll();  // already expected to be invoked by updateMotionDetectedPixel
}

static void modeBasicClockShowTemperature(DisplayInternalInfo& displayInternalInfo) {
  HT1632Class& HT1632 = displayInternalInfo.ht1632;
  Dictionary& dictionary = displayInternalInfo.dictionary;
  char localDisplayBuffer[MESSAGE_MAX_SIZE];
  std::string value;
  bool valueFound;
  const int xPos = 109;

  HT1632.drawTarget(BUFFER_BOARD(1));
  value = dictionary.get(dictionaryTopicTemperature, &valueFound);
  if (valueFound) {
    snprintf(localDisplayBuffer, sizeof(localDisplayBuffer), "%s f", value.c_str());
    HT1632.drawText(localDisplayBuffer, xPos, 0 /*Y*/, FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH);
  }

  HT1632.drawTarget(BUFFER_BOARD(2));
  value = dictionary.get(dictionaryTopicHumidity, &valueFound);
  if (valueFound) {
    snprintf(localDisplayBuffer, sizeof(localDisplayBuffer), "%s %%", value.c_str());
    HT1632.drawText(localDisplayBuffer, xPos, 6 /*Y*/, FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH);
  }
}

static void modeBasicClockShowSeconds(DisplayInternalInfo& displayInternalInfo) {
    HT1632Class& HT1632 = displayInternalInfo.ht1632;
  struct tm timeInfo;

  getTimeInfo(timeInfo);

  // explicitly invoke slow refresh if this is a minute update
  if (timeInfo.tm_sec == 0) modeBasicClockSlow(displayInternalInfo);

# ifdef BASIC_CLOCK_SECONDS_BOX
  static const int initialX = 39;
  static const int initialY = 1;
  static const int dotsPerRow = 8;

  // 1->green  2->red
  for (int currColor = 1; currColor <= 2; ++currColor) {
    displayInternalInfo.ht1632.drawTarget(BUFFER_BOARD(currColor));
    for (int currSec = 1; currSec <= 60; ++currSec) {
      const int currSecX = ((currSec - 1) % dotsPerRow) + initialX;
      const int currSecY = ((currSec - 1) / dotsPerRow) + initialY;

      // turn on pixel that represents the current seconds?
      bool setPixel;
      if (currSec == timeInfo.tm_sec) {
	setPixel = currColor == 2;
      } else if (currSec < timeInfo.tm_sec) {
	const int activeY = ((timeInfo.tm_sec - 1) / dotsPerRow) + initialY;
	setPixel = currColor == 2 || (currColor == 1 && currSecY != activeY);
      } else {
	setPixel = currColor == 1;
      }

      displayInternalInfo.ht1632.setPixel(currSecX, currSecY, setPixel);
    }
  }
#else  // ifdef BASIC_CLOCK_SECONDS_BOX
  static const int initialX = 39;
  static const int initialY = 0;
  char localDisplayBuffer[10];

  HT1632.drawTarget(BUFFER_BOARD(1));
  // note the extra spaces to erase the fatter printouts of the previous value
  snprintf(localDisplayBuffer, sizeof(localDisplayBuffer), "%02d ", timeInfo.tm_sec);
  HT1632.drawText(localDisplayBuffer, initialX /*x*/, initialY /*y*/, FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH);
#endif // ifdef BASIC_CLOCK_SECONDS_BOX

  // HT1632.renderAll();  // already expected to be invoked by updateMotionDetectedPixel
}

static void modeBasicClockSDoUpDownAnimationTemperature(DisplayInternalInfo& displayInternalInfo) {
  static const int xPos = 103;
  static const int yPos = 0;
  static int animationFrame = 0;
  std::string value;
  bool valueFound;
  Dictionary& dictionary = displayInternalInfo.dictionary;

  value = dictionary.get(dictionaryTopicTemperatureDir, &valueFound);
  if (!valueFound) return;
  if (value != dictionaryTopicDirectionUp &&
      value != dictionaryTopicDirectionDown) return;

  const ImgArtInfo imgArtInfo = value == dictionaryTopicDirectionUp ?
    getImgArtInfo( (ImgArt) ((int)imgArtUp21 + animationFrame) ) :
    getImgArtInfo( (ImgArt) ((int)imgArtDown21 + animationFrame) );
  animationFrame = (animationFrame + 1) % 4;

  HT1632Class& HT1632 = displayInternalInfo.ht1632;
  HT1632.drawTarget(BUFFER_BOARD(1));
  HT1632.drawImage(imgArtInfo.img, imgArtInfo.width, imgArtInfo.height, xPos, yPos);
  HT1632.render();
}

static void modeBasicClockSDoUpDownAnimationHumidity(DisplayInternalInfo& displayInternalInfo) {
  static const int xPos = 103;
  static const int yPos = 6;
  static int animationFrame = 0;
  std::string value;
  bool valueFound;
  Dictionary& dictionary = displayInternalInfo.dictionary;

  value = dictionary.get(dictionaryTopicHumidityDir, &valueFound);
  if (!valueFound) return;
  if (value != dictionaryTopicDirectionUp &&
      value != dictionaryTopicDirectionDown) return;

  const ImgArtInfo imgArtInfo = value == dictionaryTopicDirectionUp ?
    getImgArtInfo( (ImgArt) ((int)imgArtUp21 + animationFrame) ) :
    getImgArtInfo( (ImgArt) ((int)imgArtDown21 + animationFrame) );
  animationFrame = (animationFrame + 1) % 4;

  HT1632Class& HT1632 = displayInternalInfo.ht1632;
  HT1632.drawTarget(BUFFER_BOARD(2));
  HT1632.drawImage(imgArtInfo.img, imgArtInfo.width, imgArtInfo.height, xPos, yPos);
  HT1632.render();
}

static void modeBasicClockSDoCarAnimation(DisplayInternalInfo& displayInternalInfo) {
  static const int xPos = 86;
  static const int yPos = 8;
  static int animationFrame = 0;
  static const int animationsAfterOff = 80;  // factor in the ticks (250 ms) == ~22 secs
  static int animationCounter = animationsAfterOff;
  static Int32U blinkerEffect = 0;
  static const ImgArtInfo imgArtInfoBlank = getImgArtInfo(imgArtBlank);
  Dictionary& dictionary = displayInternalInfo.dictionary;
  bool value1Found;
  bool value2Found;
  bool value3Found;
  std::string value1;
  std::string value2;
  std::string value3;

  value1 = dictionary.get(dictionaryTopicGarageMotion1, &value1Found);
  value2 = dictionary.get(dictionaryTopicGarageMotion2, &value2Found);
  value3 = dictionary.get(dictionaryTopicGarageMotion3, &value3Found);
  if (!value1Found && !value2Found && !value3Found) return;

  if (value1Found && value1 == dictionaryTopicValueOn) animationCounter = 0;
  if (value2Found && value2 == dictionaryTopicValueOn) animationCounter = 0;
  if (value3Found && value3 == dictionaryTopicValueOn) animationCounter = 0;

  if (animationCounter >= animationsAfterOff) return;
  ++animationCounter;  // use animationCounter to keep it going even after dict is no longer 'on'

  ImgArtInfo imgArtInfo = getImgArtInfo( (ImgArt) ((int)imgArtCar1 + animationFrame) );
  // show car? (blink effect)
  if ((++blinkerEffect % 10) < 6) {
    animationFrame ^= 1;
  } else {
    assert(imgArtInfoBlank.width >= imgArtInfo.width);
    assert(imgArtInfoBlank.height >= imgArtInfo.height);
    imgArtInfo.img = imgArtInfoBlank.img;
  }

  HT1632Class& HT1632 = displayInternalInfo.ht1632;
  HT1632.drawTarget(BUFFER_BOARD(1));
  HT1632.drawImage(imgArtInfo.img, imgArtInfo.width, imgArtInfo.height, xPos, yPos);
  HT1632.render();
}

static void modeBasicClockSDoUpDownAnimation(DisplayInternalInfo& displayInternalInfo) {
  modeBasicClockSDoUpDownAnimationTemperature(displayInternalInfo);
  modeBasicClockSDoUpDownAnimationHumidity(displayInternalInfo);
  modeBasicClockSDoCarAnimation(displayInternalInfo);
}

static void modeBasicClockFast(DisplayInternalInfo& displayInternalInfo) {
  MotionInfo motionInfo;

  // leave clock mode if there is no motion detected for a while
  if (!displayInternalInfo.motionSensor.getMotionValue(&motionInfo) &&
      (motionInfo.lastChangedMin > 15 || motionInfo.lastChangedHour > 0)) {
    changeDisplayMode(displayModeNothing, displayInternalInfo);
    return;
  }

  modeBasicClockShowSeconds(displayInternalInfo);
  //modeBasicClockSDoUpDownAnimation(displayInternalInfo);
  updateMotionDetectedPixel(displayInternalInfo);
}

static void modeBasicClock1Sec(DisplayInternalInfo& displayInternalInfo) {
  // HT1632.renderAll();  // already expected to be invoked by updateMotionDetectedPixel
}

static void modeBasicClock5Sec(DisplayInternalInfo& displayInternalInfo) {
  // HT1632.renderAll();  // already expected to be invoked by updateMotionDetectedPixel
}

static void modeBasicClockInit(DisplayInternalInfo& displayInternalInfo, const void* /*param*/) {
  modeBasicClockSlow(displayInternalInfo);
}

static const Mode modeBasicClock = {displayModeBasicClock, "basicClock", inboxMsgTypeDisplayModeBasicClock,
				    modeBasicClockInit /*init*/, 0 /*fast*/,
				    0 /*100ms*/,
				    modeBasicClockSDoUpDownAnimation /*250ms*/,
				    modeBasicClockFast /*500ms*/,
				    modeBasicClock1Sec /*1sec*/, modeBasicClock5Sec /*5sec*/,
				    modeBasicClockSlow /*10sec*/, 0 /*25sec*/, 0 /*1min*/};

// ----------------------------------------

// modeMessage

static void initModeMessageData(int currX, int currY, bool incrementX, bool incrementY,
				int confetti, bool blink, Font font, Int32U timeout) {
  // config (only changed by user)
  modeMessageData.msg[0] = 0;
  modeMessageData.incrementX = incrementX;
  modeMessageData.modeMsgsIndex = modeMsgsIndexLast;
  modeMessageData.confetti = confetti;
  modeMessageData.alternateFont = false;
  modeMessageData.displayColor = displayColorAlternate; // displayColorGreen, displayColorRed, ...
  modeMessageData.blink = blink;
  modeMessageData.completedCallback = changeDisplayModeBasicClock; // default: go back to basic clock
  modeMessageData.completedCallbackParam = 0;

  // config/runtime (user set, changes as it runs)
  modeMessageData.incrementY = incrementY ? INCREMENT_Y_VALUE : 0;
  modeMessageData.repeats = ~0;  // repeat forever, until timeout
  modeMessageData.timeout = timeout;  // seconds until next mode
  modeMessageData.font = font;

  // runtime
  modeMessageData.currX = currX;
  modeMessageData.currYFactor = currY * INCREMENT_Y_SCALE;
  modeMessageData.blinkBlankInEffect = modeMessageData.blink;
  ++modeMessageDataColorEffect;
}

static void modeMessageInit(DisplayInternalInfo& displayInternalInfo, const void* param) {
  HT1632Class& HT1632 = displayInternalInfo.ht1632;

  if (param != nullptr) {
    snprintf(modeMessageData.msg, sizeof(modeMessageData.msg), "%s", (const char*) param);
  } else if (modeMessageData.modeMsgsIndex >= (ModeMsgsIndex) 0 && modeMessageData.modeMsgsIndex < modeMsgsIndexLast) {
    strncpy(modeMessageData.msg, modeMessageMsgs[modeMessageData.modeMsgsIndex], sizeof(modeMessageData.msg));
  }

  // runtime
  modeMessageData.wd = HT1632.getTextWidth(modeMessageData.msg,
					   getFontWidth(modeMessageData.font),
					   getFontHeight(modeMessageData.font));
}

static void modeMessageFast(DisplayInternalInfo& displayInternalInfo) {
  int boardId, i;

  HT1632Class& HT1632 = displayInternalInfo.ht1632;
  HT1632.clearAll();

  const int currColorEffect = modeMessageDataColorEffect % 3;
  for (i=0; i < BUFFER_SECONDARY; ++i) {
    if (modeMessageData.blinkBlankInEffect) break;  // blinkBlankInEffect in effect? If so, write no chars

    switch (modeMessageData.displayColor) {
        case displayColorGreen: boardId = 0; break;
        case displayColorRed: boardId = 1; break;
        case displayColorYellow: boardId = i; break;
        case displayColorAlternate:  // fall thru
        default: boardId = currColorEffect == 2 ? i : currColorEffect; break;
    }

    HT1632.drawTarget(BUFFER_BOARD(boardId+1));

    // if bouncing, make sure sure y is within range
    const int wantedY = modeMessageData.currYFactor / INCREMENT_Y_SCALE;
    const int adjustedY = modeMessageData.incrementY ? getAdjustedTextY(modeMessageData.font, wantedY) : wantedY;

    HT1632.drawText(modeMessageData.msg,
		    modeMessageData.incrementX ? (OUT_SIZE - modeMessageData.currX) : modeMessageData.currX /*x*/,
		    adjustedY /*y*/,
		    getFontData(modeMessageData.font),
		    getFontWidth(modeMessageData.font),
		    getFontHeight(modeMessageData.font),
		    getFontGlyphStep(modeMessageData.font));

    if (modeMessageData.displayColor == displayColorAlternate && currColorEffect == 2) continue;
    if (modeMessageData.displayColor != displayColorYellow) break;
  }

  drawBackgroundMessages(displayInternalInfo);
  drawBackgroundImgs(displayInternalInfo);

  // confetti
  if (modeMessageData.confetti > 0) {
    for (boardId=0; boardId < BUFFER_SECONDARY; ++boardId) {
      HT1632.drawTarget(BUFFER_BOARD(boardId+1));
      for (int xx = 0, yy = (int) getRandomNumber(modeMessageData.confetti); xx <= yy ; ++xx) {
	HT1632.setPixel( (int) getRandomNumber(OUT_SIZE), (int) getRandomNumber(COM_SIZE));
      }
    }
  }

  HT1632.renderAll();

  // text wrap
  if (modeMessageData.incrementX && ++modeMessageData.currX >= (modeMessageData.wd + OUT_SIZE)) {
    modeMessageData.currX = 0;
    ++modeMessageDataColorEffect;

    if (modeMessageData.alternateFont) {
      modeMessageData.font = getNextFont(modeMessageData.font);
      modeMessageData.wd = HT1632.getTextWidth(modeMessageData.msg,
					       getFontWidth(modeMessageData.font),
					       getFontHeight(modeMessageData.font));
    }

    // repeats?
    if (modeMessageData.repeats != ~0) {
      // mode exit (1 of 2)
      if (--modeMessageData.repeats < 0) {
	modeMessageData.repeats = ~0;  // avoid getting here again...
	if (modeMessageData.completedCallback != nullptr) {
	  (*(modeMessageData.completedCallback))(displayInternalInfo, modeMessageData.completedCallbackParam);
	  return;
	}
      }
    }
  }

  // Y (bounce effect)
  if (modeMessageData.incrementY != 0) {
    modeMessageData.currYFactor += modeMessageData.incrementY;

    const int maxY = COM_SIZE - getFontHeight(modeMessageData.font);
    if (modeMessageData.incrementY < 0 && modeMessageData.currYFactor < 0) {
      modeMessageData.incrementY *= -1;
    } else if (modeMessageData.incrementY > 0 && (modeMessageData.currYFactor >= maxY * INCREMENT_Y_SCALE)) {
      modeMessageData.incrementY *= -1;

      if (!modeMessageData.incrementX) {
	++modeMessageDataColorEffect;
	if (modeMessageData.alternateFont) {
	  modeMessageData.font = getNextFont(modeMessageData.font);
	  // modeMessageData.wd = HT1632.getTextWidth(modeMessageData.msg,
	  //				  	   getFontWidth(modeMessageData.font),
	  //					   getFontHeight(modeMessageData.font));
	}
      }
    }
  }
}

static void modeMessageCheckBlink(DisplayInternalInfo& /*displayInternalInfo*/) {
  if (modeMessageData.blink) modeMessageData.blinkBlankInEffect = !modeMessageData.blinkBlankInEffect;
}

static void modeMessageCheckTimeout(DisplayInternalInfo& displayInternalInfo) {
  // timeout?
  if (modeMessageData.timeout != (Int32U) ~0) {
    // mode exit (2 of 2)
    if (--modeMessageData.timeout <= 0) {
      modeMessageData.timeout = ~0;  // avoid getting here again...
      if (modeMessageData.completedCallback != nullptr) {
	(*(modeMessageData.completedCallback))(displayInternalInfo, modeMessageData.completedCallbackParam);
	return;
      }
    }
  }
}

static const Mode modeMessage = {displayModeMessage, "message", inboxMsgTypeDisplayModeMessage,
				 modeMessageInit /*init*/, modeMessageFast /*fast*/, 0 /*100ms*/,
				 modeMessageCheckBlink /*250ms*/, 0 /*500ms*/, modeMessageCheckTimeout /*1sec*/,
				 0 /*5sec*/, 0 /*10sec*/, 0 /*25sec*/, 0 /*1min*/};

// ----------------------------------------

// modeNothing

static void modeNothingInit(DisplayInternalInfo& /*displayInternalInfo*/, const void* /*param*/) {
}

static void modeNothingCheckMotion(DisplayInternalInfo& displayInternalInfo) {
  static int row = 0; static int col = 0; static Int8U color = 0;

  if (displayInternalInfo.motionSensor.getMotionValue()) {
    changeDisplayMode(displayModeBasicClock, displayInternalInfo);
    return;
  }

  HT1632Class& HT1632 = displayInternalInfo.ht1632;
  HT1632.clearAll();
  for (int boardId=0; boardId < BUFFER_SECONDARY; ++boardId) {
    if (color != (Int8U) displayColorYellow && color != (Int8U) boardId) continue;

    HT1632.drawTarget(BUFFER_BOARD(boardId+1));
    HT1632.setPixel(row, col, true);
  }
  HT1632.renderAll();

  // Prepare statics for next iteration
  if (++color > (Int8U) displayColorYellow) {
    color = 0;
    if (++row >= OUT_SIZE) { if (++col >= COM_SIZE) col = 0; row = 0; }
  }
}

static const Mode modeNothing = {displayModeNothing, "nothing", inboxMsgTypeDisplayModeNothing,
				 modeNothingInit /*init*/, 0 /*fast*/, 0 /*100ms*/, 0 /*250ms*/, 0 /*500ms*/,
				 modeNothingCheckMotion /*1sec*/, 0 /*5sec*/, 0 /*10sec*/, 0 /*25sec*/, 0 /*1min*/};

// ----------------------------------------

static std::string lookupDictValue(DisplayInternalInfo& displayInternalInfo, const char* key) {
  return displayInternalInfo.dictionary.get(key);
}

static void updateMotionDetectedPixel(DisplayInternalInfo& displayInternalInfo, bool invokeRender) {
  HT1632Class& HT1632 = displayInternalInfo.ht1632;

  // Update motion detection pixel
  const bool currMotionDetected = displayInternalInfo.motionSensor.getMotionValue();
  for (int i = 1; i <= 2; ++i) {
    displayInternalInfo.ht1632.drawTarget(BUFFER_BOARD(i));
    displayInternalInfo.ht1632.setPixel(OUT_SIZE - 1 /*loc_x*/, COM_SIZE - 1 /*loc_y*/, currMotionDetected);
  }
  if (invokeRender) HT1632.renderAll();
}

static void updateDim(DisplayInternalInfo& displayInternalInfo) {
  static bool lastRoomIsDark = false;
  const LightSensor& lightSensor = displayInternalInfo.lightSensor;
  const Int32U lightValue = lightSensor.getLightValue();
  InboxRegistry& inboxRegistry = displayInternalInfo.inboxRegistry;

  bool currRoomIsDark;

  if (lastRoomIsDark) {
    // room is currently declared dark. Change it to bright if its above high water mark
    currRoomIsDark = lightValue < lightSensor.darkRoomThresholdHighWaterMark;
  } else {
    // room is currently declared bright. Change it to dark if its below low water mark
    currRoomIsDark = lightValue < lightSensor.darkRoomThresholdLowWaterMark;
  }

  if (lastRoomIsDark == currRoomIsDark) return;  // no change: done

  displayInternalInfo.ht1632.setBrightness(currRoomIsDark ? 1 : 16);
  lastRoomIsDark = currRoomIsDark;

  inboxRegistry.broadcast(currRoomIsDark ? inboxMsgTypeDisplayBrightLow : inboxMsgTypeDisplayBrightHigh,
			  threadIdDisplay);
}

// ----------------------------------------

static struct Mode const allModes[] = { modeNothing, modeBasicClock, modeMessage };
static const int allModesCount = sizeof(allModes) / sizeof(allModes[0]);

static void initDisplay(DisplayInternalInfo& displayInternalInfo) {
  int i;

  for (i=0; i < BACKGROUND_MESSAGE_COUNT; ++i) initBackgroundMessage(i);
  for (i=0; i < BACKGROUND_IMG_COUNT; ++i) initBackgroundImg(i);

  initModeMessageData(1 /*currX*/, 5 /*currY*/, false /*incrementX*/, false /*incrementY*/,
		      1 /*confetti*/, false /*blink*/, font5x4 /*font*/, 5 /*timeout*/);
  modeMessageData.modeMsgsIndex = modeMsgsIndexBoot;
  modeMessageData.displayColor = displayColorYellow;
  changeDisplayMode(displayModeMessage, displayInternalInfo);
}

static DisplayMode getDisplayMode() {
  return allModes[currModeIndex].displayMode;
}

static void changeDisplayMode(DisplayMode displayMode, DisplayInternalInfo& displayInternalInfo, const void* param) {
  HT1632Class& HT1632 = displayInternalInfo.ht1632;
  InboxRegistry& inboxRegistry = displayInternalInfo.inboxRegistry;

  for (int i=0; i < allModesCount; ++i) {
    if (allModes[i].displayMode == displayMode) {
      currModeIndex = i;
      HT1632.clearAll(); HT1632.renderAll();
      if (allModes[currModeIndex].handlerInit != nullptr) (*(allModes[currModeIndex].handlerInit))(displayInternalInfo, param);
      inboxRegistry.broadcast(allModes[currModeIndex].inboxMsgType, threadIdDisplay);
      break;
    }
  }
}

static void changeDisplayModeBasicClock(DisplayInternalInfo& displayInternalInfo, const void* param) {
  changeDisplayMode(displayModeBasicClock, displayInternalInfo, param);
}

// ======================================================================

static void initBackgroundMessage(int offset) {
  if (offset < 0 || offset >= BACKGROUND_MESSAGE_COUNT) return;
  backgroundMessage[offset].enabled = false;
  backgroundMessage[offset].font = font5x4;
  backgroundMessage[offset].displayColor = displayColorYellow;
  memset( backgroundMessage[offset].msg, 0, BACKGROUND_MESSAGE_MSG_SIZE );
  backgroundMessage[offset].x = 0;
  backgroundMessage[offset].y = 0;
}

static void drawBackgroundMessages(DisplayInternalInfo& displayInternalInfo) {
  HT1632Class& HT1632 = displayInternalInfo.ht1632;
  int boardId, i, j;
  for (i=0; i < BACKGROUND_MESSAGE_COUNT; ++i) {
    if (backgroundMessage[i].enabled == false) continue;
    if (willAnimate(&backgroundMessage[i].animation) == false) continue;
    for (j=0; j < BUFFER_SECONDARY; ++j) {
      switch (backgroundMessage[i].displayColor) {
        case displayColorGreen: boardId = 0; break;
        case displayColorRed: boardId = 1; break;
        case displayColorYellow:  // fall thru...
        default: boardId = j; break;
      }
      HT1632.drawTarget(BUFFER_BOARD(boardId+1));
      HT1632.drawText(backgroundMessage[i].msg, backgroundMessage[i].x, backgroundMessage[i].y,
		      getFontData(backgroundMessage[i].font),
		      getFontWidth(backgroundMessage[i].font),
		      getFontHeight(backgroundMessage[i].font),
		      getFontGlyphStep(backgroundMessage[i].font));
      if (backgroundMessage[i].displayColor != displayColorYellow) break;
    }
  }
}

// ======================================================================

static void initBackgroundImg(int offset) {
  if (offset < 0 || offset >= BACKGROUND_IMG_COUNT) return;
  backgroundImg[offset].enabled = false;
  backgroundImg[offset].displayColor = displayColorYellow;
  backgroundImg[offset].imgArt = imgArtLast;
  backgroundImg[offset].x = 0;
  backgroundImg[offset].y = 0;
}

static void drawBackgroundImgs(DisplayInternalInfo& displayInternalInfo) {
  HT1632Class& HT1632 = displayInternalInfo.ht1632;
  int boardId, i, j;
  ImgArtInfo imgArtInfo;

  for (i=0; i < BACKGROUND_IMG_COUNT; ++i) {
    if (backgroundImg[i].enabled == false) continue;
    if (willAnimate(&backgroundImg[i].animation) == false) continue;
    imgArtInfo = getImgArtInfo(backgroundImg[i].imgArt);
    for (j=0; j < BUFFER_SECONDARY; ++j) {
      switch (backgroundImg[i].displayColor) {
        case displayColorGreen: boardId = 0; break;
        case displayColorRed: boardId = 1; break;
        case displayColorYellow:  // fall thru...
        default: boardId = j; break;
      }
      HT1632.drawTarget(BUFFER_BOARD(boardId+1));
      HT1632.drawImage(imgArtInfo.img, imgArtInfo.width, imgArtInfo.height,
		       backgroundImg[i].x, backgroundImg[i].y);
      if (backgroundImg[i].displayColor != displayColorYellow) break;
    }
  }
}

// ======================================================================

#define X(x) #x
/*extern*/ const char* imgArtStr[] = {
    IMG_ART_LIST
};
#undef X

#define IMG_CONCATENATE_DETAIL(a, b) a##b
#define IMG_CONCATENATE(a, b) IMG_CONCATENATE_DETAIL(a, b)
#define GET_ART_INFO(x) do { imgArtInfo.img = IMG_CONCATENATE(IMG_, x); \
                             imgArtInfo.width = IMG_CONCATENATE(IMG_, IMG_CONCATENATE(x, _WIDTH)); \
                             imgArtInfo.height = IMG_CONCATENATE(IMG_, IMG_CONCATENATE(x, _HEIGHT)); \
                           } while (0)
#define GET_ART_INFO_INDEX(x, i) do { imgArtInfo.img = IMG_CONCATENATE(IMG_, IMG_CONCATENATE(x, i)); \
                                      imgArtInfo.width = IMG_CONCATENATE(IMG_, IMG_CONCATENATE(x, _WIDTH)); \
                                      imgArtInfo.height = IMG_CONCATENATE(IMG_, IMG_CONCATENATE(x, _HEIGHT)); \
                                    } while (0)

static ImgArtInfo getImgArtInfo(ImgArt imgArt) {
  ImgArtInfo imgArtInfo;
  switch (imgArt) {
  case imgArtSmiley:    GET_ART_INFO(SMILEY); break;
  case imgArtWink:      GET_ART_INFO(WINK); break;
  case imgArtBigHeart:  GET_ART_INFO(BIG_HEART); break;
  case imgArtCat:       GET_ART_INFO(CAT); break;
  case imgArtOwls:      GET_ART_INFO(OWLS); break;
  // 5
  case imgArtMail:      GET_ART_INFO(MAIL); break;
  case imgArtMusic:     GET_ART_INFO(MUSIC); break;
  case imgArtMusicNote: GET_ART_INFO(MUSICNOTE); break;
  case imgArtHeart:     GET_ART_INFO(HEART); break;
  case imgArtSpeakerA:  GET_ART_INFO(SPEAKER_A); break;
  // 10
  case imgArtSpeakerB:  GET_ART_INFO(SPEAKER_B); break;
  case imgArt8x8:       GET_ART_INFO(8X8); break;
  case imgArtStickMan1: GET_ART_INFO_INDEX(STICKMAN, 1); break;
  case imgArtStickMan2: GET_ART_INFO_INDEX(STICKMAN, 2); break;
  case imgArtStickMan3: GET_ART_INFO_INDEX(STICKMAN, 3); break;
  // 15
  case imgArtStickMan4: GET_ART_INFO_INDEX(STICKMAN, 4); break;
  case imgArtWave1:     GET_ART_INFO_INDEX(WAVE, 1); break;
  case imgArtWave2:     GET_ART_INFO_INDEX(WAVE, 2); break;
  case imgArtWave3:     GET_ART_INFO_INDEX(WAVE, 3); break;
  case imgArtWave4:     GET_ART_INFO_INDEX(WAVE, 4); break;
  // 20
  case imgArtJump1:     GET_ART_INFO_INDEX(JUMP,1); break;
  case imgArtJump2:     GET_ART_INFO_INDEX(JUMP,2); break;
  case imgArtJump3:     GET_ART_INFO_INDEX(JUMP,3); break;
  case imgArtJump4:     GET_ART_INFO_INDEX(JUMP,4); break;
  case imgArtUp:        GET_ART_INFO(UP); break;
  // 25
  case imgArtDown:      GET_ART_INFO(DOWN); break;
  case imgArtUp1:       GET_ART_INFO_INDEX(ARROW_UP, 1); break;
  case imgArtUp2:       GET_ART_INFO_INDEX(ARROW_UP, 2); break;
  case imgArtUp3:       GET_ART_INFO_INDEX(ARROW_UP, 3); break;
  case imgArtUp4:       GET_ART_INFO_INDEX(ARROW_UP, 4); break;
  // 30
  case imgArtDown1:     GET_ART_INFO_INDEX(ARROW_DOWN, 1); break;
  case imgArtDown2:     GET_ART_INFO_INDEX(ARROW_DOWN, 2); break;
  case imgArtDown3:     GET_ART_INFO_INDEX(ARROW_DOWN, 3); break;
  case imgArtDown4:     GET_ART_INFO_INDEX(ARROW_DOWN, 4); break;
  case imgArtUp21:      GET_ART_INFO_INDEX(ARROW2_UP, 1); break;
  // 35
  case imgArtUp22:      GET_ART_INFO_INDEX(ARROW2_UP, 2); break;
  case imgArtUp23:      GET_ART_INFO_INDEX(ARROW2_UP, 3); break;
  case imgArtUp24:      GET_ART_INFO_INDEX(ARROW2_UP, 4); break;
  case imgArtDown21:    GET_ART_INFO_INDEX(ARROW2_DOWN, 1); break;
  case imgArtDown22:    GET_ART_INFO_INDEX(ARROW2_DOWN, 2); break;
  // 40
  case imgArtDown23:    GET_ART_INFO_INDEX(ARROW2_DOWN, 3); break;
  case imgArtDown24:    GET_ART_INFO_INDEX(ARROW2_DOWN, 4); break;
  case imgArtCar1:      GET_ART_INFO_INDEX(CAR, 1); break;
  case imgArtCar2:      GET_ART_INFO_INDEX(CAR, 2); break;
  case imgArtBlank:     GET_ART_INFO(BLANK); break;
  // 45

  default: GET_ART_INFO(SMILEY); break;
  }
  return imgArtInfo;
}

// ======================================================================

static const char* getFontData(Font font) {
  switch (font) {
      case font5x4: return FONT_5X4; break;
      case font8x4: return FONT_8X4; break;
      case font7x5: return FONT_7X5; break;
      case font8x6: return FONT_8X6; break;
      case font16x8: return FONT_16X8; break;
      default: break;
  }
  return FONT_5X4;
}

static const char* getFontWidth(Font font) {
  switch (font) {
      case font5x4: return FONT_5X4_WIDTH; break;
      case font8x4: return FONT_8X4_WIDTH; break;
      case font7x5: return FONT_7X5_WIDTH; break;
      case font8x6: return FONT_8X6_WIDTH; break;
      case font16x8: return FONT_16X8_WIDTH; break;
      default: break;
  }
  return FONT_5X4_WIDTH;
}

static char getFontHeight(Font font) {
  switch (font) {
      case font5x4: return FONT_5X4_HEIGHT; break;
      case font8x4: return FONT_8X4_HEIGHT; break;
      case font7x5: return FONT_7X5_HEIGHT; break;
      case font8x6: return FONT_8X6_HEIGHT; break;
      case font16x8: return FONT_16X8_HEIGHT; break;
      default: break;
  }
  return FONT_5X4_HEIGHT;
}

static int getFontGlyphStep(Font font) {
  switch (font) {
      case font5x4: return FONT_5X4_STEP_GLYPH; break;
      case font8x4: return FONT_8X4_STEP_GLYPH; break;
      case font7x5: return FONT_7X5_STEP_GLYPH; break;
      case font8x6: return FONT_8X6_STEP_GLYPH; break;
      case font16x8: return FONT_16X8_STEP_GLYPH; break;
      default: break;
  }
  return FONT_5X4_STEP_GLYPH;
}

static int getAdjustedTextY(Font font, int wantedY) {
  if (wantedY < 0) return 0;
  const int fontHeight = (int) getFontHeight(font);
  if (fontHeight + wantedY >= COM_SIZE) {
    return COM_SIZE - fontHeight;
  }
  return wantedY;
}

static Font getNextFont(Font font) {
  Font nextFont = (Font) (((int) modeMessageData.font) + 1);
  return nextFont >= fontLast ? (Font) 0 : nextFont;
}

static void checkHT1632(HT1632Class& ht1632) {
  static int checkCount = 0;
  static const int checkCountMax = 13;  // TWEAK ME

  if (++checkCount < checkCountMax && getDisplayMode() != displayModeMessage) return;

  // HACK: ensure all chips are enabled and kicking, even if some
  //       noise in the pins interface made them go out to lunch
  ht1632.reinit();
  checkCount = 0;
}

// ----------------------------------------
// ----------------------------------------

DisplayInternalInfo::DisplayInternalInfo(HT1632Class& ht1632) :
  ht1632(ht1632),
  dictionary(Dictionary::bind()),
  motionSensor(MotionSensor::bind()),
  lightSensor(LightSensor::bind()),
  inboxRegistry(InboxRegistry::bind()) {
  initDisplay(*this);
}

DisplayInternalInfo::~DisplayInternalInfo() {
  ht1632.clearAll();
  ht1632.renderAll();
  ht1632.blank();
}

void DisplayInternal::displayTickFast() {
  ++animationStepTickerFast;
  if (allModes[currModeIndex].handlerTickFast != nullptr) (*(allModes[currModeIndex].handlerTickFast))(*info);
}

void DisplayInternal::displayTick100ms() {
  ++animationStepTicker100ms;
  if (allModes[currModeIndex].handlerTick100ms != nullptr) (*(allModes[currModeIndex].handlerTick100ms))(*info);
}

void DisplayInternal::displayTick250ms() {
  ++animationStepTicker250ms;
  if (allModes[currModeIndex].handlerTick250ms != nullptr) (*(allModes[currModeIndex].handlerTick250ms))(*info);
}

void DisplayInternal::displayTick500ms() {
  checkHT1632(info->ht1632);
  ++animationStepTicker500ms;
  if (allModes[currModeIndex].handlerTick500ms != nullptr) (*(allModes[currModeIndex].handlerTick500ms))(*info);
}

void DisplayInternal::displayTick1sec() {
  ++animationStepTicker1sec;
  if (allModes[currModeIndex].handlerTick1Sec != nullptr) (*(allModes[currModeIndex].handlerTick1Sec))(*info);
  // updateMotionDetectedPixel(*info);
  updateDim(*info);
}

void DisplayInternal::displayTick5sec() {
  ++animationStepTicker5sec;
  if (allModes[currModeIndex].handlerTick5Sec != nullptr) (*(allModes[currModeIndex].handlerTick5Sec))(*info);
}

void DisplayInternal::displayTick10sec() {
  ++animationStepTicker10sec;
  if (allModes[currModeIndex].handlerTick10Sec != nullptr) (*(allModes[currModeIndex].handlerTick10Sec))(*info);
}

void DisplayInternal::displayTick25sec() {
  if (allModes[currModeIndex].handlerTick25Sec != nullptr) (*(allModes[currModeIndex].handlerTick25Sec))(*info);
}

void DisplayInternal::displayTick1min() {
  if (allModes[currModeIndex].handlerTick1Min != nullptr) (*(allModes[currModeIndex].handlerTick1Min))(*info);
}

void DisplayInternal::doHandleMsgModePost(const StringMap& postValues) {
  initModeMessageData(0 /*currX*/, 5 /*currY*/, true /*incrementX*/, false /*incrementY*/,
		      0 /*confetti*/, false /*blink*/, font5x4 /*font*/, 60 /*timeout*/);

  for (auto& kvp : postValues) {
    const std::string& k = kvp.first;
    const std::string& v = kvp.second;
    const char* const key = k.c_str();
    const char* const value = v.c_str();

    if (strncasecmp(key, "msg", strlen(key)) == 0) {
      if (strncasecmp(value, "#cookie", 7) == 0) {
        if (value[7] == 0) {
          modeMessageData.modeMsgsIndex = (ModeMsgsIndex) getRandomNumber(modeMsgsIndexLast);
        } else {
          modeMessageData.modeMsgsIndex = (ModeMsgsIndex) strtoul(&value[7], NULL, 10);
        }
        // nitpick: skip 0
        if (modeMessageData.modeMsgsIndex == modeMsgsIndexBoot) modeMessageData.modeMsgsIndex = modeMsgsIndexFortunate1;
      } else if (strncasecmp(value, msgDictPrefix, msgDictPrefixLen) == 0 && value[msgDictPrefixLen] != 0) {
        const std::string dictValue(lookupDictValue(*info, value + msgDictPrefixLen));
        strncpy(modeMessageData.msg, dictValue.c_str(), sizeof(modeMessageData.msg));
      } else {
        strncpy(modeMessageData.msg, value, sizeof(modeMessageData.msg));
      }
    } else if (strncasecmp(key, "x", strlen(key)) == 0) {
      modeMessageData.currX = strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "y", strlen(key)) == 0) {
      modeMessageData.currYFactor = strtoul(value, NULL, 10) * INCREMENT_Y_SCALE;
    } else if (strncasecmp(key, "font", strlen(key)) == 0) {
      modeMessageData.font = (Font) strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "alternateFont", strlen(key)) == 0) {
      modeMessageData.alternateFont = parseBooleanValue(value);
    } else if (strncasecmp(key, "confetti", strlen(key)) == 0) {
      modeMessageData.confetti = strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "bounce", strlen(key)) == 0) {
      modeMessageData.incrementY = parseBooleanValue(value) ? INCREMENT_Y_VALUE : 0;
    } else if (strncasecmp(key, "noScroll", strlen(key)) == 0) {
      modeMessageData.incrementX = parseBooleanValue(value) ? false : true;
    } else if (strncasecmp(key, "blink", strlen(key)) == 0) {
      modeMessageData.blink = parseBooleanValue(value);
    } else if (strncasecmp(key, "color", strlen(key)) == 0) {
      modeMessageData.displayColor = (DisplayColor) strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "repeats", strlen(key)) == 0) {
	modeMessageData.repeats = strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "timeout", strlen(key)) == 0) {
      modeMessageData.timeout = strtoul(value, NULL, 10);
    }
  } // for
  changeDisplayMode(displayModeMessage, *info);
}

void DisplayInternal::doHandleImgBackgroundPost(const StringMap& postValues) {
  int backgroundImgIndex = 0;
  BackgroundImg img;

  memset(&img, 0, sizeof(img));
  for (auto& kvp : postValues) {
    const std::string& k = kvp.first;
    const std::string& v = kvp.second;
    const char* const key = k.c_str();
    const char* const value = v.c_str();

    if (strncasecmp(key, "index", strlen(key)) == 0) {
      backgroundImgIndex = strtoul(value, NULL, 10);
      if (backgroundImgIndex < 0 || backgroundImgIndex >= BACKGROUND_IMG_COUNT) {
	backgroundImgIndex = 0;
      }
    } else if (strncasecmp(key, "enabled", strlen(key)) == 0) {
      img.enabled = parseBooleanValue(value);
    } else if (strncasecmp(key, "clearAll", strlen(key)) == 0) {
      if (parseBooleanValue(value)) {
	for (int i=0; i < BACKGROUND_IMG_COUNT; ++i) initBackgroundImg(i);
      }
    } else if (strncasecmp(key, "imgArt", strlen(key)) == 0) {
      img.imgArt = (ImgArt) strtoul(value, NULL, 10);
      if (img.imgArt < 0 || img.imgArt >= imgArtLast) {
	img.imgArt = (ImgArt) 0;
      }
    } else if (strncasecmp(key, "x", strlen(key)) == 0) {
      img.x = strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "y", strlen(key)) == 0) {
      img.y = strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "color", strlen(key)) == 0) {
      img.displayColor = (DisplayColor) strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "animationStep", strlen(key)) == 0) {
      img.animation.animationStep = (AnimationStep) strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "animationPhase", strlen(key)) == 0) {
      img.animation.animationStepPhase = (uint8_t) strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "animationPhaseValue", strlen(key)) == 0) {
      img.animation.animationStepPhaseValue = (uint8_t) strtoul(value, NULL, 10);
    }
  } // for

  backgroundImg[backgroundImgIndex] = img;
}

void DisplayInternal::doHandleMsgBackgroundPost(const StringMap& postValues) {
  int msgIndex = 0;
  BackgroundMessage msg;

  memset(&msg, 0, sizeof(msg));
  for (auto& kvp : postValues) {
    const std::string& k = kvp.first;
    const std::string& v = kvp.second;
    const char* const key = k.c_str();
    const char* const value = v.c_str();

    if (strncasecmp(key, "index", strlen(key)) == 0) {
      msgIndex = strtoul(value, NULL, 10);
      if (msgIndex < 0 || msgIndex >= BACKGROUND_MESSAGE_COUNT) {
	msgIndex = 0;
      }
    } else if (strncasecmp(key, "msg", strlen(key)) == 0) {
      if (strncasecmp(value, msgDictPrefix, msgDictPrefixLen) == 0 && value[msgDictPrefixLen] != 0) {
        const std::string dictValue(lookupDictValue(*info, value + msgDictPrefixLen));
        strncpy(msg.msg, dictValue.c_str(), sizeof(msg.msg));
      } else {
        strncpy(msg.msg, value, sizeof(msg.msg));
      }
    } else if (strncasecmp(key, "enabled", strlen(key)) == 0) {
      msg.enabled = parseBooleanValue(value);
    } else if (strncasecmp(key, "clearAll", strlen(key)) == 0) {
      if (parseBooleanValue(value)) {
	for (int i=0; i < BACKGROUND_MESSAGE_COUNT; ++i) initBackgroundMessage(i);
      }
    } else if (strncasecmp(key, "font", strlen(key)) == 0) {
      msg.font = (Font) strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "x", strlen(key)) == 0) {
      msg.x = strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "y", strlen(key)) == 0) {
      msg.y = strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "color", strlen(key)) == 0) {
      msg.displayColor = (DisplayColor) strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "animationStep", strlen(key)) == 0) {
      msg.animation.animationStep = (AnimationStep) strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "animationPhase", strlen(key)) == 0) {
      msg.animation.animationStepPhase = (uint8_t) strtoul(value, NULL, 10);
    } else if (strncasecmp(key, "animationPhaseValue", strlen(key)) == 0) {
      msg.animation.animationStepPhaseValue = (uint8_t) strtoul(value, NULL, 10);
    }
  } // for

  backgroundMessage[msgIndex] = msg;
}

const char* DisplayInternal::getDisplayModeStr() const {
  return allModes[currModeIndex].displayModeStr;
}

DisplayInternal::DisplayInternal(HT1632Class& ht1632) {
  info = new DisplayInternalInfo(ht1632);
}

DisplayInternal::~DisplayInternal() {
  delete info;
  // info = 0;
}

redpajama_set_name: RedPajamaGithub


text:
> Get callsites from the [V8 stack trace API](https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi)

## Install

```sh
$ npm install --save callsites
```

## Usage

```js
var callsites = require('callsites');

function unicorn() {
	console.log(callsites()[0].getFileName());
	//=> /Users/sindresorhus/dev/callsites/test.js
}

unicorn();
```

## API

Returns an array of callsite objects with the following methods:

- `getThis`: returns the value of this
- `getTypeName`: returns the type of this as a string. This is the name of the function stored in the constructor field of this, if available, otherwise the object's [[Class]] internal property.
- `getFunction`: returns the current function
- `getFunctionName`: returns the name of the current function, typically its name property. If a name property is not available an attempt will be made to try to infer a name from the function's context.
- `getMethodName`: returns the name of the property of this or one of its prototypes that holds the current function
- `getFileName`: if this function was defined in a script returns the name of the script
- `getLineNumber`: if this function was defined in a script returns the current line number
- `getColumnNumber`: if this function was defined in a script returns the current column number
- `getEvalOrigin`: if this function was created using a call to eval returns a CallSite object representing the location where eval was called
- `isToplevel`: is this a toplevel invocation, that is, is this the global object?
- `isEval`: does this call take place in code defined by a call to eval?
- `isNative`: is this call in native V8 code?
- `isConstructor`: is this a constructor call?

## License

MIT © [Sindre Sorhus](http://sindresorhus.com)


text:
iris.ui(function (self) {

	self.settings({
		id : null
	});

	var todos = iris.resource(iris.path.resource);

	self.create = function() {

		self.tmplMode(self.APPEND);
		self.tmpl(iris.path.todo.html);

		self.get("check").on("click", function () {
			todos.toggle(self.setting("id"));
		});

		self.get("destroy").on("click", function () {
			todos.remove(self.setting("id"));
		});

		self.get().on("dblclick", function () {
			self.get().addClass("editing");
			self.get("text").select();
		});

		self.get("text").on("blur change", function (e) {
			if ( !self.get().hasClass("editing") ) {
				return;
			}

			self.get().removeClass("editing");
			if ( this.value.trim() !== "" ) {
				todos.edit(self.setting("id"), this.value);
			}

		});

		self.on(todos.DESTROY_TODO, function (id) {
			if (self.setting("id") === id) {
				self.destroyUI();
			}
		});

		self.on(todos.CHANGE_TODO, function (id) {
			if (self.setting("id") === id) {
				self.render();
			}
		});
	};

	self.render = function () {
		var todo = todos.getTodo(self.setting("id"));
		self.get().toggleClass("completed", todo.completed);
		self.inflate({todo: todo});
		return self;
	};

	self.show = function () {
		self.get().hide().fadeIn("slow");
		return self;
	};

},iris.path.todo.js);


text:
'use strict';
// Tests for cli parser.
const { expect } = require('chai');
const Cli = require('../app/cli');
// Default options
const opts = {
  options: [
    ['-t, --test', 'Test'],
    ['r, --real', 'Real']
  ],
  parseropts: { script: 'cli.js' },
  argv: ['node', 'cli.js', '--test']
};

describe('Cli parser tests', () => {

  describe('constructor()', () => {
    it('should check the cli parser has the correct properties', (done) => {
      const cli = new Cli(
        opts.options,
        opts.parseropts,
        opts.argv
      );
      // Checks
      expect(cli.options).to.be.a('array');
      expect(cli.options).to.include(
        { short: '-t', long: '--test', help: 'Test' }
      );
      expect(cli.argv).to.be.a('array');
      expect(cli.argv).to.include(
        opts.argv[2]
      );
      expect(cli.parserOptions).to.be.a('object');
      expect(cli.parserOptions).to.eql(opts.parseropts);
      expect(cli.commands).to.be.a('array');
      expect(cli.commands).to.eql([]);
      expect(cli.usageString).to.be.a('string');
      expect(cli.usageString).to.equal('[options]');
      done();
    });

    it('should check that argv is set correctly if no options object is specified.', (done) => {
      const cli = new Cli(
        opts.options,
        opts.argv
      );
      expect(cli.options).to.be.a('array');
      expect(cli.options).to.include(
        { short: '-t', long: '--test', help: 'Test' }
      );
      expect(cli.parserOptions).to.be.a('object');
      expect(cli.parserOptions).to.not.eql(opts.parseropts);
      expect(cli.parserOptions).to.eql({});
      done();
    });

    it('should check that cli.script is set correctly on a windows system', (done) => {
      const cli = new Cli(
        opts.options,
        { script: 'C:\\bedel\\cli.js', platform: 'win32' },
        opts.argv
      );
      expect(cli.script).to.equal('cli.js');
      done();
    });

    it('should check that cli.script is set correctly on a non-windows system', (done) => {
      const cli = new Cli(
        opts.options,
        { script: '/bedel/cli.js',  platform: 'Linux' },
        opts.argv
      );
      expect(cli.script).to.equal('cli.js');
      done();
    });
  });

  describe('_findCommand()', () => {
    it('should find the correct command to run', (done) => {
      const cli = new Cli(
        opts.options,
        opts.parseropts,
        ['node', 'cli.js', 'test']
      );
      // Add
      cli.command('test', 'Test', () => {});
      const result = cli._findCommand();
      expect(result).to.be.a('object');
      expect(result).to.eql({
        cmd: 'test',
        index: 0
      });
      done();
    });
  });

  describe('_genoptions()', () => {
    it('should generate our options when we run cli._genoptions()', (done) => {
      expect(
        Cli.prototype._genoptions(opts.options)
      ).to.include(
        { short: '-t', long: '--test', help: 'Test' }
      );
      done();
    });

    it('should return a normal set of options when we pass in a set of options with no args', (done) => {
      const result = Cli.prototype._genoptions([['-t, --test', 'Help']]);
      expect(result[0]).to.have.property('short', '-t');
      expect(result[0]).to.have.property('long', '--test');
      expect(result[0]).to.have.property('help', 'Help');
      expect(result[0]).to.not.have.property('hasArg');
      done();
    });

    it('should return an options with no \'short\' property', (done) => {
      const result = Cli.prototype._genoptions([['--test', 'Help']]);
      expect(result[0]).to.have.property('short', null);
      expect(result[0]).to.have.property('long', '--test');
      expect(result[0]).to.have.property('help', 'Help');
      expect(result[0]).to.not.have.property('hasArg');
      done();
    });

    it('should check that options has property \'hasArg\' set to true if option has an argument', (done) => {
      const result = Cli.prototype._genoptions([['-b, --two <arg>', 'Test with arg']]);
      expect(result).to.include(
        { short: '-b', long: '--two', help: 'Test with arg', hasArg: true }
      );
      expect(result[0]).to.have.property('hasArg', true);
      done();
    });

    it('should throw a syntax error when we only have a < and no >', (done) => {
      expect( () => {
        Cli.prototype._genoptions([
          [ '-s, --syntax <error', 'test' ]
        ]);
      }).to.throw(SyntaxError, `Unmatched < or > in args config of option '-s, --syntax <error'!`);
      done();
    });

    it('should throw a syntax error when we only have a short option and no long one', (done) => {
      expect( () => {
        Cli.prototype._genoptions([
          [ '-s', 'syntax error' ]
        ]);
      }).to.throw(SyntaxError, `Short options (-x) must have a long option (--x) to go with them (option: '-s')!`);
      done();
    });
  });

  describe('_maxOptLength()', () => {
    it('should get the maximum option\'s length when we give a long & short arg as cli.options', (done) => {
      const cli = new Cli(
        opts.options,
        opts.parseropts,
        opts.argv
      );
      const result = cli._maxOptLength();
      expect(result).to.be.a('number');
      expect(result).to.equal(10);
      done();
    });
    it('should get the maximum option\'s length when we give just a long arg as cli.options', (done) => {
      const cli = new Cli(
        [['--test', 'Test']],
        opts.parseropts,
        opts.argv
      );
      const result = cli._maxOptLength();
      expect(result).to.be.a('number');
      expect(result).to.equal(6);
      done();
    });
  });

  describe('_parse()', () => {
    it('shoukd return the object { test: true, real: false }', (done) => {
      const result = Cli.prototype._parse(
        opts.argv,
        Cli.prototype._genoptions(opts.options)
      );
      expect(result).to.be.a('object');
      expect(result).to.eql({
        test: true,
        real: false
      });
      done();
    });

    it('should make sure [ --test <arg> ] comes out as { test: "<arg>" }', (done) => {
      const arg = 'test';
      const result = Cli.prototype._parse(
        Array.concat(opts.argv, [ arg ]),
        Cli.prototype._genoptions([
          ['-t, --test <arg>', 'Test']
        ])
      );
      expect(result).to.be.a('object');
      expect(result).to.eql({
        test: arg
      });
      done();
    });

    it('shoukd parse a small option (-t)', (done) => {
      const result = Cli.prototype._parse(
        ['node', 'cli.js', '-t'],
        Cli.prototype._genoptions(opts.options)
      );
      expect(result).to.be.a('object');
      expect(result).to.eql({
        test: true,
        real: false
      });
      done();
    });

    it('shoukd parse a long option (--test)', (done) => {
      const result = Cli.prototype._parse(
        ['node', 'cli.js', '--test'],
        Cli.prototype._genoptions(opts.options)
      );
      expect(result).to.be.a('object');
      expect(result).to.eql({
        test: true,
        real: false
      });
      done();
    });

    it('should parse a short option with a arg (-t <arg>)', (done) => {
      const arg = 'test';
      const result = Cli.prototype._parse(
        ['node', 'cli.js', '-t', arg],
        Cli.prototype._genoptions([
          ['-t, --test <arg>', 'Test']
        ])
      );
      expect(result).to.be.a('object');
      expect(result).to.eql({
        test: arg
      });
      done();
    });

    it('should parse a long option with a arg (--test <arg>)', (done) => {
      const arg = 'test';
      const result = Cli.prototype._parse(
        ['node', 'cli.js', '--test', arg],
        Cli.prototype._genoptions([
          ['-t, --test <arg>', 'Test']
        ])
      );
      expect(result).to.be.a('object');
      expect(result).to.eql({
        test: arg
      });
      done();
    });
  });

  describe('command()', () => {
    it('should add a command when ran', (done) => {
      const cli = new Cli(
        opts.options,
        opts.parseropts,
        opts.argv
      );
      cli.command('test', 'Test', () => {});
      expect(cli.commands[0]).to.have.property('name', 'test');
      expect(cli.commands[0]).to.have.property('help', 'Test');
      expect(cli.commands[0]).to.have.property('handle');
      expect(cli.commands[0].handle).to.be.a('function');
      done();
    });
  });

  describe('parse()', () => {
    it('should run cli.help() if --help is supplied', (done) => {
      const cli = new Cli(
        opts.options,
        opts.parseropts,
        ['node', 'cli.js', '--help']
      );
      cli.help = done;
      cli.parse();
    });

    it('should run cli.help() if no options are supplied', (done) => {
      const cli = new Cli(
        opts.options,
        opts.parseropts,
        ['node', 'cli.js']
      );
      cli.help = done;
      cli.parse();
    });

    it('should return cli._parse() when no command is passed', (done) => {
      const cli = new Cli(
        opts.options,
        opts.parseropts,
        opts.argv
      );
      expect(cli.parse()).to.deep.equal(cli._parse(cli.argv, cli.options));
      done();
    });

    it('should run a command if it is passed in the args array', (done) => {
      const cli = new Cli(
        opts.options,
        opts.parseropts,
        ['node', 'cli.js', 'test', '--test']
      );
      cli.command('test', 'Test', () => done());
      cli.parse();
    });
  });

  describe('usage()', () => {
    it('should set the usage when ran', (done) => {
      const cli = new Cli(
        opts.options,
        opts.parseropts,
        opts.argv
      );
      cli.usage('[test]');
      expect(cli.usageString).to.be.a('string');
      expect(cli.usageString).to.equal('[test]');
      done();
    });
  });

});


text:
package com.exercise.spring.di.autoconfig.soundsystem;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class CDPlayerConfig {
}


text:
static NSString *const kPlainTextContentType = @"text/plain";

@implementation JSONResponseDeserializer

#pragma mark - Initialization

- (instancetype)init {
    self = [super init];
    if (self) {
        NSMutableSet *contentTypes = [self.acceptableContentTypes mutableCopy];
        [contentTypes addObject:kPlainTextContentType];
        self.acceptableContentTypes = [contentTypes copy];
    }
    return self;
}

#pragma mark - RCFResponseDeserializer

- (void)deserializeServerResponse:(NSData *)responseData
                  completionBlock:(RCFResponseDeserializerCompletionBlock)block {
    NSAssert(block, @"Block shouldn't be nil");
    NSError *error;
    NSDictionary *deserializedResponse = [super responseObjectForResponse:nil
                                                                     data:responseData
                                                                    error:&error];
    block(deserializedResponse, error);
}

#pragma mark - Debug Description

- (NSString *)debugDescription {
    return NSStringFromClass([self class]);
}

@end


text:
heading_title = Order Statuses

action_heading_new_order_status = New Order Status
action_heading_batch_delete_order_statuses = Batch Delete Order Statuses

table_heading_order_statuses = Order Statuses
table_heading_action = Action

field_name = Name:
field_set_as_default = Set as Default?

introduction_new_order_status = Please fill in the following information for the new order status.

introduction_edit_order_status = Please make the necessary changes for this order status.

introduction_delete_order_status = Please verify the removal of this order status.
delete_error_order_status_prohibited = Error: The default order status cannot be removed. Please set another order status as the default status and try again.
delete_error_order_status_in_use = Error: This order status is currently assigned to %s orders and cannot be removed.
delete_error_order_status_used = Error: This order status has been used by %s orders and cannot be removed.

introduction_batch_delete_order_statuses = Please verify the removal of the following order statuses.
batch_delete_error_order_status_prohibited = Error: The default order status cannot be removed. Please set another order status as the default status and try again.
batch_delete_error_order_status_in_use = Error: One or more order statuses are currently assigned to orders and cannot be removed.
batch_delete_error_order_status_used = Error: One or more order statuses have been used in orders and cannot be removed.


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Mycologia 85(3): 522 (1993)

#### Original name
Kutilakesa pironii Alfieri

### Remarks
null


text:
package ai.elimu.dao.jpa;

import ai.elimu.model.contributor.ImageContributionEvent;
import ai.elimu.dao.ImageContributionEventDao;
import ai.elimu.model.content.multimedia.Image;
import ai.elimu.model.contributor.Contributor;
import java.util.List;
import org.springframework.dao.DataAccessException;

public class ImageContributionEventDaoJpa extends GenericDaoJpa<ImageContributionEvent> implements ImageContributionEventDao {

    @Override
    public List<ImageContributionEvent> readAll(Image image) throws DataAccessException {
        return em.createQuery(
            "SELECT ice " +
            "FROM ImageContributionEvent ice " +
            "WHERE ice.image = :image " +
            "ORDER BY ice.time DESC")
            .setParameter("image", image)
            .getResultList();
    }

    @Override
    public List<ImageContributionEvent> readAll(Contributor contributor) throws DataAccessException {
        return em.createQuery(
            "SELECT ice " +
            "FROM ImageContributionEvent ice " +
            "WHERE ice.contributor = :contributor " +
            "ORDER BY ice.time DESC")
            .setParameter("contributor", contributor)
            .getResultList();
    }

    @Override
    public List<ImageContributionEvent> readMostRecent(int maxResults) throws DataAccessException {
        return em.createQuery(
            "SELECT ice " +
            "FROM ImageContributionEvent ice " +
            "ORDER BY ice.time DESC")
            .setMaxResults(maxResults)
            .getResultList();
    }

    @Override
    public Long readCount(Contributor contributor) throws DataAccessException {
        return (Long) em.createQuery("SELECT COUNT(ice) " +
                "FROM ImageContributionEvent ice " +
                "WHERE ice.contributor = :contributor")
                .setParameter("contributor", contributor)
                .getSingleResult();
    }
}


text:
////////////////////////////////////////////////////////////////////////////////
// Module Name:  main.cpp
// Authors:      Nikita Marinosyan, Leonid Dworzanski, Sergey Shershakov
// Date:         06.02.2017
// Copyright (c) The Team of "Algorithms and Data Structures" 2014–2017.
//
// This is a part of the course "Algorithms and Data Structures"
// provided by  the School of Software Engineering of the Faculty
// of Computer Science at the Higher School of Economics.
////////////////////////////////////////////////////////////////////////////////

#include <fstream>
#include <iostream>
//#include <string>
//#include <cstdlib>

//#include "linked_list.h"
#include "dna_element.h"
#include "linked_list.h"

using namespace std;

// TODO: укажите здесь абсолютный путь к файлу с кусочками ДНК для восстановления
static const char* INP_FILENAME = "res/test1";

using namespace xi;

int main (int argc, char* argv[])
{
    /*try{
        DNARepairer dnarepairer;

        dnarepairer.readFile(INP_FILENAME);

        cout << "Broken DNAs" << endl;
        dnarepairer.printDNAStorage();

        dnarepairer.repairDNA();

        cout << "\nGood as it is" << endl;
        dnarepairer.printDNAStorage();
    }
    catch(exception &e) {
        cout << e.what();
    }
    catch (...){
        cout << "Something wrong happend." << endl;
    }
    cout << endl;

    */;
    DNAElement* element = new DNAElement();
    cout << (char)element->base;

    LinkedList<int> mylist {};
    int data[] = {0, 1, 2, 3, 4, 5};
    mylist.addElementToEnd(data[0]);
    mylist.addElementToEnd(data[1]);
    mylist.addElementToEnd(data[2]);
    mylist.addElementToEnd(data[3]);
    mylist.addElementToEnd(data[4]);
    mylist.addElementToEnd(data[5]);
    LinkedList<int> other {mylist};
    other.deleteNodes(other.getPreHead(), other.getPreHead()->next);
    other.deleteNodes(other.getPreHead(), other.getPreHead()->next->next);

    LinkedList<int> blabla{};
    blabla.addElementToEnd(data[5]);
    //printLinkedList(blabla, "New small list. BLABLA");
    blabla = other;
    //printLinkedList(blabla, "After Copy assignement = from other. BLABLA");
    //printLinkedList(other, "Doing a copy assignement from here. OTHER");
    blabla.moveNodeToEnd(mylist.getPreHead()->next);
    //printLinkedList(blabla, "After adding one element to blabla from mylist, should be = 1");
    blabla.moveNodesAfter(other.getPreHead()->next->next, blabla.getPreHead()->next, blabla.getPreHead()->next->next->next);
    //printLinkedList(blabla, "After moved some nodes from blabla into other. BLABLA");
    //printLinkedList(other, "After moved some nodes from blabla into other. OTHER");
    blabla.moveNodesToEnd(other.getPreHead(), other.getLastNode());
    //printLinkedList(blabla, "After moving all nodes from other to blabla's end. BLABLA");
    //printLinkedList(other, "After moving all nodes from other to blabla's end. OTHER");
    //printLinkedList(mylist, "Almost unchanged. MYLIST");

    cout << mylist[0] << endl;
    cout<< mylist[1] << endl;
 cout<< mylist[2] << endl;
    cout<< "Size: "<< mylist.size() << endl;
    cout<< mylist[ mylist.size() - 1] << endl;

    cout << other.getPreHead()->value << mylist.getPreHead()->value << blabla.getPreHead()->value;
    return EXIT_SUCCESS;
}


text:
class CreateFaGroups < ActiveRecord::Migration
  def self.up
    create_table :fa_groups do |t|
      t.string      :name
      t.text        :desc
      t.integer     :cce_exam_category_id
      t.timestamps
    end
  end

  def self.down
    drop_table :fa_groups
  end
end


text:
package org.apache.karaf.shell.obr;

import java.io.*;
import java.util.List;
import java.util.Properties;

import org.apache.felix.bundlerepository.Reason;
import org.apache.felix.bundlerepository.Repository;
import org.apache.felix.bundlerepository.RepositoryAdmin;
import org.apache.felix.bundlerepository.Requirement;
import org.apache.felix.bundlerepository.Resolver;
import org.apache.felix.bundlerepository.Resource;
import org.apache.karaf.shell.console.OsgiCommandSupport;
import org.osgi.framework.Bundle;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.Version;

public abstract class ObrCommandSupport extends OsgiCommandSupport {

    protected static final char VERSION_DELIM = ',';

    protected Object doExecute() throws Exception {
        // Get repository admin service.
        ServiceReference ref = getBundleContext().getServiceReference(RepositoryAdmin.class.getName());
        if (ref == null) {
            System.out.println("RepositoryAdmin service is unavailable.");
            return null;
        }
        try {
            RepositoryAdmin admin = (RepositoryAdmin) getBundleContext().getService(ref);
            if (admin == null) {
                System.out.println("RepositoryAdmin service is unavailable.");
                return null;
            }

            doExecute(admin);
        }
        finally {
            getBundleContext().ungetService(ref);
        }
        return null;
    }

    protected abstract void doExecute(RepositoryAdmin admin) throws Exception;

    protected Resource[] searchRepository(RepositoryAdmin admin, String targetId, String targetVersion) throws InvalidSyntaxException
    {
        // Try to see if the targetId is a bundle ID.
        try
        {
            Bundle bundle = getBundleContext().getBundle(Long.parseLong(targetId));
            targetId = bundle.getSymbolicName();
        }
        catch (NumberFormatException ex)
        {
            // It was not a number, so ignore.
        }

        // The targetId may be a bundle name or a bundle symbolic name,
        // so create the appropriate LDAP query.
        StringBuffer sb = new StringBuffer("(|(presentationname=");
        sb.append(targetId);
        sb.append(")(symbolicname=");
        sb.append(targetId);
        sb.append("))");
        if (targetVersion != null)
        {
            sb.insert(0, "(&");
            sb.append("(version=");
            sb.append(targetVersion);
            sb.append("))");
        }
        return admin.discoverResources(sb.toString());
    }

    public Resource selectNewestVersion(Resource[] resources)
    {
        int idx = -1;
        Version v = null;
        for (int i = 0; (resources != null) && (i < resources.length); i++)
        {
            if (i == 0)
            {
                idx = 0;
                v = resources[i].getVersion();
            }
            else
            {
                Version vtmp = resources[i].getVersion();
                if (vtmp.compareTo(v) > 0)
                {
                    idx = i;
                    v = vtmp;
                }
            }
        }
        return (idx < 0) ? null : resources[idx];
    }

    protected String[] getTarget(String bundle) {
        String[] target;
        int idx = bundle.indexOf(VERSION_DELIM);
        if (idx > 0) {
            target = new String[] { bundle.substring(0, idx), bundle.substring(idx+1) };
        }
        else
        {
            target = new String[] { bundle, null };
        }
        return target;
    }

    protected void printUnderline(PrintStream out, int length)
    {
        for (int i = 0; i < length; i++)
        {
            out.print('-');
        }
        out.println("");
    }

    protected void doDeploy(RepositoryAdmin admin, List<String> bundles, boolean start) throws Exception {
        Resolver resolver = admin.resolver();
        for (String bundle : bundles) {
            String[] target = getTarget(bundle);
            Resource resource = selectNewestVersion(searchRepository(admin, target[0], target[1]));
            if (resource != null)
            {
                resolver.add(resource);
            }
            else
            {
                System.err.println("Unknown bundle - " + target[0]);
            }
        }
        if ((resolver.getAddedResources() != null) &&
            (resolver.getAddedResources().length > 0))
        {
            if (resolver.resolve())
            {
                System.out.println("Target resource(s):");
                printUnderline(System.out, 19);
                Resource[] resources = resolver.getAddedResources();
                for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
                {
                    System.out.println("   " + resources[resIdx].getPresentationName()
                        + " (" + resources[resIdx].getVersion() + ")");
                }
                resources = resolver.getRequiredResources();
                if ((resources != null) && (resources.length > 0))
                {
                    System.out.println("\nRequired resource(s):");
                    printUnderline(System.out, 21);
                    for (int resIdx = 0; resIdx < resources.length; resIdx++)
                    {
                        System.out.println("   " + resources[resIdx].getPresentationName()
                            + " (" + resources[resIdx].getVersion() + ")");
                    }
                }
                resources = resolver.getOptionalResources();
                if ((resources != null) && (resources.length > 0))
                {
                    System.out.println("\nOptional resource(s):");
                    printUnderline(System.out, 21);
                    for (int resIdx = 0; resIdx < resources.length; resIdx++)
                    {
                        System.out.println("   " + resources[resIdx].getPresentationName()
                            + " (" + resources[resIdx].getVersion() + ")");
                    }
                }

                try
                {
                    System.out.print("\nDeploying...");
                    resolver.deploy(start ? Resolver.START : 0);
                    System.out.println("done.");
                }
                catch (IllegalStateException ex)
                {
                    System.err.println(ex);
                }
            }
            else
            {
                Reason[] reqs = resolver.getUnsatisfiedRequirements();
                if ((reqs != null) && (reqs.length > 0))
                {
                    System.out.println("Unsatisfied requirement(s):");
                    printUnderline(System.out, 27);
                    for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++)
                    {
                        System.out.println("   " + reqs[reqIdx].getRequirement().getFilter());
                        System.out.println("      " + reqs[reqIdx].getResource().getPresentationName());
                    }
                }
                else
                {
                    System.out.println("Could not resolve targets.");
                }
            }
        }

    }

    protected Requirement parseRequirement(RepositoryAdmin admin, String req) throws InvalidSyntaxException {
        int p = req.indexOf(':');
        String name;
        String filter;
        if (p > 0) {
            name = req.substring(0, p);
            filter = req.substring(p + 1);
        } else {
            if (req.contains("package")) {
                name = "package";
            } else if (req.contains("service")) {
                name = "service";
            } else {
                name = "bundle";
            }
            filter = req;
        }
        if (!filter.startsWith("(")) {
            filter = "(" + filter + ")";
        }
        return admin.getHelper().requirement(name, filter);
    }

    protected Requirement[] parseRequirements(RepositoryAdmin admin, List<String> requirements) throws InvalidSyntaxException {
        Requirement[] reqs = new Requirement[requirements.size()];
        for (int i = 0; i < reqs.length; i++) {
            reqs[i] = parseRequirement(admin, requirements.get(i));
        }
        return reqs;
    }

    public static final String REPOSITORY_URL_PROP = "obr.repository.url";

    protected void persistRepositoryList(RepositoryAdmin admin) {
        try {
            StringBuilder sb = new StringBuilder();
            for (Repository repo : admin.listRepositories()) {
                if (sb.length() > 0) {
                    sb.append(" ");
                }
                sb.append(repo.getURI());
            }
            File base = new File(System.getProperty("karaf.base"));
            File sys = new File(base, "etc/config.properties");
            File sysTmp = new File(base, "etc/config.properties.tmp");

            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(sysTmp)));
            boolean modified = false;
            try {
                if (sys.exists()) {
                    BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(sys)));
                    try {
                        String line = reader.readLine();
                        while (line != null) {
                            if (line.matches("obr\\.repository\\.url[:= ].*")) {
                                modified = true;
                                line = "obr.repository.url = " + sb.toString();
                            }
                            writer.write(line);
                            writer.newLine();
                            line = reader.readLine();
                        }
                    } finally {
                        reader.close();
                    }
                }
                if (!modified) {
                    writer.newLine();
                    writer.write("# ");
                    writer.newLine();
                    writer.write("# OBR Repository list");
                    writer.newLine();
                    writer.write("# ");
                    writer.newLine();
                    writer.write("obr.repository.url = " + sb.toString());
                    writer.newLine();
                    writer.newLine();
                }
            } finally {
                writer.close();
            }

            sys.delete();
            sysTmp.renameTo(sys);

        } catch (Exception e) {
            System.err.println("Error while persisting repository list");
        }
    }

}


text:
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">

NCGA: Summary Info for Representative Verla Insko (D) - District 56

Sponsored Bills (20 total)

Bill Keywords

Co-Sponsors


text:
using ISimpleHttpServer.Model;
using ISocketLite.PCL.Interface;

namespace SimpleHttpServer.Model.Base
{
    public abstract class ParseControlBase : IParseControl
    {
        public RequestType RequestType { get; internal set; }
        public ITcpSocketClient TcpSocketClient { get; internal set; }

        public bool IsEndOfRequest { get; internal set; }

        public bool IsRequestTimedOut { get; internal set; } = false;

        public bool IsUnableToParseHttp { get; internal set; } = false;

        public string RemoteAddress { get; internal set; }

        public int RemotePort { get; internal set; }

        protected ParseControlBase() { }

    }
}


text:
namespace disccord
{
    namespace models
    {
        guild::guild()
            : entity(), name(""), region(""), icon(), splash(), owner_id(0),
            afk_channel_id(), embed_channel_id(), afk_timeout(0),
            mfa_level(0), verification_level(0),
            default_message_notifications(0), embed_enabled(false),
            features(), roles(), emojis(), members(), channels(), presences()
        { }

        guild::~guild()
        { }

        void guild::decode(web::json::value json)
        {
            entity::decode(json);

            #define get_field(var, conv) \
                if (json.has_field(#var)) { \
                    auto field = json.at(#var); \
                    if (!field.is_null()) { \
                        var = decltype(var)(field.conv()); \
                    } else { \
                        var = decltype(var)::no_value(); \
                    } \
                } else { \
                    var = decltype(var)(); \
                }
            #define get_id_field(var) \
                if (json.has_field(#var)) { \
                    auto field = json.at(#var); \
                    if (!field.is_null()) { \
                        var = decltype(var)(std::stoull(field.as_string())); \
                    } else { \
                        var = decltype(var)::no_value(); \
                    } \
                } else { \
                    var = decltype(var)(); \
                }
            #define get_composite_field_vector(var, type) \
                if (json.has_field(#var)) { \
                    auto _fields_array = json.at(#var).as_array(); \
                    std::vector<type> fields_array(_fields_array.size()); \
                    std::transform(_fields_array.begin(), \
                    _fields_array.end(), fields_array.begin(), \
                    [](web::json::value _field){ \
                        type field; \
                        field.decode(_field); \
                        return field; \
                    }); \
                    var = decltype(var)(fields_array); \
                } else { \
                    var = decltype(var)(); \
                }

            name = json.at("name").as_string();
            get_field(icon, as_string);
            get_field(splash, as_string);
            owner_id = std::stoull(json.at("owner_id").as_string());
            region = json.at("region").as_string();
            get_id_field(afk_channel_id);
            afk_timeout = json.at("afk_timeout").as_integer();
            mfa_level = json.at("mfa_level").as_integer();
            verification_level = json.at("verification_level").as_integer();
            default_message_notifications =
                json.at("default_message_notifications").as_integer();
            embed_enabled = json.at("embed_enabled").as_bool();
            get_id_field(embed_channel_id);
            get_composite_field_vector(roles, role);
            get_composite_field_vector(emojis, emoji);
            get_composite_field_vector(members, guild_member);
            get_composite_field_vector(channels, channel);
            get_composite_field_vector(presences, presence);

            if (json.has_field("features"))
            {
                auto _features_array = json.at("features").as_array();
                std::vector<std::string>
                    features_array(_features_array.size());
                std::transform(_features_array.begin(),
                               _features_array.end(),
                               features_array.begin(),
                               [](web::json::value _feature)
                    {
                        return _feature.as_string();
                    });
                features = features_array;
            }

            #undef get_field
            #undef get_id_field
            #undef get_composite_field_vector
        }

        void guild::encode_to(std::unordered_map<std::string,
                                                 web::json::value> &info)
        {
            entity::encode_to(info);

            info["name"] = web::json::value(get_name());
            if (get_icon().is_specified())
                info["icon"] = get_icon();
            if (get_splash().is_specified())
                info["splash"] = get_splash();
            info["owner_id"] =
                web::json::value::string(std::to_string(get_owner_id()));
            info["region"] = web::json::value(get_region());
            if (get_afk_channel_id().is_specified()) {
                auto afk_ch = std::to_string(get_afk_channel_id().get_value());
                info["afk_channel_id"] = web::json::value(afk_ch);
            }
            info["afk_timeout"] = web::json::value(get_afk_timeout());
            info["mfa_level"] = web::json::value(mfa_level);
            info["verification_level"] = web::json::value(verification_level);
            info["default_message_notifications"] =
                web::json::value(default_message_notifications);
            info["embed_enabled"] = web::json::value(get_embed_enabled());
            if (get_embed_channel_id().is_specified()) {
                auto e_ch = std::to_string(get_embed_channel_id().get_value());
                info["embed_channel_id"] = web::json::value(e_ch);
            }

            {
                auto _features = get_features();
                std::vector<web::json::value> features_array(_features.size());
                std::transform(_features.begin(),
                               _features.end(),
                               features_array.begin(),
                               [](std::string feature)
                    {
                        return web::json::value(feature);
                    });
                info["features"] = web::json::value::array(features_array);
            }

            #define encode_composite_vector(var, type) \
                if (var.is_specified()) { \
                    auto _array = get_##var().get_value(); \
                    std::vector<web::json::value> array(_array.size()); \
                    std::transform(_array.begin(), \
                     _array.end(), array.begin(), \
                    [](type _field){ \
                        return _field.encode(); \
                    }); \
                    info[#var] = web::json::value::array(array); \
                }

            encode_composite_vector(voice_states, voice_state);
            encode_composite_vector(roles, role);
            encode_composite_vector(emojis, emoji);
            encode_composite_vector(members, guild_member);
            encode_composite_vector(channels, channel);
            encode_composite_vector(presences, presence);

            #undef encode_composite_vector
        }

        #define define_get_method(field_name) \
            decltype(guild::field_name) guild::get_##field_name() { \
                return field_name; \
            }

        define_get_method(name)
        define_get_method(icon)
        define_get_method(splash)
        define_get_method(owner_id)
        define_get_method(region)
        define_get_method(afk_channel_id)
        define_get_method(afk_timeout)
        define_get_method(mfa_level)
        define_get_method(verification_level)
        define_get_method(default_message_notifications)
        define_get_method(embed_enabled)
        define_get_method(embed_channel_id)
        define_get_method(voice_states)
        define_get_method(features)
        define_get_method(roles)
        define_get_method(emojis)
        define_get_method(members)
        define_get_method(channels)
        define_get_method(presences)

        #undef define_get_method
    }
}


text:
<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model app\models\sanpham */
/* @var $form yii\widgets\ActiveForm */
?>

    <?php $form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'sanpham_id')->textInput() ?>

    <?= $form->field($model, 'loaisanpham_id')->textInput() ?>

    <?= $form->field($model, 'ten')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'masp')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'mota')->textInput(['maxlength' => true]) ?>

        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>

    <?php ActiveForm::end(); ?>


text:
<!DOCTYPE html>
<!--
Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/ui/base/d3.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/chart_base.html">
<link rel="stylesheet" href="/tracing/ui/base/pie_chart.css">

<script>
'use strict';

tr.exportTo('tr.ui.b', function() {
  var ChartBase = tr.ui.b.ChartBase;
  var getColorOfKey = tr.ui.b.getColorOfKey;

  var MIN_RADIUS = 100;

  /**
   * @constructor
   */
  var PieChart = tr.ui.b.define('pie-chart', ChartBase);

  PieChart.prototype = {
    __proto__: ChartBase.prototype,

    decorate: function() {
      ChartBase.prototype.decorate.call(this);
      this.classList.add('pie-chart');

      this.data_ = undefined;
      this.seriesKeys_ = undefined;

      var chartAreaSel = d3.select(this.chartAreaElement);
      var pieGroupSel = chartAreaSel.append('g')
        .attr('class', 'pie-group');
      this.pieGroup_ = pieGroupSel.node();

      this.pathsGroup_ = pieGroupSel.append('g')
        .attr('class', 'paths')
        .node();
      this.labelsGroup_ = pieGroupSel.append('g')
        .attr('class', 'labels')
        .node();
      this.linesGroup_ = pieGroupSel.append('g')
        .attr('class', 'lines')
        .node();
    },

    get data() {
      return this.data_;
    },

    /**
     * @param {Array} data Data for the chart, where each element in the array
     * must be of the form {label: str, value: number}.
     */
    set data(data) {
      if (data !== undefined) {
        // Figure out the label values in the data set. E.g. from
        //   [{label: 'a', ...}, {label: 'b', ...}]
        // we would commpute ['a', 'y']. These become the series keys.
        var seriesKeys = [];
        var seenSeriesKeys = {};
        data.forEach(function(d) {
          var k = d.label;
          if (seenSeriesKeys[k])
            throw new Error('Label ' + k + ' has been used already');
          seriesKeys.push(k);
          seenSeriesKeys[k] = true;
        }, this);
        this.seriesKeys_ = seriesKeys;
      } else {
        this.seriesKeys_ = undefined;
      }
      this.data_ = data;
      this.updateContents_();
    },

    get margin() {
      var margin = {top: 0, right: 0, bottom: 0, left: 0};
      if (this.chartTitle_)
        margin.top += 40;
      return margin;
    },

    getMinSize: function() {
      this.updateContents_();

      var labelSel = d3.select(this.labelsGroup_).selectAll('.label');
      var maxLabelWidth = -Number.MAX_VALUE;
      var leftTextHeightSum = 0;
      var rightTextHeightSum = 0;
      labelSel.each(function(l) {
        var r = this.getBoundingClientRect();
        maxLabelWidth = Math.max(maxLabelWidth, r.width + 32);
        if (this.style.textAnchor == 'end') {
          leftTextHeightSum += r.height;
        } else {
          rightTextHeightSum += r.height;
        }
      });

      var titleWidth = this.querySelector(
          '#title').getBoundingClientRect().width;
      var margin = this.margin;
      var marginWidth = margin.left + margin.right;
      var marginHeight = margin.top + margin.bottom;
      return {
        width: Math.max(2 * MIN_RADIUS + 2 * maxLabelWidth,
                        titleWidth * 1.1) + marginWidth,
        height: marginHeight + Math.max(2 * MIN_RADIUS,
                                        leftTextHeightSum,
                                        rightTextHeightSum) * 1.25
      };
    },

    getLegendKeys_: function() {
      // This class creates its own legend, instead of using ChartBase.
      return undefined;
    },

    updateScales_: function(width, height) {
      if (this.data_ === undefined)
        return;
    },

    updateContents_: function() {
      ChartBase.prototype.updateContents_.call(this);
      if (!this.data_)
        return;

      var width = this.chartAreaSize.width;
      var height = this.chartAreaSize.height;
      var radius = Math.max(MIN_RADIUS, Math.min(width, height * 0.95) / 2);

      d3.select(this.pieGroup_).attr(
          'transform',
          'translate(' + width / 2 + ',' + height / 2 + ')');

      // Bind the pie layout to its data
      var pieLayout = d3.layout.pie()
        .value(function(d) { return d.value; })
        .sort(null);

      var piePathsSel = d3.select(this.pathsGroup_)
          .datum(this.data_)
          .selectAll('path')
          .data(pieLayout);

      function midAngle(d) {
        return d.startAngle + (d.endAngle - d.startAngle) / 2;
      }

      var pathsArc = d3.svg.arc()
        .innerRadius(0)
        .outerRadius(radius - 30);

      var valueLabelArc = d3.svg.arc()
        .innerRadius(radius - 100)
        .outerRadius(radius - 30);

      var lineBeginArc = d3.svg.arc()
        .innerRadius(radius - 50)
        .outerRadius(radius - 50);

      var lineEndArc = d3.svg.arc()
        .innerRadius(radius)
        .outerRadius(radius);

      // Paths.
      piePathsSel.enter().append('path')
        .attr('class', 'arc')
        .attr('fill', function(d, i) {
            var origData = this.data_[i];
            var highlighted = (origData.label ===
                               this.currentHighlightedLegendKey);
            return getColorOfKey(origData.label, highlighted);
          }.bind(this))
        .attr('d', pathsArc)
        .on('click', function(d, i) {
            var origData = this.data_[i];
            var event = new tr.b.Event('item-click');
            event.data = origData;
            event.index = i;
            this.dispatchEvent(event);
            d3.event.stopPropagation();
          }.bind(this))
        .on('mouseenter', function(d, i) {
            var origData = this.data_[i];
            this.pushTempHighlightedLegendKey(origData.label);
          }.bind(this))
        .on('mouseleave', function(d, i) {
            var origData = this.data_[i];
            this.popTempHighlightedLegendKey(origData.label);
          }.bind(this));

      // Value labels.
      piePathsSel.enter().append('text')
        .attr('class', 'arc-text')
        .attr('transform', function(d) {
            return 'translate(' + valueLabelArc.centroid(d) + ')';
          })
        .attr('dy', '.35em')
        .style('text-anchor', 'middle')
        .text(function(d, i) {
            var origData = this.data_[i];
            if (origData.valueText === undefined)
              return '';

            if (d.endAngle - d.startAngle < 0.4)
              return '';
            return origData.valueText;
          }.bind(this));

      piePathsSel.exit().remove();

      // Labels.
      var labelSel = d3.select(this.labelsGroup_).selectAll('.label')
          .data(pieLayout(this.data_));
      labelSel.enter()
          .append('text')
          .attr('class', 'label')
          .attr('dy', '.35em');

      labelSel.text(function(d) {
        if (d.data.label.length > 40)
          return d.data.label.substr(0, 40) + '...';
        return d.data.label;
      });
      labelSel.attr('transform', function(d) {
        var pos = lineEndArc.centroid(d);
        pos[0] = radius * (midAngle(d) < Math.PI ? 1 : -1);
        return 'translate(' + pos + ')';
      });
      labelSel.style('text-anchor', function(d) {
        return midAngle(d) < Math.PI ? 'start' : 'end';
      });

      // Lines.
      var lineSel = d3.select(this.linesGroup_).selectAll('.line')
          .data(pieLayout(this.data_));
      lineSel.enter()
        .append('polyline')
        .attr('class', 'line')
        .attr('dy', '.35em');
      lineSel.attr('points', function(d) {
        var pos = lineEndArc.centroid(d);
        pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1);
        return [lineBeginArc.centroid(d), lineEndArc.centroid(d), pos];
      });
    },

    updateHighlight_: function() {
      ChartBase.prototype.updateHighlight_.call(this);
      // Update color of pie segments.
      var pathsGroupSel = d3.select(this.pathsGroup_);
      var that = this;
      pathsGroupSel.selectAll('.arc').each(function(d, i) {
        var origData = that.data_[i];
        var highlighted = origData.label == that.currentHighlightedLegendKey;
        var color = getColorOfKey(origData.label, highlighted);
        this.style.fill = color;
      });
    }
  };

  return {
    PieChart: PieChart
  };
});
</script>